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.
@@ -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 start a batch execution (that's \`/orch all\` or \`/orch <areas>\`)
2155
- 2. Never modify existing code files (only create config/scaffolding)
2156
- 3. Never \`git push\` to any remote
2157
- 4. Never overwrite existing config files without asking
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: 10,
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 = 10 * 60 * 1000;
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,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: task-reviewer
3
3
  # tools: read,write,bash,grep,find,ls
4
- # model: openai/gpt-5.3-codex
4
+ # model:
5
5
  # standalone: true
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: task-worker
3
3
  # tools: read,write,edit,bash,grep,find,ls
4
- # model: anthropic/claude-sonnet-4-20250514
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
- - Fresh-context loop behavior and iteration rules
17
- - Git commit conventions and .DONE file creation
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: