taskplane 0.7.1 → 0.8.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/dashboard/public/app.js +43 -18
- package/extensions/task-runner.ts +346 -127
- package/extensions/taskplane/config-loader.ts +1 -1
- package/extensions/taskplane/config-schema.ts +7 -5
- package/extensions/taskplane/engine.ts +6 -6
- package/extensions/taskplane/extension.ts +207 -5
- package/extensions/taskplane/merge.ts +21 -21
- package/extensions/taskplane/messages.ts +4 -4
- package/extensions/taskplane/resume.ts +6 -6
- package/extensions/taskplane/supervisor.ts +141 -9
- package/extensions/taskplane/types.ts +4 -4
- package/extensions/taskplane/worktree.ts +13 -0
- package/package.json +1 -1
- package/templates/agents/local/task-reviewer.md +1 -1
- package/templates/agents/local/task-worker.md +4 -3
- package/templates/agents/task-merger.md +215 -215
- package/templates/agents/task-reviewer.md +1 -1
- package/templates/agents/task-worker.md +18 -13
- package/templates/config/task-orchestrator.yaml +1 -1
- package/templates/config/task-runner.yaml +3 -3
|
@@ -2028,7 +2028,38 @@ When the conversation reaches the config generation phase, create ALL of these
|
|
|
2028
2028
|
- \`.gitignore\` entries — add Taskplane working file patterns if not already present
|
|
2029
2029
|
|
|
2030
2030
|
Use conservative creation: check if each file exists before writing. If files
|
|
2031
|
-
already exist (partial setup), read and merge rather than overwrite
|
|
2031
|
+
already exist (partial setup), read and merge rather than overwrite.
|
|
2032
|
+
|
|
2033
|
+
### CRITICAL: Task Area Registration
|
|
2034
|
+
|
|
2035
|
+
**Every task folder MUST be registered in \`.pi/taskplane-config.json\` under
|
|
2036
|
+
\`taskRunner.taskAreas\`.** Without registration, \`/orch all\` will fail with
|
|
2037
|
+
"no task areas configured" — even if the folders and tasks physically exist.
|
|
2038
|
+
|
|
2039
|
+
When creating a task folder (e.g., \`taskplane-tasks/\`):
|
|
2040
|
+
1. Create the folder and its \`CONTEXT.md\`
|
|
2041
|
+
2. Register it in \`.pi/taskplane-config.json\`:
|
|
2042
|
+
\`\`\`json
|
|
2043
|
+
{
|
|
2044
|
+
"taskRunner": {
|
|
2045
|
+
"taskAreas": {
|
|
2046
|
+
"general": {
|
|
2047
|
+
"path": "taskplane-tasks",
|
|
2048
|
+
"prefix": "TP",
|
|
2049
|
+
"context": "taskplane-tasks/CONTEXT.md"
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
\`\`\`
|
|
2055
|
+
3. **Verify** by reading the config back to confirm the area is registered
|
|
2056
|
+
|
|
2057
|
+
When creating tasks inside an area, check that the area is registered first.
|
|
2058
|
+
If it's not (e.g., operator created the folder manually), register it before
|
|
2059
|
+
proceeding.
|
|
2060
|
+
|
|
2061
|
+
This also applies when creating tasks later in the conversation — always verify
|
|
2062
|
+
the task area is registered in the config before offering to run \`/orch all\`.`;
|
|
2032
2063
|
break;
|
|
2033
2064
|
|
|
2034
2065
|
case "pending-tasks":
|
|
@@ -2068,7 +2099,14 @@ Follow the primer's **"Script 6: Batch Planning"** section
|
|
|
2068
2099
|
5. **Offer a health check** (Script 7) if the operator prefers to assess
|
|
2069
2100
|
project state rather than create tasks
|
|
2070
2101
|
6. **Graceful fallback**: If \`gh\` CLI is unavailable, skip GitHub checks and
|
|
2071
|
-
mention it to the operator — continue with CONTEXT.md and TODO scanning
|
|
2102
|
+
mention it to the operator — continue with CONTEXT.md and TODO scanning
|
|
2103
|
+
|
|
2104
|
+
### Important: Task Area Verification
|
|
2105
|
+
|
|
2106
|
+
Before creating any tasks, verify that the target task area folder is registered
|
|
2107
|
+
in \`.pi/taskplane-config.json\` under \`taskRunner.taskAreas\`. If it's missing
|
|
2108
|
+
(e.g., the folder exists but was never registered), register it first. Without
|
|
2109
|
+
registration, \`/orch all\` will fail with "no task areas configured."`;
|
|
2072
2110
|
break;
|
|
2073
2111
|
|
|
2074
2112
|
case "completed-batch":
|
|
@@ -2149,13 +2187,30 @@ Read the relevant script section now before starting the conversation.
|
|
|
2149
2187
|
- Summarize what you'll create before writing files — let the operator confirm
|
|
2150
2188
|
- If the operator says "just give me defaults", do it and move on
|
|
2151
2189
|
|
|
2190
|
+
## Starting a Batch
|
|
2191
|
+
|
|
2192
|
+
When the operator wants to run pending tasks, use the \`/orch all\` command.
|
|
2193
|
+
You can invoke it directly — it will seamlessly transition you from conversational
|
|
2194
|
+
mode to batch monitoring mode. Examples of operator intent:
|
|
2195
|
+
|
|
2196
|
+
- "run the open tasks" → respond with a brief confirmation, then invoke \`/orch all\`
|
|
2197
|
+
- "start the batch" → invoke \`/orch all\`
|
|
2198
|
+
- "run just the platform tasks" → invoke \`/orch platform\` (with the area name)
|
|
2199
|
+
|
|
2200
|
+
Before starting, you may optionally:
|
|
2201
|
+
- Show a quick summary of pending tasks and wave plan (\`/orch-plan all\`)
|
|
2202
|
+
- Ask for confirmation if the operator's intent was ambiguous
|
|
2203
|
+
|
|
2204
|
+
After \`/orch all\` starts, your system prompt will automatically switch to
|
|
2205
|
+
batch monitoring mode. You'll have full visibility into wave progress, task
|
|
2206
|
+
outcomes, and can handle failures.
|
|
2207
|
+
|
|
2152
2208
|
## What You Must NEVER Do
|
|
2153
2209
|
|
|
2154
|
-
1. Never
|
|
2155
|
-
2. Never
|
|
2156
|
-
3. Never
|
|
2157
|
-
4. Never
|
|
2158
|
-
5. Never make assumptions about project conventions — detect them
|
|
2210
|
+
1. Never modify existing code files (only create config/scaffolding)
|
|
2211
|
+
2. Never \`git push\` to any remote
|
|
2212
|
+
3. Never overwrite existing config files without asking
|
|
2213
|
+
4. Never make assumptions about project conventions — detect them
|
|
2159
2214
|
`;
|
|
2160
2215
|
|
|
2161
2216
|
return prompt;
|
|
@@ -2252,7 +2307,7 @@ export function freshSupervisorState(): SupervisorState {
|
|
|
2252
2307
|
* @returns The resolved Model, or undefined if not found
|
|
2253
2308
|
* @since TP-041
|
|
2254
2309
|
*/
|
|
2255
|
-
function resolveModelFromString(
|
|
2310
|
+
export function resolveModelFromString(
|
|
2256
2311
|
modelStr: string,
|
|
2257
2312
|
ctx: ExtensionContext,
|
|
2258
2313
|
): Model<Api> | undefined {
|
|
@@ -2504,6 +2559,78 @@ export async function deactivateSupervisor(
|
|
|
2504
2559
|
state.pendingSummaryDeps = null;
|
|
2505
2560
|
}
|
|
2506
2561
|
|
|
2562
|
+
/**
|
|
2563
|
+
* Transition the supervisor from batch-monitoring mode back to routing mode.
|
|
2564
|
+
*
|
|
2565
|
+
* Called after a batch completes (or fails/pauses) instead of fully deactivating.
|
|
2566
|
+
* Tears down batch-monitoring infrastructure (lockfile, heartbeat, event tailer)
|
|
2567
|
+
* but keeps the supervisor active with a routing context — so the operator can
|
|
2568
|
+
* continue the conversation (plan next batch, create tasks, integrate, etc.)
|
|
2569
|
+
* without needing to re-invoke `/orch`.
|
|
2570
|
+
*
|
|
2571
|
+
* This enables the continuous workflow:
|
|
2572
|
+
* /orch → conversation → "run the tasks" → batch runs → batch completes →
|
|
2573
|
+
* conversation continues → "create more tasks" → "run them" → repeat
|
|
2574
|
+
*
|
|
2575
|
+
* @param pi - The ExtensionAPI instance
|
|
2576
|
+
* @param state - Supervisor state to transition
|
|
2577
|
+
* @param routingContext - The routing context for the new conversational mode
|
|
2578
|
+
*
|
|
2579
|
+
* @since TP-128
|
|
2580
|
+
*/
|
|
2581
|
+
export async function transitionToRoutingMode(
|
|
2582
|
+
pi: ExtensionAPI,
|
|
2583
|
+
state: SupervisorState,
|
|
2584
|
+
routingContext: SupervisorRoutingContext,
|
|
2585
|
+
): Promise<void> {
|
|
2586
|
+
if (!state.active) return;
|
|
2587
|
+
|
|
2588
|
+
// Tear down batch-monitoring infrastructure
|
|
2589
|
+
stopEventTailer(state.eventTailer);
|
|
2590
|
+
|
|
2591
|
+
if (state.heartbeatTimer) {
|
|
2592
|
+
clearInterval(state.heartbeatTimer);
|
|
2593
|
+
state.heartbeatTimer = null;
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
// Remove lockfile (no active batch to protect)
|
|
2597
|
+
if (state.stateRoot && state.lockSessionId) {
|
|
2598
|
+
const currentLock = readLockfile(state.stateRoot);
|
|
2599
|
+
if (!currentLock || currentLock.sessionId === state.lockSessionId) {
|
|
2600
|
+
removeLockfile(state.stateRoot);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
state.lockSessionId = "";
|
|
2604
|
+
|
|
2605
|
+
// Present deferred batch summary if any
|
|
2606
|
+
if (state.pendingSummaryDeps && state.batchStateRef && state.stateRoot) {
|
|
2607
|
+
const deps = state.pendingSummaryDeps;
|
|
2608
|
+
presentBatchSummary(pi, state.batchStateRef, state.stateRoot, deps.opId, deps.diagnostics, deps.mergeResults);
|
|
2609
|
+
state.pendingSummaryDeps = null;
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
// Switch to routing mode — keep supervisor active with new context
|
|
2613
|
+
state.routingContext = routingContext;
|
|
2614
|
+
state.batchId = "";
|
|
2615
|
+
// Keep batchStateRef/orchConfigRef/stateRoot — routing prompt may need them
|
|
2616
|
+
// Keep model override — don't switch models mid-conversation
|
|
2617
|
+
|
|
2618
|
+
// Notify the operator that conversational mode is back
|
|
2619
|
+
pi.sendMessage(
|
|
2620
|
+
{
|
|
2621
|
+
customType: "supervisor-routing-transition",
|
|
2622
|
+
content: [{
|
|
2623
|
+
type: "text",
|
|
2624
|
+
text:
|
|
2625
|
+
`🔀 **Supervisor returning to conversational mode.**\n\n` +
|
|
2626
|
+
routingContext.contextMessage,
|
|
2627
|
+
}],
|
|
2628
|
+
display: `Supervisor — ${routingContext.routingState}`,
|
|
2629
|
+
},
|
|
2630
|
+
{ triggerTurn: true, deliverAs: "nextTurn" },
|
|
2631
|
+
);
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2507
2634
|
/**
|
|
2508
2635
|
* Register the before_agent_start hook for persistent system prompt injection.
|
|
2509
2636
|
*
|
|
@@ -2956,11 +3083,16 @@ export function startHeartbeat(
|
|
|
2956
3083
|
return;
|
|
2957
3084
|
}
|
|
2958
3085
|
|
|
2959
|
-
// Update heartbeat
|
|
3086
|
+
// Update heartbeat (and refresh batchId if it was initially unknown)
|
|
2960
3087
|
try {
|
|
2961
3088
|
const lock = readLockfile(stateRoot);
|
|
2962
3089
|
if (lock && lock.sessionId === sessionId) {
|
|
2963
3090
|
lock.heartbeat = new Date().toISOString();
|
|
3091
|
+
// TP-130: batchId may have been "(initializing)" at lock creation
|
|
3092
|
+
// because the batch hadn't started yet. Refresh from live state ref.
|
|
3093
|
+
if (state.batchStateRef?.batchId && lock.batchId !== state.batchStateRef.batchId) {
|
|
3094
|
+
lock.batchId = state.batchStateRef.batchId;
|
|
3095
|
+
}
|
|
2964
3096
|
writeLockfile(stateRoot, lock);
|
|
2965
3097
|
}
|
|
2966
3098
|
} catch {
|
|
@@ -182,7 +182,7 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
|
|
|
182
182
|
tools: "read,write,edit,bash,grep,find,ls",
|
|
183
183
|
verify: [],
|
|
184
184
|
order: "fewest-files-first",
|
|
185
|
-
timeout_minutes:
|
|
185
|
+
timeout_minutes: 90,
|
|
186
186
|
},
|
|
187
187
|
failure: {
|
|
188
188
|
on_task_failure: "skip-dependents",
|
|
@@ -1225,7 +1225,7 @@ export class MergeError extends Error {
|
|
|
1225
1225
|
* is generous and covers verification (go build) on large codebases.
|
|
1226
1226
|
*/
|
|
1227
1227
|
/** Default merge agent timeout. Use config.merge.timeout_minutes to override. */
|
|
1228
|
-
export const MERGE_TIMEOUT_MS =
|
|
1228
|
+
export const MERGE_TIMEOUT_MS = 90 * 60 * 1000;
|
|
1229
1229
|
|
|
1230
1230
|
/**
|
|
1231
1231
|
* Polling interval for merge result file (ms).
|
|
@@ -1736,7 +1736,7 @@ export type MergeRetryLoopOutcome =
|
|
|
1736
1736
|
*/
|
|
1737
1737
|
export interface MergeRetryCallbacks {
|
|
1738
1738
|
/** Re-invoke mergeWaveByRepo and return the new result */
|
|
1739
|
-
performMerge: () => MergeWaveResult
|
|
1739
|
+
performMerge: () => MergeWaveResult | Promise<MergeWaveResult>;
|
|
1740
1740
|
/** Persist batch state with a trigger label */
|
|
1741
1741
|
persist: (trigger: string) => void;
|
|
1742
1742
|
/** Log a message */
|
|
@@ -1746,7 +1746,7 @@ export interface MergeRetryCallbacks {
|
|
|
1746
1746
|
/** Update the merge result in tracking arrays */
|
|
1747
1747
|
updateMergeResult: (result: MergeWaveResult) => void;
|
|
1748
1748
|
/** Sleep for cooldown (allows test injection) */
|
|
1749
|
-
sleep: (ms: number) => void
|
|
1749
|
+
sleep: (ms: number) => void | Promise<void>;
|
|
1750
1750
|
/**
|
|
1751
1751
|
* Optional callback fired when a retry attempt is about to be executed.
|
|
1752
1752
|
* Provides the retry decision with classification, attempt count, and cooldown
|
|
@@ -598,6 +598,19 @@ export function sleepSync(ms: number): void {
|
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
/**
|
|
602
|
+
* Async sleep for a given number of milliseconds.
|
|
603
|
+
*
|
|
604
|
+
* Unlike `sleepSync`, this yields the event loop so that other async work
|
|
605
|
+
* (supervisor heartbeats, user input, dashboard updates) can proceed while
|
|
606
|
+
* waiting. Use this in async code paths such as merge polling.
|
|
607
|
+
*
|
|
608
|
+
* @param ms - Milliseconds to sleep
|
|
609
|
+
*/
|
|
610
|
+
export function sleepAsync(ms: number): Promise<void> {
|
|
611
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
612
|
+
}
|
|
613
|
+
|
|
601
614
|
/**
|
|
602
615
|
* Determine if a git worktree remove error is retriable.
|
|
603
616
|
*
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: task-worker
|
|
3
3
|
# tools: read,write,edit,bash,grep,find,ls
|
|
4
|
-
# model:
|
|
4
|
+
# model:
|
|
5
5
|
# standalone: true
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -13,8 +13,9 @@ name: task-worker
|
|
|
13
13
|
|
|
14
14
|
The base prompt (maintained by taskplane) handles:
|
|
15
15
|
- STATUS.md-first workflow and checkpoint discipline
|
|
16
|
-
-
|
|
17
|
-
-
|
|
16
|
+
- Multi-step execution (worker handles all remaining steps per invocation)
|
|
17
|
+
- Iteration recovery (context limit → next invocation resumes from STATUS.md)
|
|
18
|
+
- Git commit conventions (per-step commits) and .DONE file creation
|
|
18
19
|
- Review response handling
|
|
19
20
|
|
|
20
21
|
Add project-specific rules below. Common examples:
|