@loneexile/omp-superpowers 7.0.1-omp.4 → 7.0.2-omp.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi/extensions/superpowers.ts +3 -13
- package/CHANGELOG.md +43 -1
- package/README.md +64 -24
- package/package.json +1 -1
- package/skills/brainstorming/SKILL.md +63 -41
- package/skills/brainstorming/scripts/start-server.sh +7 -0
- package/skills/executing-plans/SKILL.md +14 -11
- package/skills/executing-plans/scripts/task-done +5 -2
- package/skills/executing-plans/scripts/task-start +5 -1
- package/skills/finishing-a-development-branch/SKILL.md +50 -0
- package/skills/subagent-driven-development/SKILL.md +27 -7
- package/skills/subagent-driven-development/re-review-prompt.md +1 -0
- package/skills/subagent-driven-development/scripts/review-package +25 -14
- package/skills/subagent-driven-development/scripts/sdd-repo +54 -0
- package/skills/subagent-driven-development/scripts/sdd-workspace +28 -5
- package/skills/subagent-driven-development/scripts/task-brief +75 -10
- package/skills/subagent-driven-development/task-reviewer-prompt.md +4 -2
- package/skills/systematic-debugging/CREATION-LOG.md +0 -119
- package/skills/systematic-debugging/test-academic.md +0 -14
- package/skills/systematic-debugging/test-pressure-1.md +0 -58
- package/skills/systematic-debugging/test-pressure-2.md +0 -68
- package/skills/systematic-debugging/test-pressure-3.md +0 -69
|
@@ -153,7 +153,8 @@ The workspace and ledger are shared with superpowers:subagent-driven-development
|
|
|
153
153
|
and the new one resumes from the same ledger.
|
|
154
154
|
|
|
155
155
|
- Each plan owns a workspace: at skill start, run
|
|
156
|
-
`../subagent-driven-development/scripts/sdd-workspace PLAN_FILE`
|
|
156
|
+
`../subagent-driven-development/scripts/sdd-workspace PLAN_FILE` by its
|
|
157
|
+
absolute path, from the working tree you're executing in — it
|
|
157
158
|
prints the plan's git-ignored directory
|
|
158
159
|
(`<repo-root>/.superpowers/sdd/<plan-basename>/`), home to every
|
|
159
160
|
artifact for THIS plan: ledger, briefs, review packages. Another plan's
|
|
@@ -175,8 +176,9 @@ and the new one resumes from the same ledger.
|
|
|
175
176
|
if that happens, recover from `git log`.
|
|
176
177
|
- **On omp, resolve the scripts directories first.** The relative paths in
|
|
177
178
|
this skill (`scripts/task-start`, `../subagent-driven-development/scripts/…`)
|
|
178
|
-
do not resolve from the repo root,
|
|
179
|
-
but gives no filesystem path. Once,
|
|
179
|
+
do not resolve from the repo root, so each script runs by its absolute path,
|
|
180
|
+
and `omp read skill://…` lists the files but gives no filesystem path. Once,
|
|
181
|
+
before the first script, run
|
|
180
182
|
`realpath skill://executing-plans/scripts` and
|
|
181
183
|
`realpath skill://subagent-driven-development/scripts` in the `bash` tool
|
|
182
184
|
and add the printed paths to the ledger, after the identity line, as
|
|
@@ -187,11 +189,11 @@ and the new one resumes from the same ledger.
|
|
|
187
189
|
`rtk ls`. Use the printed paths everywhere else. Ledger lines are found by
|
|
188
190
|
their prefix, never by position. This ledger is shared with
|
|
189
191
|
subagent-driven-development, which writes only `SDD scripts:`: add
|
|
190
|
-
whichever of the two lines it lacks. Then run
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
`
|
|
194
|
-
|
|
192
|
+
whichever of the two lines it lacks. Then run each script by its
|
|
193
|
+
absolute path, `bash <dir>/<name>`, from the working tree you're executing
|
|
194
|
+
in (the scripts act on its repository, as git does): `task-start` and
|
|
195
|
+
`task-done` from the executing-plans directory, `sdd-workspace` and
|
|
196
|
+
`review-package` from the SDD one. The invocation lines in this skill
|
|
195
197
|
stay as upstream wrote them.
|
|
196
198
|
|
|
197
199
|
Read the plan once, note its context and Global Constraints, and create a
|
|
@@ -223,7 +225,8 @@ in the workspace and read its tail; read a brief, not the whole plan.
|
|
|
223
225
|
|
|
224
226
|
### 1. Take the task
|
|
225
227
|
|
|
226
|
-
- Run this skill's `scripts/task-start PLAN_FILE N
|
|
228
|
+
- Run this skill's `scripts/task-start PLAN_FILE N` by its absolute path,
|
|
229
|
+
from the working tree you're executing in. It prints the brief
|
|
227
230
|
path and BASE (the commit the task's range is cut from) in one call.
|
|
228
231
|
Read the brief for every task, including ones you remember from setup:
|
|
229
232
|
what you remember is a summary, the brief has the exact values,
|
|
@@ -276,7 +279,7 @@ the claim. If any item is missing, the task is not complete: finish it.
|
|
|
276
279
|
### 4. Complete the task
|
|
277
280
|
|
|
278
281
|
Run this skill's `scripts/task-done PLAN_FILE N BASE -- <test command>`
|
|
279
|
-
with the test command the brief names for the whole task. It runs the
|
|
282
|
+
by its absolute path, from the working tree you're executing in, with the test command the brief names for the whole task. It runs the
|
|
280
283
|
tests, keeps the full output in the workspace, prints the tail, and — only
|
|
281
284
|
if they pass — appends the completion line to the ledger:
|
|
282
285
|
|
|
@@ -288,7 +291,7 @@ mark the todo complete and take the next task.
|
|
|
288
291
|
## Final Review
|
|
289
292
|
|
|
290
293
|
Run `../subagent-driven-development/scripts/review-package PLAN_FILE MERGE_BASE HEAD`
|
|
291
|
-
(MERGE_BASE = the commit the branch started from, e.g.
|
|
294
|
+
by its absolute path, from the working tree you're executing in (MERGE_BASE = the commit the branch started from, e.g.
|
|
292
295
|
`git merge-base main HEAD`) and review from the file it prints.
|
|
293
296
|
|
|
294
297
|
**With a subagent tool:** dispatch the reviewer on the most capable
|
|
@@ -20,7 +20,10 @@ base=$3
|
|
|
20
20
|
shift 4
|
|
21
21
|
sdd="$(cd "$(dirname "$0")/../../subagent-driven-development/scripts" && pwd)"
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
# The repository the workspace and ledger belong to (see sdd-repo); BASE and
|
|
24
|
+
# HEAD are read there, not in the bare cwd.
|
|
25
|
+
repo=$("${BASH:-bash}" "$sdd/sdd-repo" --with-commit)
|
|
26
|
+
git -C "$repo" rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
|
|
24
27
|
|
|
25
28
|
dir=$("$sdd/sdd-workspace" "$plan")
|
|
26
29
|
log="$dir/task-${n}-tests.log"
|
|
@@ -47,6 +50,6 @@ fi
|
|
|
47
50
|
|
|
48
51
|
last=$(grep -v '^[[:space:]]*$' "$log" | tail -n 1) || last="(no output)"
|
|
49
52
|
[ -f "$ledger" ] || printf '# SDD ledger — plan: %s\n' "$plan" > "$ledger"
|
|
50
|
-
line="Task $n: complete (commits $(git rev-parse --short=7 "$base")..$(git rev-parse --short=7 HEAD), tests: $cmd → $last)"
|
|
53
|
+
line="Task $n: complete (commits $(git -C "$repo" rev-parse --short=7 "$base")..$(git -C "$repo" rev-parse --short=7 HEAD), tests: $cmd → $last)"
|
|
51
54
|
printf '%s\n' "$line" >> "$ledger"
|
|
52
55
|
echo "ledger: $line"
|
|
@@ -20,9 +20,13 @@ plan=$1
|
|
|
20
20
|
n=$2
|
|
21
21
|
sdd="$(cd "$(dirname "$0")/../../subagent-driven-development/scripts" && pwd)"
|
|
22
22
|
|
|
23
|
+
# BASE comes from the same repository the brief is written into (sdd-repo
|
|
24
|
+
# also refuses one with no commit yet), not from the bare cwd.
|
|
25
|
+
repo=$("${BASH:-bash}" "$sdd/sdd-repo" --with-commit)
|
|
23
26
|
out=$("$sdd/task-brief" "$plan" "$n")
|
|
24
27
|
brief=$(printf '%s\n' "$out" | sed -n 's/^wrote \(.*\): [0-9][0-9]* lines$/\1/p')
|
|
25
28
|
[ -n "$brief" ] || { echo "task-brief did not report a path: $out" >&2; exit 1; }
|
|
29
|
+
base=$(git -C "$repo" rev-parse --verify HEAD)
|
|
26
30
|
|
|
27
31
|
echo "brief: $brief"
|
|
28
|
-
echo "base: $
|
|
32
|
+
echo "base: $base"
|
|
@@ -43,6 +43,15 @@ This determines which menu to show and how cleanup works:
|
|
|
43
43
|
| `GIT_DIR != GIT_COMMON`, named branch | Standard 3 options | Provenance-based (see Step 6) |
|
|
44
44
|
| `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced 2 options (no merge) | Externally managed — leave in place |
|
|
45
45
|
|
|
46
|
+
**On omp, check for an ovnfs checkout too:** `git config --get ovnfs.checkout`
|
|
47
|
+
prints the checkout's name inside one and nothing elsewhere. An ovnfs
|
|
48
|
+
checkout is a copy-on-write copy of your human partner's folder with its
|
|
49
|
+
own private git directory. The table calls it a normal repo
|
|
50
|
+
(`GIT_DIR == GIT_COMMON`), but nothing committed in it is in their
|
|
51
|
+
repository until it is applied, and the `MAIN_ROOT` lines below fail there
|
|
52
|
+
(`fatal: not a git repository`). Present the standard 3 options and carry
|
|
53
|
+
out the choice as *In an ovnfs checkout* (end of Step 5) says.
|
|
54
|
+
|
|
46
55
|
## Step 3: Determine Base Branch
|
|
47
56
|
|
|
48
57
|
The base branch is whatever this work forked from — usually named in the
|
|
@@ -160,6 +169,47 @@ git switch <base-branch> # normal repo only
|
|
|
160
169
|
git branch -D <feature-branch>
|
|
161
170
|
```
|
|
162
171
|
|
|
172
|
+
### In an ovnfs checkout
|
|
173
|
+
|
|
174
|
+
`<checkout>` is the name Step 2 printed. Your human partner's repository is
|
|
175
|
+
the folder `ovnfs ls` lists as that checkout's SOURCE. Run these from the
|
|
176
|
+
checkout, still on `<feature-branch>`: ovnfs applies the checkout's HEAD.
|
|
177
|
+
|
|
178
|
+
**Option 1:**
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
ovnfs apply <checkout> --branch <feature-branch>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
That makes the checkout's commits `<feature-branch>` in the folder's
|
|
185
|
+
repository and changes no file there. Then merge in the folder, with the
|
|
186
|
+
`bash` tool's `cwd` set to it: if `git branch --show-current` prints
|
|
187
|
+
`<base-branch>` and `git status --porcelain` prints nothing, run `git pull`,
|
|
188
|
+
`git merge <feature-branch>` and the tests there, and once they pass,
|
|
189
|
+
`git branch -d <feature-branch>`. Otherwise stop and tell your human partner
|
|
190
|
+
that `<feature-branch>` is now in their repository and why you did not
|
|
191
|
+
merge it. `ovnfs apply <checkout> --branch <base-branch>` while the folder
|
|
192
|
+
has `<base-branch>` checked out moves that branch and its index but leaves
|
|
193
|
+
the folder's files as they were, so the merge shows there as uncommitted
|
|
194
|
+
changes that undo it. Plain `ovnfs apply <checkout>`, without `--branch`,
|
|
195
|
+
brings the changes back as uncommitted edits, without the commits.
|
|
196
|
+
|
|
197
|
+
**Option 2:** as above; the push goes from the checkout.
|
|
198
|
+
|
|
199
|
+
**Option 3:** report "Keeping branch <name> in ovnfs checkout <checkout>
|
|
200
|
+
(<path>). `ovnfs apply <checkout> --branch <name>` puts it in your
|
|
201
|
+
repository."
|
|
202
|
+
|
|
203
|
+
**Discard:** in the checkout, `git switch <base-branch>` and
|
|
204
|
+
`git branch -D <feature-branch>`. The branch never reached the folder.
|
|
205
|
+
|
|
206
|
+
**The checkout itself:** after Option 1 or a discard, remove it with
|
|
207
|
+
`ovnfs rm <checkout>`, run from the folder, only if this session opened it
|
|
208
|
+
with `ovnfs new`, the session's working directory is not inside it, and
|
|
209
|
+
`git status --porcelain` in it prints nothing. Otherwise leave it and tell
|
|
210
|
+
your human partner that `ovnfs rm <checkout>`, run from their folder,
|
|
211
|
+
removes it.
|
|
212
|
+
|
|
163
213
|
## Step 6: Cleanup Workspace
|
|
164
214
|
|
|
165
215
|
**Runs for Option 1 and confirmed discards.** Options 2 and 3 always
|
|
@@ -191,7 +191,8 @@ sequences — the single most expensive failure observed. Track progress in
|
|
|
191
191
|
a ledger file, not only in todos.
|
|
192
192
|
|
|
193
193
|
- Each plan owns a workspace: at skill start, run this skill's
|
|
194
|
-
`bash scripts/sdd-workspace PLAN_FILE`
|
|
194
|
+
`bash scripts/sdd-workspace PLAN_FILE` by its absolute path, from the
|
|
195
|
+
working tree you're executing in — it prints the plan's git-ignored
|
|
195
196
|
directory (under `<repo-root>/.superpowers/sdd/`), home to
|
|
196
197
|
every artifact for THIS plan: ledger, briefs, reports, review packages.
|
|
197
198
|
Another plan's directory is never yours to read or write.
|
|
@@ -497,7 +498,8 @@ the review package and fix-round diffs need it. Every task in a wave shares
|
|
|
497
498
|
the wave's BASE.
|
|
498
499
|
|
|
499
500
|
- **Task brief:** before dispatching an implementer, run this skill's
|
|
500
|
-
`bash scripts/task-brief PLAN_FILE N`
|
|
501
|
+
`bash scripts/task-brief PLAN_FILE N` by its absolute path, from the
|
|
502
|
+
working tree you're executing in — it extracts the task's full text to a
|
|
501
503
|
uniquely named file and prints the path. Compose the dispatch so the
|
|
502
504
|
brief stays the single source of
|
|
503
505
|
requirements. Your dispatch should contain: (1) one line on where this
|
|
@@ -573,6 +575,20 @@ the wave's BASE.
|
|
|
573
575
|
omp worktree add -b "sdd/<plan>/task-<N>" ~/.omp/wt/"$repo-<plan>-task-<N>"
|
|
574
576
|
```
|
|
575
577
|
|
|
578
|
+
**With ovnfs on PATH, wave tasks still use `omp worktree add`,** though
|
|
579
|
+
omp's system prompt then asks for ovnfs checkouts as second copies. A
|
|
580
|
+
wave task's branch must be in the plan checkout's repository, where the
|
|
581
|
+
review packages and the merge read it. `omp worktree add` puts it there,
|
|
582
|
+
inside an ovnfs checkout too. An ovnfs checkout keeps its commits in its
|
|
583
|
+
own private git directory, and its `ovnfs apply --branch` writes them to
|
|
584
|
+
the folder ovnfs copied, which is not the plan checkout when the plan
|
|
585
|
+
checkout is an ovnfs checkout itself. If a wave task's copy is an ovnfs
|
|
586
|
+
checkout anyway, bring its branch into the plan checkout with
|
|
587
|
+
`git fetch <its path> sdd/<plan>/task-<N>:sdd/<plan>/task-<N>` before
|
|
588
|
+
each review package and before the merge, never with `ovnfs apply`, and
|
|
589
|
+
remove it with `ovnfs rm <name>` where this skill says
|
|
590
|
+
`git worktree remove`.
|
|
591
|
+
|
|
576
592
|
`<plan>` is the plan file's name without `.md`;
|
|
577
593
|
superpowers:using-git-worktrees says why `omp worktree add` and
|
|
578
594
|
`~/.omp/wt/`. Then, in each new worktree and before dispatching, run the
|
|
@@ -627,7 +643,7 @@ your own checkout gained no changes. A task that wrote into your checkout
|
|
|
627
643
|
goes back to its implementer with the paths. Then check the task's line in
|
|
628
644
|
the review list.
|
|
629
645
|
|
|
630
|
-
- **`review per-task`:** generate the review package (`bash scripts/review-package PLAN_FILE BASE HEAD
|
|
646
|
+
- **`review per-task`:** generate the review package (`bash scripts/review-package PLAN_FILE BASE HEAD` by its absolute path, from the working tree you're executing in — it prints the unique file path it wrote; BASE is the commit you recorded before dispatching the implementer — never `HEAD~1`, which silently drops all but the last commit of a multi-commit task; for a wave task, its branch `sdd/<plan>/task-<N>` stands in for HEAD), then dispatch `sdd-reviewer` with the printed path.
|
|
631
647
|
- **`review at final`:** run the covering test command from the brief yourself, once, in the task's checkout, with its output redirected to a file in the plan's workspace; read the tail. A brief that names no test (docs, configuration) gets the cheapest check that can fail instead (a build, a lint, a parse), or goes on the review list. That run is the only check this task gets before the final review, so never take the implementer's report in its place. A pass completes the task (step 5). A failure goes back to the implementer with the output file's path: rounds 1-2 resume it, round 3 is a fresh `sdd-escalation-implementer`, as in the fix loop, and each round ends when your rerun passes, with no re-review. A failure after round 3 is a plan the tests disagree with: stop and ask.
|
|
632
648
|
|
|
633
649
|
**DONE_WITH_CONCERNS:** The implementer completed the work but flagged doubts. Read the concerns before proceeding. If the concerns are about correctness or scope, address them before review, and put a `review at final` task on the review list (`Task <N>: review per-task — <concern>`). A wave task that changed a file outside its brief's Files list broke its wave's independence: merge it after its wave's other tasks, and run their covering tests too on the merged tree. If the concerns are observations (e.g., "this file is getting large"), note them and proceed.
|
|
@@ -666,7 +682,8 @@ self-review never replaces a review: for a listed task the task review is
|
|
|
666
682
|
it, for any other the final review is.
|
|
667
683
|
|
|
668
684
|
- Hand the reviewer its diff as a file: run this skill's
|
|
669
|
-
`bash scripts/review-package PLAN_FILE BASE HEAD`
|
|
685
|
+
`bash scripts/review-package PLAN_FILE BASE HEAD` by its absolute path, from
|
|
686
|
+
the working tree you're executing in, and pass the reviewer the file path
|
|
670
687
|
it prints (or, without bash: `git log --oneline`, `git diff --stat`,
|
|
671
688
|
and `git diff -U10` for the range, redirected to one uniquely named
|
|
672
689
|
file). The output never enters your own context, and the reviewer sees
|
|
@@ -802,7 +819,8 @@ covering test files in the fix message — a one-line fix does not need the
|
|
|
802
819
|
whole suite.
|
|
803
820
|
|
|
804
821
|
**The re-review is scoped.** Run `bash scripts/review-package PLAN_FILE FIX_BASE HEAD`
|
|
805
|
-
|
|
822
|
+
by its absolute path, from the working tree you're executing in, where
|
|
823
|
+
FIX_BASE is the head the previous review saw, as a commit SHA (for a
|
|
806
824
|
wave task, its branch tip then: `git rev-parse sdd/<plan>/task-<N>`; never
|
|
807
825
|
the branch name, which moves with the fix), and dispatch
|
|
808
826
|
`sdd-rereviewer` with [re-review-prompt.md](re-review-prompt.md): the
|
|
@@ -938,7 +956,8 @@ the cap.
|
|
|
938
956
|
## Final Review
|
|
939
957
|
|
|
940
958
|
The final whole-branch review gets a package too: run
|
|
941
|
-
`bash scripts/review-package PLAN_FILE MERGE_BASE HEAD`
|
|
959
|
+
`bash scripts/review-package PLAN_FILE MERGE_BASE HEAD` by its absolute path,
|
|
960
|
+
from the working tree you're executing in (MERGE_BASE = the commit the
|
|
942
961
|
branch started from, e.g. `git merge-base main HEAD`) and include the
|
|
943
962
|
printed path in the final review dispatch, so the final reviewer reads
|
|
944
963
|
one file instead of re-deriving the branch diff with git commands. Dispatch
|
|
@@ -970,7 +989,8 @@ with the complete findings list — not one fixer per finding.
|
|
|
970
989
|
Per-finding fixers each rebuild context and re-run suites; a real
|
|
971
990
|
session's final-review fix wave cost more than all its tasks combined.
|
|
972
991
|
Then run exactly one scoped re-review of the fix wave
|
|
973
|
-
(`bash scripts/review-package PLAN_FILE FIX_BASE HEAD`
|
|
992
|
+
(`bash scripts/review-package PLAN_FILE FIX_BASE HEAD` by its absolute path,
|
|
993
|
+
from the working tree you're executing in, over the fix range,
|
|
974
994
|
[re-review-prompt.md](re-review-prompt.md)).
|
|
975
995
|
Adjudicate any residual findings as in the task loop's breaker: park with
|
|
976
996
|
rulings, or rule on the load-bearing ones and ledger what you decided. Only
|
|
@@ -118,6 +118,7 @@ that the fix itself broke nothing.
|
|
|
118
118
|
- `[HEAD_SHA]` — current commit; for a wave task that has not merged yet,
|
|
119
119
|
its branch tip (`git rev-parse sdd/<plan>/task-<N>`)
|
|
120
120
|
- `[DIFF_FILE]` — the path `bash scripts/review-package PLAN_FILE FIX_BASE HEAD` printed
|
|
121
|
+
(run by its absolute path, from the working tree you're executing in)
|
|
121
122
|
- `[CHECKOUT_LINE]` — same as the task reviewer's: the worktree line for a wave
|
|
122
123
|
task that has not merged yet, omitted otherwise
|
|
123
124
|
|
|
@@ -4,13 +4,22 @@
|
|
|
4
4
|
# call. Using the recorded per-task BASE (not HEAD~1) keeps multi-commit
|
|
5
5
|
# tasks intact.
|
|
6
6
|
#
|
|
7
|
-
# Usage: review-package PLAN_FILE BASE HEAD [OUTFILE]
|
|
7
|
+
# Usage: review-package [-C DIR] PLAN_FILE BASE HEAD [OUTFILE]
|
|
8
8
|
# Default OUTFILE: <repo-root>/.superpowers/sdd/<plan-basename>/review-<base7>..<head7>.diff
|
|
9
9
|
# (named per range, so a re-review after fixes gets a distinct fresh file).
|
|
10
|
+
# The repository is the one sdd-repo names; -C DIR runs as if started in DIR,
|
|
11
|
+
# as in sdd-workspace.
|
|
10
12
|
set -euo pipefail
|
|
11
13
|
|
|
14
|
+
here=$(cd "$(dirname "$0")" && pwd)
|
|
15
|
+
if [ "${1:-}" = "-C" ]; then
|
|
16
|
+
[ -d "${2:-}" ] || { echo "bad -C directory: ${2:-}" >&2; exit 2; }
|
|
17
|
+
cd "$2"
|
|
18
|
+
shift 2
|
|
19
|
+
fi
|
|
20
|
+
|
|
12
21
|
if [ $# -lt 3 ] || [ $# -gt 4 ]; then
|
|
13
|
-
echo "usage: review-package PLAN_FILE BASE HEAD [OUTFILE]" >&2
|
|
22
|
+
echo "usage: review-package [-C DIR] PLAN_FILE BASE HEAD [OUTFILE]" >&2
|
|
14
23
|
exit 2
|
|
15
24
|
fi
|
|
16
25
|
|
|
@@ -19,35 +28,37 @@ base=$2
|
|
|
19
28
|
head=$3
|
|
20
29
|
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
# Invoke via bash rather than direct exec: some extractors (Python zipfile)
|
|
32
|
+
# strip Unix exec bits when unpacking marketplace packages (#2040).
|
|
33
|
+
repo=$("${BASH:-bash}" "$here/sdd-repo" --with-commit)
|
|
34
|
+
|
|
35
|
+
git -C "$repo" rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
|
|
36
|
+
git -C "$repo" rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
|
|
24
37
|
|
|
25
38
|
# Range guards (exit 3): a wrong-branch HEAD yields a range that is empty or
|
|
26
39
|
# not rooted at BASE; either would silently produce a bogus review package.
|
|
27
|
-
git merge-base --is-ancestor "$base" "$head" || { echo "HEAD is not a descendant of BASE: ${base}..${head}" >&2; exit 3; }
|
|
28
|
-
[ "$(git rev-list --count "${base}..${head}")" -gt 0 ] || { echo "empty commit range: ${base}..${head}" >&2; exit 3; }
|
|
40
|
+
git -C "$repo" merge-base --is-ancestor "$base" "$head" || { echo "HEAD is not a descendant of BASE: ${base}..${head}" >&2; exit 3; }
|
|
41
|
+
[ "$(git -C "$repo" rev-list --count "${base}..${head}")" -gt 0 ] || { echo "empty commit range: ${base}..${head}" >&2; exit 3; }
|
|
29
42
|
|
|
30
43
|
if [ $# -eq 4 ]; then
|
|
31
44
|
out=$4
|
|
32
45
|
else
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
dir=$("${BASH:-bash}" "$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
|
|
36
|
-
out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"
|
|
46
|
+
dir=$("${BASH:-bash}" "$here/sdd-workspace" "$plan")
|
|
47
|
+
out="$dir/review-$(git -C "$repo" rev-parse --short "$base")..$(git -C "$repo" rev-parse --short "$head").diff"
|
|
37
48
|
fi
|
|
38
49
|
|
|
39
50
|
{
|
|
40
51
|
echo "# Review package: ${base}..${head}"
|
|
41
52
|
echo
|
|
42
53
|
echo "## Commits"
|
|
43
|
-
git log --oneline "${base}..${head}"
|
|
54
|
+
git -C "$repo" log --oneline "${base}..${head}"
|
|
44
55
|
echo
|
|
45
56
|
echo "## Files changed"
|
|
46
|
-
git diff --stat "${base}..${head}"
|
|
57
|
+
git -C "$repo" diff --stat "${base}..${head}"
|
|
47
58
|
echo
|
|
48
59
|
echo "## Diff"
|
|
49
|
-
git diff -U10 "${base}..${head}"
|
|
60
|
+
git -C "$repo" diff -U10 "${base}..${head}"
|
|
50
61
|
} > "$out"
|
|
51
62
|
|
|
52
|
-
commits=$(git rev-list --count "${base}..${head}")
|
|
63
|
+
commits=$(git -C "$repo" rev-list --count "${base}..${head}")
|
|
53
64
|
echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Print the top-level directory of the git working tree the SDD scripts use:
|
|
3
|
+
# the current directory's, exactly as git itself picks one. A caller that
|
|
4
|
+
# means a different working tree says so with the scripts' -C DIR, which
|
|
5
|
+
# they apply (cd) before calling this.
|
|
6
|
+
#
|
|
7
|
+
# The plan file's location never picks the repository. An executor working
|
|
8
|
+
# in a linked worktree commonly holds an absolute path to the plan in the
|
|
9
|
+
# main checkout (writing-plans leaves the plan uncommitted there), and its
|
|
10
|
+
# workspace and commits belong to the worktree it is working in. And a
|
|
11
|
+
# caller standing outside any repository, such as the skill's own directory
|
|
12
|
+
# in an installed plugin, is in the wrong place: guessing a repository from
|
|
13
|
+
# the plan would silently act on whichever checkout the path points into.
|
|
14
|
+
#
|
|
15
|
+
# Outside any working tree, stop. --with-commit also stops on a repository
|
|
16
|
+
# with no commit yet, for callers that need HEAD as a BASE or a review
|
|
17
|
+
# range. The message covers both ways to get here: running from the wrong
|
|
18
|
+
# directory (where 'git init' would be the wrong fix) and a new project
|
|
19
|
+
# that has no repository or commit yet.
|
|
20
|
+
#
|
|
21
|
+
# Single source of truth for which repository the SDD and executing-plans
|
|
22
|
+
# scripts work in, so no two of them can disagree.
|
|
23
|
+
#
|
|
24
|
+
# Usage: sdd-repo [--with-commit]
|
|
25
|
+
set -euo pipefail
|
|
26
|
+
|
|
27
|
+
with_commit=false
|
|
28
|
+
if [ "${1:-}" = "--with-commit" ]; then
|
|
29
|
+
with_commit=true
|
|
30
|
+
shift
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
if [ $# -ne 0 ]; then
|
|
34
|
+
echo "usage: sdd-repo [--with-commit]" >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if root=$(git rev-parse --show-toplevel 2>/dev/null); then
|
|
39
|
+
if [ "$with_commit" = false ] || git -C "$root" rev-parse --verify --quiet HEAD >/dev/null; then
|
|
40
|
+
printf '%s\n' "$root"
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
said=$(git -C "$root" rev-parse --verify HEAD 2>&1 >/dev/null) || true
|
|
44
|
+
else
|
|
45
|
+
said=$(git rev-parse --show-toplevel 2>&1 >/dev/null) || true
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# git's own first line always follows the shared message: where git refuses
|
|
49
|
+
# a working tree the caller is inside (dubious ownership, git missing from
|
|
50
|
+
# PATH, the cwd inside .git), the shared message alone would be wrong, and
|
|
51
|
+
# git's line names the real fix.
|
|
52
|
+
echo "SDD scripts must run from inside the git working tree you're executing in, with at least one commit (current directory: $PWD). If this is a new project, run 'git init' and make a first commit, then rerun." >&2
|
|
53
|
+
echo "git said: ${said%%$'\n'*}" >&2
|
|
54
|
+
exit 2
|
|
@@ -27,11 +27,23 @@
|
|
|
27
27
|
# Single source of truth for the workspace location, so task-brief and
|
|
28
28
|
# review-package cannot drift to different directories.
|
|
29
29
|
#
|
|
30
|
-
#
|
|
30
|
+
# The repository is the current directory's (see sdd-repo). -C DIR runs as
|
|
31
|
+
# if started in DIR, the way git -C does: a caller working on another
|
|
32
|
+
# checkout or worktree needs no `cd DIR ;` prefix, a compound that harnesses
|
|
33
|
+
# cannot allowlist because DIR differs on every run (#1799).
|
|
34
|
+
#
|
|
35
|
+
# Usage: sdd-workspace [-C DIR] PLAN_FILE
|
|
31
36
|
set -euo pipefail
|
|
32
37
|
|
|
38
|
+
here=$(cd "$(dirname "$0")" && pwd)
|
|
39
|
+
if [ "${1:-}" = "-C" ]; then
|
|
40
|
+
[ -d "${2:-}" ] || { echo "bad -C directory: ${2:-}" >&2; exit 2; }
|
|
41
|
+
cd "$2"
|
|
42
|
+
shift 2
|
|
43
|
+
fi
|
|
44
|
+
|
|
33
45
|
if [ $# -ne 1 ]; then
|
|
34
|
-
echo "usage: sdd-workspace PLAN_FILE" >&2
|
|
46
|
+
echo "usage: sdd-workspace [-C DIR] PLAN_FILE" >&2
|
|
35
47
|
exit 2
|
|
36
48
|
fi
|
|
37
49
|
|
|
@@ -44,8 +56,12 @@ slug=$(basename "$plan" .md)
|
|
|
44
56
|
|
|
45
57
|
# Physical path, spelled the way pwd -P spells the plan path below: on Git
|
|
46
58
|
# Bash, rev-parse prints C:/Users/... while pwd prints /c/Users/..., and the
|
|
47
|
-
# repo-relative marker check needs both in the same form.
|
|
48
|
-
|
|
59
|
+
# repo-relative marker check needs both in the same form. Two steps, so a
|
|
60
|
+
# failing sdd-repo stops the script instead of handing cd an empty path.
|
|
61
|
+
# Invoke via bash rather than direct exec: some extractors (Python zipfile)
|
|
62
|
+
# strip Unix exec bits when unpacking marketplace packages (#2040).
|
|
63
|
+
toplevel=$("${BASH:-bash}" "$here/sdd-repo")
|
|
64
|
+
root=$(CDPATH='' cd -- "$toplevel" && pwd -P)
|
|
49
65
|
base="$root/.superpowers/sdd"
|
|
50
66
|
|
|
51
67
|
# Normalize the plan path (physical directory, so relative/absolute/../
|
|
@@ -84,4 +100,11 @@ fi
|
|
|
84
100
|
# Create-only: a repo may commit its own .gitignore here (e.g. to version
|
|
85
101
|
# progress.md ledgers); overwriting it would revert that on every run.
|
|
86
102
|
[ -e "$base/.gitignore" ] || printf '*\n' > "$base/.gitignore"
|
|
87
|
-
|
|
103
|
+
|
|
104
|
+
# On Windows (Git Bash, MSYS2, Cygwin) print C:/Users/... rather than
|
|
105
|
+
# /c/Users/... or /tmp/...: the caller may be PowerShell or another native
|
|
106
|
+
# tool, which can't resolve MSYS paths, and bash accepts this form too.
|
|
107
|
+
# Only the printed path changes; the plan-path markers above keep pwd -P's
|
|
108
|
+
# spelling, so existing workspaces still match their plans.
|
|
109
|
+
CDPATH='' cd -- "$dir"
|
|
110
|
+
if command -v cygpath >/dev/null 2>&1; then cygpath -m "$PWD"; else pwd; fi
|
|
@@ -3,14 +3,21 @@
|
|
|
3
3
|
# implementer reads in one call, so the task text never has to be pasted
|
|
4
4
|
# through the controller's context.
|
|
5
5
|
#
|
|
6
|
-
# Usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]
|
|
6
|
+
# Usage: task-brief [-C DIR] PLAN_FILE TASK_NUMBER [OUTFILE]
|
|
7
7
|
# Default OUTFILE: <repo-root>/.superpowers/sdd/<plan-basename>/task-<N>-brief.md
|
|
8
8
|
# (per plan and per worktree; concurrent runs of the SAME plan in the same
|
|
9
|
-
# working tree share it).
|
|
9
|
+
# working tree share it). -C DIR runs as if started in DIR, as in sdd-workspace.
|
|
10
10
|
set -euo pipefail
|
|
11
11
|
|
|
12
|
+
here=$(cd "$(dirname "$0")" && pwd)
|
|
13
|
+
if [ "${1:-}" = "-C" ]; then
|
|
14
|
+
[ -d "${2:-}" ] || { echo "bad -C directory: ${2:-}" >&2; exit 2; }
|
|
15
|
+
cd "$2"
|
|
16
|
+
shift 2
|
|
17
|
+
fi
|
|
18
|
+
|
|
12
19
|
if [ $# -lt 2 ] || [ $# -gt 3 ]; then
|
|
13
|
-
echo "usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]" >&2
|
|
20
|
+
echo "usage: task-brief [-C DIR] PLAN_FILE TASK_NUMBER [OUTFILE]" >&2
|
|
14
21
|
exit 2
|
|
15
22
|
fi
|
|
16
23
|
|
|
@@ -23,17 +30,75 @@ if [ $# -eq 3 ]; then
|
|
|
23
30
|
else
|
|
24
31
|
# Invoke via bash rather than direct exec: some extractors (Python zipfile)
|
|
25
32
|
# strip Unix exec bits when unpacking marketplace packages (#2040).
|
|
26
|
-
dir=$("${BASH:-bash}" "$
|
|
33
|
+
dir=$("${BASH:-bash}" "$here/sdd-workspace" "$plan")
|
|
27
34
|
out="$dir/task-${n}-brief.md"
|
|
28
35
|
fi
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
# A task heading is `Task` followed by an ID: letters and digits, optionally
|
|
38
|
+
# dot-separated, containing at least one digit (3, 6b, A1, 2.1). The digit
|
|
39
|
+
# keeps headings like "## Task Overview" or "#### Task notes" from becoming
|
|
40
|
+
# task boundaries. The ID is compared to TASK_NUMBER as a whole string, so
|
|
41
|
+
# Task 6 never matches Task 6b, Task 1 never matches Task 1.1, and
|
|
42
|
+
# TASK_NUMBER never reaches awk as a regex (#2459). A deeper Task heading
|
|
43
|
+
# whose ID extends the requested one with a letter or dot is a sub-task and
|
|
44
|
+
# stays in its brief (### Task 7 keeps #### Task 7a), as it always has.
|
|
45
|
+
# Depth alone is not enough: plans drift from "## Task 1" to "### Task 2".
|
|
46
|
+
#
|
|
47
|
+
# The word stays the English literal "Task", whatever language the rest of
|
|
48
|
+
# the plan is in. A plan with no Task headings at all usually translated it
|
|
49
|
+
# ("## Tarea 1"), so list the headings shaped like tasks before the
|
|
50
|
+
# not-found error instead of implying the plan has no task 1 (#2496).
|
|
51
|
+
#
|
|
52
|
+
# A fence that never closes hides every Task heading after it (#2436). When
|
|
53
|
+
# it hides one while the requested task is being captured, that task's end
|
|
54
|
+
# can't be found and the brief would run on through every later task: refuse
|
|
55
|
+
# (exit 4) rather than hand an implementer several tasks as its requirements.
|
|
56
|
+
# When it hides the requested heading itself, say so before the not-found
|
|
57
|
+
# error. A stray fence that hides no Task heading (real plans end with a lone
|
|
58
|
+
# ``` line) leaves the brief complete, so brief it with a warning.
|
|
59
|
+
# The plan path goes through ENVIRON, not -v, which would mangle the
|
|
60
|
+
# backslashes of a Windows path.
|
|
61
|
+
rc=0
|
|
62
|
+
TASK_BRIEF_PLAN="$plan" awk -v n="$n" '
|
|
63
|
+
/^```/ { infence = !infence; if (infence) { fence_line = NR; hidden = 0 } }
|
|
64
|
+
infence && /^#+[ \t]+Task[ \t]/ { hidden = 1 }
|
|
65
|
+
!infence && /^#+[ \t]+Task[ \t]/ {
|
|
66
|
+
id = $0
|
|
67
|
+
sub(/^#+[ \t]+Task[ \t]+/, "", id)
|
|
68
|
+
if (match(id, /^[A-Za-z0-9]+(\.[A-Za-z0-9]+)*/) && substr(id, 1, RLENGTH) ~ /[0-9]/) {
|
|
69
|
+
tasks++
|
|
70
|
+
id = substr(id, 1, RLENGTH)
|
|
71
|
+
match($0, /^#+/)
|
|
72
|
+
subtask = intask && RLENGTH > level && substr(id, 1, length(n)) == n \
|
|
73
|
+
&& substr(id, length(n) + 1, 1) ~ /[A-Za-z.]/
|
|
74
|
+
if (!subtask) {
|
|
75
|
+
intask = (id == n)
|
|
76
|
+
level = RLENGTH
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
!infence && /^#+[ \t]+[^ \t]+[ \t]+[A-Za-z0-9.]*[0-9]/ && shaped < 5 { shaped_heading[++shaped] = $0 }
|
|
81
|
+
intask { print; found = 1 }
|
|
82
|
+
END {
|
|
83
|
+
where = "the code fence opened at line " fence_line " of " ENVIRON["TASK_BRIEF_PLAN"] " never closes"
|
|
84
|
+
if (infence && hidden && (intask || !found)) {
|
|
85
|
+
print "task-brief: " where ", so no Task heading after it can be seen; close that fence in the plan and rerun" | "cat >&2"
|
|
86
|
+
if (intask) exit 4
|
|
87
|
+
} else if (infence && intask) {
|
|
88
|
+
print "task-brief: warning: " where "; it hides no Task heading, so this brief is complete" | "cat >&2"
|
|
89
|
+
}
|
|
90
|
+
# An open fence that hid Task headings already explains why none were
|
|
91
|
+
# seen; the English-word hint would contradict it.
|
|
92
|
+
if (!tasks && shaped && !(infence && hidden)) {
|
|
93
|
+
print "task-brief: no task headings found. Task headings must use the English word \"Task\" (\"### Task 1: ...\"), even when the rest of the plan is in another language. Headings shaped like tasks:" | "cat >&2"
|
|
94
|
+
for (i = 1; i <= shaped; i++) print " " shaped_heading[i] | "cat >&2"
|
|
95
|
+
}
|
|
34
96
|
}
|
|
35
|
-
|
|
36
|
-
|
|
97
|
+
' "$plan" > "$out" || rc=$?
|
|
98
|
+
if [ "$rc" -ne 0 ]; then
|
|
99
|
+
if [ -f "$out" ]; then rm -f "$out"; fi
|
|
100
|
+
exit "$rc"
|
|
101
|
+
fi
|
|
37
102
|
|
|
38
103
|
if [ ! -s "$out" ]; then
|
|
39
104
|
echo "task ${n} not found in ${plan} (no heading matching 'Task ${n}')" >&2
|
|
@@ -194,7 +194,8 @@ more, nothing less) and is well-built (clean, tested, maintainable)
|
|
|
194
194
|
|
|
195
195
|
**Placeholders:**
|
|
196
196
|
- `agent: sdd-reviewer` — REQUIRED (see SKILL.md Agent Selection)
|
|
197
|
-
- `[BRIEF_FILE]` — REQUIRED: the task brief file (`bash scripts/task-brief PLAN N
|
|
197
|
+
- `[BRIEF_FILE]` — REQUIRED: the task brief file (`bash scripts/task-brief PLAN N`,
|
|
198
|
+
run by its absolute path, from the working tree you're executing in,
|
|
198
199
|
prints the path; same file the implementer worked from)
|
|
199
200
|
- `[GLOBAL_CONSTRAINTS]` — the binding requirements copied verbatim from
|
|
200
201
|
the plan's Global Constraints section or the spec: exact values, formats,
|
|
@@ -207,7 +208,8 @@ more, nothing less) and is well-built (clean, tested, maintainable)
|
|
|
207
208
|
its branch tip (`git rev-parse sdd/<plan>/task-<N>`). Record this SHA:
|
|
208
209
|
it is the next re-review's FIX_BASE
|
|
209
210
|
- `[DIFF_FILE]` — REQUIRED: the path the controller wrote the review
|
|
210
|
-
package to (`bash scripts/review-package PLAN_FILE BASE HEAD
|
|
211
|
+
package to (`bash scripts/review-package PLAN_FILE BASE HEAD`, run by its
|
|
212
|
+
absolute path, from the working tree you're executing in, prints the unique
|
|
211
213
|
path it wrote; the package never enters the controller's context)
|
|
212
214
|
- `[CHECKOUT_LINE]` — for a wave task that has not merged yet: `**Checkout:**
|
|
213
215
|
<worktree absolute path> — the task's code lives here, not in your
|