@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 +548 -551
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
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
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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
|
|
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
|
|
1243
|
+
await fsp4.unlink(sessionPath);
|
|
1056
1244
|
deletedFromDisk = true;
|
|
1057
1245
|
} catch {
|
|
1058
1246
|
}
|
|
1059
1247
|
try {
|
|
1060
|
-
await
|
|
1248
|
+
await fsp4.rm(opts.paths.projectSpecs, { recursive: true, force: true });
|
|
1061
1249
|
} catch {
|
|
1062
1250
|
}
|
|
1063
1251
|
try {
|
|
1064
|
-
await
|
|
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
|
-
}
|
|
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
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
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
|
|
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
|
|
1616
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
5148
|
-
await
|
|
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
|
|
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
|
|
5373
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
6813
|
-
await
|
|
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
|
|
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
|
|
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
|
|
7005
|
-
await
|
|
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
|
-
|
|
7028
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
9172
|
+
await fsp4.mkdir(deps.paths.projectSessions, { recursive: true });
|
|
9180
9173
|
const probe = path8.join(deps.paths.projectSessions, `.probe-${Date.now()}`);
|
|
9181
|
-
await
|
|
9182
|
-
await
|
|
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
|
|
9284
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
10210
|
+
await fsp4.access(path8.join(runDir, "fleet.json"));
|
|
10218
10211
|
manifest = true;
|
|
10219
10212
|
} catch {
|
|
10220
10213
|
}
|
|
10221
10214
|
try {
|
|
10222
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
12055
|
+
const bar = renderProgress3(ratio, 6);
|
|
12063
12056
|
return `${bar} ${pct2}% (${fmtTok(used)}/${fmtTok(max)})`;
|
|
12064
12057
|
}
|
|
12065
|
-
function
|
|
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 =
|
|
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
|
|
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
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 };
|