taskplane 0.28.7 → 0.29.0
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/bin/get-version.mjs +50 -0
- package/bin/taskplane.mjs +5 -8
- package/dashboard/public/app.js +7 -3
- package/dashboard/public/style.css +16 -13
- package/extensions/taskplane/agent-bridge-extension.ts +58 -3
- package/extensions/taskplane/agent-host.ts +11 -17
- package/extensions/taskplane/config-schema.ts +17 -12
- package/extensions/taskplane/engine-worker.ts +27 -0
- package/extensions/taskplane/engine.ts +78 -1
- package/extensions/taskplane/execution.ts +23 -1
- package/extensions/taskplane/extension.ts +303 -0
- package/extensions/taskplane/lane-runner.ts +74 -3
- package/extensions/taskplane/mailbox.ts +83 -0
- package/extensions/taskplane/messages.ts +19 -0
- package/extensions/taskplane/path-resolver.ts +63 -24
- package/extensions/taskplane/persistence.ts +378 -3
- package/extensions/taskplane/resume.ts +56 -6
- package/extensions/taskplane/tool-allowlist-constants.ts +37 -0
- package/extensions/taskplane/types.ts +34 -5
- package/extensions/taskplane/worktree.ts +101 -2
- package/package.json +1 -1
- package/skills/create-taskplane-task/SKILL.md +37 -0
- package/templates/agents/supervisor.md +62 -1
- package/templates/agents/task-reviewer.md +68 -0
- package/templates/agents/task-worker.md +58 -6
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import type { ExitClassification, TaskExitDiagnostic } from "./diagnostics.js";
|
|
7
|
+
// TP-189 (Cluster B): single source of truth for the worker user-tools
|
|
8
|
+
// default literal. The constants module is import-free so this does NOT
|
|
9
|
+
// create a cycle (types.ts -> tool-allowlist-constants.ts is a leaf).
|
|
10
|
+
import { DEFAULT_WORKER_USER_TOOLS } from "./tool-allowlist-constants.ts";
|
|
7
11
|
|
|
8
12
|
// ── Types ────────────────────────────────────────────────────────────
|
|
9
13
|
|
|
@@ -390,11 +394,12 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
|
|
|
390
394
|
},
|
|
391
395
|
merge: {
|
|
392
396
|
model: "",
|
|
393
|
-
//
|
|
394
|
-
// `
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
|
|
397
|
+
// TP-189 (Cluster B): merge default sourced from the import-free
|
|
398
|
+
// `tool-allowlist-constants.ts` module. The previous concern about
|
|
399
|
+
// importing from `agent-host.ts` (which DOES depend on types.ts and
|
|
400
|
+
// would create a cycle) no longer applies because the constant
|
|
401
|
+
// lives in a leaf module that imports nothing.
|
|
402
|
+
tools: DEFAULT_WORKER_USER_TOOLS,
|
|
398
403
|
thinking: "off",
|
|
399
404
|
verify: [],
|
|
400
405
|
order: "fewest-files-first",
|
|
@@ -2189,6 +2194,30 @@ export interface SupervisorAlert {
|
|
|
2189
2194
|
*/
|
|
2190
2195
|
export type SupervisorAlertCallback = (alert: SupervisorAlert) => void;
|
|
2191
2196
|
|
|
2197
|
+
/**
|
|
2198
|
+
* Information about a lane that has just reached a terminal state.
|
|
2199
|
+
*
|
|
2200
|
+
* Emitted at the no-progress kill and hard-fail decision points so the
|
|
2201
|
+
* supervisor process can mark the lane as terminated and drop any further
|
|
2202
|
+
* alerts queued for it (see {@link LaneTerminatedCallback}).
|
|
2203
|
+
*
|
|
2204
|
+
* @since TP-187 (#538)
|
|
2205
|
+
*/
|
|
2206
|
+
export interface LaneTerminatedInfo {
|
|
2207
|
+
laneNumber: number;
|
|
2208
|
+
agentId: string;
|
|
2209
|
+
batchId: string;
|
|
2210
|
+
terminatedAt: number;
|
|
2211
|
+
reason: "no-progress-kill" | "hard-fail" | "supervisor-takeover";
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
/**
|
|
2215
|
+
* Callback invoked when a lane reaches a terminal state.
|
|
2216
|
+
*
|
|
2217
|
+
* @since TP-187 (#538)
|
|
2218
|
+
*/
|
|
2219
|
+
export type LaneTerminatedCallback = (info: LaneTerminatedInfo) => void;
|
|
2220
|
+
|
|
2192
2221
|
/**
|
|
2193
2222
|
* Build a batch progress snapshot from runtime state.
|
|
2194
2223
|
*
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module orch/worktree
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync, mkdirSync, readdirSync, realpathSync, rmdirSync, rmSync } from "fs";
|
|
6
|
-
import { execSync } from "child_process";
|
|
6
|
+
import { execSync, execFileSync } from "child_process";
|
|
7
7
|
import { join, basename, resolve } from "path";
|
|
8
8
|
|
|
9
9
|
import { execLog } from "./execution.ts";
|
|
@@ -639,6 +639,57 @@ export function isRetriableRemoveError(stderr: string): boolean {
|
|
|
639
639
|
return false;
|
|
640
640
|
}
|
|
641
641
|
|
|
642
|
+
/**
|
|
643
|
+
* Detect Windows MAX_PATH ("Filename too long") errors from `git worktree remove`.
|
|
644
|
+
*
|
|
645
|
+
* On Windows with default `core.longpaths = false`, git refuses to delete
|
|
646
|
+
* paths that exceed MAX_PATH (260 characters). Deep `node_modules` trees
|
|
647
|
+
* commonly trip this. Native `cmd` `rd /s /q` uses a different deletion
|
|
648
|
+
* code path (NT object namespace, longer path tolerance) and usually
|
|
649
|
+
* succeeds where git fails.
|
|
650
|
+
*
|
|
651
|
+
* @param stderr - Error output from `git worktree remove`
|
|
652
|
+
* @returns true if the failure looks like the Windows MAX_PATH case
|
|
653
|
+
* @since TP-188 (#543)
|
|
654
|
+
*/
|
|
655
|
+
export function isWindowsMaxPathError(stderr: string): boolean {
|
|
656
|
+
if (process.platform !== "win32") return false;
|
|
657
|
+
return /filename too long/i.test(stderr);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Run `cmd /c rd /s /q <path>` to recursively delete a directory on Windows.
|
|
662
|
+
*
|
|
663
|
+
* Used as a fallback after `git worktree remove` fails with the Windows
|
|
664
|
+
* MAX_PATH ("Filename too long") error. Caller must ensure platform is win32
|
|
665
|
+
* and the path is absolute. Path separators are normalized to backslashes
|
|
666
|
+
* because cmd's `rd` is more reliable with native Windows paths.
|
|
667
|
+
*
|
|
668
|
+
* @param absolutePath - Absolute path to remove (forward or back slashes accepted)
|
|
669
|
+
* @returns { ok, stdout, stderr }
|
|
670
|
+
* @since TP-188 (#543)
|
|
671
|
+
*/
|
|
672
|
+
export function runWindowsCmdRd(
|
|
673
|
+
absolutePath: string,
|
|
674
|
+
): { ok: boolean; stdout: string; stderr: string } {
|
|
675
|
+
const winPath = absolutePath.replace(/\//g, "\\");
|
|
676
|
+
try {
|
|
677
|
+
const stdout = execFileSync("cmd", ["/c", "rd", "/s", "/q", winPath], {
|
|
678
|
+
encoding: "utf-8",
|
|
679
|
+
timeout: 60_000,
|
|
680
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
681
|
+
}).toString().trim();
|
|
682
|
+
return { ok: true, stdout, stderr: "" };
|
|
683
|
+
} catch (err: unknown) {
|
|
684
|
+
const e = err as { stdout?: string; stderr?: string; message?: string };
|
|
685
|
+
return {
|
|
686
|
+
ok: false,
|
|
687
|
+
stdout: (e.stdout ?? "").toString().trim(),
|
|
688
|
+
stderr: (e.stderr ?? e.message ?? "unknown error").toString().trim(),
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
642
693
|
/**
|
|
643
694
|
* Remove a git worktree and clean up its associated branch.
|
|
644
695
|
*
|
|
@@ -733,6 +784,50 @@ export function removeWorktree(
|
|
|
733
784
|
|
|
734
785
|
lastError = removeResult.stderr;
|
|
735
786
|
|
|
787
|
+
// ── Windows MAX_PATH fallback (#543) ────────────────────────
|
|
788
|
+
// On Windows, `git worktree remove` fails with "Filename too long"
|
|
789
|
+
// when the worktree contains deep `node_modules` trees (most
|
|
790
|
+
// non-trivial Node projects) and `core.longpaths = false` (default).
|
|
791
|
+
// `cmd /c rd /s /q <path>` uses a different deletion code path
|
|
792
|
+
// that tolerates long paths better. Try it ONCE before classifying
|
|
793
|
+
// the error as terminal/retriable so other error classes still
|
|
794
|
+
// surface unchanged.
|
|
795
|
+
if (isWindowsMaxPathError(lastError)) {
|
|
796
|
+
execLog(
|
|
797
|
+
"cleanup",
|
|
798
|
+
"worktree",
|
|
799
|
+
`Windows MAX_PATH detected — falling back to cmd "rd /s /q"`,
|
|
800
|
+
{ path: worktreePath, attempt },
|
|
801
|
+
);
|
|
802
|
+
const fallback = runWindowsCmdRd(worktreePath);
|
|
803
|
+
if (fallback.ok) {
|
|
804
|
+
execLog(
|
|
805
|
+
"cleanup",
|
|
806
|
+
"worktree",
|
|
807
|
+
`cmd "rd /s /q" fallback succeeded; pruning git worktree state`,
|
|
808
|
+
{ path: worktreePath },
|
|
809
|
+
);
|
|
810
|
+
// The on-disk tree is gone; git's bookkeeping still has a
|
|
811
|
+
// stale entry. Prune so isRegisteredWorktree() returns false
|
|
812
|
+
// during post-removal verification below.
|
|
813
|
+
runGit(["worktree", "prune"], repoRoot);
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
// Fallback also failed — enrich error so the operator sees both
|
|
817
|
+
// attempts, then fall through to the existing terminal/retry
|
|
818
|
+
// classification (which will throw because "Filename too long"
|
|
819
|
+
// is non-retriable per isRetriableRemoveError).
|
|
820
|
+
execLog(
|
|
821
|
+
"cleanup",
|
|
822
|
+
"worktree",
|
|
823
|
+
`cmd "rd /s /q" fallback failed`,
|
|
824
|
+
{ path: worktreePath, error: fallback.stderr.slice(0, 200) },
|
|
825
|
+
);
|
|
826
|
+
lastError =
|
|
827
|
+
`git worktree remove failed: ${lastError}; ` +
|
|
828
|
+
`cmd rd /s /q fallback failed: ${fallback.stderr}`;
|
|
829
|
+
}
|
|
830
|
+
|
|
736
831
|
// Check if error is terminal (non-retriable)
|
|
737
832
|
if (!isRetriableRemoveError(lastError)) {
|
|
738
833
|
throw new WorktreeError(
|
|
@@ -1806,7 +1901,11 @@ export function runPreflight(config: OrchestratorConfig, repoRoot?: string): Pre
|
|
|
1806
1901
|
switch (piResult.errorKind) {
|
|
1807
1902
|
case "not-found":
|
|
1808
1903
|
message = "Pi not found on PATH";
|
|
1809
|
-
|
|
1904
|
+
// Issue #560: Pi was renamed from @mariozechner to @earendil-works
|
|
1905
|
+
// in v0.74.0. Recommend the new scope for new installs; the legacy
|
|
1906
|
+
// scope still resolves at runtime via Pi's bundled aliasing if a
|
|
1907
|
+
// transitional install has it.
|
|
1908
|
+
hint = "Install Pi: npm install -g @earendil-works/pi-coding-agent (legacy: @mariozechner/pi-coding-agent)";
|
|
1810
1909
|
break;
|
|
1811
1910
|
case "timeout":
|
|
1812
1911
|
message = `Pi did not respond within ${PI_PREFLIGHT_TIMEOUT_MS / 1000}s (retried once)`;
|
package/package.json
CHANGED
|
@@ -153,6 +153,43 @@ Individual steps can override the task-level review:
|
|
|
153
153
|
> **Review override: code review** — This step touches authorization.
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
### Per-Step Reviews vs. Consolidated Reviews (Checkpoint Markers)
|
|
157
|
+
|
|
158
|
+
A second axis sits alongside the Review Level: **how many** reviews fire
|
|
159
|
+
for a given level. PROMPT authors should make this choice deliberately.
|
|
160
|
+
|
|
161
|
+
**Default — per-step reviews:** at Review Level ≥ 1, the worker fires a
|
|
162
|
+
plan review BEFORE each implementation step and (at Level ≥ 2) a code
|
|
163
|
+
review AFTER. A 5-implementation-step Level 2 task therefore fires
|
|
164
|
+
~5 plan + ~5 code = ~10 reviews. This is the right default for tasks
|
|
165
|
+
where each step is an independent piece of work (e.g., a multi-cluster
|
|
166
|
+
polish bundle, a multi-feature sprint).
|
|
167
|
+
|
|
168
|
+
**Opt-in — consolidated via checkpoint markers:** a PROMPT can include
|
|
169
|
+
`**Plan-review checkpoint**` or `**Code review checkpoint**` markers in
|
|
170
|
+
specific steps. The worker treats those markers as instructions to fire
|
|
171
|
+
the corresponding review at *that* step only, instead of per-step. A
|
|
172
|
+
single-deliverable task that decomposes into 1 design step + 3 mechanical
|
|
173
|
+
implementation steps + 1 verify-everything step might mark the design
|
|
174
|
+
step as the plan checkpoint and the verify step as the code checkpoint,
|
|
175
|
+
for a total of 2 reviews instead of ~8.
|
|
176
|
+
|
|
177
|
+
**When to use which:**
|
|
178
|
+
|
|
179
|
+
- **Per-step (default):** independent multi-feature work, polish bundles,
|
|
180
|
+
refactor sweeps. Per-cluster review feedback is more useful than a
|
|
181
|
+
consolidated review across unrelated changes.
|
|
182
|
+
- **Consolidated (checkpoint markers):** single-deliverable tasks where
|
|
183
|
+
the steps are mechanical applications of one design decision. TP-186
|
|
184
|
+
(the `review_step` death-spiral fix) is a real example: 1 prompt-design
|
|
185
|
+
deliverable + 3 mechanical implementation steps + 1 code-review-
|
|
186
|
+
everything step → 2 reviews total instead of ~8.
|
|
187
|
+
|
|
188
|
+
**How to choose at PROMPT-authoring time:** ask "would the reviewer
|
|
189
|
+
benefit from seeing each step in isolation, or only the whole picture?"
|
|
190
|
+
If each step touches a different concern, per-step. If every step is
|
|
191
|
+
the same change applied to a different file, consolidate.
|
|
192
|
+
|
|
156
193
|
---
|
|
157
194
|
|
|
158
195
|
## Task Sizing
|
|
@@ -143,6 +143,15 @@ You can invoke these tools directly — no need to ask the operator or use slash
|
|
|
143
143
|
- **orch_pause()** — Pause the running batch (current tasks finish, no new tasks start)
|
|
144
144
|
- **orch_resume(force?)** — Resume a paused or interrupted batch. Use `force=true` for stuck batches.
|
|
145
145
|
- **orch_abort(hard?)** — Abort the running batch. Use `hard=true` for immediate kill.
|
|
146
|
+
- **supervisor_takeover(reason)** — **Non-destructive escape hatch.** Pause the
|
|
147
|
+
wave, drain all per-agent on-disk outboxes, and suppress in-transit zombie
|
|
148
|
+
alerts from already-running lanes. Worktrees, branches, batch state, and
|
|
149
|
+
sessions are preserved. Distinct from `orch_abort`, which kills sessions and
|
|
150
|
+
deletes state. Use this when the batch is producing alert spam or has hit a
|
|
151
|
+
death-spiral pattern but you may still want to resume the same batch later.
|
|
152
|
+
After takeover, call `orch_status()` to inspect, then either
|
|
153
|
+
`orch_resume(force=true)` to continue (alert suppression is lifted
|
|
154
|
+
automatically) or `orch_abort()` to escalate to destructive shutdown.
|
|
146
155
|
- **orch_integrate(mode?, force?, branch?)** — Integrate completed batch into working branch.
|
|
147
156
|
Modes: `"fast-forward"` (default), `"merge"`, `"pr"`.
|
|
148
157
|
|
|
@@ -153,12 +162,64 @@ Use tools **proactively** when the situation calls for it:
|
|
|
153
162
|
- Operator asks "how's it going?" → call `orch_status()` first, then summarize
|
|
154
163
|
- Batch paused due to a failure you diagnosed and fixed → call `orch_resume()`
|
|
155
164
|
- Batch completed successfully → offer to call `orch_integrate()` (fast-forward is default and cleanest; use `mode="merge"` if diverged, `mode="pr"` only if remotes exist and branch is protected)
|
|
156
|
-
- Batch is stuck or
|
|
165
|
+
- Batch is stuck, producing alert spam, or hitting a death-spiral → call `orch_status()` to diagnose, then **prefer `supervisor_takeover(reason)`** to park the batch non-destructively (worktrees + state preserved; resume with `orch_resume(force=true)` afterward). Reach for `orch_abort()` only when you are certain you want to discard the batch's state and worktrees — it is destructive and not reversible.
|
|
157
166
|
- Need to investigate before more tasks launch → call `orch_pause()` first
|
|
158
167
|
|
|
159
168
|
These tools are preferred over reading batch-state.json directly because they handle
|
|
160
169
|
disk fallback, in-memory state, and all edge cases automatically.
|
|
161
170
|
|
|
171
|
+
## Worker exit-intercept replies (text-reply parser semantics)
|
|
172
|
+
|
|
173
|
+
When a worker lane is about to exit without making progress, the lane-runner
|
|
174
|
+
fires an alert (`worker-exit-intercept`) and waits up to **60 seconds** for
|
|
175
|
+
you to reply via the worker's mailbox inbox (e.g., via `send_agent_message`).
|
|
176
|
+
|
|
177
|
+
Replies fall into two categories. The lane-runner classifies them by **shape**,
|
|
178
|
+
not by intent:
|
|
179
|
+
|
|
180
|
+
### Close directives
|
|
181
|
+
|
|
182
|
+
These close the worker session without re-prompting. They MUST be:
|
|
183
|
+
|
|
184
|
+
1. **Short** — the entire reply is **under 30 characters**, AND
|
|
185
|
+
2. **Either an exact match for a close keyword OR a close keyword followed by
|
|
186
|
+
`:`, ` ` (space), `.`, or ` -` (space-dash).**
|
|
187
|
+
|
|
188
|
+
Close keywords: `skip`, `let it fail`, `close`, `abort`, `stop`.
|
|
189
|
+
|
|
190
|
+
Examples that close the session:
|
|
191
|
+
|
|
192
|
+
- `skip`
|
|
193
|
+
- `let it fail`
|
|
194
|
+
- `stop.`
|
|
195
|
+
- `skip - blocker logged`
|
|
196
|
+
|
|
197
|
+
Examples that do NOT close the session (treated as instructional re-prompts):
|
|
198
|
+
|
|
199
|
+
- `Stop trying that approach — use the alternate path described in CONTEXT.md`
|
|
200
|
+
(longer than 30 chars, so it is a re-prompt, not a stop directive)
|
|
201
|
+
- `let it fail because the dependency is missing` (longer than 30 chars)
|
|
202
|
+
- `Skip the file-system check and proceed with the in-memory test` (longer
|
|
203
|
+
than 30 chars)
|
|
204
|
+
|
|
205
|
+
### Instructional replies
|
|
206
|
+
|
|
207
|
+
Anything that is not a close directive is treated as a re-prompt: the worker
|
|
208
|
+
resumes with your reply text as additional instructions for the next iteration.
|
|
209
|
+
This is the right shape for steering messages.
|
|
210
|
+
|
|
211
|
+
### Practical rule of thumb
|
|
212
|
+
|
|
213
|
+
- To **close** a stuck lane: send a one-word reply (`skip`, `stop`, `abort`).
|
|
214
|
+
- To **steer** a stuck lane: send a multi-sentence message with concrete
|
|
215
|
+
instructions. Do NOT prefix instructions with one of the close keywords —
|
|
216
|
+
if your message starts with `stop` or `abort` and is short, the worker will
|
|
217
|
+
exit instead of taking your instructions.
|
|
218
|
+
|
|
219
|
+
Replies that arrive after the 60-second timeout are ignored; the lane proceeds
|
|
220
|
+
with its corrective re-spawn behavior. After three iterations without progress
|
|
221
|
+
the lane is killed regardless of replies.
|
|
222
|
+
|
|
162
223
|
## Startup Checklist
|
|
163
224
|
|
|
164
225
|
Now that you've activated:
|
|
@@ -50,6 +50,74 @@ You handle a single review request and then exit.
|
|
|
50
50
|
Do NOT just respond with text — the orchestrator reads the OUTPUT FILE to get
|
|
51
51
|
your verdict. If you don't write the file, your review is lost.
|
|
52
52
|
|
|
53
|
+
## Quality-check verification (code reviews only)
|
|
54
|
+
|
|
55
|
+
**This section applies to code reviews only.** For plan reviews, skip this
|
|
56
|
+
section entirely — there is no code to type-check or lint yet.
|
|
57
|
+
|
|
58
|
+
Before returning a code-review verdict, run the project's declared
|
|
59
|
+
typecheck / lint / format-check commands against the post-change tree. A
|
|
60
|
+
behavioural-correctness APPROVE is **invalidated** by failing quality checks.
|
|
61
|
+
|
|
62
|
+
The reviewer's tool allowlist already includes `bash`, so you can invoke these
|
|
63
|
+
commands directly — no special tooling is required.
|
|
64
|
+
|
|
65
|
+
### How to discover the commands
|
|
66
|
+
|
|
67
|
+
1. **Project config first.** Read `.pi/taskplane-config.json` (or the legacy
|
|
68
|
+
`.pi/task-runner.yaml` / `.pi/task-runner.json` fallbacks) and look at
|
|
69
|
+
`taskRunner.testing.commands` — a `Record<string, string>` mapping a
|
|
70
|
+
command name (e.g. `typecheck`, `lint`, `format:check`) to a
|
|
71
|
+
shell command. Run any command whose key matches one of
|
|
72
|
+
`typecheck` / `tsc` / `types` / `lint` / `format:check`.
|
|
73
|
+
**Prefer `format:check` over `format`** — the latter typically rewrites
|
|
74
|
+
files in place, which would mutate the working tree the reviewer is
|
|
75
|
+
evaluating. If only a mutating `format` script is available in either
|
|
76
|
+
source, skip it and note this in the Summary; do not run mutating
|
|
77
|
+
commands from the reviewer.
|
|
78
|
+
2. **Fallback to `package.json` scripts.** If step 1 did not yield any
|
|
79
|
+
relevant commands — either because `taskRunner.testing.commands` is
|
|
80
|
+
absent OR because it exists but contains no keys matching the
|
|
81
|
+
typecheck/lint/format-check set — read `package.json` and run any of
|
|
82
|
+
these scripts that exist, in this order:
|
|
83
|
+
`npm run typecheck`, `npm run lint`, `npm run format:check`.
|
|
84
|
+
Skip a script if `package.json#scripts` does not declare it — do not
|
|
85
|
+
invent commands.
|
|
86
|
+
3. **Skip silently** if neither source yields a relevant command. Do not fail
|
|
87
|
+
the review just because the project has no quality-check pipeline
|
|
88
|
+
configured. Note this in the Summary so the operator knows quality checks
|
|
89
|
+
were not exercised.
|
|
90
|
+
|
|
91
|
+
Do NOT run the project's full test suite from this section — that is the
|
|
92
|
+
worker's Testing & Verification step. The quality checks here are
|
|
93
|
+
**fast static checks** (typecheck, lint, format) that are cheap to run and
|
|
94
|
+
high-signal for catching regressions the behavioural diff review would miss.
|
|
95
|
+
|
|
96
|
+
### What to do with the results
|
|
97
|
+
|
|
98
|
+
- **All quality checks pass** → proceed to behavioural code review as normal.
|
|
99
|
+
- **A quality check fails** → surface each failing command as an entry in
|
|
100
|
+
**Issues Found** with severity `important`. Include:
|
|
101
|
+
- The command that failed (e.g. `npm run typecheck`)
|
|
102
|
+
- The first few lines of the failing output (file/line locations are
|
|
103
|
+
most useful)
|
|
104
|
+
- A concrete suggested fix where the failure makes one obvious
|
|
105
|
+
- **Verdict downgrade rule:** If quality checks fail, the verdict is
|
|
106
|
+
**REVISE** — even if the behavioural code review would otherwise have
|
|
107
|
+
been APPROVE. Quality-check failures are blocking by definition: they
|
|
108
|
+
would surface at the worker's Testing & Verification step and force a
|
|
109
|
+
redo of the entire review cycle, so it is strictly cheaper to surface
|
|
110
|
+
them here.
|
|
111
|
+
|
|
112
|
+
### Worked example (Issues Found entry)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
1. **[npm run typecheck:1] [important]** — 5 strict-mode errors in
|
|
116
|
+
tests/foo.test.ts. Sample: "Argument of type 'undefined' is not
|
|
117
|
+
assignable to parameter of type 'string'" at line 42. Fix: narrow
|
|
118
|
+
`getThing()` return type or assert non-null at call site.
|
|
119
|
+
```
|
|
120
|
+
|
|
53
121
|
## Verdict Criteria
|
|
54
122
|
|
|
55
123
|
- **APPROVE** — Step will achieve its stated outcomes. Minor suggestions belong
|
|
@@ -33,9 +33,22 @@ visibility into your progress. If you batch updates, the dashboard shows
|
|
|
33
33
|
3. **Hydrate if needed** (see STATUS.md Hydration below)
|
|
34
34
|
4. Within that step, find the **first unchecked checkbox** (`- [ ]`)
|
|
35
35
|
5. Resume from there — do NOT redo checked items (`- [x]`)
|
|
36
|
-
6. When a step's items are all checked,
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
6. When a step's checkbox items are all checked, the next move depends on
|
|
37
|
+
the task's Review Level:
|
|
38
|
+
- **Review Level 0 or 1** (no code review): the step is done. Commit
|
|
39
|
+
the implementation and proceed to the next incomplete step.
|
|
40
|
+
- **Review Level 2 or 3** (code review required): the step is NOT
|
|
41
|
+
done yet. Commit the implementation, call
|
|
42
|
+
`review_step(step=N, type="code")`, and only flip the step's
|
|
43
|
+
`**Status:**` heading to `✅ Complete` AFTER the reviewer returns
|
|
44
|
+
APPROVE. See **Order of Operations for steps with code review**
|
|
45
|
+
below for the full sequence and the recovery recipe if the order
|
|
46
|
+
gets violated.
|
|
47
|
+
7. If all steps are complete, update the top-of-file STATUS.md **Status**
|
|
48
|
+
field to `✅ Complete` and **Current Step** to the last step name —
|
|
49
|
+
this is your final action. (The top-of-file Status is the task-level
|
|
50
|
+
field; per-step `**Status:** ✅ Complete` headings are governed by
|
|
51
|
+
the Order of Operations rule.)
|
|
39
52
|
|
|
40
53
|
## CRITICAL: Do NOT Create .DONE Files
|
|
41
54
|
|
|
@@ -61,6 +74,29 @@ There is NO other reason to exit. Do not exit after completing a step to
|
|
|
61
74
|
"hand off" to the next iteration. Do not exit to report progress. Do not
|
|
62
75
|
exit because you've been working for a while. Just keep going.
|
|
63
76
|
|
|
77
|
+
### ⚠️ MANDATORY: If you DO exit-with-no-progress, state the reason
|
|
78
|
+
|
|
79
|
+
If you genuinely must exit an iteration without checking any new boxes (no
|
|
80
|
+
blocker logged, no soft progress), the lane-runner will intercept and ask
|
|
81
|
+
the supervisor for guidance. The alert sent to the supervisor includes a
|
|
82
|
+
`Worker said:` field populated from your most recent assistant message.
|
|
83
|
+
|
|
84
|
+
**You MUST emit a one-sentence assistant message stating the specific reason
|
|
85
|
+
before exiting.** Examples of acceptable reasons:
|
|
86
|
+
|
|
87
|
+
- "Stuck on TS error in lane-runner.ts:691 — emitAlert types mismatched, need
|
|
88
|
+
to check SupervisorAlertContext shape."
|
|
89
|
+
- "Tests for the new helper need fixtures that don't exist; cannot proceed
|
|
90
|
+
without the supervisor pointing me at the right pattern."
|
|
91
|
+
- "The reviewer's REVISE feedback contradicts the TP-187 design; need
|
|
92
|
+
clarification on whether wave-plan reconstruction is in scope."
|
|
93
|
+
|
|
94
|
+
Empty/silent exits are still intercepted, but the supervisor sees `Worker
|
|
95
|
+
said: ""` (or a fallback to your most-recent visible assistant message)
|
|
96
|
+
which is much harder to act on. Always articulate the blocker before
|
|
97
|
+
exiting — it is the difference between getting useful steering and burning
|
|
98
|
+
an iteration on a generic re-prompt.
|
|
99
|
+
|
|
64
100
|
## CRITICAL: Never Narrate What You Plan To Do — Just Do It
|
|
65
101
|
|
|
66
102
|
**YOUR #1 FAILURE MODE:** Producing a message like "Now let me fix this:" or
|
|
@@ -126,14 +162,30 @@ orchestrator and you will be re-spawned to do it again.
|
|
|
126
162
|
### Git commits (after completing a STEP)
|
|
127
163
|
|
|
128
164
|
Git commits happen at **step boundaries**, not after every checkbox. When all
|
|
129
|
-
checkboxes in a step are checked off:
|
|
165
|
+
checkboxes in a step are checked off, commit the implementation:
|
|
130
166
|
|
|
131
167
|
```bash
|
|
132
|
-
git add -A && git commit -m "feat(TASK-ID):
|
|
168
|
+
git add -A && git commit -m "feat(TASK-ID): step N implementation"
|
|
133
169
|
```
|
|
134
170
|
|
|
171
|
+
For **Review Level 0 or 1** tasks, this commit completes the step — the next
|
|
172
|
+
thing you do is move to step N+1.
|
|
173
|
+
|
|
174
|
+
For **Review Level 2 or 3** tasks, this commit is the *implementation* commit;
|
|
175
|
+
the step is not done yet. After committing, call `review_step(type="code")`,
|
|
176
|
+
then — once the reviewer returns APPROVE — flip the step's `**Status:**`
|
|
177
|
+
heading to `✅ Complete` and commit that status update separately:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
git commit -am "chore(TASK-ID): step N complete (code review APPROVE)"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
See **Order of Operations for steps with code review** below for the full
|
|
184
|
+
sequence and the recovery recipe if the order is violated.
|
|
185
|
+
|
|
135
186
|
This keeps the git history meaningful — one coherent commit per step instead of
|
|
136
|
-
dozens of micro-commits that nobody reads
|
|
187
|
+
dozens of micro-commits that nobody reads, with an explicit review-gating
|
|
188
|
+
commit when applicable.
|
|
137
189
|
|
|
138
190
|
**Exceptions** — commit immediately (before step completion) in these cases:
|
|
139
191
|
- **Hydration:** After expanding STATUS.md with new checkboxes, commit before
|