superpowers-mcp 6.3.6 → 6.3.8
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/README.ja.md +56 -62
- package/README.ko.md +56 -64
- package/README.md +58 -65
- package/README.zh-TW.md +56 -64
- package/docs/maintainers/upstream-sync.md +42 -0
- package/docs/skill-compositions.ja.md +194 -0
- package/docs/skill-compositions.ko.md +194 -0
- package/docs/skill-compositions.md +216 -0
- package/docs/skill-compositions.zh-TW.md +194 -0
- package/out/server.js +105 -146
- package/out/setup-runner.js +16 -16
- package/out/setup.js +17 -17
- package/package.json +12 -6
- package/scripts/upstream-drift.js +346 -0
- package/skills/brainstorming/SKILL.md +125 -25
- package/skills/brainstorming/scripts/helper.js +1 -1
- package/skills/brainstorming/scripts/server.cjs +61 -6
- package/skills/brainstorming/scripts/start-server.ps1 +20 -1
- package/skills/brainstorming/scripts/start-server.sh +2 -2
- package/skills/executing-plans/SKILL.md +7 -1
- package/skills/finishing-a-development-branch/SKILL.md +15 -0
- package/skills/subagent-driven-development/SKILL.md +121 -36
- package/skills/subagent-driven-development/implementer-prompt.md +19 -0
- package/skills/subagent-driven-development/re-review-prompt.md +10 -4
- package/skills/subagent-driven-development/scripts/review-package +6 -0
- package/skills/subagent-driven-development/scripts/review-package.ps1 +7 -0
- package/skills/subagent-driven-development/scripts/sdd-workspace +11 -4
- package/skills/subagent-driven-development/scripts/sdd-workspace.ps1 +28 -3
- package/skills/subagent-driven-development/task-reviewer-prompt.md +28 -10
- package/skills/systematic-debugging/SKILL.md +1 -1
- package/skills/systematic-debugging/find-polluter.ps1 +7 -5
- package/skills/systematic-debugging/find-polluter.sh +11 -9
- package/skills/systematic-debugging/root-cause-tracing.md +2 -2
- package/skills/test-driven-development/SKILL.md +27 -3
- package/skills/test-driven-development/writing-good-tests.md +7 -0
- package/skills/using-git-worktrees/SKILL.md +12 -0
- package/skills/using-superpowers/SKILL.md +1 -1
- package/skills/verification-before-completion/SKILL.md +54 -1
- package/skills/writing-plans/SKILL.md +20 -5
- package/skills/writing-skills/SKILL.md +30 -0
|
@@ -6,7 +6,7 @@ const net = require('net');
|
|
|
6
6
|
|
|
7
7
|
// ========== WebSocket Protocol (RFC 6455) ==========
|
|
8
8
|
|
|
9
|
-
const OPCODES = { TEXT: 0x01, CLOSE: 0x08, PING: 0x09, PONG: 0x0A };
|
|
9
|
+
const OPCODES = { CONTINUATION: 0x00, TEXT: 0x01, CLOSE: 0x08, PING: 0x09, PONG: 0x0A };
|
|
10
10
|
const WS_MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
|
|
11
11
|
const MAX_FRAME_PAYLOAD_BYTES = 10 * 1024 * 1024;
|
|
12
12
|
// Bound concurrent WebSocket clients (each holds a frame buffer up to
|
|
@@ -52,6 +52,8 @@ function encodeFrame(opcode, payload) {
|
|
|
52
52
|
function decodeFrame(buffer) {
|
|
53
53
|
if (buffer.length < 2) return null;
|
|
54
54
|
|
|
55
|
+
const fin = (buffer[0] & 0x80) !== 0;
|
|
56
|
+
const rsv = buffer[0] & 0x70;
|
|
55
57
|
const secondByte = buffer[1];
|
|
56
58
|
const opcode = buffer[0] & 0x0F;
|
|
57
59
|
const masked = (secondByte & 0x80) !== 0;
|
|
@@ -59,6 +61,10 @@ function decodeFrame(buffer) {
|
|
|
59
61
|
let offset = 2;
|
|
60
62
|
|
|
61
63
|
if (!masked) throw new Error('Client frames must be masked');
|
|
64
|
+
if (rsv !== 0) throw new Error('WebSocket extensions are not supported');
|
|
65
|
+
if (![OPCODES.CONTINUATION, OPCODES.TEXT, OPCODES.CLOSE, OPCODES.PING, OPCODES.PONG].includes(opcode)) {
|
|
66
|
+
throw new Error('Unsupported WebSocket opcode');
|
|
67
|
+
}
|
|
62
68
|
|
|
63
69
|
if (payloadLen === 126) {
|
|
64
70
|
if (buffer.length < 4) return null;
|
|
@@ -83,6 +89,9 @@ function decodeFrame(buffer) {
|
|
|
83
89
|
if (opcode >= 0x8 && payloadLen > 125) {
|
|
84
90
|
throw new Error('WebSocket control frame payload exceeds 125 bytes');
|
|
85
91
|
}
|
|
92
|
+
if (opcode >= 0x8 && !fin) {
|
|
93
|
+
throw new Error('WebSocket control frames must not be fragmented');
|
|
94
|
+
}
|
|
86
95
|
|
|
87
96
|
const maskOffset = offset;
|
|
88
97
|
const dataOffset = offset + 4;
|
|
@@ -95,7 +104,7 @@ function decodeFrame(buffer) {
|
|
|
95
104
|
data[i] = buffer[dataOffset + i] ^ mask[i % 4];
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
return { opcode, payload: data, bytesConsumed: totalLen };
|
|
107
|
+
return { fin, opcode, payload: data, bytesConsumed: totalLen };
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
// ========== Configuration ==========
|
|
@@ -351,7 +360,7 @@ function openPrivateAppendFile(filePath) {
|
|
|
351
360
|
}
|
|
352
361
|
|
|
353
362
|
let fd = null;
|
|
354
|
-
const appendFlags = fs.constants.
|
|
363
|
+
const appendFlags = fs.constants.O_RDWR | fs.constants.O_APPEND | fs.constants.O_CREAT | noFollow;
|
|
355
364
|
try {
|
|
356
365
|
if (!before) {
|
|
357
366
|
try {
|
|
@@ -762,6 +771,9 @@ function handleUpgrade(req, socket) {
|
|
|
762
771
|
let buffer = Buffer.alloc(0);
|
|
763
772
|
let closed = false;
|
|
764
773
|
let partialFrameTimer = null;
|
|
774
|
+
let fragmentedOpcode = null;
|
|
775
|
+
let fragmentedPayloads = [];
|
|
776
|
+
let fragmentedBytes = 0;
|
|
765
777
|
clients.add(socket);
|
|
766
778
|
|
|
767
779
|
const clearPartialFrameTimer = () => {
|
|
@@ -820,7 +832,36 @@ function handleUpgrade(req, socket) {
|
|
|
820
832
|
|
|
821
833
|
switch (result.opcode) {
|
|
822
834
|
case OPCODES.TEXT:
|
|
823
|
-
|
|
835
|
+
if (fragmentedOpcode !== null) {
|
|
836
|
+
closeSocket(1002);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
if (result.fin) {
|
|
840
|
+
handleMessage(result.payload.toString());
|
|
841
|
+
} else {
|
|
842
|
+
fragmentedOpcode = OPCODES.TEXT;
|
|
843
|
+
fragmentedPayloads = [result.payload];
|
|
844
|
+
fragmentedBytes = result.payload.length;
|
|
845
|
+
}
|
|
846
|
+
break;
|
|
847
|
+
case OPCODES.CONTINUATION:
|
|
848
|
+
if (fragmentedOpcode === null) {
|
|
849
|
+
closeSocket(1002);
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
fragmentedBytes += result.payload.length;
|
|
853
|
+
if (fragmentedBytes > MAX_FRAME_PAYLOAD_BYTES) {
|
|
854
|
+
closeSocket(1009);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
fragmentedPayloads.push(result.payload);
|
|
858
|
+
if (result.fin) {
|
|
859
|
+
const message = Buffer.concat(fragmentedPayloads, fragmentedBytes);
|
|
860
|
+
fragmentedOpcode = null;
|
|
861
|
+
fragmentedPayloads = [];
|
|
862
|
+
fragmentedBytes = 0;
|
|
863
|
+
handleMessage(message.toString());
|
|
864
|
+
}
|
|
824
865
|
break;
|
|
825
866
|
case OPCODES.CLOSE:
|
|
826
867
|
closeSocket();
|
|
@@ -834,6 +875,7 @@ function handleUpgrade(req, socket) {
|
|
|
834
875
|
closeSocket(1003);
|
|
835
876
|
return;
|
|
836
877
|
}
|
|
878
|
+
if (fragmentedOpcode !== null) armPartialFrameTimer();
|
|
837
879
|
}
|
|
838
880
|
});
|
|
839
881
|
|
|
@@ -866,7 +908,16 @@ function appendEvent(event) {
|
|
|
866
908
|
try {
|
|
867
909
|
const current = fs.fstatSync(fd);
|
|
868
910
|
if (current.size + lineBytes > MAX_EVENTS_FILE_BYTES) {
|
|
911
|
+
const keepBytes = MAX_EVENTS_FILE_BYTES - lineBytes;
|
|
912
|
+
const existing = Buffer.alloc(Math.min(current.size, MAX_EVENTS_FILE_BYTES));
|
|
913
|
+
const bytesRead = fs.readSync(fd, existing, 0, existing.length, Math.max(0, current.size - existing.length));
|
|
914
|
+
let retained = existing.subarray(Math.max(0, bytesRead - keepBytes), bytesRead);
|
|
915
|
+
if (retained.length < bytesRead) {
|
|
916
|
+
const firstNewline = retained.indexOf(0x0a);
|
|
917
|
+
retained = firstNewline >= 0 ? retained.subarray(firstNewline + 1) : Buffer.alloc(0);
|
|
918
|
+
}
|
|
869
919
|
fs.ftruncateSync(fd, 0);
|
|
920
|
+
if (retained.length > 0) fs.writeSync(fd, retained);
|
|
870
921
|
}
|
|
871
922
|
fs.writeSync(fd, line);
|
|
872
923
|
} catch (e) {
|
|
@@ -894,8 +945,12 @@ function handleMessage(text) {
|
|
|
894
945
|
? logLine
|
|
895
946
|
: JSON.stringify({ source: 'user-event', truncated: true });
|
|
896
947
|
console.log(logOutput);
|
|
897
|
-
if (event && event
|
|
898
|
-
|
|
948
|
+
if (event && typeof event === 'object') {
|
|
949
|
+
if (event.choice) {
|
|
950
|
+
appendEvent(event);
|
|
951
|
+
} else if (event.type === 'choice' && event.value) {
|
|
952
|
+
appendEvent({ ...event, choice: event.value });
|
|
953
|
+
}
|
|
899
954
|
}
|
|
900
955
|
}
|
|
901
956
|
|
|
@@ -67,7 +67,9 @@ $projectDir = ""
|
|
|
67
67
|
$foreground = $false
|
|
68
68
|
$forceBackground = $false
|
|
69
69
|
$bindHost = "127.0.0.1"
|
|
70
|
+
if ($env:BRAINSTORM_HOST) { $bindHost = $env:BRAINSTORM_HOST }
|
|
70
71
|
$urlHost = ""
|
|
72
|
+
if ($env:BRAINSTORM_URL_HOST) { $urlHost = $env:BRAINSTORM_URL_HOST }
|
|
71
73
|
$idleTimeoutMinutes = ""
|
|
72
74
|
|
|
73
75
|
for ($i = 0; $i -lt $args.Count; $i++) {
|
|
@@ -151,17 +153,34 @@ if ($env:CODEX_CI -and -not $foreground -and -not $forceBackground) {
|
|
|
151
153
|
$foreground = $true
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
$
|
|
156
|
+
$baseSessionId = "$PID-$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())"
|
|
155
157
|
$brainstormRoot = ""
|
|
156
158
|
if ($projectDir -ne "") {
|
|
157
159
|
$brainstormRoot = Join-Path $projectDir ".superpowers/brainstorm"
|
|
160
|
+
# $PID is the invoking host process, so two starts in the same second from
|
|
161
|
+
# one pwsh session would resolve to the same id and die on the live
|
|
162
|
+
# session's redirected log file. Take the next free directory instead.
|
|
163
|
+
$sessionId = $baseSessionId
|
|
158
164
|
$sessionDir = Join-Path $brainstormRoot $sessionId
|
|
165
|
+
$sessionSuffix = 2
|
|
166
|
+
while (Test-Path -LiteralPath $sessionDir) {
|
|
167
|
+
$sessionId = "$baseSessionId-$sessionSuffix"
|
|
168
|
+
$sessionDir = Join-Path $brainstormRoot $sessionId
|
|
169
|
+
$sessionSuffix++
|
|
170
|
+
}
|
|
159
171
|
# Reuse the last bound port and session key so a restart keeps an
|
|
160
172
|
# already-open browser tab connected to the same URL with a valid cookie.
|
|
161
173
|
$env:BRAINSTORM_PORT_FILE = Join-Path $brainstormRoot ".last-port"
|
|
162
174
|
$env:BRAINSTORM_TOKEN_FILE = Join-Path $brainstormRoot ".last-token"
|
|
163
175
|
} else {
|
|
176
|
+
$sessionId = $baseSessionId
|
|
164
177
|
$sessionDir = Join-Path ([System.IO.Path]::GetTempPath()) "brainstorm-$sessionId"
|
|
178
|
+
$sessionSuffix = 2
|
|
179
|
+
while (Test-Path -LiteralPath $sessionDir) {
|
|
180
|
+
$sessionId = "$baseSessionId-$sessionSuffix"
|
|
181
|
+
$sessionDir = Join-Path ([System.IO.Path]::GetTempPath()) "brainstorm-$sessionId"
|
|
182
|
+
$sessionSuffix++
|
|
183
|
+
}
|
|
165
184
|
# $env: assignments persist in the invoking pwsh session; a stale project
|
|
166
185
|
# token/port file from an earlier --project-dir run must not leak into an
|
|
167
186
|
# ephemeral session (it would defeat key rotation and could overwrite the
|
|
@@ -23,8 +23,8 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
23
23
|
PROJECT_DIR=""
|
|
24
24
|
FOREGROUND="false"
|
|
25
25
|
FORCE_BACKGROUND="false"
|
|
26
|
-
BIND_HOST="127.0.0.1"
|
|
27
|
-
URL_HOST=""
|
|
26
|
+
BIND_HOST="${BRAINSTORM_HOST:-127.0.0.1}"
|
|
27
|
+
URL_HOST="${BRAINSTORM_URL_HOST:-}"
|
|
28
28
|
IDLE_TIMEOUT_MINUTES=""
|
|
29
29
|
while [[ $# -gt 0 ]]; do
|
|
30
30
|
case "$1" in
|
|
@@ -28,7 +28,11 @@ For each task:
|
|
|
28
28
|
1. Mark as in_progress
|
|
29
29
|
2. Follow each step exactly (plan has bite-sized steps)
|
|
30
30
|
3. Run verifications as specified
|
|
31
|
-
4. Mark as completed
|
|
31
|
+
4. Mark as completed — the todo **and** the plan file: edit it and flip this
|
|
32
|
+
task's steps from `- [ ]` to `- [x]`. The plan is the artifact a human
|
|
33
|
+
reads to see where things stand, and nothing else in this skill writes
|
|
34
|
+
back to it. Leave a step unticked only when its deliverable does not exist
|
|
35
|
+
yet; never tick one you skipped.
|
|
32
36
|
|
|
33
37
|
### Step 3: Complete Development
|
|
34
38
|
|
|
@@ -62,3 +66,5 @@ After all tasks complete and verified:
|
|
|
62
66
|
- Reference skills when plan says to
|
|
63
67
|
- Stop when blocked, don't guess
|
|
64
68
|
- Never start implementation on main/master branch without explicit user consent
|
|
69
|
+
- Commits stay local — no push/pull/fetch unless the plan or your human partner says so. At each checkpoint glance at `git status -sb`: a branch tracking or ahead of a shared branch (main/dev/production) is a stop-and-fix, not a footnote
|
|
70
|
+
- Never rewrite a shared branch (`git push --force*` to main/dev/production) to undo a mistake — a forward-only `git revert` is the only remedy you apply yourself; anything more is your human partner's call
|
|
@@ -85,6 +85,14 @@ is theirs.
|
|
|
85
85
|
|
|
86
86
|
### Option 1: Merge Locally
|
|
87
87
|
|
|
88
|
+
If the branch came from subagent-driven-development, commit the plan ledger's
|
|
89
|
+
deferred findings first: carry every ledger line tagged `minor (deferred)`,
|
|
90
|
+
`parked`, or `Ruling:` into
|
|
91
|
+
`docs/superpowers/follow-ups/<plan-basename>.md` (append under a dated
|
|
92
|
+
heading if the file already exists) and commit it to the branch before the
|
|
93
|
+
merge — subagent-driven-development's Finish rule owns the details, and the
|
|
94
|
+
file must land here so it survives the branch deletion.
|
|
95
|
+
|
|
88
96
|
```bash
|
|
89
97
|
# Get main repo root for CWD safety
|
|
90
98
|
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
|
@@ -123,6 +131,13 @@ tooling — its CLI if one is available, or the creation URL most forges
|
|
|
123
131
|
print when you push — following the repo's PR template and conventions if
|
|
124
132
|
present, and report the URL to your human partner.
|
|
125
133
|
|
|
134
|
+
If the branch came from subagent-driven-development, append the plan
|
|
135
|
+
ledger's deferred findings to the PR description before reporting the URL —
|
|
136
|
+
a "Deferred items" checklist carrying every ledger line tagged `minor
|
|
137
|
+
(deferred)`, `parked`, or `Ruling:`, verbatim. Subagent-driven-development's
|
|
138
|
+
Finish rule owns the details; the checklist must land here, where your human
|
|
139
|
+
partner reviews.
|
|
140
|
+
|
|
126
141
|
Keep the worktree — your human partner iterates on PR feedback there.
|
|
127
142
|
|
|
128
143
|
### Option 3: Keep As-Is
|
|
@@ -87,8 +87,9 @@ digraph process {
|
|
|
87
87
|
"More tasks remain?" [shape=diamond];
|
|
88
88
|
"Dispatch final code reviewer (../requesting-code-review/code-reviewer.md)" [shape=box];
|
|
89
89
|
"Final findings? ONE fix dispatch, one scoped re-review, adjudicate residuals" [shape=box];
|
|
90
|
-
"
|
|
91
|
-
"
|
|
90
|
+
"Use superpowers:finishing-a-development-branch" [shape=box];
|
|
91
|
+
"Finish path resolved: export deferred findings to its durable artifact" [shape=box];
|
|
92
|
+
"Delete this plan's workspace (only after the export; keep-as-is keeps it)" [shape=box style=filled fillcolor=lightgreen];
|
|
92
93
|
|
|
93
94
|
"Setup: worktree, ledger check, read plan, pre-flight review" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
|
94
95
|
"Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer asks questions?";
|
|
@@ -116,8 +117,9 @@ digraph process {
|
|
|
116
117
|
"More tasks remain?" -> "Dispatch implementer subagent (./implementer-prompt.md)" [label="yes"];
|
|
117
118
|
"More tasks remain?" -> "Dispatch final code reviewer (../requesting-code-review/code-reviewer.md)" [label="no"];
|
|
118
119
|
"Dispatch final code reviewer (../requesting-code-review/code-reviewer.md)" -> "Final findings? ONE fix dispatch, one scoped re-review, adjudicate residuals";
|
|
119
|
-
"Final findings? ONE fix dispatch, one scoped re-review, adjudicate residuals" -> "
|
|
120
|
-
"
|
|
120
|
+
"Final findings? ONE fix dispatch, one scoped re-review, adjudicate residuals" -> "Use superpowers:finishing-a-development-branch";
|
|
121
|
+
"Use superpowers:finishing-a-development-branch" -> "Finish path resolved: export deferred findings to its durable artifact";
|
|
122
|
+
"Finish path resolved: export deferred findings to its durable artifact" -> "Delete this plan's workspace (only after the export; keep-as-is keeps it)";
|
|
121
123
|
}
|
|
122
124
|
```
|
|
123
125
|
|
|
@@ -142,14 +144,21 @@ a ledger file, not only in todos.
|
|
|
142
144
|
line names your plan file, tasks with a `Task <N>: complete` line are DONE
|
|
143
145
|
— do not re-dispatch them; resume at the first task without one. A task
|
|
144
146
|
whose last line is a fix round is mid-loop: resume the loop at the next
|
|
145
|
-
round. A
|
|
147
|
+
round. A resumed controller also reads the ledger's `## Discoveries`
|
|
148
|
+
section: it holds what completed tasks found that the plan could not
|
|
149
|
+
know, and it is the source for clause (3) of the next dispatch. A ledger
|
|
150
|
+
whose first line names a different plan file — or a stray
|
|
146
151
|
ledger at the old flat path `.superpowers/sdd/progress.md` — is another
|
|
147
152
|
plan's progress: leave it in place and start your own, fresh.
|
|
148
153
|
- Create the ledger with its identity as the first line:
|
|
149
154
|
`# SDD ledger — plan: <plan file path>`.
|
|
150
155
|
- The ledger is your recovery map: the commits it names exist in git even
|
|
151
156
|
when your context no longer remembers creating them. After compaction,
|
|
152
|
-
trust the ledger and `git log` over your own recollection.
|
|
157
|
+
trust the ledger and `git log` over your own recollection. The ledger's
|
|
158
|
+
`## Discoveries` section is the same map for knowledge: what earlier tasks
|
|
159
|
+
found that the plan could not know. A resumed controller composes clause
|
|
160
|
+
(3) of every dispatch from that section, never from recollection of a
|
|
161
|
+
context it no longer has.
|
|
153
162
|
- `git clean -fdx` will destroy the workspace (it's git-ignored scratch); if
|
|
154
163
|
that happens, recover from `git log`.
|
|
155
164
|
|
|
@@ -272,9 +281,12 @@ and fix-round diffs need it.
|
|
|
272
281
|
task fits in the project; (2) the brief path, introduced as "read this
|
|
273
282
|
first — it is your requirements, with the exact values to use verbatim";
|
|
274
283
|
(3) interfaces and decisions from earlier tasks that the brief cannot
|
|
275
|
-
know
|
|
276
|
-
|
|
277
|
-
|
|
284
|
+
know — read them from the ledger's Discoveries section, not from your
|
|
285
|
+
memory of past reports: copy the entries the task's interfaces touch, in
|
|
286
|
+
full, and skip the rest; (4) your resolution of any ambiguity you noticed
|
|
287
|
+
in the brief; (5) the report-file path and report contract. Exact values
|
|
288
|
+
(numbers, magic strings, signatures, test cases) appear only in the
|
|
289
|
+
brief. Never
|
|
278
290
|
make a subagent read the whole plan file. When the brief is a contract
|
|
279
291
|
(goal, success criteria, interfaces) rather than written-out code, item
|
|
280
292
|
(3) also carries the elaboration the contract leaves to dispatch time:
|
|
@@ -290,7 +302,10 @@ and fix-round diffs need it.
|
|
|
290
302
|
paste accumulated prior-task summaries ("state after Tasks 1-3") into
|
|
291
303
|
later dispatches — a real session's dispatch hit 42k chars of which 99%
|
|
292
304
|
was pasted history. A fresh subagent needs its task, the interfaces it
|
|
293
|
-
touches, and the global constraints. Nothing else.
|
|
305
|
+
touches, and the global constraints. Nothing else. A curated slice copied
|
|
306
|
+
from the Discoveries section is not pasted history — it is clause (3)
|
|
307
|
+
above, kept small enough to read in full because each entry is a delta
|
|
308
|
+
from the plan.
|
|
294
309
|
- The dispatch carries the no-subagents contract (it is in the
|
|
295
310
|
implementer template): the implementer never dispatches subagents —
|
|
296
311
|
not helpers, and never a reviewer. Review arrives from you, after the
|
|
@@ -366,9 +381,16 @@ needed.
|
|
|
366
381
|
call. Use the BASE you recorded before dispatching the implementer —
|
|
367
382
|
never `HEAD~1`, which silently truncates multi-commit tasks. Never
|
|
368
383
|
dispatch a task reviewer without a diff file.
|
|
369
|
-
- **Reviewer inputs:** the task reviewer gets
|
|
370
|
-
file, the report file,
|
|
371
|
-
|
|
384
|
+
- **Reviewer inputs:** the task reviewer gets four paths — the same brief
|
|
385
|
+
file, the report file, the review package, and a review file to write
|
|
386
|
+
to (brief `…/task-N-brief.md` → review `…/task-N-review.md`) — plus
|
|
387
|
+
the global constraints that bind the task.
|
|
388
|
+
- **Review file:** the reviewer writes its full report there and returns
|
|
389
|
+
only verdicts, ⚠️ items, one line per Critical/Important finding, a
|
|
390
|
+
Minor count, and the path. Don't read the review file during the loop —
|
|
391
|
+
the final message is your decision surface; the detail is for fix
|
|
392
|
+
subagents. One exception: when you ledger a task's deferred minors, copy
|
|
393
|
+
each one-liner from the review file's Minor section.
|
|
372
394
|
- The global-constraints block you hand the reviewer is its attention
|
|
373
395
|
lens. Copy the binding requirements verbatim from the plan's Global
|
|
374
396
|
Constraints section or the spec: exact values, exact formats, and the
|
|
@@ -402,9 +424,12 @@ finding, or a ⚠️ item you confirmed as a real gap.
|
|
|
402
424
|
|
|
403
425
|
Before the loop starts, two routes leave it immediately:
|
|
404
426
|
|
|
405
|
-
-
|
|
406
|
-
|
|
407
|
-
|
|
427
|
+
- Dispatch fix subagents for Critical and Important findings, passing the
|
|
428
|
+
review file path for the full detail. Record each task's Minor count,
|
|
429
|
+
review file path, and one ledger line per deferred minor copied from the
|
|
430
|
+
review file's Minor section (`Task <N>: minor (deferred): <one-liner>` —
|
|
431
|
+
the deferred-findings export greps these lines), and point the final
|
|
432
|
+
whole-branch review at those files so it can triage which must be fixed
|
|
408
433
|
before merge. A roll-up nobody reads is a silent discard. Minor findings
|
|
409
434
|
never enter the loop.
|
|
410
435
|
- A finding labeled plan-mandated — or any finding that conflicts with
|
|
@@ -417,14 +442,16 @@ Everything else enters the loop. A fix round is one fix dispatch plus one
|
|
|
417
442
|
scoped re-review. Five rounds maximum per task:
|
|
418
443
|
|
|
419
444
|
**Rounds 1-3 — resume the original implementer.** Send it the open findings
|
|
420
|
-
verbatim
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
445
|
+
verbatim, plus the review file path for the full detail. Its context is
|
|
446
|
+
intact: it knows the task, the code, and its own choices. If your harness
|
|
447
|
+
cannot send another message to a live subagent, dispatch a fresh
|
|
448
|
+
implementer carrying the brief path, the report-file path, the review file
|
|
449
|
+
path, and the findings — the report file is the persistent memory either
|
|
450
|
+
way.
|
|
424
451
|
|
|
425
452
|
**Rounds 4-5 — dispatch a fresh implementer on a more capable model** (per
|
|
426
|
-
Model Selection), with the brief path, the report-file path, the
|
|
427
|
-
findings, and this framing: "A prior implementer attempted this task
|
|
453
|
+
Model Selection), with the brief path, the report-file path, the review
|
|
454
|
+
file path, the open findings, and this framing: "A prior implementer attempted this task
|
|
428
455
|
[N] times; you own it now. Read the report file for what was tried." A loop
|
|
429
456
|
that survives three resumes usually means the implementer cannot see its
|
|
430
457
|
own problem — fresh eyes and a capability bump in one move.
|
|
@@ -441,7 +468,8 @@ whole suite.
|
|
|
441
468
|
(or `scripts/review-package.ps1 PLAN_FILE FIX_BASE HEAD` on Windows PowerShell)
|
|
442
469
|
where FIX_BASE is the head the previous review saw, and dispatch
|
|
443
470
|
[re-review-prompt.md](re-review-prompt.md) with the findings list, the
|
|
444
|
-
brief, the report file,
|
|
471
|
+
brief, the report file, the review file to append its verdicts to, and the
|
|
472
|
+
printed diff path. The re-reviewer verdicts
|
|
445
473
|
each finding ADDRESSED or NOT ADDRESSED and flags new breakage in the fix
|
|
446
474
|
diff only. New Critical/Important breakage in the fix diff joins the open
|
|
447
475
|
findings list. Out-of-scope observations go to the ledger as deferred
|
|
@@ -483,6 +511,27 @@ message as your other bookkeeping:
|
|
|
483
511
|
- `Task <N>: complete (commits <base7>..<head7>, <K> parked)` after a
|
|
484
512
|
tripped breaker
|
|
485
513
|
|
|
514
|
+
Copy the task's Discoveries into the ledger in the same message, from the
|
|
515
|
+
report's "Discoveries for later tasks" field: append a `### Task <N>`
|
|
516
|
+
heading under the ledger's `## Discoveries` section (create the section on
|
|
517
|
+
first use) with each discovery as one line, or `- None` when the field is
|
|
518
|
+
empty. Keep it a delta from the plan: only what a later task needs and the
|
|
519
|
+
plan could not know — corrections to the plan, negative results, resolved
|
|
520
|
+
unknowns, interfaces discovered in the code. If it does not change what a
|
|
521
|
+
later task does, it does not go in.
|
|
522
|
+
|
|
523
|
+
In the same message, **edit the plan file and flip this task's steps from
|
|
524
|
+
`- [ ]` to `- [x]`**. The plan is what a human reads to see where the work
|
|
525
|
+
stands; the ledger is yours. Tie the two to this one event so they cannot
|
|
526
|
+
drift — a plan left at 0 while its tasks are done and deployed reads as
|
|
527
|
+
"nothing happened", and nothing downstream will catch it: the task reviewer
|
|
528
|
+
sees a diff, the re-review sees findings, the final review sees the ledger.
|
|
529
|
+
None of them ever opens the plan.
|
|
530
|
+
|
|
531
|
+
Leave a step unticked only when its deliverable does not exist yet — a step
|
|
532
|
+
that waits on someone else, or on an event that has not happened. Never tick
|
|
533
|
+
a step you skipped.
|
|
534
|
+
|
|
486
535
|
**On a skeleton-first plan,** write one plan-check line with the
|
|
487
536
|
completion line. Re-read the remaining tasks against what this task
|
|
488
537
|
actually established — interfaces as built, environment facts,
|
|
@@ -541,13 +590,45 @@ took on your human partner's behalf reach them — they read it and rework
|
|
|
541
590
|
whatever you got wrong. A ruling that dies with the workspace was a decision
|
|
542
591
|
made in secret.
|
|
543
592
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
593
|
+
Rulings are not the only content that dies with the workspace. Findings you
|
|
594
|
+
chose not to fix are the record of what was *not* done — git history cannot
|
|
595
|
+
carry them, because git records what was done. So export them before
|
|
596
|
+
anything is deleted: grep the progress ledger for its three finding tags
|
|
597
|
+
|
|
598
|
+
```bash
|
|
599
|
+
grep -E 'Ruling:|^(Task [0-9]+: )?(minor \(deferred\)|parked)' <workspace>/progress.md
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
and carry every matching line, verbatim, into a durable, human-reachable
|
|
603
|
+
artifact. The chat roll-up does not satisfy this — scrollback, compaction,
|
|
604
|
+
and session end all eat it. Where the artifact lives depends on how
|
|
605
|
+
finishing-a-development-branch resolves (it carries the same obligation from
|
|
606
|
+
its side):
|
|
607
|
+
|
|
608
|
+
- **Option 2 (push and create PR):** append the lines to the PR description
|
|
609
|
+
under a "Deferred items" checklist. That is where your human partner
|
|
610
|
+
reviews, and checkboxes survive the merge.
|
|
611
|
+
- **Option 1 (merge locally):** write them to
|
|
612
|
+
`docs/superpowers/follow-ups/<plan-basename>.md` — append under a dated
|
|
613
|
+
heading if a re-run under the same basename already created the file — and
|
|
614
|
+
commit the file to the branch before the merge so it survives the branch
|
|
615
|
+
deletion.
|
|
616
|
+
- **Option 3 (keep as-is):** the workspace stays, so there is nothing to
|
|
617
|
+
export.
|
|
618
|
+
- **Explicit discard:** your human partner asked to throw the work away, so
|
|
619
|
+
no export is required.
|
|
548
620
|
|
|
549
621
|
Use superpowers:finishing-a-development-branch.
|
|
550
622
|
|
|
623
|
+
When the finish path has resolved and its export exists — the checklist in
|
|
624
|
+
the PR description, or the committed follow-ups file — delete this plan's
|
|
625
|
+
workspace (`rm -rf <workspace>`), provided the final whole-branch review was
|
|
626
|
+
clean and its fixes are merged. The export, not git history, is the record
|
|
627
|
+
of the deferred findings. Sibling directories belong to other plans; leave
|
|
628
|
+
them alone. On an explicit discard there is no export, but the workspace is
|
|
629
|
+
deleted together with the branch — a ledger describing thrown-away work is
|
|
630
|
+
a false record.
|
|
631
|
+
|
|
551
632
|
## Common Rationalizations
|
|
552
633
|
|
|
553
634
|
| Excuse | Reality |
|
|
@@ -586,11 +667,12 @@ Implementer: [Later]
|
|
|
586
667
|
- Self-review: Found I missed --force flag, added it
|
|
587
668
|
- Committed
|
|
588
669
|
|
|
589
|
-
[Run review-package PLAN_FILE BASE HEAD; dispatch task reviewer with the printed path]
|
|
590
|
-
Task reviewer: Spec
|
|
591
|
-
|
|
670
|
+
[Run review-package PLAN_FILE BASE HEAD; dispatch task reviewer with the printed path + review file]
|
|
671
|
+
Task reviewer: Spec ✅. Quality: Approved. Minor: 0.
|
|
672
|
+
Full report: task-1-review.md
|
|
592
673
|
|
|
593
674
|
[Ledger: Task 1: complete (commits a1b2c3d..d4e5f6a, review clean)]
|
|
675
|
+
[Ledger: Discoveries — Task 1: hooks dir must be created before install; none other]
|
|
594
676
|
|
|
595
677
|
Task 2: Recovery modes
|
|
596
678
|
|
|
@@ -601,22 +683,23 @@ Implementer: [No questions]
|
|
|
601
683
|
- 8/8 tests passing
|
|
602
684
|
- Committed
|
|
603
685
|
|
|
604
|
-
[Run review-package PLAN_FILE BASE HEAD; dispatch task reviewer with the printed path]
|
|
686
|
+
[Run review-package PLAN_FILE BASE HEAD; dispatch task reviewer with the printed path + review file]
|
|
605
687
|
Task reviewer: Spec ❌:
|
|
606
688
|
- Missing: Progress reporting (spec says "report every 100 items")
|
|
607
|
-
|
|
689
|
+
Important: Magic number (100). Minor: 0. Full report: task-2-review.md
|
|
608
690
|
|
|
609
|
-
[Fix round 1: resume the implementer with
|
|
691
|
+
[Fix round 1: resume the implementer with the review file path]
|
|
610
692
|
Implementer: Added progress reporting, extracted PROGRESS_INTERVAL constant.
|
|
611
693
|
Re-ran test/recovery.test.js — 10/10 passing. Fix report appended.
|
|
612
694
|
|
|
613
|
-
[Run review-package PLAN_FILE FIX_BASE HEAD; dispatch scoped re-review]
|
|
695
|
+
[Run review-package PLAN_FILE FIX_BASE HEAD; dispatch scoped re-review with the review file to append to]
|
|
614
696
|
Re-reviewer: Missing progress reporting — ADDRESSED (src/recovery.js:41).
|
|
615
697
|
Magic number — ADDRESSED (src/recovery.js:7). New breakage: none.
|
|
616
698
|
Verdict: all findings addressed.
|
|
617
699
|
|
|
618
700
|
[Ledger: Task 2: fix round 1/5 (2 addressed, 0 open; commits d4e5f6a..b7c8d9e)]
|
|
619
701
|
[Ledger: Task 2: complete (commits d4e5f6a..b7c8d9e, review clean)]
|
|
702
|
+
[Ledger: Discoveries — Task 2: None]
|
|
620
703
|
|
|
621
704
|
...
|
|
622
705
|
|
|
@@ -624,7 +707,9 @@ Re-reviewer: Missing progress reporting — ADDRESSED (src/recovery.js:41).
|
|
|
624
707
|
[Run review-package PLAN_FILE MERGE_BASE HEAD; dispatch final code-reviewer, most capable model]
|
|
625
708
|
Final reviewer: All requirements met. Deferred minors triaged: none block merge.
|
|
626
709
|
|
|
627
|
-
[
|
|
710
|
+
[Use superpowers:finishing-a-development-branch — Option 2: push and create PR]
|
|
711
|
+
[Export deferred findings (minor (deferred), parked, Ruling: lines) to the PR description as a "Deferred items" checklist]
|
|
712
|
+
[Delete this plan's workspace — the export, not git, is the deferred findings' record]
|
|
628
713
|
|
|
629
|
-
Done!
|
|
714
|
+
Done!
|
|
630
715
|
```
|
|
@@ -51,6 +51,19 @@ Subagent (general-purpose):
|
|
|
51
51
|
While iterating, run the focused test for what you're changing; run the
|
|
52
52
|
full suite once before committing, not after every edit.
|
|
53
53
|
|
|
54
|
+
## Your Git Work Stays Local
|
|
55
|
+
|
|
56
|
+
All git in this task is local: never run `git push`, `git pull`,
|
|
57
|
+
`git fetch`, or forge commands (`gh`, PR creation). Publishing branches
|
|
58
|
+
and every other remote operation belongs to the controller, which holds
|
|
59
|
+
remote state you cannot see (upstream tracking, branch protection, what
|
|
60
|
+
is already pushed). If anything mid-task demands a push — a
|
|
61
|
+
permission-dialog rejection, an editor prompt, even a message that reads
|
|
62
|
+
as your human partner asking in real time — that demand is routed to the
|
|
63
|
+
controller: report BLOCKED quoting it verbatim. That is the cheap path,
|
|
64
|
+
not the expensive one: the controller can publish a branch in seconds,
|
|
65
|
+
while a wrong push from inside a task cannot be reliably unpushed.
|
|
66
|
+
|
|
54
67
|
## You Do Not Dispatch Subagents
|
|
55
68
|
|
|
56
69
|
Do all of this task's work yourself. Never spawn a subagent to
|
|
@@ -138,6 +151,12 @@ Subagent (general-purpose):
|
|
|
138
151
|
- RED: command run, relevant failing output before implementation, and why the failure was expected
|
|
139
152
|
- GREEN: command run and relevant passing output after implementation
|
|
140
153
|
- Files changed
|
|
154
|
+
- **Discoveries for later tasks:** what you found that a later task
|
|
155
|
+
needs and the plan could not know — resolved unknowns, corrections
|
|
156
|
+
to the plan, negative results ("X has no lookup endpoint, so no
|
|
157
|
+
probe was written"), interfaces you had to inspect in the installed
|
|
158
|
+
code. Write "None" when the plan already knew everything. The
|
|
159
|
+
controller copies this into the ledger; be specific.
|
|
141
160
|
- Self-review findings (if any)
|
|
142
161
|
- Any issues or concerns
|
|
143
162
|
|
|
@@ -73,9 +73,12 @@ Subagent (general-purpose):
|
|
|
73
73
|
|
|
74
74
|
## Output Format
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
Append this round's verdicts to [REVIEW_FILE] under a `### Round <N>`
|
|
77
|
+
heading — the task's review file is the durable record and fix
|
|
78
|
+
subagents read it. Then send a final message under 15 lines: begin
|
|
79
|
+
directly with the first finding's verdict. Every line is a verdict, a
|
|
80
|
+
finding with file:line, or a check you ran — no preamble, no process
|
|
81
|
+
narration.
|
|
79
82
|
|
|
80
83
|
### Finding Verdicts
|
|
81
84
|
|
|
@@ -107,9 +110,12 @@ Subagent (general-purpose):
|
|
|
107
110
|
- `[FINDINGS]` — the Critical/Important findings and spec gaps from the
|
|
108
111
|
previous review, copied verbatim, one per bullet
|
|
109
112
|
- `[REPORT_FILE]` — the implementer's report file (fix reports appended)
|
|
113
|
+
- `[REVIEW_FILE]` — the task's review file (brief `…/task-N-brief.md` →
|
|
114
|
+
review `…/task-N-review.md`); append this round's verdicts to it
|
|
110
115
|
- `[FIX_BASE_SHA]` — the head the previous review saw
|
|
111
116
|
- `[HEAD_SHA]` — current commit
|
|
112
117
|
- `[DIFF_FILE]` — the path `scripts/review-package PLAN_FILE FIX_BASE HEAD` printed
|
|
113
118
|
|
|
114
119
|
**Re-reviewer returns:** per-finding verdicts (ADDRESSED / NOT ADDRESSED),
|
|
115
|
-
new breakage in the fix diff, out-of-scope observations, and a round verdict
|
|
120
|
+
new breakage in the fix diff, out-of-scope observations, and a round verdict —
|
|
121
|
+
appended to `[REVIEW_FILE]`, with a short final message.
|
|
@@ -19,6 +19,12 @@ base=$2
|
|
|
19
19
|
head=$3
|
|
20
20
|
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
|
21
21
|
|
|
22
|
+
git rev-parse --git-dir >/dev/null 2>&1 || {
|
|
23
|
+
echo "error: not a git repository — review-package needs the BASE and HEAD commits of the task under review." >&2
|
|
24
|
+
echo "A greenfield plan's first task creates the repo itself: run this from inside the repo once that task has committed." >&2
|
|
25
|
+
exit 2
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; }
|
|
23
29
|
git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; }
|
|
24
30
|
|
|
@@ -19,6 +19,13 @@ if (-not (Test-Path -LiteralPath $plan -PathType Leaf)) {
|
|
|
19
19
|
exit 2
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
& git rev-parse --git-dir *> $null
|
|
23
|
+
if ($LASTEXITCODE -ne 0) {
|
|
24
|
+
[Console]::Error.WriteLine("error: not a git repository — review-package needs the BASE and HEAD commits of the task under review.")
|
|
25
|
+
[Console]::Error.WriteLine("A greenfield plan's first task creates the repo itself: run this from inside the repo once that task has committed.")
|
|
26
|
+
exit 2
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
& git rev-parse --verify --quiet $base *> $null
|
|
23
30
|
if ($LASTEXITCODE -ne 0) {
|
|
24
31
|
[Console]::Error.WriteLine("bad BASE: $base")
|