@wrongstack/cli 0.66.13 → 0.68.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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import { color, writeErr, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, atomicWrite, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, SpecVersioning, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, bootConfig as bootConfig$1, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, onResize, ERROR_CODES, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, InputBuilder, FsError } from '@wrongstack/core';
2
3
  import * as path8 from 'path';
3
4
  import { join } from 'path';
4
- import * as fsp3 from 'fs/promises';
5
- import { color, writeErr, DefaultTaskStore, TaskTracker, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, renderTaskGraph, SpecVersioning, DefaultSecretScrubber, atomicWrite, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, bootConfig as bootConfig$1, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, onResize, ERROR_CODES, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, InputBuilder, FsError } from '@wrongstack/core';
5
+ import * as fsp4 from 'fs/promises';
6
6
  import { createRequire } from 'module';
7
7
  import * as os2 from 'os';
8
8
  import os2__default from 'os';
@@ -53,32 +53,8 @@ var __copyProps = (to, from, except, desc) => {
53
53
  return to;
54
54
  };
55
55
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
56
-
57
- // src/slash-commands/sdd.ts
58
- var sdd_exports = {};
59
- __export(sdd_exports, {
60
- advanceToNextTask: () => advanceToNextTask,
61
- autoDetectTaskCompletion: () => autoDetectTaskCompletion,
62
- buildSddCommand: () => buildSddCommand,
63
- getActiveBuilder: () => getActiveBuilder,
64
- getActiveSDDContext: () => getActiveSDDContext,
65
- getActiveSDDPhase: () => getActiveSDDPhase,
66
- getCurrentExecutingContext: () => getCurrentExecutingContext,
67
- getCurrentTask: () => getCurrentTask,
68
- getTaskGraphId: () => getTaskGraphId,
69
- getTaskListText: () => getTaskListText,
70
- getTaskProgress: () => getTaskProgress,
71
- getTaskTracker: () => getTaskTracker,
72
- markTaskCompleted: () => markTaskCompleted,
73
- renderTaskListWithProgress: () => renderTaskListWithProgress,
74
- trySaveImplementationPlan: () => trySaveImplementationPlan,
75
- trySaveSpecFromAIOutput: () => trySaveSpecFromAIOutput,
76
- trySaveTasksFromAIOutput: () => trySaveTasksFromAIOutput
77
- });
78
56
  function getSessionState(ctx) {
79
- if (!ctx) {
80
- return sddState;
81
- }
57
+ if (!ctx) return sddState;
82
58
  let state = ctx.meta[SDD_META_KEY];
83
59
  if (!state) {
84
60
  state = new SDDState();
@@ -86,19 +62,103 @@ function getSessionState(ctx) {
86
62
  }
87
63
  return state;
88
64
  }
89
- function getActiveSDDContext() {
90
- return sddState.getContext();
91
- }
92
- function getActiveSDDPhase() {
93
- return sddState.getPhase();
65
+ var SDD_META_KEY, SDDState, sddState;
66
+ var init_state = __esm({
67
+ "src/slash-commands/sdd/state.ts"() {
68
+ SDD_META_KEY = "sdd.state";
69
+ SDDState = class {
70
+ builder = null;
71
+ taskStore = null;
72
+ taskTracker = null;
73
+ taskGraphId = null;
74
+ sessionStartTime = Date.now();
75
+ phaseStartTime = Date.now();
76
+ versioning = null;
77
+ getBuilder() {
78
+ return this.builder;
79
+ }
80
+ setBuilder(b) {
81
+ this.builder = b;
82
+ }
83
+ getTaskStore() {
84
+ return this.taskStore;
85
+ }
86
+ setTaskStore(s) {
87
+ this.taskStore = s;
88
+ }
89
+ getTaskTracker() {
90
+ return this.taskTracker;
91
+ }
92
+ setTaskTracker(t) {
93
+ this.taskTracker = t;
94
+ }
95
+ getTaskGraphId() {
96
+ return this.taskGraphId;
97
+ }
98
+ setTaskGraphId(id) {
99
+ this.taskGraphId = id;
100
+ }
101
+ getSessionStartTime() {
102
+ return this.sessionStartTime;
103
+ }
104
+ setSessionStartTime(t) {
105
+ this.sessionStartTime = t;
106
+ }
107
+ setPhaseStartTime(t) {
108
+ this.phaseStartTime = t;
109
+ }
110
+ getPhaseStartTime() {
111
+ return this.phaseStartTime;
112
+ }
113
+ getSessionElapsed() {
114
+ return Date.now() - this.sessionStartTime;
115
+ }
116
+ getPhaseElapsed() {
117
+ return Date.now() - this.phaseStartTime;
118
+ }
119
+ getVersioning() {
120
+ if (this.versioning === null) this.versioning = new SpecVersioning();
121
+ return this.versioning;
122
+ }
123
+ clearTaskState() {
124
+ this.taskStore = null;
125
+ this.taskTracker = null;
126
+ this.taskGraphId = null;
127
+ }
128
+ getContext() {
129
+ if (!this.builder) return null;
130
+ const session = this.builder.getSession();
131
+ if (session.phase === "done") return null;
132
+ return this.builder.getAIPrompt();
133
+ }
134
+ getPhase() {
135
+ return this.builder?.getPhase() ?? null;
136
+ }
137
+ };
138
+ sddState = new SDDState();
139
+ }
140
+ });
141
+ function formatElapsed(ms) {
142
+ if (ms < 1e3) return `${ms}ms`;
143
+ const s = Math.floor(ms / 1e3);
144
+ if (s < 60) return `${s}s`;
145
+ const m = Math.floor(s / 60);
146
+ const remS = s % 60;
147
+ if (m < 60) return remS > 0 ? `${m}m ${remS}s` : `${m}m`;
148
+ const h = Math.floor(m / 60);
149
+ const remM = m % 60;
150
+ return `${h}h ${remM}m`;
94
151
  }
95
- async function trySaveSpecFromAIOutput(aiOutput) {
96
- const builder = sddState.getBuilder();
97
- if (!builder) return false;
98
- const spec = builder.tryParseSpecFromOutput(aiOutput);
99
- if (!spec) return false;
100
- builder.setSpec(spec);
101
- return true;
152
+ function addTaskToTracker(tracker, task) {
153
+ tracker.addNode({
154
+ title: String(task.title),
155
+ description: String(task.description ?? ""),
156
+ type: ["feature", "bugfix", "refactor", "docs", "test", "chore"].includes(String(task.type)) ? String(task.type) : "feature",
157
+ priority: ["critical", "high", "medium", "low"].includes(String(task.priority)) ? String(task.priority) : "medium",
158
+ status: "pending",
159
+ estimateHours: Number(task.estimateHours) || 2,
160
+ tags: Array.isArray(task.tags) ? task.tags.map(String) : []
161
+ });
102
162
  }
103
163
  async function trySaveTasksFromAIOutput(aiOutput) {
104
164
  const builder = sddState.getBuilder();
@@ -118,45 +178,13 @@ async function trySaveTasksFromAIOutput(aiOutput) {
118
178
  if (validTasks.length === 0) return false;
119
179
  const existingTracker = sddState.getTaskTracker();
120
180
  if (existingTracker) {
121
- for (const task of validTasks) {
122
- const title = String(task.title);
123
- const description = String(task.description ?? "");
124
- const type = ["feature", "bugfix", "refactor", "docs", "test", "chore"].includes(String(task.type)) ? String(task.type) : "feature";
125
- const priority = ["critical", "high", "medium", "low"].includes(String(task.priority)) ? String(task.priority) : "medium";
126
- const estimateHours = Number(task.estimateHours) || 2;
127
- const tags = Array.isArray(task.tags) ? task.tags.map(String) : [];
128
- existingTracker.addNode({
129
- title,
130
- description,
131
- type,
132
- priority,
133
- status: "pending",
134
- estimateHours,
135
- tags
136
- });
137
- }
181
+ for (const task of validTasks) addTaskToTracker(existingTracker, task);
138
182
  return true;
139
183
  }
140
184
  const store = new DefaultTaskStore();
141
185
  const tracker = new TaskTracker({ store });
142
186
  const graph = await tracker.createGraph(session.spec.id, session.spec.title);
143
- for (const task of validTasks) {
144
- const title = String(task.title);
145
- const description = String(task.description ?? "");
146
- const type = ["feature", "bugfix", "refactor", "docs", "test", "chore"].includes(String(task.type)) ? String(task.type) : "feature";
147
- const priority = ["critical", "high", "medium", "low"].includes(String(task.priority)) ? String(task.priority) : "medium";
148
- const estimateHours = Number(task.estimateHours) || 2;
149
- const tags = Array.isArray(task.tags) ? task.tags.map(String) : [];
150
- tracker.addNode({
151
- title,
152
- description,
153
- type,
154
- priority,
155
- status: "pending",
156
- estimateHours,
157
- tags
158
- });
159
- }
187
+ for (const task of validTasks) addTaskToTracker(tracker, task);
160
188
  sddState.setTaskStore(store);
161
189
  sddState.setTaskTracker(tracker);
162
190
  sddState.setTaskGraphId(graph.id);
@@ -174,15 +202,7 @@ function getCurrentTask() {
174
202
  const nodes = tracker.getAllNodes({ status: ["in_progress"] });
175
203
  if (nodes.length === 0) return null;
176
204
  const n = nodes[0];
177
- return {
178
- id: n.id,
179
- title: n.title,
180
- description: n.description,
181
- priority: n.priority,
182
- estimateHours: n.estimateHours ?? 0,
183
- tags: n.tags ?? [],
184
- startedAt: n.startedAt
185
- };
205
+ return { id: n.id, title: n.title, description: n.description, priority: n.priority, estimateHours: n.estimateHours ?? 0, tags: n.tags ?? [], startedAt: n.startedAt };
186
206
  }
187
207
  function advanceToNextTask() {
188
208
  const tracker = sddState.getTaskTracker();
@@ -196,27 +216,15 @@ function advanceToNextTask() {
196
216
  }
197
217
  return false;
198
218
  }
199
- function formatElapsed(ms) {
200
- if (ms < 1e3) return `${ms}ms`;
201
- const s = Math.floor(ms / 1e3);
202
- if (s < 60) return `${s}s`;
203
- const m = Math.floor(s / 60);
204
- const remS = s % 60;
205
- if (m < 60) return remS > 0 ? `${m}m ${remS}s` : `${m}m`;
206
- const h = Math.floor(m / 60);
207
- const remM = m % 60;
208
- return `${h}h ${remM}m`;
209
- }
210
219
  function getTaskListText() {
211
220
  const tracker = sddState.getTaskTracker();
212
221
  if (!tracker) return null;
213
222
  const nodes = tracker.getAllNodes();
214
223
  if (nodes.length === 0) return null;
215
- const lines = nodes.map((n, i) => {
224
+ return nodes.map((n, i) => {
216
225
  const status = n.status === "completed" ? "\u2705" : n.status === "in_progress" ? "\u{1F504}" : "\u23F3";
217
226
  return `${i + 1}. ${status} [${n.priority}] ${n.title}`;
218
- });
219
- return lines.join("\n");
227
+ }).join("\n");
220
228
  }
221
229
  function renderTaskListWithProgress() {
222
230
  const tracker = sddState.getTaskTracker();
@@ -225,20 +233,8 @@ function renderTaskListWithProgress() {
225
233
  if (nodes.length === 0) return null;
226
234
  const progress = tracker.getProgress();
227
235
  const phase = sddState.getPhase();
228
- const phaseLabel = {
229
- questioning: "\u2753 Questioning",
230
- spec_review: "\u{1F4CB} Spec Review",
231
- implementation: "\u{1F3D7}\uFE0F Implementation",
232
- task_review: "\u{1F4DD} Task Review",
233
- executing: "\u26A1 Executing",
234
- done: "\u2705 Done"
235
- };
236
- const lines = [
237
- `**${phaseLabel[phase ?? ""] ?? phase} \u2014 Task Status**`,
238
- "",
239
- renderProgress(progress),
240
- ""
241
- ];
236
+ const phaseLabel = { questioning: "\u2753 Questioning", spec_review: "\u{1F4CB} Spec Review", implementation: "\u{1F3D7}\uFE0F Implementation", task_review: "\u{1F4DD} Task Review", executing: "\u26A1 Executing", done: "\u2705 Done" };
237
+ const lines = [`**${phaseLabel[phase ?? ""] ?? phase} \u2014 Task Status**`, "", renderProgress(progress), ""];
242
238
  const sorted = [...nodes].sort((a, b) => {
243
239
  const order = { in_progress: 0, pending: 1, review: 2, blocked: 3, failed: 4, completed: 5 };
244
240
  return (order[a.status] ?? 6) - (order[b.status] ?? 6);
@@ -248,9 +244,7 @@ function renderTaskListWithProgress() {
248
244
  const status = n.status === "completed" ? "\u2705" : n.status === "in_progress" ? "\u{1F504}" : n.status === "failed" ? "\u274C" : n.status === "blocked" ? "\u{1F6AB}" : n.status === "review" ? "\u{1F441}" : "\u23F3";
249
245
  const title = n.title.length > 50 ? n.title.slice(0, 49) + "\u2026" : n.title;
250
246
  let elapsed = "";
251
- if (n.status === "in_progress" && n.startedAt) {
252
- elapsed = ` \xB7 ${formatElapsed(Date.now() - n.startedAt)}`;
253
- }
247
+ if (n.status === "in_progress" && n.startedAt) elapsed = ` \xB7 ${formatElapsed(Date.now() - n.startedAt)}`;
254
248
  lines.push(`${i + 1}. ${status} ${title}${elapsed}`);
255
249
  }
256
250
  return lines.join("\n");
@@ -274,13 +268,114 @@ function markTaskCompleted(taskTitle) {
274
268
  const tracker = sddState.getTaskTracker();
275
269
  if (!tracker) return false;
276
270
  const nodes = tracker.getAllNodes({ status: ["pending", "in_progress"] });
277
- const match = nodes.find(
278
- (n) => n.title.toLowerCase().includes(taskTitle.toLowerCase()) || taskTitle.toLowerCase().includes(n.title.toLowerCase())
279
- );
271
+ const match = nodes.find((n) => n.title.toLowerCase().includes(taskTitle.toLowerCase()) || taskTitle.toLowerCase().includes(n.title.toLowerCase()));
280
272
  if (!match) return false;
281
273
  tracker.updateNodeStatus(match.id, "completed");
282
274
  return true;
283
275
  }
276
+ function getTaskGraphId() {
277
+ return sddState.getTaskGraphId();
278
+ }
279
+ function getTaskTrackerExport() {
280
+ return sddState.getTaskTracker();
281
+ }
282
+ var init_task_manager = __esm({
283
+ "src/slash-commands/sdd/task-manager.ts"() {
284
+ init_state();
285
+ }
286
+ });
287
+ function getActiveBuilder() {
288
+ return sddState.getBuilder();
289
+ }
290
+ function getActiveSDDContext() {
291
+ return sddState.getContext();
292
+ }
293
+ function getActiveSDDPhase() {
294
+ return sddState.getPhase();
295
+ }
296
+ async function findSpec(store, idOrTitle) {
297
+ if (!idOrTitle) return null;
298
+ const byId = await store.load(idOrTitle);
299
+ if (byId) return byId;
300
+ const all = await store.list();
301
+ const match = all.find(
302
+ (e) => e.id.startsWith(idOrTitle) || e.title.toLowerCase().includes(idOrTitle.toLowerCase())
303
+ );
304
+ if (match) return store.load(match.id);
305
+ return null;
306
+ }
307
+ async function gatherProjectContext2(projectRoot) {
308
+ const parts = [];
309
+ try {
310
+ const pkgPath = path8.join(projectRoot, "package.json");
311
+ const pkgRaw = await fsp4.readFile(pkgPath, "utf8");
312
+ const pkg = JSON.parse(pkgRaw);
313
+ parts.push(`Project: ${String(pkg.name ?? "unknown")}`);
314
+ parts.push(`Description: ${String(pkg.description ?? "none")}`);
315
+ if (pkg.dependencies) {
316
+ const deps = Object.keys(pkg.dependencies);
317
+ parts.push(`Dependencies: ${deps.slice(0, 20).join(", ")}${deps.length > 20 ? "..." : ""}`);
318
+ }
319
+ if (pkg.devDependencies) {
320
+ const devDeps = Object.keys(pkg.devDependencies);
321
+ parts.push(`Dev Dependencies: ${devDeps.slice(0, 15).join(", ")}${devDeps.length > 15 ? "..." : ""}`);
322
+ }
323
+ } catch {
324
+ }
325
+ try {
326
+ const tsconfigPath = path8.join(projectRoot, "tsconfig.json");
327
+ await fsp4.access(tsconfigPath);
328
+ parts.push("Language: TypeScript");
329
+ } catch {
330
+ }
331
+ try {
332
+ const srcDir = path8.join(projectRoot, "src");
333
+ const entries = await fsp4.readdir(srcDir, { withFileTypes: true });
334
+ const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
335
+ if (dirs.length > 0) parts.push(`Source structure: src/${dirs.join(", src/")}`);
336
+ } catch {
337
+ }
338
+ return parts.join("\n");
339
+ }
340
+ var init_project_context = __esm({
341
+ "src/slash-commands/sdd/project-context.ts"() {
342
+ init_state();
343
+ }
344
+ });
345
+
346
+ // src/slash-commands/sdd/spec-detection.ts
347
+ function isExplanatoryText(text) {
348
+ const lower = text.toLowerCase();
349
+ return lower.startsWith("i'") || lower.startsWith("i will") || lower.startsWith("let me") || lower.startsWith("here's my") || lower.startsWith("here is my") || lower.startsWith("i'm going to") || lower.startsWith("first, let me") || lower.startsWith("sure") || lower.startsWith("of course") || lower.startsWith("okay") || lower.startsWith("ok,") || lower.startsWith("sounds good") || lower.startsWith("no problem") || text.split("\n").length < 3 && !text.includes(".");
350
+ }
351
+ async function trySaveSpecFromAIOutput(aiOutput) {
352
+ const builder = sddState.getBuilder();
353
+ if (!builder) return false;
354
+ const spec = builder.tryParseSpecFromOutput(aiOutput);
355
+ if (!spec) return false;
356
+ builder.setSpec(spec);
357
+ return true;
358
+ }
359
+ function trySaveImplementationPlan(aiOutput) {
360
+ const builder = sddState.getBuilder();
361
+ if (!builder) return false;
362
+ const session = builder.getSession();
363
+ if (session.phase !== "implementation") return false;
364
+ const current = session.implementation ?? "";
365
+ const jsonMatch = aiOutput.match(/```json\s*\[/);
366
+ if (jsonMatch?.index && jsonMatch.index > 0) {
367
+ const plan = aiOutput.substring(0, jsonMatch.index).trim();
368
+ if (plan.length > 50 && plan !== current && !isExplanatoryText(plan)) {
369
+ builder.setImplementation(plan);
370
+ return true;
371
+ }
372
+ }
373
+ if (aiOutput.length > 100 && !aiOutput.includes("```json") && aiOutput !== current && !isExplanatoryText(aiOutput)) {
374
+ builder.setImplementation(aiOutput.trim());
375
+ return true;
376
+ }
377
+ return false;
378
+ }
284
379
  function autoDetectTaskCompletion(aiOutput) {
285
380
  const tracker = sddState.getTaskTracker();
286
381
  if (!tracker) return 0;
@@ -301,9 +396,7 @@ function autoDetectTaskCompletion(aiOutput) {
301
396
  completed++;
302
397
  }
303
398
  } else {
304
- const match = pending.find(
305
- (n) => n.title.toLowerCase().includes(target.toLowerCase()) || target.toLowerCase().includes(n.title.toLowerCase())
306
- );
399
+ const match = pending.find((n) => n.title.toLowerCase().includes(target.toLowerCase()) || target.toLowerCase().includes(n.title.toLowerCase()));
307
400
  if (match && match.status !== "completed") {
308
401
  tracker.updateNodeStatus(match.id, "completed");
309
402
  completed++;
@@ -314,9 +407,7 @@ function autoDetectTaskCompletion(aiOutput) {
314
407
  const checkmarkMatch = trimmed.match(/^✅\s*(?:Task:\s*)?(.+)/i);
315
408
  if (checkmarkMatch?.[1]) {
316
409
  const title = checkmarkMatch[1].trim();
317
- const match = pending.find(
318
- (n) => n.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(n.title.toLowerCase())
319
- );
410
+ const match = pending.find((n) => n.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(n.title.toLowerCase()));
320
411
  if (match && match.status !== "completed") {
321
412
  tracker.updateNodeStatus(match.id, "completed");
322
413
  completed++;
@@ -338,9 +429,7 @@ function autoDetectTaskCompletion(aiOutput) {
338
429
  const completedMatch = trimmed.match(/^(?:Completed|Done|Finished)\s*[:]\s*(.+)/i);
339
430
  if (completedMatch?.[1]) {
340
431
  const title = completedMatch[1].trim();
341
- const match = pending.find(
342
- (n) => n.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(n.title.toLowerCase())
343
- );
432
+ const match = pending.find((n) => n.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(n.title.toLowerCase()));
344
433
  if (match && match.status !== "completed") {
345
434
  tracker.updateNodeStatus(match.id, "completed");
346
435
  completed++;
@@ -349,33 +438,132 @@ function autoDetectTaskCompletion(aiOutput) {
349
438
  }
350
439
  return completed;
351
440
  }
352
- function trySaveImplementationPlan(aiOutput) {
353
- const builder = sddState.getBuilder();
354
- if (!builder) return false;
355
- const session = builder.getSession();
356
- if (session.phase !== "implementation") return false;
357
- const current = session.implementation ?? "";
358
- const jsonMatch = aiOutput.match(/```json\s*\[/);
359
- if (jsonMatch?.index && jsonMatch.index > 0) {
360
- const plan = aiOutput.substring(0, jsonMatch.index).trim();
361
- if (plan.length > 50 && plan !== current && !isExplanatoryText(plan)) {
362
- builder.setImplementation(plan);
363
- return true;
364
- }
365
- }
366
- if (aiOutput.length > 100 && !aiOutput.includes("```json") && aiOutput !== current && !isExplanatoryText(aiOutput)) {
367
- builder.setImplementation(aiOutput.trim());
368
- return true;
441
+ var init_spec_detection = __esm({
442
+ "src/slash-commands/sdd/spec-detection.ts"() {
443
+ init_state();
444
+ }
445
+ });
446
+
447
+ // src/slash-commands/sdd/rendering.ts
448
+ function sddHelp() {
449
+ return [
450
+ "",
451
+ "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557",
452
+ "\u2551 \u{1F680} SDD \u2014 AI-Driven Spec Builder \u2551",
453
+ "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D",
454
+ "",
455
+ " \u250C\u2500 \u{1F195} Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
456
+ " \u2502 /sdd new [title] Start a new spec session \u2502",
457
+ " \u2502 /sdd new --force Start fresh (skip resume check) \u2502",
458
+ " \u2502 /sdd resume Resume a saved session \u2502",
459
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
460
+ "",
461
+ " \u250C\u2500 \u{1F504} Flow \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
462
+ " \u2502 /sdd approve Approve current phase \u2502",
463
+ " \u2502 /sdd spec Show current session's spec \u2502",
464
+ " \u2502 /sdd plan Show implementation plan \u2502",
465
+ " \u2502 /sdd execute Execute generated tasks \u2502",
466
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
467
+ "",
468
+ " \u250C\u2500 \u23F8 Goal Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
469
+ " \u2502 /sdd goal Show current goal + journal \u2502",
470
+ " \u2502 /sdd goal set <text> Set autonomous mission \u2502",
471
+ " \u2502 /sdd goal pause Pause at end of current iteration \u2502",
472
+ " \u2502 /sdd goal resume Resume a paused goal \u2502",
473
+ " \u2502 /sdd goal journal [N] Show recent journal entries \u2502",
474
+ " \u2502 /sdd goal clear Clear goal + stop eternal mode \u2502",
475
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
476
+ "",
477
+ " \u250C\u2500 \u{1F4E1} Eternal Stage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
478
+ " \u2502 decide \u2192 execute \u2192 reflect \u2192 sleep | paused | stopped \u2502",
479
+ " \u2502 Stage shown in real-time during /sdd goal mode \u2502",
480
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
481
+ "",
482
+ " \u250C\u2500 \u{1F527} Task Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
483
+ " \u2502 /sdd tasks Show task list + progress bar \u2502",
484
+ " \u2502 /sdd next Show next executable task \u2502",
485
+ " \u2502 /sdd done <N> Complete a task \u2502",
486
+ " \u2502 /sdd skip <N> Skip a task (back to pending) \u2502",
487
+ " \u2502 /sdd fail <N> Mark task as failed \u2502",
488
+ " \u2502 /sdd review <N> Send task to review \u2502",
489
+ " \u2502 /sdd edit <N> <txt> Edit task title or description \u2502",
490
+ " \u2502 /sdd undo Undo last completion \u2502",
491
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
492
+ "",
493
+ " \u250C\u2500 \u{1F4CA} Session Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
494
+ " \u2502 /sdd status Full session status + tasks preview \u2502",
495
+ " \u2502 /sdd cancel Cancel session \u2502",
496
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
497
+ "",
498
+ " \u250C\u2500 \u{1F4C1} Spec History \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
499
+ " \u2502 /sdd list List saved specs \u2502",
500
+ " \u2502 /sdd show <id> Show spec details \u2502",
501
+ " \u2502 /sdd templates List available templates \u2502",
502
+ " \u2502 /sdd from <tmpl> Create from template \u2502",
503
+ " \u2502 /sdd version <id> Show version history \u2502",
504
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
505
+ "",
506
+ " \u250C\u2500 \u{1F4A1} Quick Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
507
+ " \u2502 \u2502",
508
+ " \u2502 1. /sdd new Auth System \u2502",
509
+ " \u2502 \u2192 AI starts asking questions \u2502",
510
+ " \u2502 \u2502",
511
+ " \u2502 2. Just type your answers naturally \u2502",
512
+ " \u2502 \u2192 AI continues the interview \u2502",
513
+ " \u2502 \u2502",
514
+ " \u2502 3. AI generates spec (auto-detected) \u2502",
515
+ " \u2502 \u2192 /sdd approve \u2502",
516
+ " \u2502 \u2502",
517
+ " \u2502 3. AI generates implementation + tasks \u2502",
518
+ " \u2502 \u2192 /sdd approve \u2502",
519
+ " \u2502 \u2502",
520
+ " \u2502 4. AI executes tasks one by one \u2502",
521
+ " \u2502 \u2192 /sdd tasks (view progress) \u2502",
522
+ " \u2502 \u2192 /sdd done 1 (mark task complete) \u2502",
523
+ " \u2502 \u2502",
524
+ " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
525
+ "",
526
+ " Tip: tasks are shown with progress bar after each AI turn.",
527
+ ""
528
+ ].join("\n");
529
+ }
530
+ var init_rendering = __esm({
531
+ "src/slash-commands/sdd/rendering.ts"() {
369
532
  }
370
- return false;
371
- }
372
- function isExplanatoryText(text) {
373
- const lower = text.toLowerCase();
374
- return lower.startsWith("i'") || lower.startsWith("i will") || lower.startsWith("let me") || lower.startsWith("here's my") || lower.startsWith("here is my") || lower.startsWith("i'm going to") || lower.startsWith("first, let me") || lower.startsWith("sure") || lower.startsWith("of course") || lower.startsWith("okay") || lower.startsWith("ok,") || lower.startsWith("sounds good") || lower.startsWith("no problem") || // Skip if mostly code-like with minimal prose
375
- text.split("\n").length < 3 && !text.includes(".");
376
- }
377
- function getActiveBuilder() {
378
- return sddState.getBuilder();
533
+ });
534
+
535
+ // src/slash-commands/sdd.ts
536
+ var sdd_exports = {};
537
+ __export(sdd_exports, {
538
+ SDDState: () => SDDState,
539
+ advanceToNextTask: () => advanceToNextTask,
540
+ autoDetectTaskCompletion: () => autoDetectTaskCompletion,
541
+ buildSddCommand: () => buildSddCommand,
542
+ findSpec: () => findSpec,
543
+ formatElapsed: () => formatElapsed,
544
+ gatherProjectContext: () => gatherProjectContext2,
545
+ getActiveBuilder: () => getActiveBuilder,
546
+ getActiveSDDContext: () => getActiveSDDContext,
547
+ getActiveSDDPhase: () => getActiveSDDPhase,
548
+ getCurrentExecutingContext: () => getCurrentExecutingContext,
549
+ getCurrentTask: () => getCurrentTask,
550
+ getSessionState: () => getSessionState,
551
+ getTaskGraphId: () => getTaskGraphId,
552
+ getTaskListText: () => getTaskListText,
553
+ getTaskProgress: () => getTaskProgress,
554
+ getTaskTracker: () => getTaskTracker,
555
+ getTaskTrackerExport: () => getTaskTrackerExport,
556
+ isExplanatoryText: () => isExplanatoryText,
557
+ markTaskCompleted: () => markTaskCompleted,
558
+ renderProgress: () => renderProgress,
559
+ renderTaskListWithProgress: () => renderTaskListWithProgress,
560
+ sddState: () => sddState,
561
+ trySaveImplementationPlan: () => trySaveImplementationPlan,
562
+ trySaveSpecFromAIOutput: () => trySaveSpecFromAIOutput,
563
+ trySaveTasksFromAIOutput: () => trySaveTasksFromAIOutput
564
+ });
565
+ function getTaskTracker() {
566
+ return getTaskTrackerExport();
379
567
  }
380
568
  function buildSddCommand(opts) {
381
569
  const sessionState = getSessionState(opts.context);
@@ -401,7 +589,7 @@ function buildSddCommand(opts) {
401
589
  if (!sessionState.getBuilder() && !forceFlag) {
402
590
  const sessionPath = opts.paths.projectSddSession;
403
591
  try {
404
- await fsp3.access(sessionPath);
592
+ await fsp4.access(sessionPath);
405
593
  const projectContext2 = await gatherProjectContext2(opts.context?.projectRoot ?? process.cwd());
406
594
  const tempBuilder = new AISpecBuilder({
407
595
  store: specStore,
@@ -1052,16 +1240,16 @@ Start executing the tasks one by one.`
1052
1240
  const sessionPath = opts.paths.projectSddSession;
1053
1241
  let deletedFromDisk = false;
1054
1242
  try {
1055
- await fsp3.unlink(sessionPath);
1243
+ await fsp4.unlink(sessionPath);
1056
1244
  deletedFromDisk = true;
1057
1245
  } catch {
1058
1246
  }
1059
1247
  try {
1060
- await fsp3.rm(opts.paths.projectSpecs, { recursive: true, force: true });
1248
+ await fsp4.rm(opts.paths.projectSpecs, { recursive: true, force: true });
1061
1249
  } catch {
1062
1250
  }
1063
1251
  try {
1064
- await fsp3.rm(opts.paths.projectTaskGraphs, { recursive: true, force: true });
1252
+ await fsp4.rm(opts.paths.projectTaskGraphs, { recursive: true, force: true });
1065
1253
  } catch {
1066
1254
  }
1067
1255
  const cancelBuilder = sddState.getBuilder();
@@ -1252,275 +1440,76 @@ ${lines.join("\n")}`
1252
1440
  }
1253
1441
  const analysis = analyzeCriticalPath(graph);
1254
1442
  const lines = [
1255
- `\u256D\u2500\u2500\u2500 Critical Path Analysis \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E`,
1256
- "",
1257
- ` Critical path length: ${analysis.criticalPath.length} tasks`,
1258
- ` Estimated total time: ${analysis.totalHours}h`,
1259
- ""
1260
- ];
1261
- if (analysis.criticalPath.length > 0) {
1262
- lines.push(` \u{1F534} Critical path:`);
1263
- analysis.criticalPath.forEach((taskId, i) => {
1264
- const node = graph.nodes.get(taskId);
1265
- if (node) {
1266
- lines.push(` ${i + 1}. ${node.title} [${node.priority}] \u2014 ${node.estimateHours}h`);
1267
- }
1268
- });
1269
- }
1270
- if (analysis.bottlenecks.length > 0) {
1271
- lines.push("");
1272
- lines.push(` \u{1F6AB} Bottlenecks (blocking most downstream):`);
1273
- for (const bt of analysis.bottlenecks) {
1274
- const node = graph.nodes.get(bt.taskId);
1275
- if (node) {
1276
- lines.push(` \u2022 ${node.title} (blocks ${bt.blockedCount} task(s))`);
1277
- }
1278
- }
1279
- }
1280
- if (analysis.parallelGroups.length > 0) {
1281
- lines.push("");
1282
- lines.push(` \u26A1 Parallel groups (can run concurrently):`);
1283
- analysis.parallelGroups.forEach((group, i) => {
1284
- const names = group.map((id) => graph.nodes.get(id)?.title ?? "?").join(" | ");
1285
- lines.push(` Group ${i + 1}: ${names}`);
1286
- });
1287
- }
1288
- if (analysis.readyTasks.length > 0) {
1289
- lines.push("");
1290
- lines.push(` \u2705 Ready to start now:`);
1291
- for (const taskId of analysis.readyTasks) {
1292
- const node = graph.nodes.get(taskId);
1293
- if (node) {
1294
- lines.push(` \u2022 ${node.title}`);
1295
- }
1296
- }
1297
- }
1298
- lines.push(`\u2570${"\u2500".repeat(55)}\u256F`);
1299
- return { message: lines.join("\n") };
1300
- } catch {
1301
- return { message: "Could not analyze critical path." };
1302
- }
1303
- }
1304
- default:
1305
- return {
1306
- message: `Unknown command "${verb}".
1307
-
1308
- ${sddHelp()}`
1309
- };
1310
- }
1311
- }
1312
- };
1313
- }
1314
- function sddHelp() {
1315
- return [
1316
- "",
1317
- "\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557",
1318
- "\u2551 \u{1F680} SDD \u2014 AI-Driven Spec Builder \u2551",
1319
- "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D",
1320
- "",
1321
- " \u250C\u2500 \u{1F195} Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1322
- " \u2502 /sdd new [title] Start a new spec session \u2502",
1323
- " \u2502 /sdd new --force Start fresh (skip resume check) \u2502",
1324
- " \u2502 /sdd resume Resume a saved session \u2502",
1325
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1326
- "",
1327
- " \u250C\u2500 \u{1F504} Flow \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1328
- " \u2502 /sdd approve Approve current phase \u2502",
1329
- " \u2502 /sdd spec Show current session's spec \u2502",
1330
- " \u2502 /sdd plan Show implementation plan \u2502",
1331
- " \u2502 /sdd execute Execute generated tasks \u2502",
1332
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1333
- "",
1334
- " \u250C\u2500 \u23F8 Goal Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1335
- " \u2502 /sdd goal Show current goal + journal \u2502",
1336
- " \u2502 /sdd goal set <text> Set autonomous mission \u2502",
1337
- " \u2502 /sdd goal pause Pause at end of current iteration \u2502",
1338
- " \u2502 /sdd goal resume Resume a paused goal \u2502",
1339
- " \u2502 /sdd goal journal [N] Show recent journal entries \u2502",
1340
- " \u2502 /sdd goal clear Clear goal + stop eternal mode \u2502",
1341
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1342
- "",
1343
- " \u250C\u2500 \u{1F4E1} Eternal Stage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1344
- " \u2502 decide \u2192 execute \u2192 reflect \u2192 sleep | paused | stopped \u2502",
1345
- " \u2502 Stage shown in real-time during /sdd goal mode \u2502",
1346
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1347
- "",
1348
- " \u250C\u2500 \u{1F527} Task Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1349
- " \u2502 /sdd tasks Show task list + progress bar \u2502",
1350
- " \u2502 /sdd next Show next executable task \u2502",
1351
- " \u2502 /sdd done <N> Complete a task \u2502",
1352
- " \u2502 /sdd skip <N> Skip a task (back to pending) \u2502",
1353
- " \u2502 /sdd fail <N> Mark task as failed \u2502",
1354
- " \u2502 /sdd review <N> Send task to review \u2502",
1355
- " \u2502 /sdd edit <N> <txt> Edit task title or description \u2502",
1356
- " \u2502 /sdd undo Undo last completion \u2502",
1357
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1358
- "",
1359
- " \u250C\u2500 \u{1F4CA} Session Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1360
- " \u2502 /sdd status Full session status + tasks preview \u2502",
1361
- " \u2502 /sdd cancel Cancel session \u2502",
1362
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1363
- "",
1364
- " \u250C\u2500 \u{1F4C1} Spec History \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1365
- " \u2502 /sdd list List saved specs \u2502",
1366
- " \u2502 /sdd show <id> Show spec details \u2502",
1367
- " \u2502 /sdd templates List available templates \u2502",
1368
- " \u2502 /sdd from <tmpl> Create from template \u2502",
1369
- " \u2502 /sdd version <id> Show version history \u2502",
1370
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1371
- "",
1372
- " \u250C\u2500 \u{1F4A1} Quick Start \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
1373
- " \u2502 \u2502",
1374
- " \u2502 1. /sdd new Auth System \u2502",
1375
- " \u2502 \u2192 AI starts asking questions \u2502",
1376
- " \u2502 \u2502",
1377
- " \u2502 2. Just type your answers naturally \u2502",
1378
- " \u2502 \u2192 AI continues the interview \u2502",
1379
- " \u2502 \u2502",
1380
- " \u2502 3. AI generates spec (auto-detected) \u2502",
1381
- " \u2502 \u2192 /sdd approve \u2502",
1382
- " \u2502 \u2502",
1383
- " \u2502 3. AI generates implementation + tasks \u2502",
1384
- " \u2502 \u2192 /sdd approve \u2502",
1385
- " \u2502 \u2502",
1386
- " \u2502 4. AI executes tasks one by one \u2502",
1387
- " \u2502 \u2192 /sdd tasks (view progress) \u2502",
1388
- " \u2502 \u2192 /sdd done 1 (mark task complete) \u2502",
1389
- " \u2502 \u2502",
1390
- " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
1391
- "",
1392
- " Tip: tasks are shown with progress bar after each AI turn.",
1393
- ""
1394
- ].join("\n");
1395
- }
1396
- async function gatherProjectContext2(projectRoot) {
1397
- const parts = [];
1398
- try {
1399
- const pkgPath = path8.join(projectRoot, "package.json");
1400
- const pkgRaw = await fsp3.readFile(pkgPath, "utf8");
1401
- const pkg = JSON.parse(pkgRaw);
1402
- parts.push(`Project: ${String(pkg.name ?? "unknown")}`);
1403
- parts.push(`Description: ${String(pkg.description ?? "none")}`);
1404
- if (pkg.dependencies) {
1405
- const deps = Object.keys(pkg.dependencies);
1406
- parts.push(`Dependencies: ${deps.slice(0, 20).join(", ")}${deps.length > 20 ? "..." : ""}`);
1407
- }
1408
- if (pkg.devDependencies) {
1409
- const devDeps = Object.keys(pkg.devDependencies);
1410
- parts.push(`Dev Dependencies: ${devDeps.slice(0, 15).join(", ")}${devDeps.length > 15 ? "..." : ""}`);
1411
- }
1412
- } catch {
1413
- }
1414
- try {
1415
- const tsconfigPath = path8.join(projectRoot, "tsconfig.json");
1416
- await fsp3.access(tsconfigPath);
1417
- parts.push("Language: TypeScript");
1418
- } catch {
1419
- }
1420
- try {
1421
- const srcDir = path8.join(projectRoot, "src");
1422
- const entries = await fsp3.readdir(srcDir, { withFileTypes: true });
1423
- const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
1424
- if (dirs.length > 0) {
1425
- parts.push(`Source structure: src/${dirs.join(", src/")}`);
1443
+ `\u256D\u2500\u2500\u2500 Critical Path Analysis \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E`,
1444
+ "",
1445
+ ` Critical path length: ${analysis.criticalPath.length} tasks`,
1446
+ ` Estimated total time: ${analysis.totalHours}h`,
1447
+ ""
1448
+ ];
1449
+ if (analysis.criticalPath.length > 0) {
1450
+ lines.push(` \u{1F534} Critical path:`);
1451
+ analysis.criticalPath.forEach((taskId, i) => {
1452
+ const node = graph.nodes.get(taskId);
1453
+ if (node) {
1454
+ lines.push(` ${i + 1}. ${node.title} [${node.priority}] \u2014 ${node.estimateHours}h`);
1455
+ }
1456
+ });
1457
+ }
1458
+ if (analysis.bottlenecks.length > 0) {
1459
+ lines.push("");
1460
+ lines.push(` \u{1F6AB} Bottlenecks (blocking most downstream):`);
1461
+ for (const bt of analysis.bottlenecks) {
1462
+ const node = graph.nodes.get(bt.taskId);
1463
+ if (node) {
1464
+ lines.push(` \u2022 ${node.title} (blocks ${bt.blockedCount} task(s))`);
1465
+ }
1466
+ }
1467
+ }
1468
+ if (analysis.parallelGroups.length > 0) {
1469
+ lines.push("");
1470
+ lines.push(` \u26A1 Parallel groups (can run concurrently):`);
1471
+ analysis.parallelGroups.forEach((group, i) => {
1472
+ const names = group.map((id) => graph.nodes.get(id)?.title ?? "?").join(" | ");
1473
+ lines.push(` Group ${i + 1}: ${names}`);
1474
+ });
1475
+ }
1476
+ if (analysis.readyTasks.length > 0) {
1477
+ lines.push("");
1478
+ lines.push(` \u2705 Ready to start now:`);
1479
+ for (const taskId of analysis.readyTasks) {
1480
+ const node = graph.nodes.get(taskId);
1481
+ if (node) {
1482
+ lines.push(` \u2022 ${node.title}`);
1483
+ }
1484
+ }
1485
+ }
1486
+ lines.push(`\u2570${"\u2500".repeat(55)}\u256F`);
1487
+ return { message: lines.join("\n") };
1488
+ } catch {
1489
+ return { message: "Could not analyze critical path." };
1490
+ }
1491
+ }
1492
+ default:
1493
+ return {
1494
+ message: `Unknown command "${verb}".
1495
+
1496
+ ${sddHelp()}`
1497
+ };
1498
+ }
1426
1499
  }
1427
- } catch {
1428
- }
1429
- return parts.join("\n");
1430
- }
1431
- async function findSpec(store, idOrTitle) {
1432
- if (!idOrTitle) return null;
1433
- const byId = await store.load(idOrTitle);
1434
- if (byId) return byId;
1435
- const all = await store.list();
1436
- const match = all.find(
1437
- (e) => e.id.startsWith(idOrTitle) || e.title.toLowerCase().includes(idOrTitle.toLowerCase())
1438
- );
1439
- if (match) return store.load(match.id);
1440
- return null;
1441
- }
1442
- function getTaskGraphId() {
1443
- return sddState.getTaskGraphId();
1444
- }
1445
- function getTaskTracker() {
1446
- return sddState.getTaskTracker();
1500
+ };
1447
1501
  }
1448
- var SDD_META_KEY, SDDState, sddState;
1449
1502
  var init_sdd = __esm({
1450
1503
  "src/slash-commands/sdd.ts"() {
1451
- SDD_META_KEY = "sdd.state";
1452
- SDDState = class {
1453
- builder = null;
1454
- taskStore = null;
1455
- taskTracker = null;
1456
- taskGraphId = null;
1457
- sessionStartTime = Date.now();
1458
- phaseStartTime = Date.now();
1459
- versioning = null;
1460
- getBuilder() {
1461
- return this.builder;
1462
- }
1463
- setBuilder(b) {
1464
- this.builder = b;
1465
- }
1466
- getTaskStore() {
1467
- return this.taskStore;
1468
- }
1469
- setTaskStore(s) {
1470
- this.taskStore = s;
1471
- }
1472
- getTaskTracker() {
1473
- return this.taskTracker;
1474
- }
1475
- setTaskTracker(t) {
1476
- this.taskTracker = t;
1477
- }
1478
- getTaskGraphId() {
1479
- return this.taskGraphId;
1480
- }
1481
- setTaskGraphId(id) {
1482
- this.taskGraphId = id;
1483
- }
1484
- getSessionStartTime() {
1485
- return this.sessionStartTime;
1486
- }
1487
- setSessionStartTime(t) {
1488
- this.sessionStartTime = t;
1489
- }
1490
- setPhaseStartTime(t) {
1491
- this.phaseStartTime = t;
1492
- }
1493
- getPhaseStartTime() {
1494
- return this.phaseStartTime;
1495
- }
1496
- getSessionElapsed() {
1497
- return Date.now() - this.sessionStartTime;
1498
- }
1499
- getPhaseElapsed() {
1500
- return Date.now() - this.phaseStartTime;
1501
- }
1502
- getVersioning() {
1503
- if (this.versioning === null) {
1504
- this.versioning = new SpecVersioning();
1505
- }
1506
- return this.versioning;
1507
- }
1508
- clearTaskState() {
1509
- this.taskStore = null;
1510
- this.taskTracker = null;
1511
- this.taskGraphId = null;
1512
- }
1513
- getContext() {
1514
- if (!this.builder) return null;
1515
- const session = this.builder.getSession();
1516
- if (session.phase === "done") return null;
1517
- return this.builder.getAIPrompt();
1518
- }
1519
- getPhase() {
1520
- return this.builder?.getPhase() ?? null;
1521
- }
1522
- };
1523
- sddState = new SDDState();
1504
+ init_state();
1505
+ init_task_manager();
1506
+ init_project_context();
1507
+ init_state();
1508
+ init_spec_detection();
1509
+ init_task_manager();
1510
+ init_project_context();
1511
+ init_task_manager();
1512
+ init_rendering();
1524
1513
  }
1525
1514
  });
1526
1515
  function normalizeKeys(cfg) {
@@ -1601,7 +1590,7 @@ function isNewer(a, b) {
1601
1590
  }
1602
1591
  async function readCache(homeFn = defaultHomeDir2) {
1603
1592
  try {
1604
- const raw = await fsp3.readFile(cachePath(homeFn), "utf8");
1593
+ const raw = await fsp4.readFile(cachePath(homeFn), "utf8");
1605
1594
  const entry = JSON.parse(raw);
1606
1595
  if (Date.now() - entry.timestamp > CACHE_TTL_MS) return null;
1607
1596
  return entry;
@@ -1612,8 +1601,8 @@ async function readCache(homeFn = defaultHomeDir2) {
1612
1601
  async function writeCache(entry, homeFn = defaultHomeDir2) {
1613
1602
  try {
1614
1603
  const dir = path8.dirname(cachePath(homeFn));
1615
- await fsp3.mkdir(dir, { recursive: true });
1616
- await fsp3.writeFile(cachePath(homeFn), JSON.stringify(entry, null, 2), "utf8");
1604
+ await fsp4.mkdir(dir, { recursive: true });
1605
+ await fsp4.writeFile(cachePath(homeFn), JSON.stringify(entry, null, 2), "utf8");
1617
1606
  } catch {
1618
1607
  }
1619
1608
  }
@@ -2375,7 +2364,7 @@ async function runWebUI(opts) {
2375
2364
  if (!opts.globalConfigPath) return {};
2376
2365
  let raw;
2377
2366
  try {
2378
- raw = await fsp3.readFile(opts.globalConfigPath, "utf8");
2367
+ raw = await fsp4.readFile(opts.globalConfigPath, "utf8");
2379
2368
  } catch {
2380
2369
  return {};
2381
2370
  }
@@ -2395,7 +2384,7 @@ async function runWebUI(opts) {
2395
2384
  let raw;
2396
2385
  let fileExists = true;
2397
2386
  try {
2398
- raw = await fsp3.readFile(opts.globalConfigPath, "utf8");
2387
+ raw = await fsp4.readFile(opts.globalConfigPath, "utf8");
2399
2388
  } catch (err) {
2400
2389
  if (err.code !== "ENOENT") {
2401
2390
  throw new Error(
@@ -2433,6 +2422,25 @@ var init_webui_server = __esm({
2433
2422
  init_provider_config_utils();
2434
2423
  }
2435
2424
  });
2425
+ var req = createRequire(import.meta.url);
2426
+ function readOwnVersion() {
2427
+ const candidates = ["../package.json", "../../package.json"];
2428
+ for (const rel of candidates) {
2429
+ try {
2430
+ const pkg = req(rel);
2431
+ if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
2432
+ } catch {
2433
+ }
2434
+ }
2435
+ return "dev";
2436
+ }
2437
+ var CLI_VERSION = readOwnVersion();
2438
+ var API_VERSION = "0.0.0";
2439
+ try {
2440
+ const corePkg = req("@wrongstack/core/package.json");
2441
+ if (corePkg.wrongstackApiVersion) API_VERSION = corePkg.wrongstackApiVersion;
2442
+ } catch {
2443
+ }
2436
2444
 
2437
2445
  // src/slash-commands/commit-llm.ts
2438
2446
  async function generateCommitMessageWithLLM(diff, opts) {
@@ -2686,7 +2694,7 @@ function parseSpawnFlags(input) {
2686
2694
  }
2687
2695
  async function pathExists(file) {
2688
2696
  try {
2689
- await fsp3.access(file);
2697
+ await fsp4.access(file);
2690
2698
  return true;
2691
2699
  } catch {
2692
2700
  return false;
@@ -2721,7 +2729,7 @@ function parseMakeTargets(makefile) {
2721
2729
  async function detectProjectFacts(root) {
2722
2730
  const facts = { hints: [] };
2723
2731
  try {
2724
- const pkg = JSON.parse(await fsp3.readFile(path8.join(root, "package.json"), "utf8"));
2732
+ const pkg = JSON.parse(await fsp4.readFile(path8.join(root, "package.json"), "utf8"));
2725
2733
  const scripts = pkg.scripts ?? {};
2726
2734
  const pm = await detectPackageManager(root, pkg.packageManager);
2727
2735
  if (hasUsableScript(scripts, "build")) facts.build = `${pm} run build`;
@@ -2759,7 +2767,7 @@ async function detectProjectFacts(root) {
2759
2767
  } catch {
2760
2768
  }
2761
2769
  try {
2762
- const makefile = await fsp3.readFile(path8.join(root, "Makefile"), "utf8");
2770
+ const makefile = await fsp4.readFile(path8.join(root, "Makefile"), "utf8");
2763
2771
  const targets = parseMakeTargets(makefile);
2764
2772
  facts.build ??= targets.has("build") ? "make build" : "make";
2765
2773
  if (targets.has("test")) facts.test ??= "make test";
@@ -3131,7 +3139,7 @@ function formatPhaseList(graph) {
3131
3139
  }
3132
3140
  async function gatherProjectContext(projectRoot) {
3133
3141
  try {
3134
- const raw = await fsp3.readFile(path8.join(projectRoot, "package.json"), "utf8");
3142
+ const raw = await fsp4.readFile(path8.join(projectRoot, "package.json"), "utf8");
3135
3143
  const pkg = JSON.parse(raw);
3136
3144
  const parts = [
3137
3145
  `Project: ${String(pkg.name ?? "unknown")}`,
@@ -3726,7 +3734,7 @@ async function persistContextConfig(opts, patch) {
3726
3734
  if (!opts.configStore || !opts.paths) return "Cannot persist context settings: config store not available.";
3727
3735
  let raw = "{}";
3728
3736
  try {
3729
- raw = await fsp3.readFile(opts.paths.globalConfig, "utf8");
3737
+ raw = await fsp4.readFile(opts.paths.globalConfig, "utf8");
3730
3738
  } catch (err) {
3731
3739
  if (err.code !== "ENOENT") {
3732
3740
  return `Could not read ${opts.paths.globalConfig}: ${err.message}`;
@@ -5144,8 +5152,8 @@ function buildInitCommand(opts) {
5144
5152
  const file = path8.join(dir, "AGENTS.md");
5145
5153
  const detected = await detectProjectFacts(ctx.projectRoot);
5146
5154
  const body = renderAgentsTemplate(detected);
5147
- await fsp3.mkdir(dir, { recursive: true });
5148
- await fsp3.writeFile(file, body, "utf8");
5155
+ await fsp4.mkdir(dir, { recursive: true });
5156
+ await fsp4.writeFile(file, body, "utf8");
5149
5157
  if (detected.hints.length > 0) {
5150
5158
  const msg2 = `Wrote ${file}
5151
5159
  Pre-filled: ${detected.hints.join(", ")}. Edit the file with project context and instructions the system prompt should carry.`;
@@ -5358,7 +5366,7 @@ function stateBadge(state) {
5358
5366
  }
5359
5367
  async function readConfig(path25) {
5360
5368
  try {
5361
- return JSON.parse(await fsp3.readFile(path25, "utf8"));
5369
+ return JSON.parse(await fsp4.readFile(path25, "utf8"));
5362
5370
  } catch {
5363
5371
  return {};
5364
5372
  }
@@ -5369,8 +5377,8 @@ function isMcpServerRecord(value) {
5369
5377
  async function writeConfig(path25, cfg) {
5370
5378
  const raw = JSON.stringify(cfg, null, 2);
5371
5379
  const tmp = path25 + ".tmp";
5372
- await fsp3.writeFile(tmp, raw, "utf8");
5373
- await fsp3.rename(tmp, path25);
5380
+ await fsp4.writeFile(tmp, raw, "utf8");
5381
+ await fsp4.rename(tmp, path25);
5374
5382
  }
5375
5383
 
5376
5384
  // src/slash-commands/mcp.ts
@@ -5562,7 +5570,7 @@ async function patchGlobalConfig(globalConfigPath, mutate) {
5562
5570
  let raw = "{}";
5563
5571
  let fileExists = true;
5564
5572
  try {
5565
- raw = await fsp3.readFile(globalConfigPath, "utf8");
5573
+ raw = await fsp4.readFile(globalConfigPath, "utf8");
5566
5574
  } catch (err) {
5567
5575
  if (err.code !== "ENOENT") throw err;
5568
5576
  fileExists = false;
@@ -6067,7 +6075,7 @@ async function patchGlobalConfig2(globalConfigPath, mutate) {
6067
6075
  let raw = "{}";
6068
6076
  let fileExists = true;
6069
6077
  try {
6070
- raw = await fsp3.readFile(globalConfigPath, "utf8");
6078
+ raw = await fsp4.readFile(globalConfigPath, "utf8");
6071
6079
  } catch (err) {
6072
6080
  if (err.code !== "ENOENT") throw err;
6073
6081
  fileExists = false;
@@ -6246,7 +6254,7 @@ async function persistAutonomySetting(deps, mutator) {
6246
6254
  let raw;
6247
6255
  let fileExists = true;
6248
6256
  try {
6249
- raw = await fsp3.readFile(deps.globalConfigPath, "utf8");
6257
+ raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
6250
6258
  } catch (err) {
6251
6259
  if (err.code !== "ENOENT") {
6252
6260
  throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
@@ -6473,7 +6481,7 @@ function resolveConfigPath() {
6473
6481
  async function loadStatuslineConfig() {
6474
6482
  const p = resolveConfigPath();
6475
6483
  try {
6476
- const raw = await fsp3.readFile(p, "utf8");
6484
+ const raw = await fsp4.readFile(p, "utf8");
6477
6485
  return { ...DEFAULTS, ...JSON.parse(raw) };
6478
6486
  } catch {
6479
6487
  return { ...DEFAULTS };
@@ -6482,7 +6490,7 @@ async function loadStatuslineConfig() {
6482
6490
  async function saveStatuslineConfig(cfg) {
6483
6491
  const p = resolveConfigPath();
6484
6492
  try {
6485
- await fsp3.mkdir(path8.dirname(p), { recursive: true });
6493
+ await fsp4.mkdir(path8.dirname(p), { recursive: true });
6486
6494
  await atomicWrite(p, JSON.stringify(cfg, null, 2));
6487
6495
  } catch (err) {
6488
6496
  throw new FsError({
@@ -6791,13 +6799,13 @@ var MANIFESTS = [
6791
6799
  ];
6792
6800
  async function detectProjectKind(projectRoot) {
6793
6801
  try {
6794
- await fsp3.access(path8.join(projectRoot, ".wrongstack", "AGENTS.md"));
6802
+ await fsp4.access(path8.join(projectRoot, ".wrongstack", "AGENTS.md"));
6795
6803
  return "initialized";
6796
6804
  } catch {
6797
6805
  }
6798
6806
  for (const m of MANIFESTS) {
6799
6807
  try {
6800
- await fsp3.access(path8.join(projectRoot, m));
6808
+ await fsp4.access(path8.join(projectRoot, m));
6801
6809
  return "project";
6802
6810
  } catch {
6803
6811
  }
@@ -6809,8 +6817,8 @@ async function scaffoldAgentsMd(projectRoot) {
6809
6817
  const file = path8.join(dir, "AGENTS.md");
6810
6818
  const facts = await detectProjectFacts(projectRoot);
6811
6819
  const body = renderAgentsTemplate(facts);
6812
- await fsp3.mkdir(dir, { recursive: true });
6813
- await fsp3.writeFile(file, body, "utf8");
6820
+ await fsp4.mkdir(dir, { recursive: true });
6821
+ await fsp4.writeFile(file, body, "utf8");
6814
6822
  return file;
6815
6823
  }
6816
6824
  async function runProjectCheck(opts) {
@@ -6853,7 +6861,7 @@ async function runProjectCheck(opts) {
6853
6861
  const gitDir = path8.join(projectRoot, ".git");
6854
6862
  let hasGit = false;
6855
6863
  try {
6856
- await fsp3.access(gitDir);
6864
+ await fsp4.access(gitDir);
6857
6865
  hasGit = true;
6858
6866
  } catch {
6859
6867
  }
@@ -6993,7 +7001,7 @@ var ReadlineInputReader = class {
6993
7001
  }
6994
7002
  async loadHistory() {
6995
7003
  try {
6996
- const raw = await fsp3.readFile(this.historyFile, "utf8");
7004
+ const raw = await fsp4.readFile(this.historyFile, "utf8");
6997
7005
  this.history = raw.split("\n").filter(Boolean).slice(-1e3);
6998
7006
  } catch {
6999
7007
  this.history = [];
@@ -7001,8 +7009,8 @@ var ReadlineInputReader = class {
7001
7009
  }
7002
7010
  async saveHistory() {
7003
7011
  try {
7004
- await fsp3.mkdir(path8.dirname(this.historyFile), { recursive: true });
7005
- await fsp3.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
7012
+ await fsp4.mkdir(path8.dirname(this.historyFile), { recursive: true });
7013
+ await fsp4.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
7006
7014
  } catch {
7007
7015
  }
7008
7016
  }
@@ -7024,10 +7032,17 @@ var ReadlineInputReader = class {
7024
7032
  }
7025
7033
  this.pending = true;
7026
7034
  try {
7027
- const rl = this.ensure();
7028
- if (rl.closed || rl._flushed) {
7029
- rl.close();
7035
+ if (this.rl) {
7036
+ const old = this.rl;
7030
7037
  this.rl = void 0;
7038
+ await new Promise((resolve4) => {
7039
+ if (old.closed) {
7040
+ resolve4();
7041
+ } else {
7042
+ old.once("close", resolve4);
7043
+ old.close();
7044
+ }
7045
+ });
7031
7046
  }
7032
7047
  const fresh = this.ensure();
7033
7048
  return new Promise((resolve4) => {
@@ -7041,7 +7056,6 @@ var ReadlineInputReader = class {
7041
7056
  fresh.once("close", () => resolve4(""));
7042
7057
  }).then((result) => {
7043
7058
  this.rl?.close();
7044
- this.rl = void 0;
7045
7059
  return result;
7046
7060
  });
7047
7061
  } finally {
@@ -7222,7 +7236,7 @@ async function buildPickableProviders(modelsRegistry, config) {
7222
7236
  var defaultUidFn = () => os2__default.userInfo().uid;
7223
7237
  async function getFileUid(filePath) {
7224
7238
  try {
7225
- const stat4 = await fsp3.stat(filePath);
7239
+ const stat4 = await fsp4.stat(filePath);
7226
7240
  return stat4.uid;
7227
7241
  } catch {
7228
7242
  return void 0;
@@ -7262,7 +7276,7 @@ async function safeDelete(filePath) {
7262
7276
  const filename = path8.basename(filePath);
7263
7277
  try {
7264
7278
  assertSafeToDelete(filename, dir);
7265
- await fsp3.unlink(filePath);
7279
+ await fsp4.unlink(filePath);
7266
7280
  } catch (err) {
7267
7281
  if (err instanceof Error && err.message.startsWith("Refusing")) {
7268
7282
  writeErr(`[config-history] SAFETY: ${err.message}
@@ -7320,7 +7334,7 @@ function entryId(ts) {
7320
7334
  }
7321
7335
  async function ensureHistoryDir(homeFn = defaultHomeDir) {
7322
7336
  try {
7323
- await fsp3.mkdir(historyDir(homeFn), { recursive: true });
7337
+ await fsp4.mkdir(historyDir(homeFn), { recursive: true });
7324
7338
  } catch (err) {
7325
7339
  throw new FsError({
7326
7340
  message: err instanceof Error ? err.message : String(err),
@@ -7332,7 +7346,7 @@ async function ensureHistoryDir(homeFn = defaultHomeDir) {
7332
7346
  }
7333
7347
  async function readIndex(homeFn = defaultHomeDir) {
7334
7348
  try {
7335
- const raw = await fsp3.readFile(historyIndexPath(homeFn), "utf8");
7349
+ const raw = await fsp4.readFile(historyIndexPath(homeFn), "utf8");
7336
7350
  return JSON.parse(raw);
7337
7351
  } catch {
7338
7352
  return { version: 1, entries: [] };
@@ -7357,7 +7371,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
7357
7371
  const ts = Date.now();
7358
7372
  let content;
7359
7373
  try {
7360
- content = await fsp3.readFile(cfg, "utf8");
7374
+ content = await fsp4.readFile(cfg, "utf8");
7361
7375
  } catch {
7362
7376
  }
7363
7377
  if (content !== void 0) {
@@ -7375,7 +7389,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
7375
7389
  }
7376
7390
  try {
7377
7391
  const dir = path8.join(homeFn(), ".wrongstack");
7378
- const files = await fsp3.readdir(dir);
7392
+ const files = await fsp4.readdir(dir);
7379
7393
  const baks = files.filter((f) => f.startsWith("config.json.") && f.endsWith(".bak")).sort().reverse();
7380
7394
  for (const f of baks.slice(10)) {
7381
7395
  await safeDelete(path8.join(dir, f));
@@ -7395,7 +7409,7 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
7395
7409
  diffSummary: diffSummary(oldCfg, newCfg)
7396
7410
  };
7397
7411
  try {
7398
- await fsp3.writeFile(
7412
+ await fsp4.writeFile(
7399
7413
  path8.join(historyDir(homeFn), `${id}.json`),
7400
7414
  JSON.stringify(entry, null, 2),
7401
7415
  "utf8"
@@ -7419,7 +7433,7 @@ async function listHistory(homeFn = defaultHomeDir) {
7419
7433
  }
7420
7434
  async function getHistoryEntry(id, homeFn = defaultHomeDir) {
7421
7435
  try {
7422
- const raw = await fsp3.readFile(path8.join(historyDir(homeFn), `${id}.json`), "utf8");
7436
+ const raw = await fsp4.readFile(path8.join(historyDir(homeFn), `${id}.json`), "utf8");
7423
7437
  return JSON.parse(raw);
7424
7438
  } catch {
7425
7439
  return null;
@@ -7434,7 +7448,7 @@ async function restoreFromHistory(id, homeFn = defaultHomeDir) {
7434
7448
  await backupCurrent(homeFn);
7435
7449
  let oldCfg = {};
7436
7450
  try {
7437
- const raw = await fsp3.readFile(configPath(homeFn), "utf8");
7451
+ const raw = await fsp4.readFile(configPath(homeFn), "utf8");
7438
7452
  oldCfg = JSON.parse(raw);
7439
7453
  } catch {
7440
7454
  }
@@ -7456,13 +7470,13 @@ async function restoreLast(homeFn = defaultHomeDir) {
7456
7470
  const cfg = configPath(homeFn);
7457
7471
  let oldCfg = {};
7458
7472
  try {
7459
- const raw = await fsp3.readFile(cfg, "utf8");
7473
+ const raw = await fsp4.readFile(cfg, "utf8");
7460
7474
  oldCfg = JSON.parse(raw);
7461
7475
  } catch {
7462
7476
  }
7463
7477
  let lastCfg = {};
7464
7478
  try {
7465
- const raw = await fsp3.readFile(last, "utf8");
7479
+ const raw = await fsp4.readFile(last, "utf8");
7466
7480
  lastCfg = JSON.parse(raw);
7467
7481
  } catch {
7468
7482
  return { ok: false, error: "No prior backup found" };
@@ -8926,7 +8940,7 @@ async function readKeyInput(deps, intent) {
8926
8940
  async function loadProviders(deps) {
8927
8941
  let raw;
8928
8942
  try {
8929
- raw = await fsp3.readFile(deps.globalConfigPath, "utf8");
8943
+ raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
8930
8944
  } catch (err) {
8931
8945
  if (err.code !== "ENOENT") {
8932
8946
  deps.renderer.writeWarning(
@@ -8951,7 +8965,7 @@ async function mutateProviders(deps, mutator) {
8951
8965
  let raw;
8952
8966
  let fileExists = true;
8953
8967
  try {
8954
- raw = await fsp3.readFile(deps.globalConfigPath, "utf8");
8968
+ raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
8955
8969
  } catch (err) {
8956
8970
  if (err.code !== "ENOENT") {
8957
8971
  throw new Error(
@@ -9063,27 +9077,6 @@ Update failed: ${msg}
9063
9077
  return 1;
9064
9078
  }
9065
9079
  };
9066
- var req = createRequire(import.meta.url);
9067
- function readOwnVersion() {
9068
- const candidates = ["../package.json", "../../package.json"];
9069
- for (const rel of candidates) {
9070
- try {
9071
- const pkg = req(rel);
9072
- if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
9073
- } catch {
9074
- }
9075
- }
9076
- return "dev";
9077
- }
9078
- var CLI_VERSION = readOwnVersion();
9079
- var API_VERSION = "0.0.0";
9080
- try {
9081
- const corePkg = req("@wrongstack/core/package.json");
9082
- if (corePkg.wrongstackApiVersion) API_VERSION = corePkg.wrongstackApiVersion;
9083
- } catch {
9084
- }
9085
-
9086
- // src/subcommands/handlers/diag-doctor.ts
9087
9080
  var diagCmd = async (_args, deps) => {
9088
9081
  const cfg = deps.config;
9089
9082
  const age = await deps.modelsRegistry.ageSeconds();
@@ -9166,7 +9159,7 @@ var doctorCmd = async (_args, deps) => {
9166
9159
  });
9167
9160
  }
9168
9161
  try {
9169
- await fsp3.access(deps.paths.secretsKey);
9162
+ await fsp4.access(deps.paths.secretsKey);
9170
9163
  checks.push({ name: "secret vault", status: "ok", detail: deps.paths.secretsKey });
9171
9164
  } catch {
9172
9165
  checks.push({
@@ -9176,10 +9169,10 @@ var doctorCmd = async (_args, deps) => {
9176
9169
  });
9177
9170
  }
9178
9171
  try {
9179
- await fsp3.mkdir(deps.paths.projectSessions, { recursive: true });
9172
+ await fsp4.mkdir(deps.paths.projectSessions, { recursive: true });
9180
9173
  const probe = path8.join(deps.paths.projectSessions, `.probe-${Date.now()}`);
9181
- await fsp3.writeFile(probe, "");
9182
- await fsp3.unlink(probe);
9174
+ await fsp4.writeFile(probe, "");
9175
+ await fsp4.unlink(probe);
9183
9176
  checks.push({ name: "sessions writable", status: "ok", detail: deps.paths.projectSessions });
9184
9177
  } catch (err) {
9185
9178
  checks.push({
@@ -9280,8 +9273,8 @@ var exportCmd = async (args, deps) => {
9280
9273
  return 1;
9281
9274
  }
9282
9275
  if (output) {
9283
- await fsp3.mkdir(path8.dirname(path8.resolve(deps.cwd, output)), { recursive: true });
9284
- await fsp3.writeFile(path8.resolve(deps.cwd, output), rendered, "utf8");
9276
+ await fsp4.mkdir(path8.dirname(path8.resolve(deps.cwd, output)), { recursive: true });
9277
+ await fsp4.writeFile(path8.resolve(deps.cwd, output), rendered, "utf8");
9285
9278
  deps.renderer.write(`Wrote ${rendered.length} bytes to ${output}
9286
9279
  `);
9287
9280
  } else {
@@ -9348,13 +9341,13 @@ var initCmd = async (_args, deps) => {
9348
9341
  } else {
9349
9342
  deps.renderer.writeInfo(`Found API key in env (${provider.envVars.join(" / ")}).`);
9350
9343
  }
9351
- await fsp3.mkdir(deps.paths.globalRoot, { recursive: true });
9344
+ await fsp4.mkdir(deps.paths.globalRoot, { recursive: true });
9352
9345
  const config = { version: 1, provider: providerId, model: modelId };
9353
9346
  if (apiKey) config.apiKey = apiKey;
9354
9347
  const vault = new DefaultSecretVault({ keyFile: deps.paths.secretsKey });
9355
9348
  const encrypted = encryptConfigSecrets(config, vault);
9356
9349
  await atomicWrite(deps.paths.globalConfig, JSON.stringify(encrypted, null, 2), { mode: 384 });
9357
- await fsp3.mkdir(path8.join(deps.projectRoot, ".wrongstack"), { recursive: true });
9350
+ await fsp4.mkdir(path8.join(deps.projectRoot, ".wrongstack"), { recursive: true });
9358
9351
  const agentsFile = path8.join(deps.projectRoot, ".wrongstack", "AGENTS.md");
9359
9352
  const projectFacts = await detectProjectFacts(deps.projectRoot);
9360
9353
  await atomicWrite(agentsFile, renderAgentsTemplate(projectFacts));
@@ -9580,7 +9573,7 @@ async function addMcpServer(args, deps) {
9580
9573
  serverCfg.enabled = enable;
9581
9574
  let existing = {};
9582
9575
  try {
9583
- existing = JSON.parse(await fsp3.readFile(deps.paths.globalConfig, "utf8"));
9576
+ existing = JSON.parse(await fsp4.readFile(deps.paths.globalConfig, "utf8"));
9584
9577
  } catch {
9585
9578
  }
9586
9579
  const mcpServers = existing.mcpServers ?? {};
@@ -9600,7 +9593,7 @@ async function addMcpServer(args, deps) {
9600
9593
  async function removeMcpServer(name, deps) {
9601
9594
  let existing = {};
9602
9595
  try {
9603
- existing = JSON.parse(await fsp3.readFile(deps.paths.globalConfig, "utf8"));
9596
+ existing = JSON.parse(await fsp4.readFile(deps.paths.globalConfig, "utf8"));
9604
9597
  } catch {
9605
9598
  deps.renderer.writeError("No config file found.\n");
9606
9599
  return 1;
@@ -9721,7 +9714,7 @@ function renderConfiguredPlugins(config) {
9721
9714
  }
9722
9715
  async function readConfig2(file) {
9723
9716
  try {
9724
- return JSON.parse(await fsp3.readFile(file, "utf8"));
9717
+ return JSON.parse(await fsp4.readFile(file, "utf8"));
9725
9718
  } catch {
9726
9719
  return {};
9727
9720
  }
@@ -9814,7 +9807,7 @@ var usageCmd = async (_args, deps) => {
9814
9807
  var projectsCmd = async (_args, deps) => {
9815
9808
  const projectsRoot = path8.join(deps.paths.globalRoot, "projects");
9816
9809
  try {
9817
- const entries = await fsp3.readdir(projectsRoot);
9810
+ const entries = await fsp4.readdir(projectsRoot);
9818
9811
  if (entries.length === 0) {
9819
9812
  deps.renderer.write("No projects tracked.\n");
9820
9813
  return 0;
@@ -9822,7 +9815,7 @@ var projectsCmd = async (_args, deps) => {
9822
9815
  for (const hash of entries) {
9823
9816
  try {
9824
9817
  const meta = JSON.parse(
9825
- await fsp3.readFile(path8.join(projectsRoot, hash, "meta.json"), "utf8")
9818
+ await fsp4.readFile(path8.join(projectsRoot, hash, "meta.json"), "utf8")
9826
9819
  );
9827
9820
  deps.renderer.write(
9828
9821
  ` ${color.dim(hash)} ${color.dim(meta.lastSeen ?? "")} ${meta.root ?? "?"}
@@ -10032,7 +10025,7 @@ async function mutateModelsConfig(deps, mutator) {
10032
10025
  let fileExists = true;
10033
10026
  let raw;
10034
10027
  try {
10035
- raw = await fsp3.readFile(configPath2, "utf8");
10028
+ raw = await fsp4.readFile(configPath2, "utf8");
10036
10029
  } catch (err) {
10037
10030
  if (err.code !== "ENOENT") throw err;
10038
10031
  fileExists = false;
@@ -10193,7 +10186,7 @@ var sessionsFleetCmd = async (args, deps) => {
10193
10186
  async function listFleetRuns(deps) {
10194
10187
  let entries = [];
10195
10188
  try {
10196
- entries = await fsp3.readdir(deps.paths.projectSessions);
10189
+ entries = await fsp4.readdir(deps.paths.projectSessions);
10197
10190
  } catch {
10198
10191
  deps.renderer.writeError(`Cannot read projectSessions: ${deps.paths.projectSessions}
10199
10192
  `);
@@ -10204,7 +10197,7 @@ async function listFleetRuns(deps) {
10204
10197
  const runDir = path8.join(deps.paths.projectSessions, id);
10205
10198
  let stat4;
10206
10199
  try {
10207
- stat4 = await fsp3.stat(runDir);
10200
+ stat4 = await fsp4.stat(runDir);
10208
10201
  } catch {
10209
10202
  continue;
10210
10203
  }
@@ -10214,18 +10207,18 @@ async function listFleetRuns(deps) {
10214
10207
  let subagentCount = 0;
10215
10208
  let subagentsDir;
10216
10209
  try {
10217
- await fsp3.access(path8.join(runDir, "fleet.json"));
10210
+ await fsp4.access(path8.join(runDir, "fleet.json"));
10218
10211
  manifest = true;
10219
10212
  } catch {
10220
10213
  }
10221
10214
  try {
10222
- await fsp3.access(path8.join(runDir, "checkpoint.json"));
10215
+ await fsp4.access(path8.join(runDir, "checkpoint.json"));
10223
10216
  checkpoint = true;
10224
10217
  } catch {
10225
10218
  }
10226
10219
  try {
10227
10220
  subagentsDir = path8.join(runDir, "subagents");
10228
- const files = await fsp3.readdir(subagentsDir);
10221
+ const files = await fsp4.readdir(subagentsDir);
10229
10222
  subagentCount = files.filter((f) => f.endsWith(".jsonl")).length;
10230
10223
  } catch {
10231
10224
  }
@@ -10256,7 +10249,7 @@ async function showFleetRun(runId, deps) {
10256
10249
  const runDir = path8.join(deps.paths.projectSessions, runId);
10257
10250
  let stat4;
10258
10251
  try {
10259
- stat4 = await fsp3.stat(runDir);
10252
+ stat4 = await fsp4.stat(runDir);
10260
10253
  } catch {
10261
10254
  deps.renderer.writeError(`Fleet run not found: ${runId}
10262
10255
  `);
@@ -10273,7 +10266,7 @@ Fleet Run: ${runId}
10273
10266
  const manifestPath = path8.join(runDir, "fleet.json");
10274
10267
  let manifestData = null;
10275
10268
  try {
10276
- manifestData = await fsp3.readFile(manifestPath, "utf8");
10269
+ manifestData = await fsp4.readFile(manifestPath, "utf8");
10277
10270
  const manifest = JSON.parse(manifestData);
10278
10271
  const subagents = manifest.subagents ?? [];
10279
10272
  const tasks = manifest.tasks ?? [];
@@ -10289,12 +10282,12 @@ Fleet Run: ${runId}
10289
10282
  const checkpointPath = path8.join(runDir, "checkpoint.json");
10290
10283
  let checkpointData = null;
10291
10284
  try {
10292
- checkpointData = await fsp3.readFile(checkpointPath, "utf8");
10285
+ checkpointData = await fsp4.readFile(checkpointPath, "utf8");
10293
10286
  const snap = JSON.parse(checkpointData);
10294
10287
  const lockPath = `${checkpointPath}.lock`;
10295
10288
  let lockStatus = color.dim("\u25CB no lock");
10296
10289
  try {
10297
- const lockRaw = await fsp3.readFile(lockPath, "utf8");
10290
+ const lockRaw = await fsp4.readFile(lockPath, "utf8");
10298
10291
  const lock = JSON.parse(lockRaw);
10299
10292
  lockStatus = `${color.yellow("\u25B8")} lock held by pid ${lock.pid} on ${lock.hostname} (started ${lock.startedAt})`;
10300
10293
  } catch {
@@ -10336,7 +10329,7 @@ Fleet Run: ${runId}
10336
10329
  const subagentsDir = path8.join(runDir, "subagents");
10337
10330
  let subagentFiles = [];
10338
10331
  try {
10339
- subagentFiles = await fsp3.readdir(subagentsDir);
10332
+ subagentFiles = await fsp4.readdir(subagentsDir);
10340
10333
  subagentFiles = subagentFiles.filter((f) => f.endsWith(".jsonl"));
10341
10334
  } catch {
10342
10335
  }
@@ -10348,7 +10341,7 @@ Fleet Run: ${runId}
10348
10341
  const filePath = path8.join(subagentsDir, f);
10349
10342
  let size;
10350
10343
  try {
10351
- const s = await fsp3.stat(filePath);
10344
+ const s = await fsp4.stat(filePath);
10352
10345
  size = s.size;
10353
10346
  } catch {
10354
10347
  size = 0;
@@ -10364,7 +10357,7 @@ Fleet Run: ${runId}
10364
10357
  }
10365
10358
  const sharedDir = path8.join(runDir, "shared");
10366
10359
  try {
10367
- const files = await fsp3.readdir(sharedDir);
10360
+ const files = await fsp4.readdir(sharedDir);
10368
10361
  deps.renderer.write(`
10369
10362
  Shared scratchpad: ${files.length} file(s)
10370
10363
  `);
@@ -12059,10 +12052,10 @@ var EMPTY = "\u2591";
12059
12052
  function renderContextChip(used, max) {
12060
12053
  const ratio = Math.max(0, Math.min(1, used / max));
12061
12054
  const pct2 = Math.round(ratio * 100);
12062
- const bar = renderProgress2(ratio, 6);
12055
+ const bar = renderProgress3(ratio, 6);
12063
12056
  return `${bar} ${pct2}% (${fmtTok(used)}/${fmtTok(max)})`;
12064
12057
  }
12065
- function renderProgress2(ratio, width) {
12058
+ function renderProgress3(ratio, width) {
12066
12059
  const clamped = Math.max(0, Math.min(1, ratio));
12067
12060
  const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
12068
12061
  const capped = Math.min(width, filled);
@@ -12502,6 +12495,22 @@ async function execute(deps) {
12502
12495
  }
12503
12496
  return code;
12504
12497
  }
12498
+ function buildRoutingRunner(config, host) {
12499
+ const standardRunner = makeAgentSubagentRunner({
12500
+ factory: host.makeSubagentFactory(config),
12501
+ fleetBus: host.getDirector()?.fleet ?? NULL_FLEET_BUS
12502
+ });
12503
+ return async (task, ctx) => {
12504
+ const subCfg = ctx.config;
12505
+ if (subCfg.provider === "acp") {
12506
+ const cacheKey = subCfg.role ?? subCfg.name ?? subCfg.id;
12507
+ return host.buildACPRunner(cacheKey).then((r) => r(task, ctx));
12508
+ }
12509
+ return standardRunner(task, ctx);
12510
+ };
12511
+ }
12512
+
12513
+ // src/fleet/host.ts
12505
12514
  var MultiAgentHost = class {
12506
12515
  constructor(deps, opts = {}) {
12507
12516
  this.deps = deps;
@@ -13133,20 +13142,6 @@ var MultiAgentHost = class {
13133
13142
  }
13134
13143
  }
13135
13144
  };
13136
- function buildRoutingRunner(config, host) {
13137
- const standardRunner = makeAgentSubagentRunner({
13138
- factory: host.makeSubagentFactory(config),
13139
- fleetBus: host.getDirector()?.fleet ?? NULL_FLEET_BUS
13140
- });
13141
- return async (task, ctx) => {
13142
- const subCfg = ctx.config;
13143
- if (subCfg.provider === "acp") {
13144
- const cacheKey = subCfg.role ?? subCfg.name ?? subCfg.id;
13145
- return host.buildACPRunner(cacheKey).then((r) => r(task, ctx));
13146
- }
13147
- return standardRunner(task, ctx);
13148
- };
13149
- }
13150
13145
  function makePromptDelegate(reader) {
13151
13146
  return async (tool, input, suggestedPattern) => {
13152
13147
  writeOut("\x07");
@@ -13779,10 +13774,10 @@ function renderContextChip2(ctx) {
13779
13774
  const ratio = Math.max(0, Math.min(1, ctx.used / ctx.max));
13780
13775
  const pct2 = Math.round(ratio * 100);
13781
13776
  const chipColor = ratio >= 0.85 ? color.red : ratio >= 0.65 ? color.yellow : color.cyan;
13782
- const bar = renderProgress3(ratio, 8);
13777
+ const bar = renderProgress4(ratio, 8);
13783
13778
  return color.dim("ctx ") + chipColor(bar) + chipColor(` ${pct2}%`) + color.dim(` (${fmtTok(ctx.used)}/${fmtTok(ctx.max)})`);
13784
13779
  }
13785
- function renderProgress3(ratio, width) {
13780
+ function renderProgress4(ratio, width) {
13786
13781
  const clamped = Math.max(0, Math.min(1, ratio));
13787
13782
  const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
13788
13783
  const capped = Math.min(width, filled);
@@ -14042,7 +14037,7 @@ function setupMetrics(params) {
14042
14037
  name: "session-store",
14043
14038
  check: async () => {
14044
14039
  try {
14045
- await fsp3.access(wpaths.projectSessions);
14040
+ await fsp4.access(wpaths.projectSessions);
14046
14041
  return { status: "healthy" };
14047
14042
  } catch (e) {
14048
14043
  return { status: "unhealthy", detail: e instanceof Error ? e.message : "access denied" };
@@ -14425,21 +14420,6 @@ async function promptRecovery(reader, renderer, abandoned, autoRecover) {
14425
14420
  );
14426
14421
  return answer;
14427
14422
  }
14428
- var isMain = import.meta.url === `file://${process.argv[1]?.replace(/\\/g, "/")}` || process.argv[1]?.endsWith("/cli/dist/index.js") || process.argv[1]?.endsWith("\\cli\\dist\\index.js");
14429
- function runAsMain(mainFn) {
14430
- if (!isMain) return;
14431
- mainFn(process.argv.slice(2)).then(
14432
- (c) => {
14433
- process.exitCode = c;
14434
- setTimeout(() => process.exit(c), 500).unref();
14435
- },
14436
- (err) => {
14437
- writeErr((err instanceof Error ? err.stack : String(err)) + "\n");
14438
- process.exitCode = 1;
14439
- setTimeout(() => process.exit(1), 500).unref();
14440
- }
14441
- );
14442
- }
14443
14423
  async function launchEternalFromFlag(deps) {
14444
14424
  const { eternalFlag } = deps;
14445
14425
  if (eternalFlag.length === 0) return false;
@@ -14475,7 +14455,7 @@ async function launchEternalFromFlag(deps) {
14475
14455
  return true;
14476
14456
  }
14477
14457
 
14478
- // src/index.ts
14458
+ // src/cli-main.ts
14479
14459
  async function main(argv) {
14480
14460
  const ctx = await boot(argv);
14481
14461
  if (typeof ctx === "number") return ctx;
@@ -15296,7 +15276,7 @@ async function main(argv) {
15296
15276
  const subagentsRoot = path8.join(fleetRootForPromotion, "subagents");
15297
15277
  let runDirs;
15298
15278
  try {
15299
- runDirs = await fsp3.readdir(subagentsRoot);
15279
+ runDirs = await fsp4.readdir(subagentsRoot);
15300
15280
  } catch {
15301
15281
  return "No fleet transcripts on disk \u2014 no subagents have been spawned for this session.";
15302
15282
  }
@@ -15305,7 +15285,7 @@ async function main(argv) {
15305
15285
  const runDir = path8.join(subagentsRoot, runId);
15306
15286
  let files;
15307
15287
  try {
15308
- files = await fsp3.readdir(runDir);
15288
+ files = await fsp4.readdir(runDir);
15309
15289
  } catch {
15310
15290
  continue;
15311
15291
  }
@@ -15313,7 +15293,7 @@ async function main(argv) {
15313
15293
  if (!f.endsWith(".jsonl")) continue;
15314
15294
  const full = path8.join(runDir, f);
15315
15295
  try {
15316
- const stat4 = await fsp3.stat(full);
15296
+ const stat4 = await fsp4.stat(full);
15317
15297
  found.push({
15318
15298
  runId,
15319
15299
  subagentId: f.replace(/\.jsonl$/, ""),
@@ -15354,7 +15334,7 @@ async function main(argv) {
15354
15334
  ].join("\n");
15355
15335
  }
15356
15336
  const t = matches[0];
15357
- const raw = await fsp3.readFile(t.file, "utf8");
15337
+ const raw = await fsp4.readFile(t.file, "utf8");
15358
15338
  if (mode === "raw") return raw;
15359
15339
  const lines = raw.split("\n").filter((l) => l.trim());
15360
15340
  const counts = {};
@@ -15805,6 +15785,23 @@ Restart WrongStack to load or unload plugin code in this session.`;
15805
15785
  skillLoader: config.features.skills ? skillLoader : void 0
15806
15786
  });
15807
15787
  }
15788
+ var isMain = import.meta.url === `file://${process.argv[1]?.replace(/\\/g, "/")}` || process.argv[1]?.endsWith("/cli/dist/index.js") || process.argv[1]?.endsWith("\\cli\\dist\\index.js");
15789
+ function runAsMain(mainFn) {
15790
+ if (!isMain) return;
15791
+ mainFn(process.argv.slice(2)).then(
15792
+ (c) => {
15793
+ process.exitCode = c;
15794
+ setTimeout(() => process.exit(c), 500).unref();
15795
+ },
15796
+ (err) => {
15797
+ writeErr((err instanceof Error ? err.stack : String(err)) + "\n");
15798
+ process.exitCode = 1;
15799
+ setTimeout(() => process.exit(1), 500).unref();
15800
+ }
15801
+ );
15802
+ }
15803
+
15804
+ // src/index.ts
15808
15805
  runAsMain(main);
15809
15806
 
15810
15807
  export { CLI_VERSION, main };