mirror of
https://github.com/obra/superpowers.git
synced 2026-07-24 03:04:02 +08:00
Compare commits
4 Commits
exp/contro
...
fix/worktr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f0e2ab912 | ||
|
|
0146173544 | ||
|
|
54d0efefd7 | ||
|
|
55d28ddf10 |
@@ -174,6 +174,29 @@ git worktree remove "$WORKTREE_PATH"
|
|||||||
git worktree prune # Self-healing: clean up any stale registrations
|
git worktree prune # Self-healing: clean up any stale registrations
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**If removal is refused** (`contains modified or untracked files`): the
|
||||||
|
worktree holds files that exist nowhere else — uncommitted plans, notes,
|
||||||
|
or scratch work. Never `--force` on your own initiative. Show your human
|
||||||
|
partner what is at stake and ask:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C "$WORKTREE_PATH" status --porcelain
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
Worktree removal refused — these files were never committed:
|
||||||
|
|
||||||
|
<file list>
|
||||||
|
|
||||||
|
1. Commit them to <branch> before cleanup
|
||||||
|
2. Move them into <main repo root>
|
||||||
|
3. Delete them (unrecoverable)
|
||||||
|
|
||||||
|
Which?
|
||||||
|
```
|
||||||
|
|
||||||
|
Carry out the choice, then remove the worktree.
|
||||||
|
|
||||||
**Otherwise:** The host environment owns this workspace — leave it in
|
**Otherwise:** The host environment owns this workspace — leave it in
|
||||||
place. If your platform provides a workspace-exit tool, use it.
|
place. If your platform provides a workspace-exit tool, use it.
|
||||||
|
|
||||||
@@ -196,6 +219,7 @@ place. If your platform provides a workspace-exit tool, use it.
|
|||||||
| "'Yeah, get rid of it' counts as confirmation" | Only the typed word `discard` authorizes deletion. |
|
| "'Yeah, get rid of it' counts as confirmation" | Only the typed word `discard` authorizes deletion. |
|
||||||
| "The PR is up, so the worktree is clutter now" | PR feedback gets fixed in that worktree. It stays until the work lands. |
|
| "The PR is up, so the worktree is clutter now" | PR feedback gets fixed in that worktree. It stays until the work lands. |
|
||||||
| "This other worktree looks stale — I'll clean it too" | Clean up only worktrees under `.worktrees/` or `worktrees/`. Everything else belongs to the host. |
|
| "This other worktree looks stale — I'll clean it too" | Clean up only worktrees under `.worktrees/` or `worktrees/`. Everything else belongs to the host. |
|
||||||
|
| "Removal refused — `--force` is just finishing the cleanup" | The refusal means files exist only in that worktree. `--force` destroys them permanently. Show your human partner and ask. |
|
||||||
| "The merged-result failure is probably flaky" | A failing merged result stops everything. Branch and worktree stay put while you investigate. |
|
| "The merged-result failure is probably flaky" | A failing merged result stops everything. Branch and worktree stay put while you investigate. |
|
||||||
| "The base branch is obviously main" | Confirm the fork point or ask. Merging into the wrong base is expensive to undo. |
|
| "The base branch is obviously main" | Confirm the fork point or ask. Merging into the wrong base is expensive to undo. |
|
||||||
| "The push was rejected — force-push will fix it" | A rejected push means the remote moved. Investigate; force-push only on your human partner's explicit request. |
|
| "The push was rejected — force-push will fix it" | A rejected push means the remote moved. Investigate; force-push only on your human partner's explicit request. |
|
||||||
|
|||||||
@@ -18,9 +18,18 @@ echo "🔍 Searching for test that creates: $POLLUTION_CHECK"
|
|||||||
echo "Test pattern: $TEST_PATTERN"
|
echo "Test pattern: $TEST_PATTERN"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Get list of test files
|
# Get list of test files (find . emits ./-prefixed paths, so accept the
|
||||||
TEST_FILES=$(find . -path "$TEST_PATTERN" | sort)
|
# pattern written with or without a leading ./)
|
||||||
TOTAL=$(echo "$TEST_FILES" | wc -l | tr -d ' ')
|
TEST_PATTERN="${TEST_PATTERN#./}"
|
||||||
|
# find -path can't match '**/' against zero directory levels, so a pattern
|
||||||
|
# like src/**/*.test.ts would skip src/top.test.ts; also try the pattern
|
||||||
|
# with '**/' collapsed to cover files directly under the base directory.
|
||||||
|
TEST_FILES=$(find . \( -path "./$TEST_PATTERN" -o -path "./${TEST_PATTERN//\*\*\//}" \) | sort -u)
|
||||||
|
if [ -z "$TEST_FILES" ]; then
|
||||||
|
TOTAL=0
|
||||||
|
else
|
||||||
|
TOTAL=$(printf '%s\n' "$TEST_FILES" | wc -l | tr -d ' ')
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Found $TOTAL test files"
|
echo "Found $TOTAL test files"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Skills speak in actions ("dispatch a subagent", "create a todo", "read a file").
|
|||||||
|
|
||||||
| Action skills request | Antigravity CLI equivalent |
|
| Action skills request | Antigravity CLI equivalent |
|
||||||
|----------------------|----------------------|
|
|----------------------|----------------------|
|
||||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `invoke_subagent` with a built-in `TypeName` — `self` for full-capability work, `research` for read-only (see [Subagent support](#subagent-support)) |
|
| Dispatch a subagent (`Subagent (general-purpose):` template) | `invoke_subagent` with a built-in `TypeName` — `self` for full-capability work, `research` for read-only |
|
||||||
| Task tracking ("create a todo", "mark complete") | a **task artifact** — `write_to_file` with `IsArtifact: true` and `ArtifactType: "task"` (see [Task tracking](#task-tracking)). **Not** `manage_task`, which manages background processes. |
|
| Task tracking ("create a todo", "mark complete") | a **task artifact** — `write_to_file` with `IsArtifact: true` and `ArtifactType: "task"` (see [Task tracking](#task-tracking)). **Not** `manage_task`, which manages background processes. |
|
||||||
|
|
||||||
## Task tracking
|
## Task tracking
|
||||||
|
|||||||
90
tests/systematic-debugging/test-find-polluter.sh
Executable file
90
tests/systematic-debugging/test-find-polluter.sh
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
SCRIPT_UNDER_TEST="$REPO_ROOT/skills/systematic-debugging/find-polluter.sh"
|
||||||
|
|
||||||
|
FAILURES=0
|
||||||
|
TEST_ROOT="$(mktemp -d)"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf "$TEST_ROOT"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
pass() {
|
||||||
|
echo " [PASS] $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo " [FAIL] $1"
|
||||||
|
FAILURES=$((FAILURES + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_contains() {
|
||||||
|
local haystack="$1"
|
||||||
|
local needle="$2"
|
||||||
|
local description="$3"
|
||||||
|
|
||||||
|
if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
|
||||||
|
pass "$description"
|
||||||
|
else
|
||||||
|
fail "$description (expected output to contain: $needle)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toy project: one top-level test, one nested test. A stubbed `npm` on PATH
|
||||||
|
# creates the pollution marker whenever any test runs, so the first test file
|
||||||
|
# executed is always identified as the polluter.
|
||||||
|
setup_project() {
|
||||||
|
PROJECT="$TEST_ROOT/project"
|
||||||
|
rm -rf "$PROJECT"
|
||||||
|
mkdir -p "$PROJECT/src/feature" "$PROJECT/bin"
|
||||||
|
echo "test('top')" > "$PROJECT/src/top.test.ts"
|
||||||
|
echo "test('nested')" > "$PROJECT/src/feature/nested.test.ts"
|
||||||
|
cat > "$PROJECT/bin/npm" <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
touch pollution.marker
|
||||||
|
EOF
|
||||||
|
chmod +x "$PROJECT/bin/npm"
|
||||||
|
}
|
||||||
|
|
||||||
|
# run_polluter <pattern> — runs the script in the toy project with the stub
|
||||||
|
# npm first on PATH; captures combined output, never aborts on exit code.
|
||||||
|
run_polluter() {
|
||||||
|
local pattern="$1"
|
||||||
|
rm -f "$PROJECT/pollution.marker"
|
||||||
|
(
|
||||||
|
cd "$PROJECT"
|
||||||
|
PATH="$PROJECT/bin:$PATH" "$SCRIPT_UNDER_TEST" 'pollution.marker' "$pattern" 2>&1
|
||||||
|
) || true
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Test: documented pattern finds nested test files (issue #2008)"
|
||||||
|
setup_project
|
||||||
|
OUTPUT="$(run_polluter 'src/**/*.test.ts')"
|
||||||
|
assert_contains "$OUTPUT" "FOUND POLLUTER" "documented pattern runs tests and detects pollution"
|
||||||
|
|
||||||
|
echo "Test: documented pattern also finds top-level test files"
|
||||||
|
setup_project
|
||||||
|
OUTPUT="$(run_polluter 'src/**/*.test.ts')"
|
||||||
|
assert_contains "$OUTPUT" "Found 2 test files" "src/**/*.test.ts matches src/top.test.ts and src/feature/nested.test.ts"
|
||||||
|
|
||||||
|
echo "Test: ./-prefixed pattern matches the same files"
|
||||||
|
setup_project
|
||||||
|
OUTPUT="$(run_polluter './src/**/*.test.ts')"
|
||||||
|
assert_contains "$OUTPUT" "Found 2 test files" "leading ./ on the pattern is accepted"
|
||||||
|
|
||||||
|
echo "Test: non-matching pattern reports an honest zero"
|
||||||
|
setup_project
|
||||||
|
OUTPUT="$(run_polluter 'nomatch/**/*.test.ts')"
|
||||||
|
assert_contains "$OUTPUT" "Found 0 test files" "empty result counts as 0, not 1"
|
||||||
|
assert_contains "$OUTPUT" "No polluter found" "empty result exits via the clean path"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
if [ "$FAILURES" -gt 0 ]; then
|
||||||
|
echo "$FAILURES test(s) failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "All tests passed"
|
||||||
Reference in New Issue
Block a user