@wrongstack/core 0.283.1 → 0.284.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/dist/{compactor-BxddyCFu.d.ts → compactor-DQLL4HTo.d.ts} +1 -1
- package/dist/{config-DkCbA3Bw.d.ts → config-MRqn1V-u.d.ts} +130 -22
- package/dist/coordination/index.d.ts +43 -20
- package/dist/coordination/index.js +1744 -912
- package/dist/coordination/index.js.map +1 -1
- package/dist/{default-config-Buho8yge.d.ts → default-config-B79_gJYv.d.ts} +7 -0
- package/dist/defaults/index.d.ts +25 -29
- package/dist/defaults/index.js +2546 -7396
- package/dist/defaults/index.js.map +1 -1
- package/dist/{director-state-B_GPa78Q.d.ts → director-state-CMS_bMs4.d.ts} +2 -0
- package/dist/{events-KmxSmvho.d.ts → events-Bgnh43r9.d.ts} +27 -10
- package/dist/execution/index.d.ts +15 -16
- package/dist/execution/index.js +534 -140
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/{global-mailbox-rWVt8YlO.d.ts → global-mailbox-sZwyI6CS.d.ts} +13 -2
- package/dist/{goal-store-8owBXJT2.d.ts → goal-store-Datpp-ar.d.ts} +1 -1
- package/dist/hq/index.d.ts +6 -6
- package/dist/hq/index.js +58 -7
- package/dist/hq/index.js.map +1 -1
- package/dist/{index-BhCteHAF.d.ts → index--Gm41aBJ.d.ts} +26 -11
- package/dist/{index-BEFWNZYs.d.ts → index-CbyuOE5y.d.ts} +5 -1
- package/dist/index.d.ts +50 -1015
- package/dist/index.js +21028 -27775
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +9 -7
- package/dist/infrastructure/index.js +7 -2
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +11 -11
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-BUx9A_AQ.d.ts → mcp-servers-DEV4s6Ks.d.ts} +3 -3
- package/dist/models/index.d.ts +4 -4
- package/dist/models/index.js +18 -3
- package/dist/models/index.js.map +1 -1
- package/dist/{agent-subagent-runner-BsuWhB28.d.ts → multi-agent-coordinator-4RCRZKjN.d.ts} +417 -9
- package/dist/{null-fleet-bus-D4e9R7Qc.d.ts → null-fleet-bus-CFoNVQEK.d.ts} +53 -12
- package/dist/observability/index.d.ts +3 -3
- package/dist/{parallel-eternal-engine-iY2uxocj.d.ts → parallel-eternal-engine-HUrtePLd.d.ts} +4 -5
- package/dist/{permission-B6YAtNFz.d.ts → permission-ByDKXEcG.d.ts} +1 -1
- package/dist/{pipeline-ixSFe5jg.d.ts → pipeline-DGDyIohT.d.ts} +28 -7
- package/dist/{provider-model-resolve-DIxKL_T-.d.ts → provider-model-resolve-o2hHLs79.d.ts} +3 -3
- package/dist/{provider-runner-oQhDaZmH.d.ts → provider-runner-ChL-kVg6.d.ts} +3 -3
- package/dist/{retry-policy-V67lBOJz.d.ts → retry-policy-CQ7KwXJa.d.ts} +2 -2
- package/dist/{secret-vault-D7jeyXUQ.d.ts → secret-vault-DxohkUBc.d.ts} +3 -2
- package/dist/security/index.d.ts +4 -4
- package/dist/security/index.js +232 -2
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-Bx2HgUkU.d.ts → selector-D8O6B_Rm.d.ts} +1 -1
- package/dist/{session-event-bridge-Bkp7ORfc.d.ts → session-event-bridge-D_z_mBwk.d.ts} +3 -3
- package/dist/{session-reader-B-Fi9L6I.d.ts → session-reader-7Esxrkpw.d.ts} +1 -1
- package/dist/storage/index.d.ts +77 -39
- package/dist/storage/index.js +1223 -288
- package/dist/storage/index.js.map +1 -1
- package/dist/tasking/index.d.ts +124 -0
- package/dist/tasking/index.js +492 -0
- package/dist/tasking/index.js.map +1 -0
- package/dist/{todos-checkpoint-BwCrj4Cb.d.ts → todos-checkpoint-FY7PjmMx.d.ts} +13 -4
- package/dist/{tool-LVSLiE1s.d.ts → tool-BNlnIJvo.d.ts} +216 -17
- package/dist/{tool-executor-kElSEgO0.d.ts → tool-executor-CckSCM5E.d.ts} +12 -15
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +94 -19
- package/dist/types/index.js +76 -12
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +44 -10
- package/dist/utils/index.js +106 -17
- package/dist/utils/index.js.map +1 -1
- package/dist/{worktree-manager-BjyAW30D.d.ts → worktree-manager-DzwxKE35.d.ts} +1 -1
- package/instructions/coordination/subagent-baseline.md +5 -0
- package/instructions/llm/autonomy-brain.md +3 -2
- package/instructions/system.md +4 -0
- package/package.json +10 -3
- package/dist/multi-agent-coordinator-CrjeTB9i.d.ts +0 -357
- package/dist/sdd/index.d.ts +0 -1993
- package/dist/sdd/index.js +0 -9500
- package/dist/sdd/index.js.map +0 -1
- package/dist/spec-TBi3Jr6T.d.ts +0 -78
package/dist/sdd/index.d.ts
DELETED
|
@@ -1,1993 +0,0 @@
|
|
|
1
|
-
import { h as Specification, e as SpecStatus, S as SpecAnalysis, g as SpecValidationResult, f as SpecTemplate, b as SpecRequirement } from '../spec-TBi3Jr6T.js';
|
|
2
|
-
import { d as TaskGraph, e as TaskNode, k as TaskFilter, l as TaskSort, c as TaskProgress, T as TaskType, a as TaskPriority } from '../task-graph-CH3acNQ7.js';
|
|
3
|
-
import { E as EventBus, B as BrainArbiter } from '../events-KmxSmvho.js';
|
|
4
|
-
import { A as Agent, a as AgentFactory, g as TaskResult, D as DoneCondition } from '../agent-subagent-runner-BsuWhB28.js';
|
|
5
|
-
import { W as WorktreeManager } from '../worktree-manager-BjyAW30D.js';
|
|
6
|
-
import '../tool-LVSLiE1s.js';
|
|
7
|
-
import '../permission-B6YAtNFz.js';
|
|
8
|
-
import '../index-BhCteHAF.js';
|
|
9
|
-
import '../logger-B63L5bTg.js';
|
|
10
|
-
import '../pipeline-ixSFe5jg.js';
|
|
11
|
-
import '../mailbox-types-BGZWrYTJ.js';
|
|
12
|
-
import '../config-DkCbA3Bw.js';
|
|
13
|
-
import '../observability-D-HZN_mF.js';
|
|
14
|
-
import '../secret-scrubber-3MHDDAtm.js';
|
|
15
|
-
import '../retry-policy-V67lBOJz.js';
|
|
16
|
-
|
|
17
|
-
interface TaskStore {
|
|
18
|
-
saveGraph(graph: TaskGraph): Promise<void>;
|
|
19
|
-
loadGraph(id: string): Promise<TaskGraph | null>;
|
|
20
|
-
listGraphs(): Promise<{
|
|
21
|
-
id: string;
|
|
22
|
-
title: string;
|
|
23
|
-
updatedAt: number;
|
|
24
|
-
}[]>;
|
|
25
|
-
deleteGraph(id: string): Promise<void>;
|
|
26
|
-
}
|
|
27
|
-
interface TaskTrackerOptions {
|
|
28
|
-
store: TaskStore;
|
|
29
|
-
/**
|
|
30
|
-
* Called when an in-the-background persistence (`saveGraph`) rejects.
|
|
31
|
-
* The synchronous TaskTracker methods (addNode/addEdge/updateNodeStatus)
|
|
32
|
-
* fire-and-forget their writes; without this, a failing store silently
|
|
33
|
-
* loses graph mutations. Defaults to a console.warn.
|
|
34
|
-
*/
|
|
35
|
-
onPersistError?: (((err: unknown) => void)) | undefined;
|
|
36
|
-
}
|
|
37
|
-
interface TaskTransition {
|
|
38
|
-
from: TaskNode['status'];
|
|
39
|
-
to: TaskNode['status'];
|
|
40
|
-
timestamp: number;
|
|
41
|
-
reason?: string | undefined;
|
|
42
|
-
}
|
|
43
|
-
/** A change notification emitted to `TaskTracker.subscribe` listeners. */
|
|
44
|
-
interface TaskTrackerChange {
|
|
45
|
-
type: 'node_added' | 'node_updated' | 'status_changed' | 'node_removed';
|
|
46
|
-
nodeId: string;
|
|
47
|
-
/** For `node_removed` this is the node as it was just before deletion. */
|
|
48
|
-
node: TaskNode;
|
|
49
|
-
transition?: TaskTransition | undefined;
|
|
50
|
-
}
|
|
51
|
-
type TaskTrackerListener = (change: TaskTrackerChange) => void;
|
|
52
|
-
declare class TaskTracker {
|
|
53
|
-
private readonly opts;
|
|
54
|
-
private graph;
|
|
55
|
-
private transitions;
|
|
56
|
-
private listeners;
|
|
57
|
-
constructor(opts: TaskTrackerOptions);
|
|
58
|
-
/**
|
|
59
|
-
* Subscribe to live task mutations (add / update / status change). Returns an
|
|
60
|
-
* unsubscribe fn. This is the hook the board projector uses to stream a live
|
|
61
|
-
* snapshot — the tracker was previously fire-and-forget with no observability.
|
|
62
|
-
*/
|
|
63
|
-
subscribe(listener: TaskTrackerListener): () => void;
|
|
64
|
-
private notifyChange;
|
|
65
|
-
/**
|
|
66
|
-
* Attach an existing graph (used by PhaseOrchestrator to associate a tracker
|
|
67
|
-
* with a phase's pre-built task graph without re-creating it).
|
|
68
|
-
*/
|
|
69
|
-
setGraph(graph: TaskGraph): void;
|
|
70
|
-
createGraph(specId: string, title: string): Promise<TaskGraph>;
|
|
71
|
-
loadGraph(id: string): Promise<TaskGraph | null>;
|
|
72
|
-
addNode(node: Omit<TaskNode, 'id' | 'createdAt' | 'updatedAt'>): TaskNode;
|
|
73
|
-
addEdge(from: string, to: string, type?: TaskGraph['edges'][0]['type']): void;
|
|
74
|
-
/**
|
|
75
|
-
* Declare that `taskId` depends on `depId` (a `depends_on` edge `depId → taskId`),
|
|
76
|
-
* guarding against self-loops, duplicates, missing nodes, and cycles. Returns
|
|
77
|
-
* true if the dependency now holds (added or already present), false if it was
|
|
78
|
-
* rejected (would create a cycle / unknown node). This is the safe entry point
|
|
79
|
-
* for wiring agent-declared `dependsOn` references into the graph.
|
|
80
|
-
*/
|
|
81
|
-
addDependency(depId: string, taskId: string): boolean;
|
|
82
|
-
/** True when `taskId` transitively depends on `targetId` (follows depends_on blockers). */
|
|
83
|
-
private dependsOnTransitively;
|
|
84
|
-
/**
|
|
85
|
-
* Merge `patch` into a node's `metadata` (used for per-task model/provider/
|
|
86
|
-
* fallback assignment and the cancel marker). Persists + notifies as a node
|
|
87
|
-
* update. No-op if the node is missing.
|
|
88
|
-
*/
|
|
89
|
-
patchMetadata(id: string, patch: Record<string, unknown>): void;
|
|
90
|
-
/**
|
|
91
|
-
* Remove a node and every edge touching it. Intended for deleting a task that
|
|
92
|
-
* has not started yet — callers must gate on status (do not remove a running
|
|
93
|
-
* task). Dependents simply lose this blocker (re-evaluated by `canStart`).
|
|
94
|
-
* Returns true if a node was removed.
|
|
95
|
-
*/
|
|
96
|
-
removeNode(id: string): boolean;
|
|
97
|
-
updateNodeStatus(id: string, status: TaskNode['status'], reason?: string): void;
|
|
98
|
-
updateNode(id: string, patch: Partial<Pick<TaskNode, 'title' | 'description' | 'priority' | 'estimateHours' | 'tags' | 'assignee'>>): void;
|
|
99
|
-
getNode(id: string): TaskNode | undefined;
|
|
100
|
-
getAllNodes(filter?: TaskFilter, sort?: TaskSort): TaskNode[];
|
|
101
|
-
getChildren(parentId: string): TaskNode[];
|
|
102
|
-
getDependents(taskId: string): string[];
|
|
103
|
-
getBlockers(taskId: string): string[];
|
|
104
|
-
canStart(taskId: string): boolean;
|
|
105
|
-
getProgress(): TaskProgress;
|
|
106
|
-
getTransitions(_taskId?: string): TaskTransition[];
|
|
107
|
-
private unblockDependents;
|
|
108
|
-
private checkAndBlockIfNeeded;
|
|
109
|
-
/**
|
|
110
|
-
* Fire-and-forget persistence with attached error handler.
|
|
111
|
-
* Synchronous mutators (addNode/addEdge/updateNodeStatus) use this to
|
|
112
|
-
* avoid forcing an async cascade through every caller; if the store
|
|
113
|
-
* is missing or throwing, the error is surfaced via onPersistError.
|
|
114
|
-
*/
|
|
115
|
-
private persist;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
interface AutoExecutorOptions {
|
|
119
|
-
tracker: TaskTracker;
|
|
120
|
-
events: EventBus;
|
|
121
|
-
/** Maximum concurrent tasks. Defaults to 1 (sequential). */
|
|
122
|
-
maxConcurrent?: number | undefined;
|
|
123
|
-
/** Maximum retry attempts for failed tasks. */
|
|
124
|
-
maxRetries?: number | undefined;
|
|
125
|
-
/** Custom task executor function. */
|
|
126
|
-
executeTask: (task: TaskNode, context: TaskExecutionContext) => Promise<TaskExecutionResult>;
|
|
127
|
-
/** Called before each task starts. */
|
|
128
|
-
onTaskStart?: (((task: TaskNode) => void)) | undefined;
|
|
129
|
-
/** Called after each task completes. */
|
|
130
|
-
onTaskComplete?: (task: TaskNode, result: TaskExecutionResult) => void;
|
|
131
|
-
/** Called when a task fails. */
|
|
132
|
-
onTaskFail?: (task: TaskNode, error: Error, retryCount: number) => void;
|
|
133
|
-
/** Called when all tasks are done or no more can execute. */
|
|
134
|
-
onDone?: (((summary: ExecutionSummary) => void)) | undefined;
|
|
135
|
-
}
|
|
136
|
-
interface TaskExecutionContext {
|
|
137
|
-
/** The spec being implemented. */
|
|
138
|
-
spec: Specification;
|
|
139
|
-
/** The full task graph. */
|
|
140
|
-
graph: TaskGraph;
|
|
141
|
-
/** The current task being executed. */
|
|
142
|
-
task: TaskNode;
|
|
143
|
-
/** Tasks that this task depends on. */
|
|
144
|
-
dependencies: TaskNode[];
|
|
145
|
-
/** Tasks that depend on this task. */
|
|
146
|
-
dependents: TaskNode[];
|
|
147
|
-
/** Retry count for this task (0 = first attempt). */
|
|
148
|
-
retryCount: number;
|
|
149
|
-
}
|
|
150
|
-
interface TaskExecutionResult {
|
|
151
|
-
success: boolean;
|
|
152
|
-
output?: string | undefined;
|
|
153
|
-
error?: string | undefined;
|
|
154
|
-
/** If true, the task will be retried. */
|
|
155
|
-
retry?: boolean | undefined;
|
|
156
|
-
}
|
|
157
|
-
interface ExecutionSummary {
|
|
158
|
-
total: number;
|
|
159
|
-
completed: number;
|
|
160
|
-
failed: number;
|
|
161
|
-
skipped: number;
|
|
162
|
-
retried: number;
|
|
163
|
-
duration: number;
|
|
164
|
-
criticalPath: string[];
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Auto-executor that drives task execution with dependency resolution,
|
|
168
|
-
* retry logic, and critical path awareness.
|
|
169
|
-
*/
|
|
170
|
-
declare class AutoExecutor {
|
|
171
|
-
private readonly opts;
|
|
172
|
-
private stopped;
|
|
173
|
-
private retryMap;
|
|
174
|
-
constructor(opts: AutoExecutorOptions);
|
|
175
|
-
/**
|
|
176
|
-
* Execute all tasks in the graph, respecting dependencies.
|
|
177
|
-
*/
|
|
178
|
-
execute(graph: TaskGraph, spec: Specification): Promise<ExecutionSummary>;
|
|
179
|
-
/** Stop execution. */
|
|
180
|
-
stop(): void;
|
|
181
|
-
/** Get tasks that are ready to execute (all dependencies completed). */
|
|
182
|
-
private getReadyTasks;
|
|
183
|
-
/** Execute a single task with retry logic. */
|
|
184
|
-
private executeTaskWithRetry;
|
|
185
|
-
/** Get tasks that this task depends on. */
|
|
186
|
-
private getTaskDependencies;
|
|
187
|
-
/** Get tasks that depend on this task. */
|
|
188
|
-
private getTaskDependents;
|
|
189
|
-
/** Detect deadlock: all remaining tasks are blocked by failed tasks. */
|
|
190
|
-
private detectDeadlock;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Create an auto-executor that works with TaskFlow.
|
|
194
|
-
*/
|
|
195
|
-
declare function createAutoExecutor(opts: {
|
|
196
|
-
tracker: TaskTracker;
|
|
197
|
-
events: EventBus;
|
|
198
|
-
executeTask: AutoExecutorOptions['executeTask'];
|
|
199
|
-
maxConcurrent?: number | undefined;
|
|
200
|
-
maxRetries?: number | undefined;
|
|
201
|
-
}): AutoExecutor;
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* SDD live board model.
|
|
205
|
-
*
|
|
206
|
-
* A board snapshot is the canonical, surface-agnostic projection of a running
|
|
207
|
-
* (or persisted) SDD TaskGraph: tasks laid into topological dependency columns,
|
|
208
|
-
* each carrying its short id, status, blockers and the agent currently on it.
|
|
209
|
-
* The projector (sdd-board-projector.ts) emits these over the EventBus and
|
|
210
|
-
* persists them (sdd-board-store.ts); every surface (WebUI/TUI) renders the
|
|
211
|
-
* same shape.
|
|
212
|
-
*/
|
|
213
|
-
|
|
214
|
-
type SddBoardStatus = 'idle' | 'running' | 'paused' | 'stopped' | 'completed' | 'failed' | 'deadlocked';
|
|
215
|
-
/**
|
|
216
|
-
* FORGE-style display status: `queued` = pending with all blockers done;
|
|
217
|
-
* `cancelled` = a task the user stopped (stored as a terminal `failed` node
|
|
218
|
-
* carrying `metadata.cancelled`, surfaced distinctly so it doesn't read as an
|
|
219
|
-
* error). Display-only — not a core `TaskStatus`.
|
|
220
|
-
*/
|
|
221
|
-
type SddTaskDisplayStatus = TaskNode['status'] | 'queued' | 'cancelled';
|
|
222
|
-
interface SddBoardTask {
|
|
223
|
-
id: string;
|
|
224
|
-
/** Stable short id (t01, t02, …) in creation order. */
|
|
225
|
-
shortId: string;
|
|
226
|
-
title: string;
|
|
227
|
-
description: string;
|
|
228
|
-
status: TaskNode['status'];
|
|
229
|
-
displayStatus: SddTaskDisplayStatus;
|
|
230
|
-
priority: TaskNode['priority'];
|
|
231
|
-
type: TaskNode['type'];
|
|
232
|
-
/** Short ids of the tasks that block this one (depends_on edges). */
|
|
233
|
-
deps: string[];
|
|
234
|
-
/** Worker on the task right now (scientist nickname), if any. */
|
|
235
|
-
agentName?: string | undefined;
|
|
236
|
-
/** Git worktree branch this task runs in, when isolated. */
|
|
237
|
-
worktreeBranch?: string | undefined;
|
|
238
|
-
startedAt?: number | undefined;
|
|
239
|
-
completedAt?: number | undefined;
|
|
240
|
-
retries: number;
|
|
241
|
-
/** Per-task model assignment (overrides the run default), if set. */
|
|
242
|
-
model?: string | undefined;
|
|
243
|
-
/** Per-task provider assignment (overrides the run default), if set. */
|
|
244
|
-
provider?: string | undefined;
|
|
245
|
-
/** Per-task fallback model chain (overrides the run default), if set. */
|
|
246
|
-
fallbackModels?: string[] | undefined;
|
|
247
|
-
/** Per-task completion-gate verification command, if set. */
|
|
248
|
-
verificationCommand?: string | undefined;
|
|
249
|
-
}
|
|
250
|
-
/** A topological column: tasks whose deepest dependency chain is `depth`. */
|
|
251
|
-
interface SddBoardColumn {
|
|
252
|
-
label: string;
|
|
253
|
-
/** Short ids of the tasks in this column (join against `tasks`). */
|
|
254
|
-
taskIds: string[];
|
|
255
|
-
}
|
|
256
|
-
interface SddDeadlockChain {
|
|
257
|
-
/** Short id of the blocked task. */
|
|
258
|
-
blocked: string;
|
|
259
|
-
/** Short ids of the failed/incomplete blockers holding it. */
|
|
260
|
-
blockedBy: string[];
|
|
261
|
-
}
|
|
262
|
-
/** One entry in the live activity feed (the board's "what just happened" ticker). */
|
|
263
|
-
interface SddBoardFeedEntry {
|
|
264
|
-
ts: number;
|
|
265
|
-
kind: 'started' | 'completed' | 'failed' | 'retrying' | 'wave' | 'deadlock' | 'verification_failed' | 'conflict' | 'split' | 'supervisor';
|
|
266
|
-
/** Short id of the task this entry concerns, when applicable. */
|
|
267
|
-
taskShortId?: string | undefined;
|
|
268
|
-
/** Worker involved, when applicable. */
|
|
269
|
-
agentName?: string | undefined;
|
|
270
|
-
/** Human-readable one-line summary. */
|
|
271
|
-
text: string;
|
|
272
|
-
}
|
|
273
|
-
interface SddBoardSnapshot {
|
|
274
|
-
runId: string;
|
|
275
|
-
specId?: string | undefined;
|
|
276
|
-
graphId: string;
|
|
277
|
-
title: string;
|
|
278
|
-
status: SddBoardStatus;
|
|
279
|
-
startedAt: number;
|
|
280
|
-
updatedAt: number;
|
|
281
|
-
progress: TaskProgress;
|
|
282
|
-
/** Current wave index (0-based) of the parallel run. */
|
|
283
|
-
wave: number;
|
|
284
|
-
tasks: SddBoardTask[];
|
|
285
|
-
columns: SddBoardColumn[];
|
|
286
|
-
diagnostics?: {
|
|
287
|
-
deadlockChains?: SddDeadlockChain[];
|
|
288
|
-
} | undefined;
|
|
289
|
-
/** Live activity feed — most recent first (capped). */
|
|
290
|
-
feed?: SddBoardFeedEntry[] | undefined;
|
|
291
|
-
/** Run-level default worker model (task overrides take precedence). */
|
|
292
|
-
defaultModel?: string | undefined;
|
|
293
|
-
/** Run-level default worker provider. */
|
|
294
|
-
defaultProvider?: string | undefined;
|
|
295
|
-
/** Run-level default fallback model chain. */
|
|
296
|
-
fallbackModels?: string[] | undefined;
|
|
297
|
-
/** Base branch the run's squash commits land on (worktree runs only). */
|
|
298
|
-
baseBranch?: string | undefined;
|
|
299
|
-
/**
|
|
300
|
-
* Squash commits the run landed on the base branch, in landing order. Lets a
|
|
301
|
-
* post-run `/sdd rollback` revert them from disk after the live run is gone.
|
|
302
|
-
*/
|
|
303
|
-
mergedCommits?: Array<{
|
|
304
|
-
taskId: string;
|
|
305
|
-
sha: string;
|
|
306
|
-
title: string;
|
|
307
|
-
}> | undefined;
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Lay a TaskGraph's nodes into topological dependency columns with stable short
|
|
311
|
-
* ids and per-task blocker refs. Shared by the projector (live) and any static
|
|
312
|
-
* board browser. Pure; no run state — `agentName`/`worktreeBranch`/`retries`
|
|
313
|
-
* are read from the node's `assignee`/`metadata` so a reload reflects the last
|
|
314
|
-
* persisted run.
|
|
315
|
-
*/
|
|
316
|
-
/**
|
|
317
|
-
* Stable short-id map (t01, t02, …) for a graph's nodes in creation order.
|
|
318
|
-
* Shared by the board renderer and the projector (deadlock-chain labelling).
|
|
319
|
-
*/
|
|
320
|
-
declare function shortIdMap(graph: TaskGraph): Map<string, string>;
|
|
321
|
-
declare function buildBoardTasks(graph: TaskGraph): {
|
|
322
|
-
tasks: SddBoardTask[];
|
|
323
|
-
columns: SddBoardColumn[];
|
|
324
|
-
};
|
|
325
|
-
/**
|
|
326
|
-
* Build a full board snapshot from a graph + run state. The projector calls
|
|
327
|
-
* this on every (throttled) change.
|
|
328
|
-
*/
|
|
329
|
-
declare function buildBoardSnapshot(graph: TaskGraph, run: {
|
|
330
|
-
runId: string;
|
|
331
|
-
specId?: string | undefined;
|
|
332
|
-
status: SddBoardStatus;
|
|
333
|
-
startedAt: number;
|
|
334
|
-
wave: number;
|
|
335
|
-
deadlockChains?: SddDeadlockChain[] | undefined;
|
|
336
|
-
defaultModel?: string | undefined;
|
|
337
|
-
defaultProvider?: string | undefined;
|
|
338
|
-
fallbackModels?: string[] | undefined;
|
|
339
|
-
baseBranch?: string | undefined;
|
|
340
|
-
mergedCommits?: Array<{
|
|
341
|
-
taskId: string;
|
|
342
|
-
sha: string;
|
|
343
|
-
title: string;
|
|
344
|
-
}> | undefined;
|
|
345
|
-
}, now: number): SddBoardSnapshot;
|
|
346
|
-
|
|
347
|
-
type ConflictSide = 'incoming' | 'base';
|
|
348
|
-
/**
|
|
349
|
-
* Resolve every standard git conflict hunk in `text` by keeping `side`. Handles
|
|
350
|
-
* both 2-way (`<<<<<<< / ======= / >>>>>>>`) and diff3 (`||||||| base`) markers.
|
|
351
|
-
* Returns the rewritten text (markers removed).
|
|
352
|
-
*/
|
|
353
|
-
declare function resolveConflictText(text: string, side: ConflictSide): string;
|
|
354
|
-
/** True when `text` still contains a git conflict marker line. */
|
|
355
|
-
declare function hasConflictMarkers(text: string): boolean;
|
|
356
|
-
/**
|
|
357
|
-
* Build a `conflictResolver` that keeps `side` of every hunk in each conflicted
|
|
358
|
-
* file. Returns false (abort → conservative fail) if any file can't be read,
|
|
359
|
-
* written, or still has markers after the rewrite.
|
|
360
|
-
*/
|
|
361
|
-
declare function makePreferSideConflictResolver(side: ConflictSide): (info: {
|
|
362
|
-
task: TaskNode;
|
|
363
|
-
conflictFiles: string[];
|
|
364
|
-
cwd: string;
|
|
365
|
-
}) => Promise<boolean>;
|
|
366
|
-
interface LlmConflictResolverOptions {
|
|
367
|
-
/** Runs one self-contained, isolated LLM turn and resolves its final text. */
|
|
368
|
-
run: (prompt: string) => Promise<string>;
|
|
369
|
-
/**
|
|
370
|
-
* Reject a resolution that shrinks the file below this fraction of its original
|
|
371
|
-
* non-marker line count — a crude guard against the model dropping content.
|
|
372
|
-
* Default 0.5.
|
|
373
|
-
*/
|
|
374
|
-
minRetainedFraction?: number;
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* Build an LLM-backed `conflictResolver`: for each conflicted file it asks the
|
|
378
|
-
* model (via one isolated `run` turn) to produce the fully resolved file and
|
|
379
|
-
* writes it back. Heavily guarded — returns false (→ conservative abort/retry)
|
|
380
|
-
* if the model leaves a marker, returns junk, or drops too much content. The
|
|
381
|
-
* WorktreeManager STILL rejects any surviving marker, and (when a `verifyTask`
|
|
382
|
-
* is configured) the run re-verifies the integrated base and reverts a
|
|
383
|
-
* regression — so a bad LLM merge can never silently stick. OFF by default.
|
|
384
|
-
*/
|
|
385
|
-
declare function makeLlmConflictResolver(opts: LlmConflictResolverOptions): (info: {
|
|
386
|
-
task: TaskNode;
|
|
387
|
-
conflictFiles: string[];
|
|
388
|
-
cwd: string;
|
|
389
|
-
}) => Promise<boolean>;
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Enhanced critical path analysis with bottleneck detection,
|
|
393
|
-
* parallel execution groups, and time estimation.
|
|
394
|
-
*/
|
|
395
|
-
interface CriticalPathAnalysis {
|
|
396
|
-
/** Ordered list of critical path task IDs. */
|
|
397
|
-
criticalPath: string[];
|
|
398
|
-
/** Total estimated hours for the critical path. */
|
|
399
|
-
totalHours: number;
|
|
400
|
-
/** Tasks that block the most downstream work. */
|
|
401
|
-
bottlenecks: BottleneckTask[];
|
|
402
|
-
/** Groups of tasks that can run in parallel. */
|
|
403
|
-
parallelGroups: string[][];
|
|
404
|
-
/** Recommended execution order respecting dependencies. */
|
|
405
|
-
executionOrder: string[];
|
|
406
|
-
/** Tasks with no blockers (can start immediately). */
|
|
407
|
-
readyTasks: string[];
|
|
408
|
-
/** Tasks that are blocked and cannot start. */
|
|
409
|
-
blockedTasks: string[];
|
|
410
|
-
}
|
|
411
|
-
interface BottleneckTask {
|
|
412
|
-
taskId: string;
|
|
413
|
-
title: string;
|
|
414
|
-
/** Number of tasks directly or transitively blocked by this task. */
|
|
415
|
-
blockedCount: number;
|
|
416
|
-
/** Total estimated hours of blocked downstream work. */
|
|
417
|
-
blockedHours: number;
|
|
418
|
-
/** Severity score (0-100). */
|
|
419
|
-
severity: number;
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Analyze a task graph and return critical path analysis.
|
|
423
|
-
*/
|
|
424
|
-
declare function analyzeCriticalPath(graph: TaskGraph): CriticalPathAnalysis;
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* SddTaskDecomposer
|
|
428
|
-
*
|
|
429
|
-
* Converts a TaskGraph (from SDD's TaskGenerator) into a dependency-aware
|
|
430
|
-
* sequence of batches for ParallelEternalEngine.
|
|
431
|
-
*
|
|
432
|
-
* Key behaviour:
|
|
433
|
-
* - Each `nextBatch()` call returns up to `parallelSlots` ready tasks
|
|
434
|
-
* (all blockers completed, sorted by priority).
|
|
435
|
-
* - Tasks that are blocked by an in-progress task are NOT included
|
|
436
|
-
* in the batch — they wait for the blocker to complete.
|
|
437
|
-
* - When `isDone()` returns true the whole graph is either completed
|
|
438
|
-
* or deadlocked (all remaining tasks are blocked by failed tasks).
|
|
439
|
-
*
|
|
440
|
-
* Usage:
|
|
441
|
-
* ```
|
|
442
|
-
* const decomposer = new SddTaskDecomposer(tracker, graph, { parallelSlots: 4 });
|
|
443
|
-
* while (!decomposer.isDone()) {
|
|
444
|
-
* const batch = decomposer.nextBatch();
|
|
445
|
-
* if (batch.length === 0) break; // deadlock
|
|
446
|
-
* await fanOut(batch);
|
|
447
|
-
* decomposer.acknowledgeBatch(batch.map(t => t.id));
|
|
448
|
-
* }
|
|
449
|
-
* ```
|
|
450
|
-
*/
|
|
451
|
-
|
|
452
|
-
interface SddTaskDecomposerOptions {
|
|
453
|
-
/** Max tasks per batch. Default: 4. Range 1–16. */
|
|
454
|
-
parallelSlots?: number | undefined;
|
|
455
|
-
}
|
|
456
|
-
interface TaskBatch {
|
|
457
|
-
/** Tasks ready to execute in this wave. */
|
|
458
|
-
tasks: TaskNode[];
|
|
459
|
-
/** 0-based wave number since the decomposer was constructed. */
|
|
460
|
-
wave: number;
|
|
461
|
-
/** True when every node in the graph is either completed or failed. */
|
|
462
|
-
allDone: boolean;
|
|
463
|
-
/** True when no batch was produced because remaining tasks are all blocked by failed nodes. */
|
|
464
|
-
deadlocked: boolean;
|
|
465
|
-
}
|
|
466
|
-
declare class SddTaskDecomposer {
|
|
467
|
-
private readonly tracker;
|
|
468
|
-
private readonly slots;
|
|
469
|
-
private wave;
|
|
470
|
-
constructor(tracker: TaskTracker, _graph: TaskGraph, opts?: SddTaskDecomposerOptions);
|
|
471
|
-
/**
|
|
472
|
-
* Return the next batch of runnable tasks.
|
|
473
|
-
* Returns `allDone: true` when every node is completed.
|
|
474
|
-
* Returns `deadlocked: true` when no batch can be produced because
|
|
475
|
-
* all remaining tasks are blocked by failed nodes.
|
|
476
|
-
*/
|
|
477
|
-
nextBatch(): TaskBatch;
|
|
478
|
-
/**
|
|
479
|
-
* Advance the wave counter after a batch completes.
|
|
480
|
-
* Call this once per `nextBatch()` result that was fan-out.
|
|
481
|
-
*/
|
|
482
|
-
acknowledgeBatch(_completedTaskIds: string[]): void;
|
|
483
|
-
/**
|
|
484
|
-
* True when every node in the graph is completed.
|
|
485
|
-
* Use this to exit the fan-out loop after `isDone() || deadlocked`.
|
|
486
|
-
*/
|
|
487
|
-
isDone(): boolean;
|
|
488
|
-
/**
|
|
489
|
-
* Total waves produced so far.
|
|
490
|
-
*/
|
|
491
|
-
getWaveCount(): number;
|
|
492
|
-
/**
|
|
493
|
-
* All ready (dependency-satisfied) pending tasks, priority-sorted — UNSLICED.
|
|
494
|
-
* The continuous scheduler fills its own free slots from this list, so unlike
|
|
495
|
-
* `nextBatch()` it does not cap at `slots`.
|
|
496
|
-
*/
|
|
497
|
-
readyNodes(): TaskNode[];
|
|
498
|
-
/**
|
|
499
|
-
* True when every node has reached a terminal state (completed or failed).
|
|
500
|
-
* This — not `isDone()` (which requires ALL completed) — is the correct loop
|
|
501
|
-
* exit for the continuous scheduler: a terminally-failed task must not keep
|
|
502
|
-
* the run spinning to its backstop.
|
|
503
|
-
*/
|
|
504
|
-
isSettled(): boolean;
|
|
505
|
-
/**
|
|
506
|
-
* Return pending nodes whose blockers are all completed.
|
|
507
|
-
* Sorted by priority (critical first), then by creation time.
|
|
508
|
-
*/
|
|
509
|
-
private pendingReadyNodes;
|
|
510
|
-
/** True when at least one non-completed, non-failed task is blocked. */
|
|
511
|
-
private hasAnyBlockedTasks;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
/** A sub-task produced by splitting a parent task (see `splitTask`). */
|
|
515
|
-
interface SddSubtaskSpec {
|
|
516
|
-
title: string;
|
|
517
|
-
description: string;
|
|
518
|
-
type?: TaskNode['type'] | undefined;
|
|
519
|
-
priority?: TaskNode['priority'] | undefined;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Verdict returned by the optional failure supervisor when a task is about to go
|
|
523
|
-
* terminal. `retry` re-queues with a fresh attempt budget; `reassign` swaps the
|
|
524
|
-
* worker model (+ optional provider) then re-queues; `split` breaks the task
|
|
525
|
-
* into sub-tasks; `fail` (or `undefined`) lets it terminal-fail.
|
|
526
|
-
*/
|
|
527
|
-
type SddSupervisorVerdict = {
|
|
528
|
-
action: 'retry';
|
|
529
|
-
} | {
|
|
530
|
-
action: 'reassign';
|
|
531
|
-
model?: string | undefined;
|
|
532
|
-
provider?: string | undefined;
|
|
533
|
-
} | {
|
|
534
|
-
action: 'split';
|
|
535
|
-
subtasks: SddSubtaskSpec[];
|
|
536
|
-
} | {
|
|
537
|
-
action: 'fail';
|
|
538
|
-
};
|
|
539
|
-
interface SddParallelRunOptions {
|
|
540
|
-
/** Pre-constructed TaskTracker (must already hold the graph's initial state). */
|
|
541
|
-
tracker: TaskTracker;
|
|
542
|
-
/** The TaskGraph produced by TaskGenerator from an approved spec. */
|
|
543
|
-
graph: TaskGraph;
|
|
544
|
-
/** The main agent — used as the subagent factory. */
|
|
545
|
-
agent: Agent;
|
|
546
|
-
/** Project root (used for coordinator id). */
|
|
547
|
-
projectRoot: string;
|
|
548
|
-
/**
|
|
549
|
-
* Override default parallel slots (1–16). Default: 2 — deliberately low so a
|
|
550
|
-
* run never juggles more git worktrees than a human can review. Independent
|
|
551
|
-
* tasks still run concurrently up to this cap; dependency chains run in order.
|
|
552
|
-
*/
|
|
553
|
-
parallelSlots?: number | undefined;
|
|
554
|
-
/**
|
|
555
|
-
* Hard wall-clock cap per task in ms. OPT-IN — `undefined` by default so a
|
|
556
|
-
* long-but-productive task is never killed merely for running long (the old
|
|
557
|
-
* 5-min default hard-killed real coding tasks with `budget_timeout`). When
|
|
558
|
-
* set, the coordinator watchdog enforces it. Prefer `taskIdleTimeoutMs`.
|
|
559
|
-
*/
|
|
560
|
-
taskTimeoutMs?: number | undefined;
|
|
561
|
-
/**
|
|
562
|
-
* Idle reaper per task in ms: reap a task only after this long with NO
|
|
563
|
-
* activity (iteration / tool call / streamed token / tool progress). Resets
|
|
564
|
-
* on every sign of forward motion, so an actively-working agent runs until
|
|
565
|
-
* its task naturally ends. Default: 600_000 (10 min of silence = genuinely
|
|
566
|
-
* stuck). This is the default guard — wall-clock (`taskTimeoutMs`) is opt-in.
|
|
567
|
-
*/
|
|
568
|
-
taskIdleTimeoutMs?: number | undefined;
|
|
569
|
-
/** Maximum in-run retry attempts for a failed task before it goes terminal. Default: 3. */
|
|
570
|
-
maxRetries?: number | undefined;
|
|
571
|
-
/**
|
|
572
|
-
* After the graph settles with terminal-failed tasks, requeue ALL failed
|
|
573
|
-
* (non-cancelled) tasks to `pending` and run them again — up to this many
|
|
574
|
-
* sweeps. Each sweep gives every failed task a fresh `maxRetries` budget. The
|
|
575
|
-
* loop stops early once a sweep produces no new completions (no progress).
|
|
576
|
-
* 0 = off. Default: 2.
|
|
577
|
-
*/
|
|
578
|
-
maxFailedRetrySweeps?: number | undefined;
|
|
579
|
-
/** Override the default agent factory. */
|
|
580
|
-
subagentFactory?: AgentFactory | undefined;
|
|
581
|
-
/**
|
|
582
|
-
* Run-level default model for worker subagents. A task's own
|
|
583
|
-
* `metadata.model` (set per-task in the WebUI) takes precedence; this is the
|
|
584
|
-
* fallback for every task that has no explicit assignment. Undefined → the
|
|
585
|
-
* factory's own default (the leader's model).
|
|
586
|
-
*/
|
|
587
|
-
defaultModel?: string | undefined;
|
|
588
|
-
/** Run-level default provider id (same precedence rules as defaultModel). */
|
|
589
|
-
defaultProvider?: string | undefined;
|
|
590
|
-
/**
|
|
591
|
-
* Run-level fallback model chain (entries: `model` / `provider/model`). A
|
|
592
|
-
* task's `metadata.fallbackModels` overrides this. The subagent factory wires
|
|
593
|
-
* these into a fallback extension so a 429/stream-hang rotates to the next.
|
|
594
|
-
*/
|
|
595
|
-
fallbackModels?: string[] | undefined;
|
|
596
|
-
/**
|
|
597
|
-
* Post-task verification gate. When set, a task whose worker reported success
|
|
598
|
-
* is NOT marked `completed` (and NOT merged) until this resolves `{ok:true}`.
|
|
599
|
-
* Runs in the task's worktree cwd (or the project root when no worktree). Core
|
|
600
|
-
* stays shell-agnostic — the caller injects a verifier that, e.g., runs the
|
|
601
|
-
* task's `metadata.verificationCommand` (tests / typecheck). A task with no
|
|
602
|
-
* command should return `{ok:true}`. An `{ok:false}` routes the task into the
|
|
603
|
-
* normal failure path (retry while attempts remain, else terminal-fail).
|
|
604
|
-
*/
|
|
605
|
-
verifyTask?: ((info: {
|
|
606
|
-
task: TaskNode;
|
|
607
|
-
result: TaskResult;
|
|
608
|
-
cwd: string;
|
|
609
|
-
}) => Promise<{
|
|
610
|
-
ok: boolean;
|
|
611
|
-
reason?: string;
|
|
612
|
-
}>) | undefined;
|
|
613
|
-
/**
|
|
614
|
-
* Optional merge-conflict resolver, forwarded to `WorktreeManager.merge`. Given
|
|
615
|
-
* the conflicted files + the base checkout cwd, return `true` once resolved (no
|
|
616
|
-
* markers left). When omitted or it returns `false`, the task is requeued (a
|
|
617
|
-
* re-run forks a fresh worktree off the advanced base) and, if retries are
|
|
618
|
-
* exhausted, terminally failed with its worktree kept for review.
|
|
619
|
-
*/
|
|
620
|
-
conflictResolver?: ((info: {
|
|
621
|
-
task: TaskNode;
|
|
622
|
-
conflictFiles: string[];
|
|
623
|
-
cwd: string;
|
|
624
|
-
}) => Promise<boolean>) | undefined;
|
|
625
|
-
/**
|
|
626
|
-
* Failure supervisor: consulted ONLY when a task has exhausted its retries and
|
|
627
|
-
* is about to go terminal-failed. Returning a verdict lets a decision agent
|
|
628
|
-
* keep the run moving — `retry` / `reassign` (swap model) / `split` — instead
|
|
629
|
-
* of dead-ending. Returning `{action:'fail'}` / `undefined` lets it fail. Each
|
|
630
|
-
* task can be rescued at most `maxSupervisorEscalations` times (loop guard).
|
|
631
|
-
*/
|
|
632
|
-
superviseFailure?: ((info: {
|
|
633
|
-
task: TaskNode;
|
|
634
|
-
error: string;
|
|
635
|
-
attempts: number;
|
|
636
|
-
}) => Promise<SddSupervisorVerdict | undefined>) | undefined;
|
|
637
|
-
/** Max times the supervisor may rescue a single task before it must fail. Default 2. */
|
|
638
|
-
maxSupervisorEscalations?: number | undefined;
|
|
639
|
-
/** Called after each wave completes. */
|
|
640
|
-
onWave?: ((wave: WaveResult) => void) | undefined;
|
|
641
|
-
/** Called with progress stats every ~2s during execution. */
|
|
642
|
-
onProgress?: ((progress: SddProgress) => void) | undefined;
|
|
643
|
-
/** Shared EventBus — when set, the run emits `sdd.*` live-board events. */
|
|
644
|
-
events?: EventBus | undefined;
|
|
645
|
-
/** Parent session id for every emitted `sdd.*` event. */
|
|
646
|
-
sessionId?: string | (() => string | undefined) | undefined;
|
|
647
|
-
/** Stable id correlating all events of this run (default: random). */
|
|
648
|
-
runId?: string | undefined;
|
|
649
|
-
/**
|
|
650
|
-
* Optional git-worktree manager. When set (and the project is a git repo),
|
|
651
|
-
* each task runs in its own isolated worktree and merges back into the base
|
|
652
|
-
* branch after success — so parallel agents never collide on the same files.
|
|
653
|
-
*/
|
|
654
|
-
worktrees?: WorktreeManager | undefined;
|
|
655
|
-
/** Run-level backstops (prevent an autonomous run from looping forever). */
|
|
656
|
-
maxTotalWaves?: number | undefined;
|
|
657
|
-
maxWallClockMs?: number | undefined;
|
|
658
|
-
/**
|
|
659
|
-
* Deadlock auto-recovery rounds: when the graph deadlocks on failed blockers,
|
|
660
|
-
* requeue those failed blockers `pending` and try again, up to N times. 0 = off.
|
|
661
|
-
*/
|
|
662
|
-
maxRecoveryRounds?: number | undefined;
|
|
663
|
-
}
|
|
664
|
-
interface SddProgress {
|
|
665
|
-
wave: number;
|
|
666
|
-
total: number;
|
|
667
|
-
completed: number;
|
|
668
|
-
inProgress: number;
|
|
669
|
-
failed: number;
|
|
670
|
-
blocked: number;
|
|
671
|
-
pending: number;
|
|
672
|
-
percent: number;
|
|
673
|
-
deadlocked: boolean;
|
|
674
|
-
}
|
|
675
|
-
interface WaveResult {
|
|
676
|
-
wave: number;
|
|
677
|
-
batch: TaskBatch;
|
|
678
|
-
results: TaskResult[];
|
|
679
|
-
successCount: number;
|
|
680
|
-
failCount: number;
|
|
681
|
-
durationMs: number;
|
|
682
|
-
stopRequested: boolean;
|
|
683
|
-
}
|
|
684
|
-
/** Result of a single task's execution in the continuous scheduler. */
|
|
685
|
-
interface TaskOutcome {
|
|
686
|
-
taskId: string;
|
|
687
|
-
success: boolean;
|
|
688
|
-
result?: TaskResult | undefined;
|
|
689
|
-
}
|
|
690
|
-
interface RunResult {
|
|
691
|
-
totalWaves: number;
|
|
692
|
-
totalCompleted: number;
|
|
693
|
-
totalFailed: number;
|
|
694
|
-
totalDurationMs: number;
|
|
695
|
-
deadlocked: boolean;
|
|
696
|
-
stopRequested: boolean;
|
|
697
|
-
finalProgress: TaskProgress;
|
|
698
|
-
}
|
|
699
|
-
declare class SddParallelRun {
|
|
700
|
-
private readonly opts;
|
|
701
|
-
private readonly slots;
|
|
702
|
-
/** Opt-in hard wall-clock cap (undefined → no cap; idle reaper guards instead). */
|
|
703
|
-
private readonly timeoutMs;
|
|
704
|
-
/** Idle reaper window (ms) — resets on activity; reaps only a genuine stall. */
|
|
705
|
-
private readonly idleTimeoutMs;
|
|
706
|
-
private readonly maxRetries;
|
|
707
|
-
/** Max supervisor rescues per task before it must terminal-fail (loop guard). */
|
|
708
|
-
private readonly maxSupervisorEscalations;
|
|
709
|
-
/** Per-task count of supervisor rescues used (resets nothing — bounds the loop). */
|
|
710
|
-
private supervisorEscalations;
|
|
711
|
-
/** Max end-of-run failed-task sweeps (see `maxFailedRetrySweeps`). */
|
|
712
|
-
private readonly maxFailedSweeps;
|
|
713
|
-
/** How many failed-task sweeps have run this `run()` so far. */
|
|
714
|
-
private failedSweeps;
|
|
715
|
-
/** Completed-count snapshot at the last sweep, to detect a no-progress sweep. */
|
|
716
|
-
private lastSweepCompleted;
|
|
717
|
-
private decomposer;
|
|
718
|
-
private coordinator;
|
|
719
|
-
private stopRequested;
|
|
720
|
-
private retryMap;
|
|
721
|
-
readonly runId: string;
|
|
722
|
-
private readonly events?;
|
|
723
|
-
private readonly sessionIdSource;
|
|
724
|
-
private readonly maxTotalWaves;
|
|
725
|
-
private readonly maxWallClockMs?;
|
|
726
|
-
private readonly maxRecoveryRounds;
|
|
727
|
-
private recoveryRounds;
|
|
728
|
-
/** Per-run worker identities, so the board shows "who is on what". */
|
|
729
|
-
private usedNicknames;
|
|
730
|
-
/** Per-task git worktree cwd (Layer 2 worktree isolation; empty otherwise). */
|
|
731
|
-
private taskCwds;
|
|
732
|
-
/** Per-task git worktree branch, for board display. */
|
|
733
|
-
private taskBranches;
|
|
734
|
-
/** Live worktree handles keyed by task id (for commit/merge/release). */
|
|
735
|
-
private taskWorktrees;
|
|
736
|
-
/** Live subagent id per running task — lets cancelTask() abort exactly one. */
|
|
737
|
-
private taskSubagents;
|
|
738
|
-
/** Tasks the user cancelled mid-flight — skip retry, mark terminal-cancelled. */
|
|
739
|
-
private cancelledTasks;
|
|
740
|
-
/**
|
|
741
|
-
* Base branch the run's squash commits land on (captured once at start when
|
|
742
|
-
* worktrees are enabled). Anchors a later `rollback()`.
|
|
743
|
-
*/
|
|
744
|
-
private baseBranch;
|
|
745
|
-
/**
|
|
746
|
-
* Squash-merge commits this run landed on the base branch, in landing order.
|
|
747
|
-
* `rollback()` reverts these (newest → oldest). Persisted via the board
|
|
748
|
-
* snapshot so a post-run rollback can read them off disk.
|
|
749
|
-
*/
|
|
750
|
-
private mergedCommits;
|
|
751
|
-
/** Monotonic dispatch counter (unique subagent ids) + dispatch-round counter. */
|
|
752
|
-
private dispatchSeq;
|
|
753
|
-
private round;
|
|
754
|
-
constructor(opts: SddParallelRunOptions);
|
|
755
|
-
/** Type-safe emit on the optional EventBus (no-op when unwired). */
|
|
756
|
-
private emit;
|
|
757
|
-
private currentSessionId;
|
|
758
|
-
private paused;
|
|
759
|
-
/** Trigger stop — causes run() to abort after the current wave. */
|
|
760
|
-
stop(): void;
|
|
761
|
-
/** Pause: no new wave starts until resume() (the current wave finishes). */
|
|
762
|
-
pause(): void;
|
|
763
|
-
resume(): void;
|
|
764
|
-
isPaused(): boolean;
|
|
765
|
-
isRunning(): boolean;
|
|
766
|
-
/** Base branch the run's squash commits land on (undefined when worktrees off). */
|
|
767
|
-
getBaseBranch(): string | undefined;
|
|
768
|
-
/** Squash commits this run landed on the base branch, in landing order. */
|
|
769
|
-
getMergedCommits(): ReadonlyArray<{
|
|
770
|
-
taskId: string;
|
|
771
|
-
sha: string;
|
|
772
|
-
title: string;
|
|
773
|
-
}>;
|
|
774
|
-
/**
|
|
775
|
-
* Remove every git worktree + branch this run (and any prior run) created.
|
|
776
|
-
* Refuses while the run is still live — cleaning a checkout under an active
|
|
777
|
-
* worker would corrupt it. Stop first. Returns the number of worktrees removed
|
|
778
|
-
* (0 when worktrees are disabled). Idempotent.
|
|
779
|
-
*/
|
|
780
|
-
cleanupWorktrees(): Promise<number>;
|
|
781
|
-
/**
|
|
782
|
-
* Undo the run's merged commits by reverting each on the base branch (history
|
|
783
|
-
* preserving). Refuses while the run is still live (stop first). Returns the
|
|
784
|
-
* revert outcome; a dirty tree or revert conflict surfaces as `ok:false`.
|
|
785
|
-
*/
|
|
786
|
-
rollback(): Promise<{
|
|
787
|
-
ok: boolean;
|
|
788
|
-
reverted: number;
|
|
789
|
-
reason?: string;
|
|
790
|
-
}>;
|
|
791
|
-
/** Requeue a task to `pending` so the scheduler re-runs it (clears retries + cancel marker). */
|
|
792
|
-
retryTask(taskId: string): boolean;
|
|
793
|
-
/** Reassign a task to a specific agent name (reflected on the board). */
|
|
794
|
-
reassignTask(taskId: string, agentName: string): boolean;
|
|
795
|
-
/**
|
|
796
|
-
* Set/override a task's worker model (and optionally provider) — applied on its
|
|
797
|
-
* NEXT dispatch (a running task must be cancelled + retried to take effect). The
|
|
798
|
-
* assignment lives on node metadata so it survives crash → resume.
|
|
799
|
-
*/
|
|
800
|
-
setTaskModel(taskId: string, model: string | undefined, provider?: string | undefined): boolean;
|
|
801
|
-
/** Set/override a task's fallback model chain (applied on its next dispatch). */
|
|
802
|
-
setTaskFallbacks(taskId: string, fallbackModels: string[] | undefined): boolean;
|
|
803
|
-
/**
|
|
804
|
-
* Set/override a task's verification command (the completion gate runs it in
|
|
805
|
-
* the task's cwd and only lets the task complete on exit 0). Empty/undefined
|
|
806
|
-
* clears it. Applied on the task's next verification — i.e. its next dispatch.
|
|
807
|
-
*/
|
|
808
|
-
setTaskVerification(taskId: string, verificationCommand: string | undefined): boolean;
|
|
809
|
-
/**
|
|
810
|
-
* Cancel a task. If it is currently running, abort its subagent and mark the
|
|
811
|
-
* node terminally failed+cancelled (so the scheduler frees the slot and does
|
|
812
|
-
* NOT retry it). If it has not started, it is simply marked cancelled. Use
|
|
813
|
-
* `retryTask` to bring a cancelled task back. Returns false for an unknown task.
|
|
814
|
-
*/
|
|
815
|
-
cancelTask(taskId: string): Promise<boolean>;
|
|
816
|
-
/**
|
|
817
|
-
* Delete a not-yet-started task from the graph (pending/blocked/failed only —
|
|
818
|
-
* never a running task; cancel it first). Removes the node and every edge
|
|
819
|
-
* touching it; dependents lose this blocker. Returns false if missing or running.
|
|
820
|
-
*/
|
|
821
|
-
deleteTask(taskId: string): boolean;
|
|
822
|
-
/**
|
|
823
|
-
* Split a task into sub-tasks and delegate them to separate workers. The new
|
|
824
|
-
* leaves inherit the parent's blockers (so they don't start before the
|
|
825
|
-
* parent's dependencies are met), every existing dependent is rewired to
|
|
826
|
-
* depend on ALL leaves (so downstream work waits for the whole split), and the
|
|
827
|
-
* parent becomes a `completed` container. Refuses a running task (cancel it
|
|
828
|
-
* first) or empty subtask list. Returns the new leaf ids (empty on refusal).
|
|
829
|
-
* The scheduler picks the new pending leaves up on its next dispatch pass.
|
|
830
|
-
*/
|
|
831
|
-
splitTask(taskId: string, subtasks: SddSubtaskSpec[]): string[];
|
|
832
|
-
private waitWhilePaused;
|
|
833
|
-
/**
|
|
834
|
-
* Continuous dependency-driven execution. Unlike a wave-barrier loop (where a
|
|
835
|
-
* whole batch must finish before the next starts), this fills free worker
|
|
836
|
-
* slots the instant a task's dependencies are satisfied: a fast task's
|
|
837
|
-
* dependent starts immediately rather than waiting for a slow sibling. Truly
|
|
838
|
-
* independent tasks run in parallel; dependency chains run in order. Returns
|
|
839
|
-
* the final summary when the graph settles, deadlocks, stops, or hits a backstop.
|
|
840
|
-
*/
|
|
841
|
-
run(): Promise<RunResult>;
|
|
842
|
-
/**
|
|
843
|
-
* Compute the blocking chains for a deadlock: every still-incomplete task and
|
|
844
|
-
* the blockers (by node id) that are NOT completed. Failed blockers are
|
|
845
|
-
* included since they're the usual deadlock cause once retries are exhausted.
|
|
846
|
-
*/
|
|
847
|
-
private computeDeadlockChains;
|
|
848
|
-
/** Requeue failed tasks that block an incomplete dependent. Returns true if any. */
|
|
849
|
-
private recoverFailedBlockers;
|
|
850
|
-
/**
|
|
851
|
-
* Requeue every terminal-failed task that the user did NOT cancel, giving each
|
|
852
|
-
* a fresh `maxRetries` budget. Shared by the automatic end-of-run sweep and
|
|
853
|
-
* the manual "retry all failed" control. Returns the number requeued.
|
|
854
|
-
*/
|
|
855
|
-
private requeueFailedTasks;
|
|
856
|
-
/**
|
|
857
|
-
* Manually requeue all failed tasks to `pending` (board "Retry all failed").
|
|
858
|
-
* Unlike the automatic sweep this also clears any `cancelled` marker, so a
|
|
859
|
-
* user can bring cancelled tasks back in the same action — mirroring
|
|
860
|
-
* `retryTask`. Picked up by the running scheduler on its next dispatch pass.
|
|
861
|
-
* Returns the number of tasks requeued.
|
|
862
|
-
*/
|
|
863
|
-
retryAllFailed(): number;
|
|
864
|
-
/** Restore per-task retry counts persisted in node metadata (resume support). */
|
|
865
|
-
private restoreRetryMap;
|
|
866
|
-
/**
|
|
867
|
-
* Reset orphaned `in_progress` tasks (no agent runs them after a crash) back
|
|
868
|
-
* to `pending` so a fresh run re-executes them. Call before constructing a run
|
|
869
|
-
* from a reloaded graph. Static so callers don't need a run instance.
|
|
870
|
-
*/
|
|
871
|
-
static resetOrphans(tracker: TaskTracker): number;
|
|
872
|
-
/** Clean teardown after a stop: reset interrupted tasks + release worktrees. */
|
|
873
|
-
private teardown;
|
|
874
|
-
private buildCoordinator;
|
|
875
|
-
private defaultFactory;
|
|
876
|
-
/**
|
|
877
|
-
* Execute a batch of tasks together. Retained as a thin wrapper over the
|
|
878
|
-
* single-task primitive `executeOne` so the wave-oriented tests and any
|
|
879
|
-
* batch callers keep working; the continuous scheduler in `run()` calls
|
|
880
|
-
* `executeOne` directly. Throws if no coordinator is wired or a spawn fails
|
|
881
|
-
* (surfaced from `executeOne`), preserving the original all-or-nothing contract.
|
|
882
|
-
*/
|
|
883
|
-
executeWave(batch: TaskBatch): Promise<WaveResult>;
|
|
884
|
-
/**
|
|
885
|
-
* Execute one task end-to-end: assign a worker identity, allocate its worktree,
|
|
886
|
-
* spawn + assign the subagent, await its result, then update tracker status
|
|
887
|
-
* (success / retry / terminal-fail / cancelled) and resolve the worktree. This
|
|
888
|
-
* is the unit the continuous scheduler dispatches into a free slot. Throws on a
|
|
889
|
-
* missing coordinator or failed spawn so callers can enforce all-or-nothing.
|
|
890
|
-
*/
|
|
891
|
-
executeOne(task: TaskNode): Promise<TaskOutcome>;
|
|
892
|
-
/**
|
|
893
|
-
* Apply a task failure: retry (→ pending, bump retry count) while attempts
|
|
894
|
-
* remain, else consult the optional supervisor (which can rescue via
|
|
895
|
-
* retry/reassign/split), else terminal-fail (→ failed). Shared by the
|
|
896
|
-
* worker-failure, verification-gate, and merge-conflict paths so all three
|
|
897
|
-
* negotiate the same retry budget and emit the same events.
|
|
898
|
-
*/
|
|
899
|
-
private applyTaskFailure;
|
|
900
|
-
/**
|
|
901
|
-
* Consult `superviseFailure` for a task that has exhausted its retries.
|
|
902
|
-
* Applies the verdict (retry / reassign+retry / split) and returns true when
|
|
903
|
-
* the task was rescued (caller must NOT terminal-fail it). Bounded per task by
|
|
904
|
-
* `maxSupervisorEscalations` so an always-"retry" supervisor can't loop forever.
|
|
905
|
-
*/
|
|
906
|
-
private trySupervisorRescue;
|
|
907
|
-
/**
|
|
908
|
-
* Integrate a verified-successful task's worktree into the base branch.
|
|
909
|
-
* Commits, squash-merges (optionally running `conflictResolver` first), and on
|
|
910
|
-
* success releases the worktree. On an UNRESOLVED conflict it returns
|
|
911
|
-
* `{ok:false}` with the conflicting files so the caller routes the task into
|
|
912
|
-
* the failure path (a retry forks a fresh worktree off the now-advanced base,
|
|
913
|
-
* which usually clears the conflict). No-op `{ok:true}` when worktrees are
|
|
914
|
-
* disabled or none was allocated for this task. Never throws — a merge hiccup
|
|
915
|
-
* degrades to a (retryable) failure rather than wedging the run.
|
|
916
|
-
*/
|
|
917
|
-
private integrateWorktree;
|
|
918
|
-
/** Allocate a fresh git worktree per task in the batch (no-op without a manager). */
|
|
919
|
-
private allocateWorktrees;
|
|
920
|
-
/**
|
|
921
|
-
* Resolve each task's worktree after its result is known. Serialized merges
|
|
922
|
-
* (one at a time) keep the base branch consistent; the wave structure already
|
|
923
|
-
* guarantees dependency order (a task's blockers merged in an earlier wave).
|
|
924
|
-
*/
|
|
925
|
-
private resolveWorktrees;
|
|
926
|
-
private forgetWorktree;
|
|
927
|
-
/** Persist a task's retry count into node metadata (survives crash → resume). */
|
|
928
|
-
private persistRetries;
|
|
929
|
-
private buildProgress;
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
interface SubtaskGeneratorOptions {
|
|
933
|
-
/** Runs one self-contained, isolated LLM turn and resolves its final text. */
|
|
934
|
-
run: (prompt: string) => Promise<string>;
|
|
935
|
-
/** Minimum well-formed sub-tasks required to accept a split. Default 2. */
|
|
936
|
-
minSubtasks?: number;
|
|
937
|
-
/** Maximum sub-tasks kept (excess is dropped). Default 4. */
|
|
938
|
-
maxSubtasks?: number;
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* Build a `SddSupervisorOptions.generateSubtasks` closure backed by an LLM turn.
|
|
942
|
-
* Returns [] on any failure (parse error, too few valid items, runner throw), so
|
|
943
|
-
* the supervisor safely degrades a `split` verdict into a retry.
|
|
944
|
-
*/
|
|
945
|
-
declare function makeLlmSubtaskGenerator(opts: SubtaskGeneratorOptions): (info: {
|
|
946
|
-
task: TaskNode;
|
|
947
|
-
error: string;
|
|
948
|
-
}) => Promise<SddSubtaskSpec[]>;
|
|
949
|
-
|
|
950
|
-
interface SddBoardStoreOptions {
|
|
951
|
-
/** Directory for board snapshots + event logs (wpaths.projectSddBoards). */
|
|
952
|
-
baseDir: string;
|
|
953
|
-
}
|
|
954
|
-
interface SddBoardIndexEntry {
|
|
955
|
-
runId: string;
|
|
956
|
-
specId?: string | undefined;
|
|
957
|
-
title: string;
|
|
958
|
-
status: string;
|
|
959
|
-
total: number;
|
|
960
|
-
completed: number;
|
|
961
|
-
updatedAt: number;
|
|
962
|
-
}
|
|
963
|
-
/** One appended line in a board's JSONL event log. */
|
|
964
|
-
interface SddBoardEvent {
|
|
965
|
-
ts: number;
|
|
966
|
-
type: string;
|
|
967
|
-
payload?: unknown;
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* File-backed SDD board storage. Each board (= one parallel run) has:
|
|
971
|
-
* - `<runId>.json` — latest full snapshot (atomic; resume + standalone-webui mirror)
|
|
972
|
-
* - `<runId>.events.jsonl`— append-only event log (audit / replay)
|
|
973
|
-
* - `<runId>.control.jsonl` — append-only command queue (cross-process control, written by readers)
|
|
974
|
-
* plus `_index.json` for fast listing. JSON for state, JSONL for streams.
|
|
975
|
-
*/
|
|
976
|
-
declare class SddBoardStore {
|
|
977
|
-
private readonly baseDir;
|
|
978
|
-
private readonly indexPath;
|
|
979
|
-
constructor(opts: SddBoardStoreOptions);
|
|
980
|
-
snapshotPath(runId: string): string;
|
|
981
|
-
eventsPath(runId: string): string;
|
|
982
|
-
controlPath(runId: string): string;
|
|
983
|
-
saveSnapshot(snapshot: SddBoardSnapshot): Promise<void>;
|
|
984
|
-
load(runId: string): Promise<SddBoardSnapshot | null>;
|
|
985
|
-
list(): Promise<SddBoardIndexEntry[]>;
|
|
986
|
-
loadLatestForSpec(specId: string): Promise<SddBoardSnapshot | null>;
|
|
987
|
-
/** Append one line to the board's JSONL event log (best-effort, never throws). */
|
|
988
|
-
appendEvent(runId: string, event: SddBoardEvent): Promise<void>;
|
|
989
|
-
/** Append a control command (used by readers to steer a CLI-owned run). */
|
|
990
|
-
appendControl(runId: string, command: {
|
|
991
|
-
ts: number;
|
|
992
|
-
type: string;
|
|
993
|
-
payload?: unknown;
|
|
994
|
-
}): Promise<void>;
|
|
995
|
-
/** Read + truncate the control queue (the run drains it). Returns parsed commands. */
|
|
996
|
-
drainControl(runId: string): Promise<Array<{
|
|
997
|
-
ts: number;
|
|
998
|
-
type: string;
|
|
999
|
-
payload?: unknown;
|
|
1000
|
-
}>>;
|
|
1001
|
-
delete(runId: string): Promise<void>;
|
|
1002
|
-
private safe;
|
|
1003
|
-
private readIndex;
|
|
1004
|
-
private updateIndex;
|
|
1005
|
-
private removeFromIndex;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
interface SddBoardProjectorOptions {
|
|
1009
|
-
runId: string;
|
|
1010
|
-
graph: TaskGraph;
|
|
1011
|
-
tracker: TaskTracker;
|
|
1012
|
-
events: EventBus;
|
|
1013
|
-
/** Parent session id for emitted `sdd.board.snapshot` events. */
|
|
1014
|
-
sessionId?: string | (() => string | undefined) | undefined;
|
|
1015
|
-
/** Persist snapshots + JSONL events (optional — omit for in-memory only). */
|
|
1016
|
-
store?: SddBoardStore | undefined;
|
|
1017
|
-
specId?: string | undefined;
|
|
1018
|
-
/** Run-level default worker model/provider/fallbacks (shown in the board header). */
|
|
1019
|
-
defaultModel?: string | undefined;
|
|
1020
|
-
defaultProvider?: string | undefined;
|
|
1021
|
-
fallbackModels?: string[] | undefined;
|
|
1022
|
-
/** Base branch the run's squash commits land on (for the board + rollback). */
|
|
1023
|
-
baseBranch?: string | undefined;
|
|
1024
|
-
/** Snapshot coalescing window in ms (default 250). */
|
|
1025
|
-
throttleMs?: number | undefined;
|
|
1026
|
-
/** Clock injection for tests; defaults to Date.now. */
|
|
1027
|
-
now?: (() => number) | undefined;
|
|
1028
|
-
}
|
|
1029
|
-
declare class SddBoardProjector {
|
|
1030
|
-
private readonly o;
|
|
1031
|
-
private readonly now;
|
|
1032
|
-
private readonly throttleMs;
|
|
1033
|
-
private readonly shortId;
|
|
1034
|
-
private status;
|
|
1035
|
-
private wave;
|
|
1036
|
-
private startedAt;
|
|
1037
|
-
private deadlockChains;
|
|
1038
|
-
/** Live activity feed, most recent first (capped). */
|
|
1039
|
-
private feed;
|
|
1040
|
-
private static readonly FEED_CAP;
|
|
1041
|
-
private finished;
|
|
1042
|
-
private runDeadlocked;
|
|
1043
|
-
private runStopped;
|
|
1044
|
-
/** Squash commits the run landed on the base branch (for post-run rollback). */
|
|
1045
|
-
private mergedCommits;
|
|
1046
|
-
/** Base branch reported by the run at start (overrides the constructor option). */
|
|
1047
|
-
private runBaseBranch;
|
|
1048
|
-
private dirty;
|
|
1049
|
-
private timer;
|
|
1050
|
-
private readonly unsubs;
|
|
1051
|
-
/** Tail of in-flight persistence, so callers can await a settled state. */
|
|
1052
|
-
private lastSave;
|
|
1053
|
-
constructor(opts: SddBoardProjectorOptions);
|
|
1054
|
-
private pushFeed;
|
|
1055
|
-
/** ` (title…)` suffix for a feed line, or '' when the node/title is missing. */
|
|
1056
|
-
private titleOf;
|
|
1057
|
-
private assigneeOf;
|
|
1058
|
-
/** Latest snapshot, built on demand (e.g. for a late-joining client). */
|
|
1059
|
-
snapshot(): SddBoardSnapshot;
|
|
1060
|
-
/** Resolve once all in-flight snapshot persistence has settled. */
|
|
1061
|
-
drain(): Promise<void>;
|
|
1062
|
-
/** Stop projecting and release subscriptions. */
|
|
1063
|
-
dispose(): void;
|
|
1064
|
-
/** Subscribe to a run event scoped to this run id; also append to JSONL. */
|
|
1065
|
-
private onRun;
|
|
1066
|
-
private resolveStatus;
|
|
1067
|
-
private build;
|
|
1068
|
-
private markDirty;
|
|
1069
|
-
private flush;
|
|
1070
|
-
private currentSessionId;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
interface SpecStoreOptions {
|
|
1074
|
-
/** Directory where spec files are stored. Defaults to `.wrongstack/specs`. */
|
|
1075
|
-
baseDir: string;
|
|
1076
|
-
}
|
|
1077
|
-
interface SpecIndexEntry {
|
|
1078
|
-
id: string;
|
|
1079
|
-
title: string;
|
|
1080
|
-
version: string;
|
|
1081
|
-
status: SpecStatus;
|
|
1082
|
-
updatedAt: number;
|
|
1083
|
-
filePath: string;
|
|
1084
|
-
}
|
|
1085
|
-
/**
|
|
1086
|
-
* File-backed spec storage. Each spec is a JSON file under `baseDir/`.
|
|
1087
|
-
* An index file (`_index.json`) tracks all specs for fast listing.
|
|
1088
|
-
*/
|
|
1089
|
-
declare class SpecStore {
|
|
1090
|
-
private readonly baseDir;
|
|
1091
|
-
private readonly indexPath;
|
|
1092
|
-
constructor(opts: SpecStoreOptions);
|
|
1093
|
-
save(spec: Specification): Promise<void>;
|
|
1094
|
-
load(id: string): Promise<Specification | null>;
|
|
1095
|
-
list(): Promise<SpecIndexEntry[]>;
|
|
1096
|
-
delete(id: string): Promise<boolean>;
|
|
1097
|
-
exists(id: string): Promise<boolean>;
|
|
1098
|
-
/** Create a new spec with defaults, assign ID, and persist. */
|
|
1099
|
-
createDraft(title: string, overview?: string): Promise<Specification>;
|
|
1100
|
-
/** Update spec fields and persist. */
|
|
1101
|
-
update(id: string, patch: Partial<Omit<Specification, 'id' | 'createdAt'>>): Promise<Specification | null>;
|
|
1102
|
-
private filePath;
|
|
1103
|
-
private readIndex;
|
|
1104
|
-
private updateIndex;
|
|
1105
|
-
private removeFromIndex;
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
type AISpecPhase = 'questioning' | 'spec_review' | 'implementation' | 'task_review' | 'executing' | 'done';
|
|
1109
|
-
interface CollectedAnswer {
|
|
1110
|
-
question: string;
|
|
1111
|
-
answer: string;
|
|
1112
|
-
timestamp: number;
|
|
1113
|
-
}
|
|
1114
|
-
interface AISpecSession {
|
|
1115
|
-
id: string;
|
|
1116
|
-
phase: AISpecPhase;
|
|
1117
|
-
title: string;
|
|
1118
|
-
userIntent: string;
|
|
1119
|
-
projectContext: string;
|
|
1120
|
-
answers: CollectedAnswer[];
|
|
1121
|
-
questionCount: number;
|
|
1122
|
-
spec?: Specification | undefined;
|
|
1123
|
-
implementation?: string | undefined;
|
|
1124
|
-
taskGraphId?: string | undefined;
|
|
1125
|
-
approved: boolean;
|
|
1126
|
-
createdAt: number;
|
|
1127
|
-
updatedAt: number;
|
|
1128
|
-
}
|
|
1129
|
-
interface AISpecBuilderOptions {
|
|
1130
|
-
store: SpecStore;
|
|
1131
|
-
/** Minimum questions the AI should ask. Default: 2 */
|
|
1132
|
-
minQuestions?: number | undefined;
|
|
1133
|
-
/** Maximum questions before forcing spec generation. Default: 10 */
|
|
1134
|
-
maxQuestions?: number | undefined;
|
|
1135
|
-
/** Project context string (package.json, file structure, etc.) */
|
|
1136
|
-
projectContext?: string | undefined;
|
|
1137
|
-
/** Path to persist session state. If set, session survives process restarts. */
|
|
1138
|
-
sessionPath?: string | undefined;
|
|
1139
|
-
}
|
|
1140
|
-
/**
|
|
1141
|
-
* AI-driven specification builder. Instead of static questions, this builder
|
|
1142
|
-
* tracks conversation state and generates prompts that instruct the AI agent
|
|
1143
|
-
* to ask contextual questions and build specifications interactively.
|
|
1144
|
-
*/
|
|
1145
|
-
declare class AISpecBuilder {
|
|
1146
|
-
private session;
|
|
1147
|
-
private readonly store;
|
|
1148
|
-
private readonly minQuestions;
|
|
1149
|
-
private readonly maxQuestions;
|
|
1150
|
-
private readonly sessionPath?;
|
|
1151
|
-
constructor(opts: AISpecBuilderOptions);
|
|
1152
|
-
/** Save session state to disk. */
|
|
1153
|
-
saveSession(): Promise<void>;
|
|
1154
|
-
/** Load session state from disk. Returns true if a session was loaded. */
|
|
1155
|
-
loadSession(): Promise<boolean>;
|
|
1156
|
-
/** Delete saved session from disk. */
|
|
1157
|
-
deleteSession(): Promise<void>;
|
|
1158
|
-
/** Auto-save helper — calls saveSession() but never throws.
|
|
1159
|
-
* Failures are surfaced via process.emitWarning so a persistent
|
|
1160
|
-
* ENOSPC / EACCES doesn't silently strand session edits in memory. */
|
|
1161
|
-
private autoSave;
|
|
1162
|
-
/** Start a new session with a title and optional intent. */
|
|
1163
|
-
startSession(title: string, intent?: string): void;
|
|
1164
|
-
/** Get current session state (readonly). */
|
|
1165
|
-
getSession(): Readonly<AISpecSession>;
|
|
1166
|
-
/** Get the current phase. */
|
|
1167
|
-
getPhase(): AISpecPhase;
|
|
1168
|
-
/**
|
|
1169
|
-
* Get the AI prompt for the current phase.
|
|
1170
|
-
* This prompt is injected into the conversation so the AI agent knows
|
|
1171
|
-
* what to do next (ask a question, generate a spec, etc.).
|
|
1172
|
-
*/
|
|
1173
|
-
getAIPrompt(): string;
|
|
1174
|
-
/**
|
|
1175
|
-
* Record a question/answer pair from the AI conversation.
|
|
1176
|
-
* Call this when the AI asks a question and the user responds.
|
|
1177
|
-
*/
|
|
1178
|
-
addAnswer(question: string, answer: string): void;
|
|
1179
|
-
/**
|
|
1180
|
-
* Check if more questions should be asked.
|
|
1181
|
-
* Returns false if max reached or if the AI has signaled it has enough info.
|
|
1182
|
-
*/
|
|
1183
|
-
shouldContinueQuestioning(): boolean;
|
|
1184
|
-
/**
|
|
1185
|
-
* Check if minimum questions have been asked.
|
|
1186
|
-
*/
|
|
1187
|
-
hasMetMinimumQuestions(): boolean;
|
|
1188
|
-
/**
|
|
1189
|
-
* Set the generated specification and move to spec_review phase.
|
|
1190
|
-
*/
|
|
1191
|
-
setSpec(spec: Specification): void;
|
|
1192
|
-
/**
|
|
1193
|
-
* Approve the current phase and advance to the next.
|
|
1194
|
-
* questioning → spec_review (requires spec to be set)
|
|
1195
|
-
* spec_review → implementation
|
|
1196
|
-
* implementation → task_review (requires implementation to be set)
|
|
1197
|
-
* task_review → executing
|
|
1198
|
-
* executing → done
|
|
1199
|
-
*/
|
|
1200
|
-
approve(): AISpecPhase;
|
|
1201
|
-
/**
|
|
1202
|
-
* Set the implementation plan text.
|
|
1203
|
-
*/
|
|
1204
|
-
setImplementation(plan: string): void;
|
|
1205
|
-
/**
|
|
1206
|
-
* Mark session as done.
|
|
1207
|
-
*/
|
|
1208
|
-
markDone(): void;
|
|
1209
|
-
/**
|
|
1210
|
-
* Set the task graph ID for this session.
|
|
1211
|
-
*/
|
|
1212
|
-
setTaskGraphId(graphId: string): void;
|
|
1213
|
-
/**
|
|
1214
|
-
* Get the task graph ID for this session.
|
|
1215
|
-
*/
|
|
1216
|
-
getTaskGraphId(): string | undefined;
|
|
1217
|
-
/**
|
|
1218
|
-
* Save the current spec to the store.
|
|
1219
|
-
*/
|
|
1220
|
-
saveSpec(): Promise<Specification>;
|
|
1221
|
-
/**
|
|
1222
|
-
* Parse a spec from a JSON string (from AI output).
|
|
1223
|
-
* Validates and normalizes the structure.
|
|
1224
|
-
*/
|
|
1225
|
-
parseSpecFromJSON(jsonStr: string): Specification;
|
|
1226
|
-
/**
|
|
1227
|
-
* Extract JSON from AI output (handles ```json blocks and raw JSON).
|
|
1228
|
-
*/
|
|
1229
|
-
extractJSON(text: string): string | null;
|
|
1230
|
-
/**
|
|
1231
|
-
* Detect if AI output contains a spec (JSON block).
|
|
1232
|
-
*/
|
|
1233
|
-
hasSpecInOutput(text: string): boolean;
|
|
1234
|
-
/**
|
|
1235
|
-
* Try to parse a spec from AI output text.
|
|
1236
|
-
* Returns null if no valid spec found.
|
|
1237
|
-
*/
|
|
1238
|
-
tryParseSpecFromOutput(text: string): Specification | null;
|
|
1239
|
-
/**
|
|
1240
|
-
* Extract a JSON array from AI output (for task lists).
|
|
1241
|
-
*/
|
|
1242
|
-
extractJSONArray(text: string): string | null;
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
interface TaskGraphStoreOptions {
|
|
1246
|
-
/** Directory where task graph files are stored. Defaults to `.wrongstack/task-graphs`. */
|
|
1247
|
-
baseDir: string;
|
|
1248
|
-
}
|
|
1249
|
-
interface TaskGraphIndexEntry {
|
|
1250
|
-
id: string;
|
|
1251
|
-
specId: string;
|
|
1252
|
-
title: string;
|
|
1253
|
-
nodeCount: number;
|
|
1254
|
-
completedCount: number;
|
|
1255
|
-
updatedAt: number;
|
|
1256
|
-
filePath: string;
|
|
1257
|
-
}
|
|
1258
|
-
/**
|
|
1259
|
-
* File-backed task graph storage. Each graph is a JSON file under `baseDir/`.
|
|
1260
|
-
* An index file (`_index.json`) tracks all graphs for fast listing.
|
|
1261
|
-
*/
|
|
1262
|
-
declare class TaskGraphStore {
|
|
1263
|
-
private readonly baseDir;
|
|
1264
|
-
private readonly indexPath;
|
|
1265
|
-
constructor(opts: TaskGraphStoreOptions);
|
|
1266
|
-
save(graph: TaskGraph): Promise<void>;
|
|
1267
|
-
load(id: string): Promise<TaskGraph | null>;
|
|
1268
|
-
list(): Promise<TaskGraphIndexEntry[]>;
|
|
1269
|
-
delete(id: string): Promise<boolean>;
|
|
1270
|
-
exists(id: string): Promise<boolean>;
|
|
1271
|
-
private filePath;
|
|
1272
|
-
private readIndex;
|
|
1273
|
-
private updateIndex;
|
|
1274
|
-
private removeFromIndex;
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
interface SddInterviewDriverOptions {
|
|
1278
|
-
/** Disk-backed spec store (`wpaths.projectSpecs`). */
|
|
1279
|
-
specStore: SpecStore;
|
|
1280
|
-
/** Disk-backed task-graph store (`wpaths.projectTaskGraphs`). */
|
|
1281
|
-
graphStore: TaskGraphStore;
|
|
1282
|
-
/** Persist the interview session here so a reconnect can resume it. */
|
|
1283
|
-
sessionPath?: string | undefined;
|
|
1284
|
-
/** Project context string injected into the questioning prompt. */
|
|
1285
|
-
projectContext?: string | undefined;
|
|
1286
|
-
minQuestions?: number | undefined;
|
|
1287
|
-
maxQuestions?: number | undefined;
|
|
1288
|
-
}
|
|
1289
|
-
/** A serialisable view of the interview, streamed to observing surfaces. */
|
|
1290
|
-
interface SddInterviewSnapshot {
|
|
1291
|
-
sessionId: string;
|
|
1292
|
-
phase: AISpecPhase;
|
|
1293
|
-
title: string;
|
|
1294
|
-
/** The operator's original goal prompt (verbatim). `title` is a short heading. */
|
|
1295
|
-
goal: string;
|
|
1296
|
-
questionCount: number;
|
|
1297
|
-
minQuestions: number;
|
|
1298
|
-
maxQuestions: number;
|
|
1299
|
-
answers: Array<{
|
|
1300
|
-
question: string;
|
|
1301
|
-
answer: string;
|
|
1302
|
-
}>;
|
|
1303
|
-
spec?: {
|
|
1304
|
-
id: string;
|
|
1305
|
-
title: string;
|
|
1306
|
-
overview: string;
|
|
1307
|
-
requirements: Array<{
|
|
1308
|
-
priority: string;
|
|
1309
|
-
description: string;
|
|
1310
|
-
}>;
|
|
1311
|
-
} | undefined;
|
|
1312
|
-
graphId?: string | undefined;
|
|
1313
|
-
taskCount: number;
|
|
1314
|
-
/**
|
|
1315
|
-
* Topologically-laid-out task graph (once decomposed) — lets the wizard
|
|
1316
|
-
* render the same animated DAG as the live board ("decomposition reveal").
|
|
1317
|
-
*/
|
|
1318
|
-
board?: {
|
|
1319
|
-
tasks: SddBoardTask[];
|
|
1320
|
-
columns: SddBoardColumn[];
|
|
1321
|
-
} | undefined;
|
|
1322
|
-
/** The current AI prompt for this phase (what to send the agent next). */
|
|
1323
|
-
prompt: string;
|
|
1324
|
-
}
|
|
1325
|
-
/** What `ingestAgentOutput` detected and acted on. */
|
|
1326
|
-
interface SddIngestResult {
|
|
1327
|
-
specDetected: boolean;
|
|
1328
|
-
implementationDetected: boolean;
|
|
1329
|
-
tasksDetected: boolean;
|
|
1330
|
-
graphId?: string | undefined;
|
|
1331
|
-
}
|
|
1332
|
-
declare class SddInterviewDriver {
|
|
1333
|
-
readonly builder: AISpecBuilder;
|
|
1334
|
-
private readonly o;
|
|
1335
|
-
private readonly minQuestions;
|
|
1336
|
-
private readonly maxQuestions;
|
|
1337
|
-
private tracker;
|
|
1338
|
-
private graph;
|
|
1339
|
-
constructor(opts: SddInterviewDriverOptions);
|
|
1340
|
-
/** Begin a fresh interview. Returns the first AI prompt (a question kickoff). */
|
|
1341
|
-
start(title: string, intent?: string): string;
|
|
1342
|
-
/**
|
|
1343
|
-
* Resume a previously-persisted interview from disk. Re-hydrates the task
|
|
1344
|
-
* graph too when one was already produced. Returns true if a session loaded.
|
|
1345
|
-
*/
|
|
1346
|
-
loadExisting(): Promise<boolean>;
|
|
1347
|
-
phase(): AISpecPhase;
|
|
1348
|
-
currentPrompt(): string;
|
|
1349
|
-
getTracker(): TaskTracker | null;
|
|
1350
|
-
getGraph(): TaskGraph | null;
|
|
1351
|
-
/** Record a Q/A pair (the agent asked `question`, the user replied `answer`). */
|
|
1352
|
-
submitAnswer(question: string, answer: string): void;
|
|
1353
|
-
/**
|
|
1354
|
-
* Feed the agent's text output back into the interview. Detects, in order:
|
|
1355
|
-
* 1. a Specification JSON → setSpec (phase → spec_review) + persist to SpecStore
|
|
1356
|
-
* 2. an implementation plan (implementation phase) → setImplementation
|
|
1357
|
-
* 3. a task JSON array → build + persist a TaskGraph
|
|
1358
|
-
* Each step is independent and best-effort; a malformed payload is ignored
|
|
1359
|
-
* rather than thrown, so a chatty agent turn never breaks the interview.
|
|
1360
|
-
*/
|
|
1361
|
-
ingestAgentOutput(text: string): Promise<SddIngestResult>;
|
|
1362
|
-
/**
|
|
1363
|
-
* Advance to the next phase (mirrors `/sdd approve`). When moving into the
|
|
1364
|
-
* executing phase, guarantees a task graph exists — deterministically
|
|
1365
|
-
* generating one from the approved spec if the agent never emitted a valid
|
|
1366
|
-
* task array. Returns the new phase and its AI prompt.
|
|
1367
|
-
*/
|
|
1368
|
-
approve(): Promise<{
|
|
1369
|
-
phase: AISpecPhase;
|
|
1370
|
-
prompt: string;
|
|
1371
|
-
}>;
|
|
1372
|
-
/**
|
|
1373
|
-
* Ensure a TaskGraph exists for the approved spec. If the agent already
|
|
1374
|
-
* produced one (via `ingestAgentOutput`), returns it; otherwise builds a
|
|
1375
|
-
* deterministic graph from the spec's requirements via TaskGenerator. This is
|
|
1376
|
-
* the robustness backstop: a run can always start, even if the model never
|
|
1377
|
-
* emitted a parseable task array.
|
|
1378
|
-
*/
|
|
1379
|
-
ensureTaskGraph(): Promise<TaskGraph | null>;
|
|
1380
|
-
snapshot(): SddInterviewSnapshot;
|
|
1381
|
-
private persistSpec;
|
|
1382
|
-
private persistGraph;
|
|
1383
|
-
/**
|
|
1384
|
-
* Port of the CLI `trySaveImplementationPlan` operating on this driver's
|
|
1385
|
-
* builder. Captures the prose plan that precedes the task JSON block.
|
|
1386
|
-
*/
|
|
1387
|
-
private trySaveImplementationPlan;
|
|
1388
|
-
/**
|
|
1389
|
-
* Port of the CLI `trySaveTasksFromAIOutput`: parse a task JSON array from the
|
|
1390
|
-
* agent output, build (or extend) the tracker + graph, persist to disk, and
|
|
1391
|
-
* link the graphId to the session. Returns the graphId on success.
|
|
1392
|
-
*/
|
|
1393
|
-
private tryBuildTasksFromOutput;
|
|
1394
|
-
}
|
|
1395
|
-
/**
|
|
1396
|
-
* True when the text reads like conversational filler rather than a structured
|
|
1397
|
-
* implementation plan. Ported verbatim from the CLI detection so behaviour is
|
|
1398
|
-
* identical across surfaces.
|
|
1399
|
-
*/
|
|
1400
|
-
declare function isExplanatoryText(text: string): boolean;
|
|
1401
|
-
|
|
1402
|
-
/** Force-remove every git worktree + branch a previous run left behind. */
|
|
1403
|
-
declare function cleanupSddWorktrees(projectRoot: string): Promise<{
|
|
1404
|
-
removed: number;
|
|
1405
|
-
}>;
|
|
1406
|
-
/**
|
|
1407
|
-
* Detect and clean up stale worktrees from a crashed previous run.
|
|
1408
|
-
* No-op when the project is clean. Called on SDD/Director boot to
|
|
1409
|
-
* prevent orphaned worktrees from conflicting with the next run's
|
|
1410
|
-
* `allocate()`.
|
|
1411
|
-
*
|
|
1412
|
-
* P2 #B6 (sprint2 audit).
|
|
1413
|
-
*/
|
|
1414
|
-
declare function cleanupStaleWorktrees(projectRoot: string): Promise<{
|
|
1415
|
-
removed: number;
|
|
1416
|
-
detected: number;
|
|
1417
|
-
}>;
|
|
1418
|
-
interface CleanupStaleSddOptions {
|
|
1419
|
-
projectRoot: string;
|
|
1420
|
-
/** Board snapshot dir (`wpaths.projectSddBoards`) — read for the liveness guard. */
|
|
1421
|
-
boardsDir: string;
|
|
1422
|
-
/** A `running` board updated within this window is treated as live → skip. Default 120_000 (2 min). */
|
|
1423
|
-
runningLiveMs?: number | undefined;
|
|
1424
|
-
/** A `paused` board updated within this window is treated as live → skip. Default 1_800_000 (30 min). */
|
|
1425
|
-
pausedLiveMs?: number | undefined;
|
|
1426
|
-
/** Injectable clock for tests. */
|
|
1427
|
-
now?: (() => number) | undefined;
|
|
1428
|
-
}
|
|
1429
|
-
interface CleanupStaleSddResult {
|
|
1430
|
-
/** True when a sweep ran (orphans were found and removed). */
|
|
1431
|
-
swept: boolean;
|
|
1432
|
-
removed: number;
|
|
1433
|
-
detected: number;
|
|
1434
|
-
/** Set when the sweep was skipped because a run appears live. */
|
|
1435
|
-
skippedReason?: string | undefined;
|
|
1436
|
-
}
|
|
1437
|
-
/**
|
|
1438
|
-
* Liveness-guarded stale-worktree sweep for boot + run-start. Worktrees live
|
|
1439
|
-
* under `<projectRoot>/.wrongstack/worktrees` and a sweep force-removes ALL of
|
|
1440
|
-
* them — so it must NEVER run under a genuinely live run (possibly in another
|
|
1441
|
-
* process). The guard reads the latest board: a `running` board updated within
|
|
1442
|
-
* `runningLiveMs`, or a `paused` one within `pausedLiveMs`, is treated as live
|
|
1443
|
-
* and the sweep is skipped. A crashed run leaves its board frozen as `running`
|
|
1444
|
-
* → once it ages past the window it is correctly swept. Any other status
|
|
1445
|
-
* (completed / failed / stopped / deadlocked / idle) is always sweepable.
|
|
1446
|
-
* Never throws — best-effort cleanup.
|
|
1447
|
-
*/
|
|
1448
|
-
declare function cleanupStaleSddWorktrees(opts: CleanupStaleSddOptions): Promise<CleanupStaleSddResult>;
|
|
1449
|
-
interface RollbackFromDiskOptions {
|
|
1450
|
-
projectRoot: string;
|
|
1451
|
-
/** Directory holding persisted board snapshots (`wpaths.projectSddBoards`). */
|
|
1452
|
-
boardsDir: string;
|
|
1453
|
-
/** Specific run to roll back. Omit → the most recently updated board. */
|
|
1454
|
-
runId?: string | undefined;
|
|
1455
|
-
}
|
|
1456
|
-
/**
|
|
1457
|
-
* Roll back a finished run's merged commits by reading its persisted board
|
|
1458
|
-
* snapshot (base branch + commit SHAs) and reverting each. History-preserving;
|
|
1459
|
-
* refuses on a dirty tree or revert conflict (surfaced in `reason`). Returns
|
|
1460
|
-
* `ok:false` with a reason when there is no board, no base branch, or nothing to
|
|
1461
|
-
* revert.
|
|
1462
|
-
*/
|
|
1463
|
-
declare function rollbackSddRunFromDisk(opts: RollbackFromDiskOptions): Promise<{
|
|
1464
|
-
ok: boolean;
|
|
1465
|
-
reverted: number;
|
|
1466
|
-
reason?: string;
|
|
1467
|
-
}>;
|
|
1468
|
-
interface DestroySddProjectOptions {
|
|
1469
|
-
projectRoot: string;
|
|
1470
|
-
/** Resolved wstack paths to delete. */
|
|
1471
|
-
paths: {
|
|
1472
|
-
projectSpecs: string;
|
|
1473
|
-
projectTaskGraphs: string;
|
|
1474
|
-
projectSddSession: string;
|
|
1475
|
-
projectSddBoards: string;
|
|
1476
|
-
};
|
|
1477
|
-
/**
|
|
1478
|
-
* Also revert this run's already-merged squash commits (history-preserving
|
|
1479
|
-
* `git revert`) BEFORE deleting the board that records them. Off by default —
|
|
1480
|
-
* a plain destroy wipes worktrees + artifacts but leaves merged commits on the
|
|
1481
|
-
* base branch (un-merged worktree work is destroyed regardless, since its
|
|
1482
|
-
* branch is force-removed). When on and the working tree is dirty, the revert
|
|
1483
|
-
* is refused and surfaced in `revertReason` (the destroy still proceeds).
|
|
1484
|
-
*/
|
|
1485
|
-
revertMerged?: boolean | undefined;
|
|
1486
|
-
/** Which run's merged commits to revert. Omit → the most recently updated board. */
|
|
1487
|
-
runId?: string | undefined;
|
|
1488
|
-
}
|
|
1489
|
-
interface DestroySddProjectResult {
|
|
1490
|
-
worktreesRemoved: number;
|
|
1491
|
-
/** Human labels of the artifacts that were deleted. */
|
|
1492
|
-
deleted: string[];
|
|
1493
|
-
/** Number of merged commits reverted (only when `revertMerged` was set). */
|
|
1494
|
-
reverted: number;
|
|
1495
|
-
/** Whether the optional merged-commit revert succeeded (undefined → not requested). */
|
|
1496
|
-
revertOk?: boolean | undefined;
|
|
1497
|
-
/** Why the revert did not fully apply (dirty tree, conflict, nothing to revert). */
|
|
1498
|
-
revertReason?: string | undefined;
|
|
1499
|
-
}
|
|
1500
|
-
/**
|
|
1501
|
-
* Destroy an SDD project: optionally revert its merged commits, then clean every
|
|
1502
|
-
* worktree + branch, then delete the on-disk artifacts (specs, task-graphs,
|
|
1503
|
-
* session, boards). The revert is opt-in (`revertMerged`) and runs FIRST — it
|
|
1504
|
-
* reads the board snapshot that the artifact deletion removes. Best-effort: a
|
|
1505
|
-
* missing path is simply skipped. The caller is responsible for stopping any
|
|
1506
|
-
* active run first.
|
|
1507
|
-
*/
|
|
1508
|
-
declare function destroySddProject(opts: DestroySddProjectOptions): Promise<DestroySddProjectResult>;
|
|
1509
|
-
/** Lifecycle operation kinds shared by every surface (WebUI / TUI / CLI). */
|
|
1510
|
-
type SddLifecycleOp = 'cleanup_worktrees' | 'rollback' | 'destroy';
|
|
1511
|
-
interface SddLifecycleOptions {
|
|
1512
|
-
projectRoot: string;
|
|
1513
|
-
/** Resolved wstack paths (required for `destroy`; boards dir is enough for `rollback`). */
|
|
1514
|
-
paths: {
|
|
1515
|
-
projectSpecs: string;
|
|
1516
|
-
projectTaskGraphs: string;
|
|
1517
|
-
projectSddSession: string;
|
|
1518
|
-
projectSddBoards: string;
|
|
1519
|
-
};
|
|
1520
|
-
/** Target a specific run (rollback / destroy). Omit → most recently updated board. */
|
|
1521
|
-
runId?: string | undefined;
|
|
1522
|
-
/** `destroy` only: also revert merged commits before wiping. */
|
|
1523
|
-
revertMerged?: boolean | undefined;
|
|
1524
|
-
}
|
|
1525
|
-
/** Uniform result for any lifecycle op — drives identical UI wording everywhere. */
|
|
1526
|
-
interface SddLifecycleResult {
|
|
1527
|
-
op: SddLifecycleOp;
|
|
1528
|
-
ok: boolean;
|
|
1529
|
-
/** Worktrees removed (cleanup_worktrees / destroy). */
|
|
1530
|
-
removed?: number | undefined;
|
|
1531
|
-
/** Merged commits reverted (rollback / destroy with revertMerged). */
|
|
1532
|
-
reverted?: number | undefined;
|
|
1533
|
-
/** Artifact labels deleted (destroy). */
|
|
1534
|
-
deleted?: string[] | undefined;
|
|
1535
|
-
/** Failure / partial reason, surfaced verbatim in the UI. */
|
|
1536
|
-
reason?: string | undefined;
|
|
1537
|
-
}
|
|
1538
|
-
/**
|
|
1539
|
-
* Apply a post-run SDD lifecycle operation from disk and return a uniform result.
|
|
1540
|
-
* The single entry point shared by the WebUI board handler, the TUI overlay, and
|
|
1541
|
-
* the CLI `/sdd` host so every surface reports the same thing. The caller must
|
|
1542
|
-
* ensure no run is active (these operate on git + on-disk state, not the live
|
|
1543
|
-
* run) — `cleanup`/`destroy` force-remove worktrees, `rollback` refuses on a
|
|
1544
|
-
* dirty tree. Never throws.
|
|
1545
|
-
*/
|
|
1546
|
-
declare function applySddLifecycle(op: SddLifecycleOp, opts: SddLifecycleOptions): Promise<SddLifecycleResult>;
|
|
1547
|
-
|
|
1548
|
-
/**
|
|
1549
|
-
* Control surface over a live SDD run, exposed to every steering surface
|
|
1550
|
-
* (TUI, CLI-hosted WebUI in-process; standalone WebUI via a control file the
|
|
1551
|
-
* run drains). The run itself stays CLI-owned — this is the only sanctioned
|
|
1552
|
-
* way to pause / retry / reassign from outside the run loop.
|
|
1553
|
-
*/
|
|
1554
|
-
interface SddRunControl {
|
|
1555
|
-
runId: string;
|
|
1556
|
-
specId?: string | undefined;
|
|
1557
|
-
pause(): void;
|
|
1558
|
-
resume(): void;
|
|
1559
|
-
stop(): void;
|
|
1560
|
-
retryTask(taskId: string): boolean;
|
|
1561
|
-
/** Requeue every failed task to pending (board "Retry all failed"). Returns the count. */
|
|
1562
|
-
retryAllFailed(): number;
|
|
1563
|
-
reassignTask(taskId: string, agentName: string): boolean;
|
|
1564
|
-
/** Set/override a task's worker model (+ optional provider). Next dispatch. */
|
|
1565
|
-
setTaskModel(taskId: string, model: string | undefined, provider?: string | undefined): boolean;
|
|
1566
|
-
/** Set/override a task's fallback model chain. Next dispatch. */
|
|
1567
|
-
setTaskFallbacks(taskId: string, fallbackModels: string[] | undefined): boolean;
|
|
1568
|
-
/** Set/override a task's completion-gate verification command. Next dispatch. */
|
|
1569
|
-
setTaskVerification(taskId: string, verificationCommand: string | undefined): boolean;
|
|
1570
|
-
/** Cancel a task — abort it if running, else mark it cancelled. */
|
|
1571
|
-
cancelTask(taskId: string): Promise<boolean> | boolean;
|
|
1572
|
-
/** Delete a not-started task from the graph (refused while running). */
|
|
1573
|
-
deleteTask(taskId: string): boolean;
|
|
1574
|
-
/** Split a task into sub-tasks (refused while running). Returns the new leaf ids. */
|
|
1575
|
-
splitTask(taskId: string, subtasks: SddSubtaskSpec[]): string[];
|
|
1576
|
-
/**
|
|
1577
|
-
* Remove every git worktree + branch the run created (refused while running —
|
|
1578
|
-
* stop first). Returns the number removed.
|
|
1579
|
-
*/
|
|
1580
|
-
cleanupWorktrees(): Promise<number>;
|
|
1581
|
-
/**
|
|
1582
|
-
* Undo the run's merged commits by reverting each on the base branch (refused
|
|
1583
|
-
* while running). History-preserving; refuses on a dirty tree / revert conflict.
|
|
1584
|
-
*/
|
|
1585
|
-
rollback(): Promise<{
|
|
1586
|
-
ok: boolean;
|
|
1587
|
-
reverted: number;
|
|
1588
|
-
reason?: string;
|
|
1589
|
-
}>;
|
|
1590
|
-
/** Base branch the run's squash commits land on (worktree runs only). */
|
|
1591
|
-
getBaseBranch(): string | undefined;
|
|
1592
|
-
/** Squash commits the run landed on the base branch, in landing order. */
|
|
1593
|
-
getMergedCommits(): ReadonlyArray<{
|
|
1594
|
-
taskId: string;
|
|
1595
|
-
sha: string;
|
|
1596
|
-
title: string;
|
|
1597
|
-
}>;
|
|
1598
|
-
/** Latest board snapshot (built on demand). */
|
|
1599
|
-
snapshot(): SddBoardSnapshot;
|
|
1600
|
-
isRunning(): boolean;
|
|
1601
|
-
}
|
|
1602
|
-
/**
|
|
1603
|
-
* In-process registry of the active SDD run. One run is active at a time (a
|
|
1604
|
-
* single fleet drives it); a new run replaces the previous. Lives in the CLI
|
|
1605
|
-
* process where the fleet runs.
|
|
1606
|
-
*/
|
|
1607
|
-
declare class SddRunRegistry {
|
|
1608
|
-
private current;
|
|
1609
|
-
register(control: SddRunControl): void;
|
|
1610
|
-
clear(runId: string): void;
|
|
1611
|
-
getActive(): SddRunControl | null;
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
interface SddSupervisorOptions {
|
|
1615
|
-
/** Decision authority (policy/LLM/human). Reuse the session's TOKENS.BrainArbiter. */
|
|
1616
|
-
brain: BrainArbiter;
|
|
1617
|
-
/**
|
|
1618
|
-
* Models to rotate through on a `reassign` verdict (e.g. the run's fallback
|
|
1619
|
-
* chain). Omit to drop the reassign option entirely.
|
|
1620
|
-
*/
|
|
1621
|
-
reassignModels?: string[] | undefined;
|
|
1622
|
-
/**
|
|
1623
|
-
* Optional sub-task generator for a `split` verdict — typically an LLM call
|
|
1624
|
-
* that decomposes the failing task into smaller pieces. Omit to drop the split
|
|
1625
|
-
* option. Returning an empty array degrades the split into a retry.
|
|
1626
|
-
*/
|
|
1627
|
-
generateSubtasks?: ((info: {
|
|
1628
|
-
task: TaskNode;
|
|
1629
|
-
error: string;
|
|
1630
|
-
}) => Promise<SddSubtaskSpec[]>) | undefined;
|
|
1631
|
-
/**
|
|
1632
|
-
* Let the tiered brain's LLM layer actually pick the verdict.
|
|
1633
|
-
*
|
|
1634
|
-
* Default (false) requests `fallback: 'continue'`, which the policy layer
|
|
1635
|
-
* answers immediately (a bounded retry) — the LLM never runs, so `reassign`/
|
|
1636
|
-
* `split` can't be chosen. Set true to request `fallback: 'ask_human'`, which
|
|
1637
|
-
* makes the policy escalate so the autonomous (LLM) layer decides.
|
|
1638
|
-
*
|
|
1639
|
-
* ONLY enable this when the supplied `brain` will NOT block on a human prompt
|
|
1640
|
-
* for an unresolved decision (i.e. it has an autonomous layer and is NOT
|
|
1641
|
-
* wrapped in `HumanEscalatingBrainArbiter`). When the LLM can't decide (no
|
|
1642
|
-
* autonomous layer / over the risk ceiling / LLM down) the brain returns
|
|
1643
|
-
* `ask_human`, which the supervisor degrades to a **bounded retry** (never a
|
|
1644
|
-
* block, never a dead-end). A human-escalating brain would instead block
|
|
1645
|
-
* inside `decide()` and wedge the run — keep this false there.
|
|
1646
|
-
*/
|
|
1647
|
-
requestLlmVerdict?: boolean | undefined;
|
|
1648
|
-
}
|
|
1649
|
-
declare class SddSupervisor {
|
|
1650
|
-
private readonly opts;
|
|
1651
|
-
constructor(opts: SddSupervisorOptions);
|
|
1652
|
-
/**
|
|
1653
|
-
* Bind this as `SddParallelRunOptions.superviseFailure`. Returns a verdict the
|
|
1654
|
-
* run applies, or `undefined`/`{action:'fail'}` to let the task terminal-fail.
|
|
1655
|
-
*/
|
|
1656
|
-
readonly superviseFailure: (info: {
|
|
1657
|
-
task: TaskNode;
|
|
1658
|
-
error: string;
|
|
1659
|
-
attempts: number;
|
|
1660
|
-
}) => Promise<SddSupervisorVerdict | undefined>;
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
declare class SpecParser {
|
|
1664
|
-
parse(content: string): Specification;
|
|
1665
|
-
private extractTitle;
|
|
1666
|
-
private extractVersion;
|
|
1667
|
-
private extractOverview;
|
|
1668
|
-
private extractSections;
|
|
1669
|
-
private extractRequirements;
|
|
1670
|
-
private parseRequirementLine;
|
|
1671
|
-
private mapSectionType;
|
|
1672
|
-
analyze(spec: Specification): SpecAnalysis;
|
|
1673
|
-
validate(spec: Specification): SpecValidationResult;
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
/**
|
|
1677
|
-
* Built-in spec templates for common development scenarios.
|
|
1678
|
-
*/
|
|
1679
|
-
declare const SPEC_TEMPLATES: SpecTemplate[];
|
|
1680
|
-
/**
|
|
1681
|
-
* Get a template by ID.
|
|
1682
|
-
*/
|
|
1683
|
-
declare function getTemplate(id: string): SpecTemplate | undefined;
|
|
1684
|
-
/**
|
|
1685
|
-
* List all available templates.
|
|
1686
|
-
*/
|
|
1687
|
-
declare function listTemplates(): Array<{
|
|
1688
|
-
id: string;
|
|
1689
|
-
name: string;
|
|
1690
|
-
description: string;
|
|
1691
|
-
}>;
|
|
1692
|
-
/**
|
|
1693
|
-
* Generate a markdown skeleton from a template.
|
|
1694
|
-
*/
|
|
1695
|
-
declare function templateToMarkdown(template: SpecTemplate, title?: string): string;
|
|
1696
|
-
|
|
1697
|
-
interface SpecVersion {
|
|
1698
|
-
version: string;
|
|
1699
|
-
spec: Specification;
|
|
1700
|
-
timestamp: number;
|
|
1701
|
-
changeDescription?: string | undefined;
|
|
1702
|
-
}
|
|
1703
|
-
interface SpecDiff {
|
|
1704
|
-
added: SpecRequirement[];
|
|
1705
|
-
removed: SpecRequirement[];
|
|
1706
|
-
modified: Array<{
|
|
1707
|
-
requirement: SpecRequirement;
|
|
1708
|
-
previousVersion: SpecRequirement;
|
|
1709
|
-
changes: string[];
|
|
1710
|
-
}>;
|
|
1711
|
-
summary: string;
|
|
1712
|
-
}
|
|
1713
|
-
/**
|
|
1714
|
-
* Track spec versions and compute diffs between versions.
|
|
1715
|
-
*/
|
|
1716
|
-
declare class SpecVersioning {
|
|
1717
|
-
private versions;
|
|
1718
|
-
/** Record a new version of a spec. */
|
|
1719
|
-
recordVersion(spec: Specification, changeDescription?: string): SpecVersion;
|
|
1720
|
-
/** Get version history for a spec. */
|
|
1721
|
-
getHistory(specId: string): SpecVersion[];
|
|
1722
|
-
/** Get a specific version of a spec. */
|
|
1723
|
-
getVersion(specId: string, version: string): SpecVersion | undefined;
|
|
1724
|
-
/** Get the latest version of a spec. */
|
|
1725
|
-
getLatest(specId: string): SpecVersion | undefined;
|
|
1726
|
-
/** Compute diff between two versions of a spec. */
|
|
1727
|
-
diff(oldSpec: Specification, newSpec: Specification): SpecDiff;
|
|
1728
|
-
/**
|
|
1729
|
-
* Update a task graph incrementally based on spec changes.
|
|
1730
|
-
* - Added requirements → new tasks
|
|
1731
|
-
* - Removed requirements → remove tasks
|
|
1732
|
-
* - Modified requirements → update task descriptions
|
|
1733
|
-
* Returns the updated graph and list of changes made.
|
|
1734
|
-
*/
|
|
1735
|
-
updateTaskGraph(graph: TaskGraph, oldSpec: Specification, newSpec: Specification): {
|
|
1736
|
-
graph: TaskGraph;
|
|
1737
|
-
changes: string[];
|
|
1738
|
-
};
|
|
1739
|
-
private compareRequirements;
|
|
1740
|
-
private buildTaskDescription;
|
|
1741
|
-
private mapReqType;
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
interface StartSddRunOptions {
|
|
1745
|
-
tracker: TaskTracker;
|
|
1746
|
-
graph: TaskGraph;
|
|
1747
|
-
/** Leader agent — seeds the default factory and the run's project context. */
|
|
1748
|
-
agent: Agent;
|
|
1749
|
-
projectRoot: string;
|
|
1750
|
-
events: EventBus;
|
|
1751
|
-
/** Parent session id for all SDD EventBus emissions. */
|
|
1752
|
-
sessionId?: string | (() => string | undefined) | undefined;
|
|
1753
|
-
/** Per-task agent factory. Omit to run every task on the leader agent. */
|
|
1754
|
-
subagentFactory?: AgentFactory | undefined;
|
|
1755
|
-
/** Board snapshot/event persistence (also drained for cross-process control). */
|
|
1756
|
-
boardStore: SddBoardStore;
|
|
1757
|
-
/** Registry the run is registered with for in-process control. */
|
|
1758
|
-
registry?: SddRunRegistry | undefined;
|
|
1759
|
-
parallelSlots?: number | undefined;
|
|
1760
|
-
/** Opt-in hard wall-clock cap per task (ms). Omit → no cap (idle reaper guards). */
|
|
1761
|
-
taskTimeoutMs?: number | undefined;
|
|
1762
|
-
/** Idle reaper per task (ms); resets on activity. Default 600_000 (10 min). */
|
|
1763
|
-
taskIdleTimeoutMs?: number | undefined;
|
|
1764
|
-
/** End-of-run failed-task auto-retry sweeps (bounded). Default 2. */
|
|
1765
|
-
maxFailedRetrySweeps?: number | undefined;
|
|
1766
|
-
/** Post-task verification gate (forwarded to SddParallelRun). Omit → no gate. */
|
|
1767
|
-
verifyTask?: SddParallelRunOptions['verifyTask'];
|
|
1768
|
-
/** Merge-conflict resolver (forwarded to SddParallelRun). Omit → retry-on-fresh-base then fail. */
|
|
1769
|
-
conflictResolver?: SddParallelRunOptions['conflictResolver'];
|
|
1770
|
-
/** Failure supervisor (forwarded to SddParallelRun). Omit → no rescue, plain terminal-fail. */
|
|
1771
|
-
superviseFailure?: SddParallelRunOptions['superviseFailure'];
|
|
1772
|
-
/** Run-level default worker model / provider / fallback chain (task overrides win). */
|
|
1773
|
-
defaultModel?: string | undefined;
|
|
1774
|
-
defaultProvider?: string | undefined;
|
|
1775
|
-
fallbackModels?: string[] | undefined;
|
|
1776
|
-
/** Per-task git worktree isolation. Omit → tasks share the working tree. */
|
|
1777
|
-
worktrees?: WorktreeManager | undefined;
|
|
1778
|
-
/** Bounded deadlock recovery rounds (default 1). */
|
|
1779
|
-
maxRecoveryRounds?: number | undefined;
|
|
1780
|
-
/** Progress callback (e.g. CLI renderer line). */
|
|
1781
|
-
onProgress?: ((p: SddProgress) => void) | undefined;
|
|
1782
|
-
/** Control-file drain interval in ms (default 500). */
|
|
1783
|
-
controlDrainMs?: number | undefined;
|
|
1784
|
-
}
|
|
1785
|
-
interface SddRunHandle {
|
|
1786
|
-
run: SddParallelRun;
|
|
1787
|
-
runId: string;
|
|
1788
|
-
projector: SddBoardProjector;
|
|
1789
|
-
/** Resolves when the run finishes AND all teardown (drain/dispose/clear) is done. */
|
|
1790
|
-
completion: Promise<RunResult>;
|
|
1791
|
-
/** Request a clean stop (idempotent). */
|
|
1792
|
-
stop(): void;
|
|
1793
|
-
}
|
|
1794
|
-
/**
|
|
1795
|
-
* Wire up and start an SDD parallel run. Returns immediately with a handle whose
|
|
1796
|
-
* `completion` promise resolves once the run finishes and teardown is complete.
|
|
1797
|
-
* Orphaned in_progress tasks are reset up-front so a crashed prior run re-executes.
|
|
1798
|
-
*/
|
|
1799
|
-
declare function startSddRun(opts: StartSddRunOptions): SddRunHandle;
|
|
1800
|
-
|
|
1801
|
-
/**
|
|
1802
|
-
* Extended event map used internally by TaskFlow and multi-agent components.
|
|
1803
|
-
* These events are emitted on the injected EventBus and are a subset of
|
|
1804
|
-
* the full EventMap — they do not require a separate registration.
|
|
1805
|
-
*/
|
|
1806
|
-
interface TaskFlowEventMap {
|
|
1807
|
-
'phase.change': {
|
|
1808
|
-
from: TaskFlowPhase;
|
|
1809
|
-
to: TaskFlowPhase;
|
|
1810
|
-
};
|
|
1811
|
-
'task.started': {
|
|
1812
|
-
taskId: string;
|
|
1813
|
-
};
|
|
1814
|
-
'task.completed': {
|
|
1815
|
-
taskId: string;
|
|
1816
|
-
result?: unknown | undefined;
|
|
1817
|
-
};
|
|
1818
|
-
'task.failed': {
|
|
1819
|
-
taskId: string;
|
|
1820
|
-
error: string;
|
|
1821
|
-
};
|
|
1822
|
-
'task.review': {
|
|
1823
|
-
taskId: string;
|
|
1824
|
-
};
|
|
1825
|
-
'spec.analyzed': {
|
|
1826
|
-
analysis: SpecAnalysis;
|
|
1827
|
-
};
|
|
1828
|
-
progress: {
|
|
1829
|
-
percent: number;
|
|
1830
|
-
message: string;
|
|
1831
|
-
};
|
|
1832
|
-
done: {
|
|
1833
|
-
graph: TaskGraph;
|
|
1834
|
-
};
|
|
1835
|
-
error: {
|
|
1836
|
-
phase: TaskFlowPhase;
|
|
1837
|
-
error: Error;
|
|
1838
|
-
};
|
|
1839
|
-
}
|
|
1840
|
-
type TaskFlowPhase = 'idle' | 'parsing' | 'analyzing' | 'generating' | 'executing' | 'reviewing' | 'completing' | 'done' | 'failed';
|
|
1841
|
-
type TaskFlowEventName = keyof TaskFlowEventMap;
|
|
1842
|
-
interface TaskFlowOptions {
|
|
1843
|
-
tracker: TaskTracker;
|
|
1844
|
-
events: EventBus;
|
|
1845
|
-
doneCondition?: DoneCondition | undefined;
|
|
1846
|
-
maxConcurrent?: number | undefined;
|
|
1847
|
-
}
|
|
1848
|
-
interface TaskFlowExecutionContext {
|
|
1849
|
-
executeTask: (task: TaskNode) => Promise<unknown>;
|
|
1850
|
-
onTaskComplete?: (task: TaskNode | undefined, result: unknown) => void;
|
|
1851
|
-
onTaskFail?: (task: TaskNode | undefined, error: Error) => void;
|
|
1852
|
-
}
|
|
1853
|
-
declare class TaskFlow {
|
|
1854
|
-
private readonly opts;
|
|
1855
|
-
private phase;
|
|
1856
|
-
private spec;
|
|
1857
|
-
private graph;
|
|
1858
|
-
private stopped;
|
|
1859
|
-
constructor(opts: TaskFlowOptions);
|
|
1860
|
-
private emit;
|
|
1861
|
-
fromSpec(specContent: string): Promise<TaskGraph>;
|
|
1862
|
-
execute(ctx: TaskFlowExecutionContext): Promise<TaskGraph>;
|
|
1863
|
-
reviewTask(taskId: string, approved: boolean, comment?: string): Promise<void>;
|
|
1864
|
-
stop(): void;
|
|
1865
|
-
getPhase(): TaskFlowPhase;
|
|
1866
|
-
getGraph(): TaskGraph | null;
|
|
1867
|
-
getSpec(): Specification | null;
|
|
1868
|
-
private setPhase;
|
|
1869
|
-
private getExecutableTasks;
|
|
1870
|
-
private executeSingleTask;
|
|
1871
|
-
private checkDoneCondition;
|
|
1872
|
-
private emitProgress;
|
|
1873
|
-
}
|
|
1874
|
-
interface SpecDrivenDevOptions {
|
|
1875
|
-
workingDirectory: string;
|
|
1876
|
-
events: EventBus;
|
|
1877
|
-
doneCondition?: DoneCondition | undefined;
|
|
1878
|
-
}
|
|
1879
|
-
declare class SpecDrivenDev {
|
|
1880
|
-
private store;
|
|
1881
|
-
private tracker;
|
|
1882
|
-
private readonly events;
|
|
1883
|
-
private flows;
|
|
1884
|
-
constructor(opts: SpecDrivenDevOptions);
|
|
1885
|
-
createFlow(specContent: string, options?: Partial<TaskFlowOptions>): Promise<TaskFlow>;
|
|
1886
|
-
getTracker(): TaskTracker;
|
|
1887
|
-
getFlow(graphId: string): TaskFlow | undefined;
|
|
1888
|
-
listFlows(): {
|
|
1889
|
-
id: string;
|
|
1890
|
-
title: string;
|
|
1891
|
-
phase: TaskFlowPhase;
|
|
1892
|
-
}[];
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
interface TaskGeneratorOptions {
|
|
1896
|
-
taskTracker: TaskTracker;
|
|
1897
|
-
/**
|
|
1898
|
-
* Opt-in (default off): derive each task's completion-gate
|
|
1899
|
-
* `metadata.verificationCommand` from an acceptance criterion that carries a
|
|
1900
|
-
* runnable-command marker (`$ <cmd>`, or `run:`/`verify:`/`cmd:` prefix). Off
|
|
1901
|
-
* by default so the common case stays fast — auto-running a check per task is
|
|
1902
|
-
* exactly the slowness the robustness initiative set out to avoid; enable it
|
|
1903
|
-
* explicitly (the CLI gates it behind WRONGSTACK_SDD_VERIFY_FROM_ACCEPTANCE).
|
|
1904
|
-
*/
|
|
1905
|
-
verificationFromAcceptance?: boolean | undefined;
|
|
1906
|
-
}
|
|
1907
|
-
/**
|
|
1908
|
-
* Pull a runnable verification command out of a requirement's acceptance
|
|
1909
|
-
* criteria. A criterion qualifies only when it carries an explicit marker —
|
|
1910
|
-
* `$ <cmd>` (shell-prompt style) or a `run:` / `verify:` / `cmd:` prefix — so
|
|
1911
|
-
* free-text criteria are never mistaken for commands. Returns the first match.
|
|
1912
|
-
*/
|
|
1913
|
-
declare function extractVerificationCommand(criteria: readonly string[]): string | undefined;
|
|
1914
|
-
interface GeneratedTask {
|
|
1915
|
-
specRequirementId?: string | undefined;
|
|
1916
|
-
title: string;
|
|
1917
|
-
description: string;
|
|
1918
|
-
type: TaskType;
|
|
1919
|
-
priority: TaskPriority;
|
|
1920
|
-
estimateHours?: number | undefined;
|
|
1921
|
-
tags?: string[] | undefined;
|
|
1922
|
-
}
|
|
1923
|
-
declare class TaskGenerator {
|
|
1924
|
-
private readonly opts;
|
|
1925
|
-
constructor(opts: TaskGeneratorOptions);
|
|
1926
|
-
generateFromSpec(spec: Specification): Promise<TaskGraph>;
|
|
1927
|
-
private createTaskFromRequirement;
|
|
1928
|
-
private createTaskFromEndpoint;
|
|
1929
|
-
private buildDescription;
|
|
1930
|
-
private mapRequirementType;
|
|
1931
|
-
private estimateHours;
|
|
1932
|
-
private estimateForEndpoint;
|
|
1933
|
-
generateSubtasks(parentTaskId: string, spec: Specification): Promise<void>;
|
|
1934
|
-
}
|
|
1935
|
-
declare class DefaultTaskStore implements TaskStore {
|
|
1936
|
-
private graphs;
|
|
1937
|
-
saveGraph(graph: TaskGraph): Promise<void>;
|
|
1938
|
-
loadGraph(id: string): Promise<TaskGraph | null>;
|
|
1939
|
-
listGraphs(): Promise<{
|
|
1940
|
-
id: string;
|
|
1941
|
-
title: string;
|
|
1942
|
-
updatedAt: number;
|
|
1943
|
-
}[]>;
|
|
1944
|
-
deleteGraph(id: string): Promise<void>;
|
|
1945
|
-
private cloneGraph;
|
|
1946
|
-
}
|
|
1947
|
-
|
|
1948
|
-
/**
|
|
1949
|
-
* Render a task graph as ASCII art for terminal display.
|
|
1950
|
-
*/
|
|
1951
|
-
declare function renderTaskGraph(graph: TaskGraph, opts?: {
|
|
1952
|
-
compact?: boolean | undefined;
|
|
1953
|
-
}): string;
|
|
1954
|
-
/**
|
|
1955
|
-
* Render a progress bar.
|
|
1956
|
-
*/
|
|
1957
|
-
declare function renderProgress(progress: TaskProgress): string;
|
|
1958
|
-
/**
|
|
1959
|
-
* Render a compact task list (for quick status checks).
|
|
1960
|
-
*/
|
|
1961
|
-
declare function renderTaskList(graph: TaskGraph): string;
|
|
1962
|
-
/**
|
|
1963
|
-
* Render spec analysis summary.
|
|
1964
|
-
*/
|
|
1965
|
-
declare function renderSpecAnalysis(spec: Specification, analysis: {
|
|
1966
|
-
completeness: number;
|
|
1967
|
-
gaps: string[];
|
|
1968
|
-
risks: string[];
|
|
1969
|
-
suggestions: string[];
|
|
1970
|
-
}): string;
|
|
1971
|
-
|
|
1972
|
-
interface CommandVerifierOptions {
|
|
1973
|
-
/** Metadata key holding the shell command to run. Default 'verificationCommand'. */
|
|
1974
|
-
metadataKey?: string;
|
|
1975
|
-
/** Kill + fail the verification after this many ms. Default 180_000 (3 min). */
|
|
1976
|
-
timeoutMs?: number;
|
|
1977
|
-
}
|
|
1978
|
-
/**
|
|
1979
|
-
* Build a `verifyTask` closure (shape matches {@link SddParallelRunOptions.verifyTask}).
|
|
1980
|
-
* Returns `{ ok: true }` immediately when the task carries no verification command,
|
|
1981
|
-
* otherwise spawns the command in `cwd` (shell, output discarded) and resolves
|
|
1982
|
-
* `{ ok: false, reason }` on non-zero exit, spawn error, or timeout.
|
|
1983
|
-
*/
|
|
1984
|
-
declare function makeCommandVerifier(options?: CommandVerifierOptions): (info: {
|
|
1985
|
-
task: TaskNode;
|
|
1986
|
-
result: TaskResult;
|
|
1987
|
-
cwd: string;
|
|
1988
|
-
}) => Promise<{
|
|
1989
|
-
ok: boolean;
|
|
1990
|
-
reason?: string;
|
|
1991
|
-
}>;
|
|
1992
|
-
|
|
1993
|
-
export { AISpecBuilder, type AISpecBuilderOptions, type AISpecPhase, type AISpecSession, AutoExecutor, type AutoExecutorOptions, type BottleneckTask, type CleanupStaleSddOptions, type CleanupStaleSddResult, type CollectedAnswer, type CommandVerifierOptions, type ConflictSide, type CriticalPathAnalysis, DefaultTaskStore, type DestroySddProjectOptions, type DestroySddProjectResult, type ExecutionSummary, type GeneratedTask, type LlmConflictResolverOptions, type RollbackFromDiskOptions, type RunResult, SPEC_TEMPLATES, type SddBoardColumn, type SddBoardEvent, type SddBoardFeedEntry, type SddBoardIndexEntry, SddBoardProjector, type SddBoardProjectorOptions, type SddBoardSnapshot, type SddBoardStatus, SddBoardStore, type SddBoardStoreOptions, type SddBoardTask, type SddDeadlockChain, type SddIngestResult, SddInterviewDriver, type SddInterviewDriverOptions, type SddInterviewSnapshot, type SddLifecycleOp, type SddLifecycleOptions, type SddLifecycleResult, SddParallelRun, type SddParallelRunOptions, type SddProgress, type SddRunControl, type SddRunHandle, SddRunRegistry, type SddSubtaskSpec, SddSupervisor, type SddSupervisorOptions, type SddSupervisorVerdict, SddTaskDecomposer, type SddTaskDecomposerOptions, type SddTaskDisplayStatus, type SpecDiff, SpecDrivenDev, type SpecDrivenDevOptions, type SpecIndexEntry, SpecParser, SpecStore, type SpecStoreOptions, type SpecVersion, SpecVersioning, type StartSddRunOptions, type SubtaskGeneratorOptions, type TaskBatch, type TaskExecutionContext, type TaskExecutionResult, TaskFlow, type TaskFlowEventMap, type TaskFlowEventName, type TaskFlowExecutionContext, type TaskFlowOptions, type TaskFlowPhase, TaskGenerator, type TaskGeneratorOptions, type TaskGraphIndexEntry, TaskGraphStore, type TaskGraphStoreOptions, type TaskStore, TaskTracker, type TaskTrackerChange, type TaskTrackerListener, type TaskTrackerOptions, type TaskTransition, type WaveResult, analyzeCriticalPath, applySddLifecycle, buildBoardSnapshot, buildBoardTasks, cleanupSddWorktrees, cleanupStaleSddWorktrees, cleanupStaleWorktrees, createAutoExecutor, destroySddProject, extractVerificationCommand, getTemplate, hasConflictMarkers, isExplanatoryText, listTemplates, makeCommandVerifier, makeLlmConflictResolver, makeLlmSubtaskGenerator, makePreferSideConflictResolver, renderProgress, renderSpecAnalysis, renderTaskGraph, renderTaskList, resolveConflictText, rollbackSddRunFromDisk, shortIdMap, startSddRun, templateToMarkdown };
|