taskplane 0.28.8 → 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/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 +5 -1
- 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-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
|
*
|
|
@@ -1901,7 +1901,11 @@ export function runPreflight(config: OrchestratorConfig, repoRoot?: string): Pre
|
|
|
1901
1901
|
switch (piResult.errorKind) {
|
|
1902
1902
|
case "not-found":
|
|
1903
1903
|
message = "Pi not found on PATH";
|
|
1904
|
-
|
|
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)";
|
|
1905
1909
|
break;
|
|
1906
1910
|
case "timeout":
|
|
1907
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:
|
|
@@ -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
|