taskplane 0.24.21 → 0.24.23

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.
@@ -62,8 +62,13 @@ export interface OrchestratorConfig {
62
62
  };
63
63
  }
64
64
 
65
- /** Stable segment identifier: `<taskId>::<repoId>` */
66
- export type SegmentId = `${string}::${string}`;
65
+ /**
66
+ * Stable segment identifier.
67
+ *
68
+ * SegmentId is opaque — never parse by string-splitting.
69
+ * Use structured node/record fields (`repoId`, `taskId`) instead.
70
+ */
71
+ export type SegmentId = `${string}::${string}` | `${string}::${string}::${number}`;
67
72
 
68
73
  /** How an intra-task segment edge was produced (for observability/debugging). */
69
74
  export type SegmentEdgeProvenance = "explicit" | "inferred";
@@ -122,11 +127,31 @@ export interface ParsedTask {
122
127
  activeSegmentId?: string | null;
123
128
  }
124
129
 
125
- /** Build a stable segment ID from task + repo identity (`<taskId>::<repoId>`). */
126
- export function buildSegmentId(taskId: string, repoId: string): SegmentId {
130
+ /** Build a stable segment ID from task + repo identity (`<taskId>::<repoId>[::N]`). */
131
+ export function buildSegmentId(taskId: string, repoId: string, sequence?: number): SegmentId {
132
+ if (typeof sequence === "number" && Number.isFinite(sequence) && sequence >= 2) {
133
+ return `${taskId}::${repoId}::${Math.floor(sequence)}` as SegmentId;
134
+ }
127
135
  return `${taskId}::${repoId}` as SegmentId;
128
136
  }
129
137
 
138
+ /**
139
+ * Read repoId from structured segment metadata.
140
+ *
141
+ * SegmentId is opaque — never parse it by string-splitting.
142
+ */
143
+ export function parseSegmentIdRepo(segment: { repoId: string }): string {
144
+ return segment.repoId;
145
+ }
146
+
147
+ /** Build a dynamic segment expansion request ID (`exp-{timestamp}-{random5}`). */
148
+ export function buildExpansionRequestId(timestamp = Date.now()): string {
149
+ const ts = Number.isFinite(timestamp) ? Math.floor(timestamp) : Date.now();
150
+ const base = Math.random().toString(36).slice(2).toLowerCase().replace(/[^a-z0-9]/g, "");
151
+ const random5 = (base + "00000").slice(0, 5);
152
+ return `exp-${ts}-${random5}`;
153
+ }
154
+
130
155
  /** One repo-scoped segment node for a task. */
131
156
  export interface TaskSegmentNode {
132
157
  segmentId: SegmentId;
@@ -167,6 +192,36 @@ export interface TaskSegmentPlan {
167
192
  mode: "explicit-dag" | "inferred-sequential" | "repo-singleton";
168
193
  }
169
194
 
195
+ /** Directed edge between repos requested in a dynamic segment expansion. */
196
+ export interface SegmentExpansionEdge {
197
+ from: string;
198
+ to: string;
199
+ }
200
+
201
+ /**
202
+ * File IPC payload for worker-initiated dynamic segment expansion requests.
203
+ *
204
+ * Written to: `.pi/mailbox/{batchId}/{agentId}/outbox/segment-expansion-{requestId}.json`
205
+ */
206
+ export interface SegmentExpansionRequest {
207
+ /** Unique request ID: `exp-{timestamp}-{random5}` */
208
+ requestId: string;
209
+ /** Task ID making the expansion request. */
210
+ taskId: string;
211
+ /** Segment active when the request was emitted. */
212
+ fromSegmentId: SegmentId;
213
+ /** Repo IDs the worker is requesting the engine to add. */
214
+ requestedRepoIds: string[];
215
+ /** Human rationale from the worker. */
216
+ rationale: string;
217
+ /** Placement directive for inserting new segments. */
218
+ placement: "after-current" | "end";
219
+ /** Optional inter-request ordering edges. */
220
+ edges: SegmentExpansionEdge[];
221
+ /** Epoch milliseconds when the request was emitted. */
222
+ timestamp: number;
223
+ }
224
+
170
225
  /**
171
226
  * TaskId-keyed segment plans.
172
227
  * Iteration order must be deterministic: sort task IDs lexicographically.
@@ -282,7 +337,7 @@ export const DEFAULT_ORCHESTRATOR_CONFIG: OrchestratorConfig = {
282
337
  merge: {
283
338
  model: "",
284
339
  tools: "read,write,edit,bash,grep,find,ls",
285
- thinking: "",
340
+ thinking: "off",
286
341
  verify: [],
287
342
  order: "fewest-files-first",
288
343
  timeout_minutes: 90,
@@ -1934,17 +1989,27 @@ export type EngineEventCallback = (event: EngineEvent) => void;
1934
1989
  * Alert category for supervisor notifications.
1935
1990
  *
1936
1991
  * Matches the alert categories in the autonomous supervisor spec:
1937
- * - `task-failure`: A task failed after deterministic recovery was exhausted
1938
- * - `merge-failure`: Wave merge failed and batch paused
1939
- * - `batch-complete`: Batch finished (all waves done)
1940
- * - `agent-message`: Runtime mailbox reply/escalation from a running agent
1992
+ * - `task-failure`: A task failed after deterministic recovery was exhausted
1993
+ * - `merge-failure`: Wave merge failed and batch paused
1994
+ * - `batch-complete`: Batch finished (all waves done)
1995
+ * - `agent-message`: Runtime mailbox reply/escalation from a running agent
1996
+ * - `segment-expansion-requested`: Worker requested dynamic segment expansion
1997
+ * - `segment-expansion-approved`: Engine approved an expansion request
1998
+ * - `segment-expansion-rejected`: Engine rejected/discarded an expansion request
1941
1999
  *
1942
2000
  * Note: `stall` detection is deferred to a future phase (requires
1943
2001
  * last-activity tracking not yet built).
1944
2002
  *
1945
2003
  * @since TP-076
1946
2004
  */
1947
- export type SupervisorAlertCategory = "task-failure" | "merge-failure" | "batch-complete" | "agent-message";
2005
+ export type SupervisorAlertCategory =
2006
+ | "task-failure"
2007
+ | "merge-failure"
2008
+ | "batch-complete"
2009
+ | "agent-message"
2010
+ | "segment-expansion-requested"
2011
+ | "segment-expansion-approved"
2012
+ | "segment-expansion-rejected";
1948
2013
 
1949
2014
  /**
1950
2015
  * Structured context payload for supervisor alerts.
@@ -1993,6 +2058,8 @@ export interface SupervisorAlertContext {
1993
2058
  agentId?: string;
1994
2059
  /** Mailbox message ID (for agent-message alerts) */
1995
2060
  messageId?: string;
2061
+ /** Segment expansion request ID (for segment-expansion alerts) */
2062
+ expansionRequestId?: string;
1996
2063
  /** Whether partial progress was preserved (for task-failure alerts) */
1997
2064
  partialProgress?: boolean;
1998
2065
  /** Batch progress summary */
@@ -2070,12 +2137,6 @@ export function buildBatchProgressSnapshot(
2070
2137
  };
2071
2138
  }
2072
2139
 
2073
- function repoIdFromSegmentId(segmentId: string): string {
2074
- const idx = segmentId.indexOf("::");
2075
- if (idx <= 0 || idx >= segmentId.length - 2) return "unknown";
2076
- return segmentId.slice(idx + 2);
2077
- }
2078
-
2079
2140
  /**
2080
2141
  * Build a task-level segment frontier snapshot for supervisor failure alerts.
2081
2142
  *
@@ -2112,7 +2173,7 @@ export function buildSupervisorSegmentFrontierSnapshot(
2112
2173
  ?? (resolvedActiveSegmentId === segmentId ? "running" : "pending");
2113
2174
  return {
2114
2175
  segmentId,
2115
- repoId: persisted?.repoId ?? repoIdFromSegmentId(segmentId),
2176
+ repoId: persisted ? parseSegmentIdRepo(persisted) : "unknown",
2116
2177
  status,
2117
2178
  dependsOnSegmentIds: persisted?.dependsOnSegmentIds ?? [],
2118
2179
  };
@@ -2692,6 +2753,10 @@ export interface PersistedSegmentRecord {
2692
2753
  exitDiagnostic?: TaskExitDiagnostic;
2693
2754
  /** Human-readable exit reason (legacy compat, same as task-level) */
2694
2755
  exitReason: string;
2756
+ /** Anchor segment ID this segment was dynamically expanded from (if any). */
2757
+ expandedFrom?: string;
2758
+ /** Segment expansion request ID that created this segment (if any). */
2759
+ expansionRequestId?: string;
2695
2760
  }
2696
2761
 
2697
2762
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskplane",
3
- "version": "0.24.21",
3
+ "version": "0.24.23",
4
4
  "description": "AI agent orchestration for pi — parallel task execution with checkpoint discipline",
5
5
  "keywords": [
6
6
  "pi-package",