@wrongstack/cli 0.66.13 → 0.73.1
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 +843 -609
- 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, DEFAULT_SUBAGENT_BASELINE, 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';
|
|
@@ -14,7 +14,7 @@ import { WebSocketServer, WebSocket } from 'ws';
|
|
|
14
14
|
import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
|
|
15
15
|
import { capabilitiesFor, buildProviderFactoriesFromRegistry, makeProviderFromConfig } from '@wrongstack/providers';
|
|
16
16
|
import { createDefaultContainer, routeImagesForModel, readClipboardImage } from '@wrongstack/runtime';
|
|
17
|
-
import { builtinToolsPack, rememberTool, forgetTool } from '@wrongstack/tools';
|
|
17
|
+
import { builtinToolsPack, rememberTool, forgetTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes } from '@wrongstack/tools';
|
|
18
18
|
import { fileURLToPath } from 'url';
|
|
19
19
|
import * as readline from 'readline';
|
|
20
20
|
import * as fs12 from 'fs';
|
|
@@ -31,12 +31,6 @@ var __defProp = Object.defineProperty;
|
|
|
31
31
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
32
32
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
33
33
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
34
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
35
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
36
|
-
}) : x)(function(x) {
|
|
37
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
38
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
39
|
-
});
|
|
40
34
|
var __esm = (fn, res) => function __init() {
|
|
41
35
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
42
36
|
};
|
|
@@ -53,32 +47,8 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
53
47
|
return to;
|
|
54
48
|
};
|
|
55
49
|
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
50
|
function getSessionState(ctx) {
|
|
79
|
-
if (!ctx)
|
|
80
|
-
return sddState;
|
|
81
|
-
}
|
|
51
|
+
if (!ctx) return sddState;
|
|
82
52
|
let state = ctx.meta[SDD_META_KEY];
|
|
83
53
|
if (!state) {
|
|
84
54
|
state = new SDDState();
|
|
@@ -86,19 +56,103 @@ function getSessionState(ctx) {
|
|
|
86
56
|
}
|
|
87
57
|
return state;
|
|
88
58
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
59
|
+
var SDD_META_KEY, SDDState, sddState;
|
|
60
|
+
var init_state = __esm({
|
|
61
|
+
"src/slash-commands/sdd/state.ts"() {
|
|
62
|
+
SDD_META_KEY = "sdd.state";
|
|
63
|
+
SDDState = class {
|
|
64
|
+
builder = null;
|
|
65
|
+
taskStore = null;
|
|
66
|
+
taskTracker = null;
|
|
67
|
+
taskGraphId = null;
|
|
68
|
+
sessionStartTime = Date.now();
|
|
69
|
+
phaseStartTime = Date.now();
|
|
70
|
+
versioning = null;
|
|
71
|
+
getBuilder() {
|
|
72
|
+
return this.builder;
|
|
73
|
+
}
|
|
74
|
+
setBuilder(b) {
|
|
75
|
+
this.builder = b;
|
|
76
|
+
}
|
|
77
|
+
getTaskStore() {
|
|
78
|
+
return this.taskStore;
|
|
79
|
+
}
|
|
80
|
+
setTaskStore(s) {
|
|
81
|
+
this.taskStore = s;
|
|
82
|
+
}
|
|
83
|
+
getTaskTracker() {
|
|
84
|
+
return this.taskTracker;
|
|
85
|
+
}
|
|
86
|
+
setTaskTracker(t) {
|
|
87
|
+
this.taskTracker = t;
|
|
88
|
+
}
|
|
89
|
+
getTaskGraphId() {
|
|
90
|
+
return this.taskGraphId;
|
|
91
|
+
}
|
|
92
|
+
setTaskGraphId(id) {
|
|
93
|
+
this.taskGraphId = id;
|
|
94
|
+
}
|
|
95
|
+
getSessionStartTime() {
|
|
96
|
+
return this.sessionStartTime;
|
|
97
|
+
}
|
|
98
|
+
setSessionStartTime(t) {
|
|
99
|
+
this.sessionStartTime = t;
|
|
100
|
+
}
|
|
101
|
+
setPhaseStartTime(t) {
|
|
102
|
+
this.phaseStartTime = t;
|
|
103
|
+
}
|
|
104
|
+
getPhaseStartTime() {
|
|
105
|
+
return this.phaseStartTime;
|
|
106
|
+
}
|
|
107
|
+
getSessionElapsed() {
|
|
108
|
+
return Date.now() - this.sessionStartTime;
|
|
109
|
+
}
|
|
110
|
+
getPhaseElapsed() {
|
|
111
|
+
return Date.now() - this.phaseStartTime;
|
|
112
|
+
}
|
|
113
|
+
getVersioning() {
|
|
114
|
+
if (this.versioning === null) this.versioning = new SpecVersioning();
|
|
115
|
+
return this.versioning;
|
|
116
|
+
}
|
|
117
|
+
clearTaskState() {
|
|
118
|
+
this.taskStore = null;
|
|
119
|
+
this.taskTracker = null;
|
|
120
|
+
this.taskGraphId = null;
|
|
121
|
+
}
|
|
122
|
+
getContext() {
|
|
123
|
+
if (!this.builder) return null;
|
|
124
|
+
const session = this.builder.getSession();
|
|
125
|
+
if (session.phase === "done") return null;
|
|
126
|
+
return this.builder.getAIPrompt();
|
|
127
|
+
}
|
|
128
|
+
getPhase() {
|
|
129
|
+
return this.builder?.getPhase() ?? null;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
sddState = new SDDState();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
function formatElapsed(ms) {
|
|
136
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
137
|
+
const s = Math.floor(ms / 1e3);
|
|
138
|
+
if (s < 60) return `${s}s`;
|
|
139
|
+
const m = Math.floor(s / 60);
|
|
140
|
+
const remS = s % 60;
|
|
141
|
+
if (m < 60) return remS > 0 ? `${m}m ${remS}s` : `${m}m`;
|
|
142
|
+
const h = Math.floor(m / 60);
|
|
143
|
+
const remM = m % 60;
|
|
144
|
+
return `${h}h ${remM}m`;
|
|
94
145
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
function addTaskToTracker(tracker, task) {
|
|
147
|
+
tracker.addNode({
|
|
148
|
+
title: String(task.title),
|
|
149
|
+
description: String(task.description ?? ""),
|
|
150
|
+
type: ["feature", "bugfix", "refactor", "docs", "test", "chore"].includes(String(task.type)) ? String(task.type) : "feature",
|
|
151
|
+
priority: ["critical", "high", "medium", "low"].includes(String(task.priority)) ? String(task.priority) : "medium",
|
|
152
|
+
status: "pending",
|
|
153
|
+
estimateHours: Number(task.estimateHours) || 2,
|
|
154
|
+
tags: Array.isArray(task.tags) ? task.tags.map(String) : []
|
|
155
|
+
});
|
|
102
156
|
}
|
|
103
157
|
async function trySaveTasksFromAIOutput(aiOutput) {
|
|
104
158
|
const builder = sddState.getBuilder();
|
|
@@ -118,45 +172,13 @@ async function trySaveTasksFromAIOutput(aiOutput) {
|
|
|
118
172
|
if (validTasks.length === 0) return false;
|
|
119
173
|
const existingTracker = sddState.getTaskTracker();
|
|
120
174
|
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
|
-
}
|
|
175
|
+
for (const task of validTasks) addTaskToTracker(existingTracker, task);
|
|
138
176
|
return true;
|
|
139
177
|
}
|
|
140
178
|
const store = new DefaultTaskStore();
|
|
141
179
|
const tracker = new TaskTracker({ store });
|
|
142
180
|
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
|
-
}
|
|
181
|
+
for (const task of validTasks) addTaskToTracker(tracker, task);
|
|
160
182
|
sddState.setTaskStore(store);
|
|
161
183
|
sddState.setTaskTracker(tracker);
|
|
162
184
|
sddState.setTaskGraphId(graph.id);
|
|
@@ -174,15 +196,7 @@ function getCurrentTask() {
|
|
|
174
196
|
const nodes = tracker.getAllNodes({ status: ["in_progress"] });
|
|
175
197
|
if (nodes.length === 0) return null;
|
|
176
198
|
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
|
-
};
|
|
199
|
+
return { id: n.id, title: n.title, description: n.description, priority: n.priority, estimateHours: n.estimateHours ?? 0, tags: n.tags ?? [], startedAt: n.startedAt };
|
|
186
200
|
}
|
|
187
201
|
function advanceToNextTask() {
|
|
188
202
|
const tracker = sddState.getTaskTracker();
|
|
@@ -196,27 +210,15 @@ function advanceToNextTask() {
|
|
|
196
210
|
}
|
|
197
211
|
return false;
|
|
198
212
|
}
|
|
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
213
|
function getTaskListText() {
|
|
211
214
|
const tracker = sddState.getTaskTracker();
|
|
212
215
|
if (!tracker) return null;
|
|
213
216
|
const nodes = tracker.getAllNodes();
|
|
214
217
|
if (nodes.length === 0) return null;
|
|
215
|
-
|
|
218
|
+
return nodes.map((n, i) => {
|
|
216
219
|
const status = n.status === "completed" ? "\u2705" : n.status === "in_progress" ? "\u{1F504}" : "\u23F3";
|
|
217
220
|
return `${i + 1}. ${status} [${n.priority}] ${n.title}`;
|
|
218
|
-
});
|
|
219
|
-
return lines.join("\n");
|
|
221
|
+
}).join("\n");
|
|
220
222
|
}
|
|
221
223
|
function renderTaskListWithProgress() {
|
|
222
224
|
const tracker = sddState.getTaskTracker();
|
|
@@ -225,20 +227,8 @@ function renderTaskListWithProgress() {
|
|
|
225
227
|
if (nodes.length === 0) return null;
|
|
226
228
|
const progress = tracker.getProgress();
|
|
227
229
|
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
|
-
];
|
|
230
|
+
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" };
|
|
231
|
+
const lines = [`**${phaseLabel[phase ?? ""] ?? phase} \u2014 Task Status**`, "", renderProgress(progress), ""];
|
|
242
232
|
const sorted = [...nodes].sort((a, b) => {
|
|
243
233
|
const order = { in_progress: 0, pending: 1, review: 2, blocked: 3, failed: 4, completed: 5 };
|
|
244
234
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
@@ -248,9 +238,7 @@ function renderTaskListWithProgress() {
|
|
|
248
238
|
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
239
|
const title = n.title.length > 50 ? n.title.slice(0, 49) + "\u2026" : n.title;
|
|
250
240
|
let elapsed = "";
|
|
251
|
-
if (n.status === "in_progress" && n.startedAt) {
|
|
252
|
-
elapsed = ` \xB7 ${formatElapsed(Date.now() - n.startedAt)}`;
|
|
253
|
-
}
|
|
241
|
+
if (n.status === "in_progress" && n.startedAt) elapsed = ` \xB7 ${formatElapsed(Date.now() - n.startedAt)}`;
|
|
254
242
|
lines.push(`${i + 1}. ${status} ${title}${elapsed}`);
|
|
255
243
|
}
|
|
256
244
|
return lines.join("\n");
|
|
@@ -274,13 +262,114 @@ function markTaskCompleted(taskTitle) {
|
|
|
274
262
|
const tracker = sddState.getTaskTracker();
|
|
275
263
|
if (!tracker) return false;
|
|
276
264
|
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
|
-
);
|
|
265
|
+
const match = nodes.find((n) => n.title.toLowerCase().includes(taskTitle.toLowerCase()) || taskTitle.toLowerCase().includes(n.title.toLowerCase()));
|
|
280
266
|
if (!match) return false;
|
|
281
267
|
tracker.updateNodeStatus(match.id, "completed");
|
|
282
268
|
return true;
|
|
283
269
|
}
|
|
270
|
+
function getTaskGraphId() {
|
|
271
|
+
return sddState.getTaskGraphId();
|
|
272
|
+
}
|
|
273
|
+
function getTaskTrackerExport() {
|
|
274
|
+
return sddState.getTaskTracker();
|
|
275
|
+
}
|
|
276
|
+
var init_task_manager = __esm({
|
|
277
|
+
"src/slash-commands/sdd/task-manager.ts"() {
|
|
278
|
+
init_state();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
function getActiveBuilder() {
|
|
282
|
+
return sddState.getBuilder();
|
|
283
|
+
}
|
|
284
|
+
function getActiveSDDContext() {
|
|
285
|
+
return sddState.getContext();
|
|
286
|
+
}
|
|
287
|
+
function getActiveSDDPhase() {
|
|
288
|
+
return sddState.getPhase();
|
|
289
|
+
}
|
|
290
|
+
async function findSpec(store, idOrTitle) {
|
|
291
|
+
if (!idOrTitle) return null;
|
|
292
|
+
const byId = await store.load(idOrTitle);
|
|
293
|
+
if (byId) return byId;
|
|
294
|
+
const all = await store.list();
|
|
295
|
+
const match = all.find(
|
|
296
|
+
(e) => e.id.startsWith(idOrTitle) || e.title.toLowerCase().includes(idOrTitle.toLowerCase())
|
|
297
|
+
);
|
|
298
|
+
if (match) return store.load(match.id);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
async function gatherProjectContext2(projectRoot) {
|
|
302
|
+
const parts = [];
|
|
303
|
+
try {
|
|
304
|
+
const pkgPath = path8.join(projectRoot, "package.json");
|
|
305
|
+
const pkgRaw = await fsp4.readFile(pkgPath, "utf8");
|
|
306
|
+
const pkg = JSON.parse(pkgRaw);
|
|
307
|
+
parts.push(`Project: ${String(pkg.name ?? "unknown")}`);
|
|
308
|
+
parts.push(`Description: ${String(pkg.description ?? "none")}`);
|
|
309
|
+
if (pkg.dependencies) {
|
|
310
|
+
const deps = Object.keys(pkg.dependencies);
|
|
311
|
+
parts.push(`Dependencies: ${deps.slice(0, 20).join(", ")}${deps.length > 20 ? "..." : ""}`);
|
|
312
|
+
}
|
|
313
|
+
if (pkg.devDependencies) {
|
|
314
|
+
const devDeps = Object.keys(pkg.devDependencies);
|
|
315
|
+
parts.push(`Dev Dependencies: ${devDeps.slice(0, 15).join(", ")}${devDeps.length > 15 ? "..." : ""}`);
|
|
316
|
+
}
|
|
317
|
+
} catch {
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
const tsconfigPath = path8.join(projectRoot, "tsconfig.json");
|
|
321
|
+
await fsp4.access(tsconfigPath);
|
|
322
|
+
parts.push("Language: TypeScript");
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
const srcDir = path8.join(projectRoot, "src");
|
|
327
|
+
const entries = await fsp4.readdir(srcDir, { withFileTypes: true });
|
|
328
|
+
const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
329
|
+
if (dirs.length > 0) parts.push(`Source structure: src/${dirs.join(", src/")}`);
|
|
330
|
+
} catch {
|
|
331
|
+
}
|
|
332
|
+
return parts.join("\n");
|
|
333
|
+
}
|
|
334
|
+
var init_project_context = __esm({
|
|
335
|
+
"src/slash-commands/sdd/project-context.ts"() {
|
|
336
|
+
init_state();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// src/slash-commands/sdd/spec-detection.ts
|
|
341
|
+
function isExplanatoryText(text) {
|
|
342
|
+
const lower = text.toLowerCase();
|
|
343
|
+
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(".");
|
|
344
|
+
}
|
|
345
|
+
async function trySaveSpecFromAIOutput(aiOutput) {
|
|
346
|
+
const builder = sddState.getBuilder();
|
|
347
|
+
if (!builder) return false;
|
|
348
|
+
const spec = builder.tryParseSpecFromOutput(aiOutput);
|
|
349
|
+
if (!spec) return false;
|
|
350
|
+
builder.setSpec(spec);
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
function trySaveImplementationPlan(aiOutput) {
|
|
354
|
+
const builder = sddState.getBuilder();
|
|
355
|
+
if (!builder) return false;
|
|
356
|
+
const session = builder.getSession();
|
|
357
|
+
if (session.phase !== "implementation") return false;
|
|
358
|
+
const current = session.implementation ?? "";
|
|
359
|
+
const jsonMatch = aiOutput.match(/```json\s*\[/);
|
|
360
|
+
if (jsonMatch?.index && jsonMatch.index > 0) {
|
|
361
|
+
const plan = aiOutput.substring(0, jsonMatch.index).trim();
|
|
362
|
+
if (plan.length > 50 && plan !== current && !isExplanatoryText(plan)) {
|
|
363
|
+
builder.setImplementation(plan);
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (aiOutput.length > 100 && !aiOutput.includes("```json") && aiOutput !== current && !isExplanatoryText(aiOutput)) {
|
|
368
|
+
builder.setImplementation(aiOutput.trim());
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
284
373
|
function autoDetectTaskCompletion(aiOutput) {
|
|
285
374
|
const tracker = sddState.getTaskTracker();
|
|
286
375
|
if (!tracker) return 0;
|
|
@@ -301,9 +390,7 @@ function autoDetectTaskCompletion(aiOutput) {
|
|
|
301
390
|
completed++;
|
|
302
391
|
}
|
|
303
392
|
} else {
|
|
304
|
-
const match = pending.find(
|
|
305
|
-
(n) => n.title.toLowerCase().includes(target.toLowerCase()) || target.toLowerCase().includes(n.title.toLowerCase())
|
|
306
|
-
);
|
|
393
|
+
const match = pending.find((n) => n.title.toLowerCase().includes(target.toLowerCase()) || target.toLowerCase().includes(n.title.toLowerCase()));
|
|
307
394
|
if (match && match.status !== "completed") {
|
|
308
395
|
tracker.updateNodeStatus(match.id, "completed");
|
|
309
396
|
completed++;
|
|
@@ -314,9 +401,7 @@ function autoDetectTaskCompletion(aiOutput) {
|
|
|
314
401
|
const checkmarkMatch = trimmed.match(/^✅\s*(?:Task:\s*)?(.+)/i);
|
|
315
402
|
if (checkmarkMatch?.[1]) {
|
|
316
403
|
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
|
-
);
|
|
404
|
+
const match = pending.find((n) => n.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(n.title.toLowerCase()));
|
|
320
405
|
if (match && match.status !== "completed") {
|
|
321
406
|
tracker.updateNodeStatus(match.id, "completed");
|
|
322
407
|
completed++;
|
|
@@ -338,9 +423,7 @@ function autoDetectTaskCompletion(aiOutput) {
|
|
|
338
423
|
const completedMatch = trimmed.match(/^(?:Completed|Done|Finished)\s*[:]\s*(.+)/i);
|
|
339
424
|
if (completedMatch?.[1]) {
|
|
340
425
|
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
|
-
);
|
|
426
|
+
const match = pending.find((n) => n.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(n.title.toLowerCase()));
|
|
344
427
|
if (match && match.status !== "completed") {
|
|
345
428
|
tracker.updateNodeStatus(match.id, "completed");
|
|
346
429
|
completed++;
|
|
@@ -349,33 +432,132 @@ function autoDetectTaskCompletion(aiOutput) {
|
|
|
349
432
|
}
|
|
350
433
|
return completed;
|
|
351
434
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
435
|
+
var init_spec_detection = __esm({
|
|
436
|
+
"src/slash-commands/sdd/spec-detection.ts"() {
|
|
437
|
+
init_state();
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// src/slash-commands/sdd/rendering.ts
|
|
442
|
+
function sddHelp() {
|
|
443
|
+
return [
|
|
444
|
+
"",
|
|
445
|
+
"\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",
|
|
446
|
+
"\u2551 \u{1F680} SDD \u2014 AI-Driven Spec Builder \u2551",
|
|
447
|
+
"\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",
|
|
448
|
+
"",
|
|
449
|
+
" \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",
|
|
450
|
+
" \u2502 /sdd new [title] Start a new spec session \u2502",
|
|
451
|
+
" \u2502 /sdd new --force Start fresh (skip resume check) \u2502",
|
|
452
|
+
" \u2502 /sdd resume Resume a saved session \u2502",
|
|
453
|
+
" \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",
|
|
454
|
+
"",
|
|
455
|
+
" \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",
|
|
456
|
+
" \u2502 /sdd approve Approve current phase \u2502",
|
|
457
|
+
" \u2502 /sdd spec Show current session's spec \u2502",
|
|
458
|
+
" \u2502 /sdd plan Show implementation plan \u2502",
|
|
459
|
+
" \u2502 /sdd execute Execute generated tasks \u2502",
|
|
460
|
+
" \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",
|
|
461
|
+
"",
|
|
462
|
+
" \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",
|
|
463
|
+
" \u2502 /sdd goal Show current goal + journal \u2502",
|
|
464
|
+
" \u2502 /sdd goal set <text> Set autonomous mission \u2502",
|
|
465
|
+
" \u2502 /sdd goal pause Pause at end of current iteration \u2502",
|
|
466
|
+
" \u2502 /sdd goal resume Resume a paused goal \u2502",
|
|
467
|
+
" \u2502 /sdd goal journal [N] Show recent journal entries \u2502",
|
|
468
|
+
" \u2502 /sdd goal clear Clear goal + stop eternal mode \u2502",
|
|
469
|
+
" \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",
|
|
470
|
+
"",
|
|
471
|
+
" \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",
|
|
472
|
+
" \u2502 decide \u2192 execute \u2192 reflect \u2192 sleep | paused | stopped \u2502",
|
|
473
|
+
" \u2502 Stage shown in real-time during /sdd goal mode \u2502",
|
|
474
|
+
" \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",
|
|
475
|
+
"",
|
|
476
|
+
" \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",
|
|
477
|
+
" \u2502 /sdd tasks Show task list + progress bar \u2502",
|
|
478
|
+
" \u2502 /sdd next Show next executable task \u2502",
|
|
479
|
+
" \u2502 /sdd done <N> Complete a task \u2502",
|
|
480
|
+
" \u2502 /sdd skip <N> Skip a task (back to pending) \u2502",
|
|
481
|
+
" \u2502 /sdd fail <N> Mark task as failed \u2502",
|
|
482
|
+
" \u2502 /sdd review <N> Send task to review \u2502",
|
|
483
|
+
" \u2502 /sdd edit <N> <txt> Edit task title or description \u2502",
|
|
484
|
+
" \u2502 /sdd undo Undo last completion \u2502",
|
|
485
|
+
" \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",
|
|
486
|
+
"",
|
|
487
|
+
" \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",
|
|
488
|
+
" \u2502 /sdd status Full session status + tasks preview \u2502",
|
|
489
|
+
" \u2502 /sdd cancel Cancel session \u2502",
|
|
490
|
+
" \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",
|
|
491
|
+
"",
|
|
492
|
+
" \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",
|
|
493
|
+
" \u2502 /sdd list List saved specs \u2502",
|
|
494
|
+
" \u2502 /sdd show <id> Show spec details \u2502",
|
|
495
|
+
" \u2502 /sdd templates List available templates \u2502",
|
|
496
|
+
" \u2502 /sdd from <tmpl> Create from template \u2502",
|
|
497
|
+
" \u2502 /sdd version <id> Show version history \u2502",
|
|
498
|
+
" \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",
|
|
499
|
+
"",
|
|
500
|
+
" \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",
|
|
501
|
+
" \u2502 \u2502",
|
|
502
|
+
" \u2502 1. /sdd new Auth System \u2502",
|
|
503
|
+
" \u2502 \u2192 AI starts asking questions \u2502",
|
|
504
|
+
" \u2502 \u2502",
|
|
505
|
+
" \u2502 2. Just type your answers naturally \u2502",
|
|
506
|
+
" \u2502 \u2192 AI continues the interview \u2502",
|
|
507
|
+
" \u2502 \u2502",
|
|
508
|
+
" \u2502 3. AI generates spec (auto-detected) \u2502",
|
|
509
|
+
" \u2502 \u2192 /sdd approve \u2502",
|
|
510
|
+
" \u2502 \u2502",
|
|
511
|
+
" \u2502 3. AI generates implementation + tasks \u2502",
|
|
512
|
+
" \u2502 \u2192 /sdd approve \u2502",
|
|
513
|
+
" \u2502 \u2502",
|
|
514
|
+
" \u2502 4. AI executes tasks one by one \u2502",
|
|
515
|
+
" \u2502 \u2192 /sdd tasks (view progress) \u2502",
|
|
516
|
+
" \u2502 \u2192 /sdd done 1 (mark task complete) \u2502",
|
|
517
|
+
" \u2502 \u2502",
|
|
518
|
+
" \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",
|
|
519
|
+
"",
|
|
520
|
+
" Tip: tasks are shown with progress bar after each AI turn.",
|
|
521
|
+
""
|
|
522
|
+
].join("\n");
|
|
523
|
+
}
|
|
524
|
+
var init_rendering = __esm({
|
|
525
|
+
"src/slash-commands/sdd/rendering.ts"() {
|
|
369
526
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// src/slash-commands/sdd.ts
|
|
530
|
+
var sdd_exports = {};
|
|
531
|
+
__export(sdd_exports, {
|
|
532
|
+
SDDState: () => SDDState,
|
|
533
|
+
advanceToNextTask: () => advanceToNextTask,
|
|
534
|
+
autoDetectTaskCompletion: () => autoDetectTaskCompletion,
|
|
535
|
+
buildSddCommand: () => buildSddCommand,
|
|
536
|
+
findSpec: () => findSpec,
|
|
537
|
+
formatElapsed: () => formatElapsed,
|
|
538
|
+
gatherProjectContext: () => gatherProjectContext2,
|
|
539
|
+
getActiveBuilder: () => getActiveBuilder,
|
|
540
|
+
getActiveSDDContext: () => getActiveSDDContext,
|
|
541
|
+
getActiveSDDPhase: () => getActiveSDDPhase,
|
|
542
|
+
getCurrentExecutingContext: () => getCurrentExecutingContext,
|
|
543
|
+
getCurrentTask: () => getCurrentTask,
|
|
544
|
+
getSessionState: () => getSessionState,
|
|
545
|
+
getTaskGraphId: () => getTaskGraphId,
|
|
546
|
+
getTaskListText: () => getTaskListText,
|
|
547
|
+
getTaskProgress: () => getTaskProgress,
|
|
548
|
+
getTaskTracker: () => getTaskTracker,
|
|
549
|
+
getTaskTrackerExport: () => getTaskTrackerExport,
|
|
550
|
+
isExplanatoryText: () => isExplanatoryText,
|
|
551
|
+
markTaskCompleted: () => markTaskCompleted,
|
|
552
|
+
renderProgress: () => renderProgress,
|
|
553
|
+
renderTaskListWithProgress: () => renderTaskListWithProgress,
|
|
554
|
+
sddState: () => sddState,
|
|
555
|
+
trySaveImplementationPlan: () => trySaveImplementationPlan,
|
|
556
|
+
trySaveSpecFromAIOutput: () => trySaveSpecFromAIOutput,
|
|
557
|
+
trySaveTasksFromAIOutput: () => trySaveTasksFromAIOutput
|
|
558
|
+
});
|
|
559
|
+
function getTaskTracker() {
|
|
560
|
+
return getTaskTrackerExport();
|
|
379
561
|
}
|
|
380
562
|
function buildSddCommand(opts) {
|
|
381
563
|
const sessionState = getSessionState(opts.context);
|
|
@@ -401,7 +583,7 @@ function buildSddCommand(opts) {
|
|
|
401
583
|
if (!sessionState.getBuilder() && !forceFlag) {
|
|
402
584
|
const sessionPath = opts.paths.projectSddSession;
|
|
403
585
|
try {
|
|
404
|
-
await
|
|
586
|
+
await fsp4.access(sessionPath);
|
|
405
587
|
const projectContext2 = await gatherProjectContext2(opts.context?.projectRoot ?? process.cwd());
|
|
406
588
|
const tempBuilder = new AISpecBuilder({
|
|
407
589
|
store: specStore,
|
|
@@ -1052,16 +1234,16 @@ Start executing the tasks one by one.`
|
|
|
1052
1234
|
const sessionPath = opts.paths.projectSddSession;
|
|
1053
1235
|
let deletedFromDisk = false;
|
|
1054
1236
|
try {
|
|
1055
|
-
await
|
|
1237
|
+
await fsp4.unlink(sessionPath);
|
|
1056
1238
|
deletedFromDisk = true;
|
|
1057
1239
|
} catch {
|
|
1058
1240
|
}
|
|
1059
1241
|
try {
|
|
1060
|
-
await
|
|
1242
|
+
await fsp4.rm(opts.paths.projectSpecs, { recursive: true, force: true });
|
|
1061
1243
|
} catch {
|
|
1062
1244
|
}
|
|
1063
1245
|
try {
|
|
1064
|
-
await
|
|
1246
|
+
await fsp4.rm(opts.paths.projectTaskGraphs, { recursive: true, force: true });
|
|
1065
1247
|
} catch {
|
|
1066
1248
|
}
|
|
1067
1249
|
const cancelBuilder = sddState.getBuilder();
|
|
@@ -1294,233 +1476,34 @@ ${lines.join("\n")}`
|
|
|
1294
1476
|
lines.push(` \u2022 ${node.title}`);
|
|
1295
1477
|
}
|
|
1296
1478
|
}
|
|
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/")}`);
|
|
1426
|
-
}
|
|
1427
|
-
} catch {
|
|
1428
|
-
}
|
|
1429
|
-
return parts.join("\n");
|
|
1430
|
-
}
|
|
1431
|
-
async function findSpec(store, idOrTitle) {
|
|
1432
|
-
if (!idOrTitle) return null;
|
|
1433
|
-
const byId = await store.load(idOrTitle);
|
|
1434
|
-
if (byId) return byId;
|
|
1435
|
-
const all = await store.list();
|
|
1436
|
-
const match = all.find(
|
|
1437
|
-
(e) => e.id.startsWith(idOrTitle) || e.title.toLowerCase().includes(idOrTitle.toLowerCase())
|
|
1438
|
-
);
|
|
1439
|
-
if (match) return store.load(match.id);
|
|
1440
|
-
return null;
|
|
1441
|
-
}
|
|
1442
|
-
function getTaskGraphId() {
|
|
1443
|
-
return sddState.getTaskGraphId();
|
|
1444
|
-
}
|
|
1445
|
-
function getTaskTracker() {
|
|
1446
|
-
return sddState.getTaskTracker();
|
|
1447
|
-
}
|
|
1448
|
-
var SDD_META_KEY, SDDState, sddState;
|
|
1449
|
-
var init_sdd = __esm({
|
|
1450
|
-
"src/slash-commands/sdd.ts"() {
|
|
1451
|
-
SDD_META_KEY = "sdd.state";
|
|
1452
|
-
SDDState = class {
|
|
1453
|
-
builder = null;
|
|
1454
|
-
taskStore = null;
|
|
1455
|
-
taskTracker = null;
|
|
1456
|
-
taskGraphId = null;
|
|
1457
|
-
sessionStartTime = Date.now();
|
|
1458
|
-
phaseStartTime = Date.now();
|
|
1459
|
-
versioning = null;
|
|
1460
|
-
getBuilder() {
|
|
1461
|
-
return this.builder;
|
|
1462
|
-
}
|
|
1463
|
-
setBuilder(b) {
|
|
1464
|
-
this.builder = b;
|
|
1465
|
-
}
|
|
1466
|
-
getTaskStore() {
|
|
1467
|
-
return this.taskStore;
|
|
1468
|
-
}
|
|
1469
|
-
setTaskStore(s) {
|
|
1470
|
-
this.taskStore = s;
|
|
1471
|
-
}
|
|
1472
|
-
getTaskTracker() {
|
|
1473
|
-
return this.taskTracker;
|
|
1474
|
-
}
|
|
1475
|
-
setTaskTracker(t) {
|
|
1476
|
-
this.taskTracker = t;
|
|
1477
|
-
}
|
|
1478
|
-
getTaskGraphId() {
|
|
1479
|
-
return this.taskGraphId;
|
|
1480
|
-
}
|
|
1481
|
-
setTaskGraphId(id) {
|
|
1482
|
-
this.taskGraphId = id;
|
|
1483
|
-
}
|
|
1484
|
-
getSessionStartTime() {
|
|
1485
|
-
return this.sessionStartTime;
|
|
1486
|
-
}
|
|
1487
|
-
setSessionStartTime(t) {
|
|
1488
|
-
this.sessionStartTime = t;
|
|
1489
|
-
}
|
|
1490
|
-
setPhaseStartTime(t) {
|
|
1491
|
-
this.phaseStartTime = t;
|
|
1492
|
-
}
|
|
1493
|
-
getPhaseStartTime() {
|
|
1494
|
-
return this.phaseStartTime;
|
|
1495
|
-
}
|
|
1496
|
-
getSessionElapsed() {
|
|
1497
|
-
return Date.now() - this.sessionStartTime;
|
|
1498
|
-
}
|
|
1499
|
-
getPhaseElapsed() {
|
|
1500
|
-
return Date.now() - this.phaseStartTime;
|
|
1501
|
-
}
|
|
1502
|
-
getVersioning() {
|
|
1503
|
-
if (this.versioning === null) {
|
|
1504
|
-
this.versioning = new SpecVersioning();
|
|
1479
|
+
}
|
|
1480
|
+
lines.push(`\u2570${"\u2500".repeat(55)}\u256F`);
|
|
1481
|
+
return { message: lines.join("\n") };
|
|
1482
|
+
} catch {
|
|
1483
|
+
return { message: "Could not analyze critical path." };
|
|
1484
|
+
}
|
|
1505
1485
|
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
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;
|
|
1486
|
+
default:
|
|
1487
|
+
return {
|
|
1488
|
+
message: `Unknown command "${verb}".
|
|
1489
|
+
|
|
1490
|
+
${sddHelp()}`
|
|
1491
|
+
};
|
|
1521
1492
|
}
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
var init_sdd = __esm({
|
|
1497
|
+
"src/slash-commands/sdd.ts"() {
|
|
1498
|
+
init_state();
|
|
1499
|
+
init_task_manager();
|
|
1500
|
+
init_project_context();
|
|
1501
|
+
init_state();
|
|
1502
|
+
init_spec_detection();
|
|
1503
|
+
init_task_manager();
|
|
1504
|
+
init_project_context();
|
|
1505
|
+
init_task_manager();
|
|
1506
|
+
init_rendering();
|
|
1524
1507
|
}
|
|
1525
1508
|
});
|
|
1526
1509
|
function normalizeKeys(cfg) {
|
|
@@ -1601,7 +1584,7 @@ function isNewer(a, b) {
|
|
|
1601
1584
|
}
|
|
1602
1585
|
async function readCache(homeFn = defaultHomeDir2) {
|
|
1603
1586
|
try {
|
|
1604
|
-
const raw = await
|
|
1587
|
+
const raw = await fsp4.readFile(cachePath(homeFn), "utf8");
|
|
1605
1588
|
const entry = JSON.parse(raw);
|
|
1606
1589
|
if (Date.now() - entry.timestamp > CACHE_TTL_MS) return null;
|
|
1607
1590
|
return entry;
|
|
@@ -1612,8 +1595,8 @@ async function readCache(homeFn = defaultHomeDir2) {
|
|
|
1612
1595
|
async function writeCache(entry, homeFn = defaultHomeDir2) {
|
|
1613
1596
|
try {
|
|
1614
1597
|
const dir = path8.dirname(cachePath(homeFn));
|
|
1615
|
-
await
|
|
1616
|
-
await
|
|
1598
|
+
await fsp4.mkdir(dir, { recursive: true });
|
|
1599
|
+
await fsp4.writeFile(cachePath(homeFn), JSON.stringify(entry, null, 2), "utf8");
|
|
1617
1600
|
} catch {
|
|
1618
1601
|
}
|
|
1619
1602
|
}
|
|
@@ -1947,7 +1930,7 @@ async function runWebUI(opts) {
|
|
|
1947
1930
|
);
|
|
1948
1931
|
}
|
|
1949
1932
|
}
|
|
1950
|
-
return new Promise((
|
|
1933
|
+
return new Promise((resolve5) => {
|
|
1951
1934
|
wss.on("listening", () => {
|
|
1952
1935
|
console.log(`[WebUI] WebSocket server running on ws://${host}:${port}`);
|
|
1953
1936
|
setupEvents();
|
|
@@ -2029,8 +2012,8 @@ async function runWebUI(opts) {
|
|
|
2029
2012
|
console.log("[WebUI] Client disconnected");
|
|
2030
2013
|
clients.delete(ws);
|
|
2031
2014
|
if (clients.size === 0 && pendingConfirms.size > 0) {
|
|
2032
|
-
for (const [id,
|
|
2033
|
-
|
|
2015
|
+
for (const [id, resolve6] of pendingConfirms) {
|
|
2016
|
+
resolve6("no");
|
|
2034
2017
|
pendingConfirms.delete(id);
|
|
2035
2018
|
}
|
|
2036
2019
|
}
|
|
@@ -2060,7 +2043,7 @@ async function runWebUI(opts) {
|
|
|
2060
2043
|
httpServer?.close();
|
|
2061
2044
|
wss.close(() => {
|
|
2062
2045
|
console.log("[WebUI] Server stopped");
|
|
2063
|
-
|
|
2046
|
+
resolve5();
|
|
2064
2047
|
});
|
|
2065
2048
|
}
|
|
2066
2049
|
process.on("SIGINT", shutdown);
|
|
@@ -2087,10 +2070,10 @@ async function runWebUI(opts) {
|
|
|
2087
2070
|
break;
|
|
2088
2071
|
case "tool.confirm_result": {
|
|
2089
2072
|
const { id, decision } = msg.payload;
|
|
2090
|
-
const
|
|
2091
|
-
if (
|
|
2073
|
+
const resolve5 = pendingConfirms.get(id);
|
|
2074
|
+
if (resolve5) {
|
|
2092
2075
|
pendingConfirms.delete(id);
|
|
2093
|
-
|
|
2076
|
+
resolve5(decision);
|
|
2094
2077
|
}
|
|
2095
2078
|
break;
|
|
2096
2079
|
}
|
|
@@ -2375,7 +2358,7 @@ async function runWebUI(opts) {
|
|
|
2375
2358
|
if (!opts.globalConfigPath) return {};
|
|
2376
2359
|
let raw;
|
|
2377
2360
|
try {
|
|
2378
|
-
raw = await
|
|
2361
|
+
raw = await fsp4.readFile(opts.globalConfigPath, "utf8");
|
|
2379
2362
|
} catch {
|
|
2380
2363
|
return {};
|
|
2381
2364
|
}
|
|
@@ -2395,7 +2378,7 @@ async function runWebUI(opts) {
|
|
|
2395
2378
|
let raw;
|
|
2396
2379
|
let fileExists = true;
|
|
2397
2380
|
try {
|
|
2398
|
-
raw = await
|
|
2381
|
+
raw = await fsp4.readFile(opts.globalConfigPath, "utf8");
|
|
2399
2382
|
} catch (err) {
|
|
2400
2383
|
if (err.code !== "ENOENT") {
|
|
2401
2384
|
throw new Error(
|
|
@@ -2433,6 +2416,25 @@ var init_webui_server = __esm({
|
|
|
2433
2416
|
init_provider_config_utils();
|
|
2434
2417
|
}
|
|
2435
2418
|
});
|
|
2419
|
+
var req = createRequire(import.meta.url);
|
|
2420
|
+
function readOwnVersion() {
|
|
2421
|
+
const candidates = ["../package.json", "../../package.json"];
|
|
2422
|
+
for (const rel of candidates) {
|
|
2423
|
+
try {
|
|
2424
|
+
const pkg = req(rel);
|
|
2425
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|
|
2426
|
+
} catch {
|
|
2427
|
+
}
|
|
2428
|
+
}
|
|
2429
|
+
return "dev";
|
|
2430
|
+
}
|
|
2431
|
+
var CLI_VERSION = readOwnVersion();
|
|
2432
|
+
var API_VERSION = "0.0.0";
|
|
2433
|
+
try {
|
|
2434
|
+
const corePkg = req("@wrongstack/core/package.json");
|
|
2435
|
+
if (corePkg.wrongstackApiVersion) API_VERSION = corePkg.wrongstackApiVersion;
|
|
2436
|
+
} catch {
|
|
2437
|
+
}
|
|
2436
2438
|
|
|
2437
2439
|
// src/slash-commands/commit-llm.ts
|
|
2438
2440
|
async function generateCommitMessageWithLLM(diff, opts) {
|
|
@@ -2564,7 +2566,6 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
2564
2566
|
"recover",
|
|
2565
2567
|
"no-alt-screen",
|
|
2566
2568
|
"alt-screen",
|
|
2567
|
-
"mouse",
|
|
2568
2569
|
"output-json",
|
|
2569
2570
|
"prompt",
|
|
2570
2571
|
"metrics",
|
|
@@ -2686,7 +2687,7 @@ function parseSpawnFlags(input) {
|
|
|
2686
2687
|
}
|
|
2687
2688
|
async function pathExists(file) {
|
|
2688
2689
|
try {
|
|
2689
|
-
await
|
|
2690
|
+
await fsp4.access(file);
|
|
2690
2691
|
return true;
|
|
2691
2692
|
} catch {
|
|
2692
2693
|
return false;
|
|
@@ -2721,7 +2722,7 @@ function parseMakeTargets(makefile) {
|
|
|
2721
2722
|
async function detectProjectFacts(root) {
|
|
2722
2723
|
const facts = { hints: [] };
|
|
2723
2724
|
try {
|
|
2724
|
-
const pkg = JSON.parse(await
|
|
2725
|
+
const pkg = JSON.parse(await fsp4.readFile(path8.join(root, "package.json"), "utf8"));
|
|
2725
2726
|
const scripts = pkg.scripts ?? {};
|
|
2726
2727
|
const pm = await detectPackageManager(root, pkg.packageManager);
|
|
2727
2728
|
if (hasUsableScript(scripts, "build")) facts.build = `${pm} run build`;
|
|
@@ -2759,7 +2760,7 @@ async function detectProjectFacts(root) {
|
|
|
2759
2760
|
} catch {
|
|
2760
2761
|
}
|
|
2761
2762
|
try {
|
|
2762
|
-
const makefile = await
|
|
2763
|
+
const makefile = await fsp4.readFile(path8.join(root, "Makefile"), "utf8");
|
|
2763
2764
|
const targets = parseMakeTargets(makefile);
|
|
2764
2765
|
facts.build ??= targets.has("build") ? "make build" : "make";
|
|
2765
2766
|
if (targets.has("test")) facts.test ??= "make test";
|
|
@@ -3131,7 +3132,7 @@ function formatPhaseList(graph) {
|
|
|
3131
3132
|
}
|
|
3132
3133
|
async function gatherProjectContext(projectRoot) {
|
|
3133
3134
|
try {
|
|
3134
|
-
const raw = await
|
|
3135
|
+
const raw = await fsp4.readFile(path8.join(projectRoot, "package.json"), "utf8");
|
|
3135
3136
|
const pkg = JSON.parse(raw);
|
|
3136
3137
|
const parts = [
|
|
3137
3138
|
`Project: ${String(pkg.name ?? "unknown")}`,
|
|
@@ -3319,6 +3320,37 @@ function buildClearCommand(opts) {
|
|
|
3319
3320
|
}
|
|
3320
3321
|
};
|
|
3321
3322
|
}
|
|
3323
|
+
function buildCodebaseReindexCommand(opts) {
|
|
3324
|
+
return {
|
|
3325
|
+
name: "codebase-reindex",
|
|
3326
|
+
aliases: ["reindex"],
|
|
3327
|
+
description: "Rebuild the codebase symbol index used by codebase-search.",
|
|
3328
|
+
argsHint: "[force]",
|
|
3329
|
+
help: [
|
|
3330
|
+
"Usage:",
|
|
3331
|
+
" /codebase-reindex Incremental reindex (only changed files).",
|
|
3332
|
+
" /codebase-reindex force Clear the index and rebuild from scratch.",
|
|
3333
|
+
"",
|
|
3334
|
+
"The index powers codebase-search. It is normally kept fresh automatically",
|
|
3335
|
+
"(at session start and as files change); use this when you want to force a",
|
|
3336
|
+
"refresh \u2014 e.g. after a large branch switch, merge, or external edit."
|
|
3337
|
+
].join("\n"),
|
|
3338
|
+
async run(args, _ctx) {
|
|
3339
|
+
const force = /\b(force|--force|-f)\b/.test(args.trim());
|
|
3340
|
+
opts.renderer.write(color.dim(`${force ? "Rebuilding" : "Reindexing"} codebase index\u2026
|
|
3341
|
+
`));
|
|
3342
|
+
try {
|
|
3343
|
+
const r = await runStartupIndex({ projectRoot: opts.projectRoot, force });
|
|
3344
|
+
const summary = `${color.green("\u2713")} codebase index ${force ? "rebuilt" : "updated"} ` + color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`) + (r.errors.length ? `
|
|
3345
|
+
${color.yellow(` ${r.errors.length} file(s) had errors`)}` : "");
|
|
3346
|
+
return { message: summary };
|
|
3347
|
+
} catch (err) {
|
|
3348
|
+
const msg = `${color.red("Codebase reindex failed:")} ${err instanceof Error ? err.message : String(err)}`;
|
|
3349
|
+
return { message: msg };
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
};
|
|
3353
|
+
}
|
|
3322
3354
|
function buildCollabCommand(opts) {
|
|
3323
3355
|
return {
|
|
3324
3356
|
name: "collab",
|
|
@@ -3726,7 +3758,7 @@ async function persistContextConfig(opts, patch) {
|
|
|
3726
3758
|
if (!opts.configStore || !opts.paths) return "Cannot persist context settings: config store not available.";
|
|
3727
3759
|
let raw = "{}";
|
|
3728
3760
|
try {
|
|
3729
|
-
raw = await
|
|
3761
|
+
raw = await fsp4.readFile(opts.paths.globalConfig, "utf8");
|
|
3730
3762
|
} catch (err) {
|
|
3731
3763
|
if (err.code !== "ENOENT") {
|
|
3732
3764
|
return `Could not read ${opts.paths.globalConfig}: ${err.message}`;
|
|
@@ -4644,6 +4676,7 @@ function buildFleetCommand(opts) {
|
|
|
4644
4676
|
" /fleet terminate <subagentId> Stop a specific subagent by id",
|
|
4645
4677
|
" /fleet kill Stop all running subagents",
|
|
4646
4678
|
" /fleet usage Token and cost breakdown across the fleet",
|
|
4679
|
+
" /fleet concurrency [n] Show or set the concurrent-subagent ceiling",
|
|
4647
4680
|
" /fleet journal Show recent journal entries from /goal journal",
|
|
4648
4681
|
"",
|
|
4649
4682
|
"In the TUI, press Ctrl+F to open the graphical fleet monitor.",
|
|
@@ -4886,6 +4919,16 @@ function buildFleetCommand(opts) {
|
|
|
4886
4919
|
opts.renderer.write(msg2);
|
|
4887
4920
|
return { message: msg2 };
|
|
4888
4921
|
}
|
|
4922
|
+
if (cmd === "concurrency" || cmd === "slots" || cmd === "parallel") {
|
|
4923
|
+
if (opts.onFleet) {
|
|
4924
|
+
const n = subargs[0];
|
|
4925
|
+
const msg3 = await opts.onFleet("concurrency", n || void 0);
|
|
4926
|
+
return { message: msg3 };
|
|
4927
|
+
}
|
|
4928
|
+
const msg2 = `${color.amber("\u26A0 /fleet concurrency is not wired in this session.")}`;
|
|
4929
|
+
opts.renderer.writeWarning(msg2);
|
|
4930
|
+
return { message: msg2 };
|
|
4931
|
+
}
|
|
4889
4932
|
if (cmd === "help" || cmd === "?") {
|
|
4890
4933
|
const msg2 = [
|
|
4891
4934
|
`${color.bold("Fleet Commands")}`,
|
|
@@ -4897,12 +4940,13 @@ function buildFleetCommand(opts) {
|
|
|
4897
4940
|
` ${color.dim("/fleet terminate <subagentId>")} Stop a specific subagent by id`,
|
|
4898
4941
|
` ${color.dim("/fleet kill")} Stop all running subagents`,
|
|
4899
4942
|
` ${color.dim("/fleet usage")} Token and cost breakdown across the fleet`,
|
|
4943
|
+
` ${color.dim("/fleet concurrency [n]")} Show or set the concurrent-subagent ceiling`,
|
|
4900
4944
|
` ${color.dim("/fleet journal")} Show recent journal entries from /goal journal`
|
|
4901
4945
|
].join("\n");
|
|
4902
4946
|
opts.renderer.write(msg2);
|
|
4903
4947
|
return { message: msg2 };
|
|
4904
4948
|
}
|
|
4905
|
-
const valid = ["status", "list", "dispatch", "usage", "spawn", "terminate", "kill", "retry", "journal"];
|
|
4949
|
+
const valid = ["status", "list", "dispatch", "usage", "spawn", "terminate", "kill", "retry", "concurrency", "journal"];
|
|
4906
4950
|
const msg = `Unknown subcommand "${cmd}". Valid subcommands: ${valid.join(", ")}. Run /fleet with no args to see status, or /fleet help for usage.`;
|
|
4907
4951
|
opts.renderer.writeWarning(msg);
|
|
4908
4952
|
return { message: msg };
|
|
@@ -5144,8 +5188,8 @@ function buildInitCommand(opts) {
|
|
|
5144
5188
|
const file = path8.join(dir, "AGENTS.md");
|
|
5145
5189
|
const detected = await detectProjectFacts(ctx.projectRoot);
|
|
5146
5190
|
const body = renderAgentsTemplate(detected);
|
|
5147
|
-
await
|
|
5148
|
-
await
|
|
5191
|
+
await fsp4.mkdir(dir, { recursive: true });
|
|
5192
|
+
await fsp4.writeFile(file, body, "utf8");
|
|
5149
5193
|
if (detected.hints.length > 0) {
|
|
5150
5194
|
const msg2 = `Wrote ${file}
|
|
5151
5195
|
Pre-filled: ${detected.hints.join(", ")}. Edit the file with project context and instructions the system prompt should carry.`;
|
|
@@ -5356,9 +5400,9 @@ function stateBadge(state) {
|
|
|
5356
5400
|
return color.dim(state);
|
|
5357
5401
|
}
|
|
5358
5402
|
}
|
|
5359
|
-
async function readConfig(
|
|
5403
|
+
async function readConfig(path26) {
|
|
5360
5404
|
try {
|
|
5361
|
-
return JSON.parse(await
|
|
5405
|
+
return JSON.parse(await fsp4.readFile(path26, "utf8"));
|
|
5362
5406
|
} catch {
|
|
5363
5407
|
return {};
|
|
5364
5408
|
}
|
|
@@ -5366,11 +5410,11 @@ async function readConfig(path25) {
|
|
|
5366
5410
|
function isMcpServerRecord(value) {
|
|
5367
5411
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5368
5412
|
}
|
|
5369
|
-
async function writeConfig(
|
|
5413
|
+
async function writeConfig(path26, cfg) {
|
|
5370
5414
|
const raw = JSON.stringify(cfg, null, 2);
|
|
5371
|
-
const tmp =
|
|
5372
|
-
await
|
|
5373
|
-
await
|
|
5415
|
+
const tmp = path26 + ".tmp";
|
|
5416
|
+
await fsp4.writeFile(tmp, raw, "utf8");
|
|
5417
|
+
await fsp4.rename(tmp, path26);
|
|
5374
5418
|
}
|
|
5375
5419
|
|
|
5376
5420
|
// src/slash-commands/mcp.ts
|
|
@@ -5562,7 +5606,7 @@ async function patchGlobalConfig(globalConfigPath, mutate) {
|
|
|
5562
5606
|
let raw = "{}";
|
|
5563
5607
|
let fileExists = true;
|
|
5564
5608
|
try {
|
|
5565
|
-
raw = await
|
|
5609
|
+
raw = await fsp4.readFile(globalConfigPath, "utf8");
|
|
5566
5610
|
} catch (err) {
|
|
5567
5611
|
if (err.code !== "ENOENT") throw err;
|
|
5568
5612
|
fileExists = false;
|
|
@@ -6067,7 +6111,7 @@ async function patchGlobalConfig2(globalConfigPath, mutate) {
|
|
|
6067
6111
|
let raw = "{}";
|
|
6068
6112
|
let fileExists = true;
|
|
6069
6113
|
try {
|
|
6070
|
-
raw = await
|
|
6114
|
+
raw = await fsp4.readFile(globalConfigPath, "utf8");
|
|
6071
6115
|
} catch (err) {
|
|
6072
6116
|
if (err.code !== "ENOENT") throw err;
|
|
6073
6117
|
fileExists = false;
|
|
@@ -6246,7 +6290,7 @@ async function persistAutonomySetting(deps, mutator) {
|
|
|
6246
6290
|
let raw;
|
|
6247
6291
|
let fileExists = true;
|
|
6248
6292
|
try {
|
|
6249
|
-
raw = await
|
|
6293
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
6250
6294
|
} catch (err) {
|
|
6251
6295
|
if (err.code !== "ENOENT") {
|
|
6252
6296
|
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
@@ -6473,7 +6517,7 @@ function resolveConfigPath() {
|
|
|
6473
6517
|
async function loadStatuslineConfig() {
|
|
6474
6518
|
const p = resolveConfigPath();
|
|
6475
6519
|
try {
|
|
6476
|
-
const raw = await
|
|
6520
|
+
const raw = await fsp4.readFile(p, "utf8");
|
|
6477
6521
|
return { ...DEFAULTS, ...JSON.parse(raw) };
|
|
6478
6522
|
} catch {
|
|
6479
6523
|
return { ...DEFAULTS };
|
|
@@ -6482,7 +6526,7 @@ async function loadStatuslineConfig() {
|
|
|
6482
6526
|
async function saveStatuslineConfig(cfg) {
|
|
6483
6527
|
const p = resolveConfigPath();
|
|
6484
6528
|
try {
|
|
6485
|
-
await
|
|
6529
|
+
await fsp4.mkdir(path8.dirname(p), { recursive: true });
|
|
6486
6530
|
await atomicWrite(p, JSON.stringify(cfg, null, 2));
|
|
6487
6531
|
} catch (err) {
|
|
6488
6532
|
throw new FsError({
|
|
@@ -6736,6 +6780,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6736
6780
|
buildClearCommand(opts),
|
|
6737
6781
|
buildCompactCommand(opts),
|
|
6738
6782
|
buildContextCommand(opts),
|
|
6783
|
+
buildCodebaseReindexCommand(opts),
|
|
6739
6784
|
buildToolsCommand(opts),
|
|
6740
6785
|
buildPluginCommand(opts),
|
|
6741
6786
|
buildMcpSlashCommand(opts),
|
|
@@ -6791,13 +6836,13 @@ var MANIFESTS = [
|
|
|
6791
6836
|
];
|
|
6792
6837
|
async function detectProjectKind(projectRoot) {
|
|
6793
6838
|
try {
|
|
6794
|
-
await
|
|
6839
|
+
await fsp4.access(path8.join(projectRoot, ".wrongstack", "AGENTS.md"));
|
|
6795
6840
|
return "initialized";
|
|
6796
6841
|
} catch {
|
|
6797
6842
|
}
|
|
6798
6843
|
for (const m of MANIFESTS) {
|
|
6799
6844
|
try {
|
|
6800
|
-
await
|
|
6845
|
+
await fsp4.access(path8.join(projectRoot, m));
|
|
6801
6846
|
return "project";
|
|
6802
6847
|
} catch {
|
|
6803
6848
|
}
|
|
@@ -6809,8 +6854,8 @@ async function scaffoldAgentsMd(projectRoot) {
|
|
|
6809
6854
|
const file = path8.join(dir, "AGENTS.md");
|
|
6810
6855
|
const facts = await detectProjectFacts(projectRoot);
|
|
6811
6856
|
const body = renderAgentsTemplate(facts);
|
|
6812
|
-
await
|
|
6813
|
-
await
|
|
6857
|
+
await fsp4.mkdir(dir, { recursive: true });
|
|
6858
|
+
await fsp4.writeFile(file, body, "utf8");
|
|
6814
6859
|
return file;
|
|
6815
6860
|
}
|
|
6816
6861
|
async function runProjectCheck(opts) {
|
|
@@ -6853,7 +6898,7 @@ async function runProjectCheck(opts) {
|
|
|
6853
6898
|
const gitDir = path8.join(projectRoot, ".git");
|
|
6854
6899
|
let hasGit = false;
|
|
6855
6900
|
try {
|
|
6856
|
-
await
|
|
6901
|
+
await fsp4.access(gitDir);
|
|
6857
6902
|
hasGit = true;
|
|
6858
6903
|
} catch {
|
|
6859
6904
|
}
|
|
@@ -6873,10 +6918,10 @@ async function runProjectCheck(opts) {
|
|
|
6873
6918
|
if (answer2 === "y" || answer2 === "yes") {
|
|
6874
6919
|
try {
|
|
6875
6920
|
const { spawn: spawn3 } = await import('child_process');
|
|
6876
|
-
await new Promise((
|
|
6921
|
+
await new Promise((resolve5, reject) => {
|
|
6877
6922
|
const child = spawn3("git", ["init"], { cwd: projectRoot });
|
|
6878
6923
|
child.on("error", reject);
|
|
6879
|
-
child.on("close", (code) => code === 0 ?
|
|
6924
|
+
child.on("close", (code) => code === 0 ? resolve5() : reject(new Error(`git init failed with ${code}`)));
|
|
6880
6925
|
});
|
|
6881
6926
|
renderer.write(` ${color.green("\u2713")} Git repository initialized
|
|
6882
6927
|
`);
|
|
@@ -6907,7 +6952,43 @@ var LaunchAbortedError = class extends Error {
|
|
|
6907
6952
|
}
|
|
6908
6953
|
};
|
|
6909
6954
|
async function runLaunchPrompts(opts) {
|
|
6910
|
-
const { renderer, reader, modePinned, yoloPinned, directorPinned, autonomyPinned } = opts;
|
|
6955
|
+
const { renderer, reader, modePinned, yoloPinned, directorPinned, autonomyPinned, lastChoices } = opts;
|
|
6956
|
+
if (modePinned !== void 0 && yoloPinned !== void 0 && directorPinned !== void 0 && autonomyPinned !== void 0) {
|
|
6957
|
+
return { mode: modePinned, yolo: yoloPinned, director: directorPinned, autonomy: autonomyPinned };
|
|
6958
|
+
}
|
|
6959
|
+
if (lastChoices) {
|
|
6960
|
+
const effective = {
|
|
6961
|
+
mode: modePinned ?? lastChoices.mode,
|
|
6962
|
+
yolo: yoloPinned ?? lastChoices.yolo,
|
|
6963
|
+
director: directorPinned ?? lastChoices.director,
|
|
6964
|
+
autonomy: autonomyPinned ?? lastChoices.autonomy
|
|
6965
|
+
};
|
|
6966
|
+
const onOff = (v) => v ? color.green("on") : color.dim("off");
|
|
6967
|
+
const modeLabel = effective.mode.toUpperCase();
|
|
6968
|
+
renderer.write(
|
|
6969
|
+
`
|
|
6970
|
+
${color.dim("Last settings:")} ${color.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Director ${onOff(effective.director)} \xB7 Autonomy ${effective.autonomy === "auto" ? color.green("auto") : color.dim("off")}
|
|
6971
|
+
`
|
|
6972
|
+
);
|
|
6973
|
+
const answer = (await reader.readLine(
|
|
6974
|
+
` ${color.amber("?")} Continue with these? ${color.dim("[Y/n/q]")} `
|
|
6975
|
+
)).trim().toLowerCase();
|
|
6976
|
+
if (answer === "q") {
|
|
6977
|
+
renderer.write(color.dim(" Goodbye!\n"));
|
|
6978
|
+
throw new LaunchAbortedError();
|
|
6979
|
+
}
|
|
6980
|
+
if (answer !== "n" && answer !== "no") {
|
|
6981
|
+
const badges2 = buildBadges(effective);
|
|
6982
|
+
const badgeStr2 = badges2.length > 0 ? ` (${badges2.join(" \xB7 ")})` : "";
|
|
6983
|
+
renderer.write(
|
|
6984
|
+
`
|
|
6985
|
+
${color.green("\u25B6")} Launching in ${color.bold(modeLabel)} mode${badgeStr2}
|
|
6986
|
+
|
|
6987
|
+
`
|
|
6988
|
+
);
|
|
6989
|
+
return effective;
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6911
6992
|
let mode;
|
|
6912
6993
|
if (modePinned) {
|
|
6913
6994
|
mode = modePinned;
|
|
@@ -6961,10 +7042,7 @@ async function runLaunchPrompts(opts) {
|
|
|
6961
7042
|
}
|
|
6962
7043
|
autonomy = answer !== "n" && answer !== "no" ? "auto" : "off";
|
|
6963
7044
|
}
|
|
6964
|
-
const badges =
|
|
6965
|
-
if (yolo) badges.push(color.yellow("YOLO"));
|
|
6966
|
-
if (director) badges.push(color.cyan("DIRECTOR"));
|
|
6967
|
-
if (autonomy !== "off") badges.push(color.magenta(`AUTONOMY:${autonomy.toUpperCase()}`));
|
|
7045
|
+
const badges = buildBadges({ yolo, director, autonomy });
|
|
6968
7046
|
const badgeStr = badges.length > 0 ? ` (${badges.join(" \xB7 ")})` : "";
|
|
6969
7047
|
renderer.write(
|
|
6970
7048
|
`
|
|
@@ -6974,6 +7052,28 @@ async function runLaunchPrompts(opts) {
|
|
|
6974
7052
|
);
|
|
6975
7053
|
return { mode, yolo, director, autonomy };
|
|
6976
7054
|
}
|
|
7055
|
+
function buildBadges(chosen) {
|
|
7056
|
+
const badges = [];
|
|
7057
|
+
if (chosen.yolo) badges.push(color.yellow("YOLO"));
|
|
7058
|
+
if (chosen.director) badges.push(color.cyan("DIRECTOR"));
|
|
7059
|
+
if (chosen.autonomy !== "off") badges.push(color.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
|
|
7060
|
+
return badges;
|
|
7061
|
+
}
|
|
7062
|
+
async function persistLaunchChoices(configPath2, choices) {
|
|
7063
|
+
let existing = {};
|
|
7064
|
+
try {
|
|
7065
|
+
const raw = await fsp4.readFile(configPath2, "utf8");
|
|
7066
|
+
existing = JSON.parse(raw);
|
|
7067
|
+
} catch {
|
|
7068
|
+
}
|
|
7069
|
+
existing.yolo = choices.yolo;
|
|
7070
|
+
existing.launch = {
|
|
7071
|
+
mode: choices.mode,
|
|
7072
|
+
director: choices.director,
|
|
7073
|
+
autonomy: choices.autonomy
|
|
7074
|
+
};
|
|
7075
|
+
await atomicWrite(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7076
|
+
}
|
|
6977
7077
|
async function bootConfig(flags) {
|
|
6978
7078
|
const opts = { flags, appLabel: "wstack" };
|
|
6979
7079
|
const { cwd, projectRoot, userHome, wpaths, pathResolver, config, vault } = await bootConfig$1(opts);
|
|
@@ -6993,7 +7093,7 @@ var ReadlineInputReader = class {
|
|
|
6993
7093
|
}
|
|
6994
7094
|
async loadHistory() {
|
|
6995
7095
|
try {
|
|
6996
|
-
const raw = await
|
|
7096
|
+
const raw = await fsp4.readFile(this.historyFile, "utf8");
|
|
6997
7097
|
this.history = raw.split("\n").filter(Boolean).slice(-1e3);
|
|
6998
7098
|
} catch {
|
|
6999
7099
|
this.history = [];
|
|
@@ -7001,8 +7101,8 @@ var ReadlineInputReader = class {
|
|
|
7001
7101
|
}
|
|
7002
7102
|
async saveHistory() {
|
|
7003
7103
|
try {
|
|
7004
|
-
await
|
|
7005
|
-
await
|
|
7104
|
+
await fsp4.mkdir(path8.dirname(this.historyFile), { recursive: true });
|
|
7105
|
+
await fsp4.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
|
|
7006
7106
|
} catch {
|
|
7007
7107
|
}
|
|
7008
7108
|
}
|
|
@@ -7020,28 +7120,34 @@ var ReadlineInputReader = class {
|
|
|
7020
7120
|
async readLine(prompt) {
|
|
7021
7121
|
if (this.history.length === 0) await this.loadHistory();
|
|
7022
7122
|
while (this.pending) {
|
|
7023
|
-
await new Promise((
|
|
7123
|
+
await new Promise((resolve5) => setTimeout(resolve5, 50));
|
|
7024
7124
|
}
|
|
7025
7125
|
this.pending = true;
|
|
7026
7126
|
try {
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
rl.close();
|
|
7127
|
+
if (this.rl) {
|
|
7128
|
+
const old = this.rl;
|
|
7030
7129
|
this.rl = void 0;
|
|
7130
|
+
await new Promise((resolve5) => {
|
|
7131
|
+
if (old.closed) {
|
|
7132
|
+
resolve5();
|
|
7133
|
+
} else {
|
|
7134
|
+
old.once("close", resolve5);
|
|
7135
|
+
old.close();
|
|
7136
|
+
}
|
|
7137
|
+
});
|
|
7031
7138
|
}
|
|
7032
7139
|
const fresh = this.ensure();
|
|
7033
|
-
return new Promise((
|
|
7140
|
+
return new Promise((resolve5) => {
|
|
7034
7141
|
fresh.question(prompt ?? "> ", (line) => {
|
|
7035
7142
|
if (line.trim()) {
|
|
7036
7143
|
this.history.push(line);
|
|
7037
7144
|
void this.saveHistory();
|
|
7038
7145
|
}
|
|
7039
|
-
|
|
7146
|
+
resolve5(line);
|
|
7040
7147
|
});
|
|
7041
|
-
fresh.once("close", () =>
|
|
7148
|
+
fresh.once("close", () => resolve5(""));
|
|
7042
7149
|
}).then((result) => {
|
|
7043
7150
|
this.rl?.close();
|
|
7044
|
-
this.rl = void 0;
|
|
7045
7151
|
return result;
|
|
7046
7152
|
});
|
|
7047
7153
|
} finally {
|
|
@@ -7050,7 +7156,7 @@ var ReadlineInputReader = class {
|
|
|
7050
7156
|
}
|
|
7051
7157
|
async readKey(prompt, options) {
|
|
7052
7158
|
writeOut(prompt);
|
|
7053
|
-
return new Promise((
|
|
7159
|
+
return new Promise((resolve5) => {
|
|
7054
7160
|
const stdin = process.stdin;
|
|
7055
7161
|
const wasRaw = stdin.isRaw;
|
|
7056
7162
|
const wasPaused = stdin.isPaused();
|
|
@@ -7061,7 +7167,7 @@ var ReadlineInputReader = class {
|
|
|
7061
7167
|
if (key === "") {
|
|
7062
7168
|
cleanup();
|
|
7063
7169
|
writeOut("\n");
|
|
7064
|
-
|
|
7170
|
+
resolve5("");
|
|
7065
7171
|
return;
|
|
7066
7172
|
}
|
|
7067
7173
|
const opt = options.find(
|
|
@@ -7071,12 +7177,12 @@ var ReadlineInputReader = class {
|
|
|
7071
7177
|
cleanup();
|
|
7072
7178
|
writeOut(`${opt.key}
|
|
7073
7179
|
`);
|
|
7074
|
-
|
|
7180
|
+
resolve5(opt.value);
|
|
7075
7181
|
}
|
|
7076
7182
|
};
|
|
7077
7183
|
const onClose = () => {
|
|
7078
7184
|
cleanup();
|
|
7079
|
-
|
|
7185
|
+
resolve5("");
|
|
7080
7186
|
};
|
|
7081
7187
|
const cleanup = () => {
|
|
7082
7188
|
stdin.off("data", onData);
|
|
@@ -7104,7 +7210,7 @@ var ReadlineInputReader = class {
|
|
|
7104
7210
|
this.rl?.close();
|
|
7105
7211
|
this.rl = void 0;
|
|
7106
7212
|
writeOut(prompt);
|
|
7107
|
-
return new Promise((
|
|
7213
|
+
return new Promise((resolve5) => {
|
|
7108
7214
|
let buf = "";
|
|
7109
7215
|
const wasRaw = stdin.isRaw;
|
|
7110
7216
|
setRawMode(stdin, true);
|
|
@@ -7122,7 +7228,7 @@ var ReadlineInputReader = class {
|
|
|
7122
7228
|
cleanup();
|
|
7123
7229
|
writeOut(` ${dim(`[${buf.length} chars]`)}
|
|
7124
7230
|
`);
|
|
7125
|
-
|
|
7231
|
+
resolve5(buf);
|
|
7126
7232
|
return;
|
|
7127
7233
|
}
|
|
7128
7234
|
if (ch === "") {
|
|
@@ -7222,7 +7328,7 @@ async function buildPickableProviders(modelsRegistry, config) {
|
|
|
7222
7328
|
var defaultUidFn = () => os2__default.userInfo().uid;
|
|
7223
7329
|
async function getFileUid(filePath) {
|
|
7224
7330
|
try {
|
|
7225
|
-
const stat4 = await
|
|
7331
|
+
const stat4 = await fsp4.stat(filePath);
|
|
7226
7332
|
return stat4.uid;
|
|
7227
7333
|
} catch {
|
|
7228
7334
|
return void 0;
|
|
@@ -7262,7 +7368,7 @@ async function safeDelete(filePath) {
|
|
|
7262
7368
|
const filename = path8.basename(filePath);
|
|
7263
7369
|
try {
|
|
7264
7370
|
assertSafeToDelete(filename, dir);
|
|
7265
|
-
await
|
|
7371
|
+
await fsp4.unlink(filePath);
|
|
7266
7372
|
} catch (err) {
|
|
7267
7373
|
if (err instanceof Error && err.message.startsWith("Refusing")) {
|
|
7268
7374
|
writeErr(`[config-history] SAFETY: ${err.message}
|
|
@@ -7320,7 +7426,7 @@ function entryId(ts) {
|
|
|
7320
7426
|
}
|
|
7321
7427
|
async function ensureHistoryDir(homeFn = defaultHomeDir) {
|
|
7322
7428
|
try {
|
|
7323
|
-
await
|
|
7429
|
+
await fsp4.mkdir(historyDir(homeFn), { recursive: true });
|
|
7324
7430
|
} catch (err) {
|
|
7325
7431
|
throw new FsError({
|
|
7326
7432
|
message: err instanceof Error ? err.message : String(err),
|
|
@@ -7332,7 +7438,7 @@ async function ensureHistoryDir(homeFn = defaultHomeDir) {
|
|
|
7332
7438
|
}
|
|
7333
7439
|
async function readIndex(homeFn = defaultHomeDir) {
|
|
7334
7440
|
try {
|
|
7335
|
-
const raw = await
|
|
7441
|
+
const raw = await fsp4.readFile(historyIndexPath(homeFn), "utf8");
|
|
7336
7442
|
return JSON.parse(raw);
|
|
7337
7443
|
} catch {
|
|
7338
7444
|
return { version: 1, entries: [] };
|
|
@@ -7357,7 +7463,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
|
|
|
7357
7463
|
const ts = Date.now();
|
|
7358
7464
|
let content;
|
|
7359
7465
|
try {
|
|
7360
|
-
content = await
|
|
7466
|
+
content = await fsp4.readFile(cfg, "utf8");
|
|
7361
7467
|
} catch {
|
|
7362
7468
|
}
|
|
7363
7469
|
if (content !== void 0) {
|
|
@@ -7375,7 +7481,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
|
|
|
7375
7481
|
}
|
|
7376
7482
|
try {
|
|
7377
7483
|
const dir = path8.join(homeFn(), ".wrongstack");
|
|
7378
|
-
const files = await
|
|
7484
|
+
const files = await fsp4.readdir(dir);
|
|
7379
7485
|
const baks = files.filter((f) => f.startsWith("config.json.") && f.endsWith(".bak")).sort().reverse();
|
|
7380
7486
|
for (const f of baks.slice(10)) {
|
|
7381
7487
|
await safeDelete(path8.join(dir, f));
|
|
@@ -7395,7 +7501,7 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
|
|
|
7395
7501
|
diffSummary: diffSummary(oldCfg, newCfg)
|
|
7396
7502
|
};
|
|
7397
7503
|
try {
|
|
7398
|
-
await
|
|
7504
|
+
await fsp4.writeFile(
|
|
7399
7505
|
path8.join(historyDir(homeFn), `${id}.json`),
|
|
7400
7506
|
JSON.stringify(entry, null, 2),
|
|
7401
7507
|
"utf8"
|
|
@@ -7419,7 +7525,7 @@ async function listHistory(homeFn = defaultHomeDir) {
|
|
|
7419
7525
|
}
|
|
7420
7526
|
async function getHistoryEntry(id, homeFn = defaultHomeDir) {
|
|
7421
7527
|
try {
|
|
7422
|
-
const raw = await
|
|
7528
|
+
const raw = await fsp4.readFile(path8.join(historyDir(homeFn), `${id}.json`), "utf8");
|
|
7423
7529
|
return JSON.parse(raw);
|
|
7424
7530
|
} catch {
|
|
7425
7531
|
return null;
|
|
@@ -7434,7 +7540,7 @@ async function restoreFromHistory(id, homeFn = defaultHomeDir) {
|
|
|
7434
7540
|
await backupCurrent(homeFn);
|
|
7435
7541
|
let oldCfg = {};
|
|
7436
7542
|
try {
|
|
7437
|
-
const raw = await
|
|
7543
|
+
const raw = await fsp4.readFile(configPath(homeFn), "utf8");
|
|
7438
7544
|
oldCfg = JSON.parse(raw);
|
|
7439
7545
|
} catch {
|
|
7440
7546
|
}
|
|
@@ -7456,13 +7562,13 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
7456
7562
|
const cfg = configPath(homeFn);
|
|
7457
7563
|
let oldCfg = {};
|
|
7458
7564
|
try {
|
|
7459
|
-
const raw = await
|
|
7565
|
+
const raw = await fsp4.readFile(cfg, "utf8");
|
|
7460
7566
|
oldCfg = JSON.parse(raw);
|
|
7461
7567
|
} catch {
|
|
7462
7568
|
}
|
|
7463
7569
|
let lastCfg = {};
|
|
7464
7570
|
try {
|
|
7465
|
-
const raw = await
|
|
7571
|
+
const raw = await fsp4.readFile(last, "utf8");
|
|
7466
7572
|
lastCfg = JSON.parse(raw);
|
|
7467
7573
|
} catch {
|
|
7468
7574
|
return { ok: false, error: "No prior backup found" };
|
|
@@ -7482,21 +7588,25 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
7482
7588
|
|
|
7483
7589
|
// src/picker.ts
|
|
7484
7590
|
var theme = { primary: color.amber };
|
|
7485
|
-
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ??
|
|
7591
|
+
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os2__default.homedir()) {
|
|
7486
7592
|
try {
|
|
7487
|
-
const { atomicWrite:
|
|
7488
|
-
const
|
|
7593
|
+
const { atomicWrite: atomicWrite14 } = await import('@wrongstack/core');
|
|
7594
|
+
const fs26 = await import('fs/promises');
|
|
7489
7595
|
let existing = {};
|
|
7490
7596
|
try {
|
|
7491
|
-
const raw = await
|
|
7597
|
+
const raw = await fs26.readFile(configPath2, "utf8");
|
|
7492
7598
|
existing = JSON.parse(raw);
|
|
7493
7599
|
} catch {
|
|
7494
7600
|
}
|
|
7495
7601
|
const oldCfg = { ...existing };
|
|
7496
7602
|
existing.provider = provider;
|
|
7497
7603
|
existing.model = model;
|
|
7498
|
-
|
|
7499
|
-
|
|
7604
|
+
try {
|
|
7605
|
+
await backupCurrent(homeFn);
|
|
7606
|
+
} catch (err) {
|
|
7607
|
+
console.warn("[picker] backupCurrent failed:", err);
|
|
7608
|
+
}
|
|
7609
|
+
await atomicWrite14(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7500
7610
|
try {
|
|
7501
7611
|
await appendHistory(
|
|
7502
7612
|
oldCfg,
|
|
@@ -7507,7 +7617,8 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
|
|
|
7507
7617
|
} catch {
|
|
7508
7618
|
}
|
|
7509
7619
|
return true;
|
|
7510
|
-
} catch {
|
|
7620
|
+
} catch (err) {
|
|
7621
|
+
console.warn("[picker] saveToGlobalConfig failed:", err instanceof Error ? err.message : String(err));
|
|
7511
7622
|
return false;
|
|
7512
7623
|
}
|
|
7513
7624
|
}
|
|
@@ -8159,14 +8270,14 @@ function summarize(value, name) {
|
|
|
8159
8270
|
if (typeof v === "object" && v !== null) {
|
|
8160
8271
|
const o = v;
|
|
8161
8272
|
if (name === "edit") {
|
|
8162
|
-
const
|
|
8273
|
+
const path26 = typeof o["path"] === "string" ? o["path"] : "";
|
|
8163
8274
|
const reps = typeof o["replacements"] === "number" ? o["replacements"] : 0;
|
|
8164
|
-
return `${
|
|
8275
|
+
return `${path26} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
|
|
8165
8276
|
}
|
|
8166
8277
|
if (name === "write") {
|
|
8167
|
-
const
|
|
8278
|
+
const path26 = typeof o["path"] === "string" ? o["path"] : "";
|
|
8168
8279
|
const bytes = typeof o["bytes"] === "number" ? o["bytes"] : void 0;
|
|
8169
|
-
return bytes !== void 0 ? `${
|
|
8280
|
+
return bytes !== void 0 ? `${path26} ${bytes}B` : path26;
|
|
8170
8281
|
}
|
|
8171
8282
|
if (typeof o["count"] === "number") {
|
|
8172
8283
|
return `${o["count"]} match${o["count"] === 1 ? "" : "es"}`;
|
|
@@ -8926,7 +9037,7 @@ async function readKeyInput(deps, intent) {
|
|
|
8926
9037
|
async function loadProviders(deps) {
|
|
8927
9038
|
let raw;
|
|
8928
9039
|
try {
|
|
8929
|
-
raw = await
|
|
9040
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
8930
9041
|
} catch (err) {
|
|
8931
9042
|
if (err.code !== "ENOENT") {
|
|
8932
9043
|
deps.renderer.writeWarning(
|
|
@@ -8951,7 +9062,7 @@ async function mutateProviders(deps, mutator) {
|
|
|
8951
9062
|
let raw;
|
|
8952
9063
|
let fileExists = true;
|
|
8953
9064
|
try {
|
|
8954
|
-
raw = await
|
|
9065
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
8955
9066
|
} catch (err) {
|
|
8956
9067
|
if (err.code !== "ENOENT") {
|
|
8957
9068
|
throw new Error(
|
|
@@ -9026,7 +9137,7 @@ var updateCmd = async (args, deps) => {
|
|
|
9026
9137
|
deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
|
|
9027
9138
|
`);
|
|
9028
9139
|
try {
|
|
9029
|
-
const result = await new Promise((
|
|
9140
|
+
const result = await new Promise((resolve5, reject) => {
|
|
9030
9141
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
9031
9142
|
const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
|
|
9032
9143
|
cwd,
|
|
@@ -9037,7 +9148,7 @@ var updateCmd = async (args, deps) => {
|
|
|
9037
9148
|
_stderr += d;
|
|
9038
9149
|
});
|
|
9039
9150
|
child.on("error", reject);
|
|
9040
|
-
child.on("close", (code) =>
|
|
9151
|
+
child.on("close", (code) => resolve5({ code: code ?? 0 }));
|
|
9041
9152
|
});
|
|
9042
9153
|
if (result.code === 0) {
|
|
9043
9154
|
deps.renderer.write(`
|
|
@@ -9063,27 +9174,6 @@ Update failed: ${msg}
|
|
|
9063
9174
|
return 1;
|
|
9064
9175
|
}
|
|
9065
9176
|
};
|
|
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
9177
|
var diagCmd = async (_args, deps) => {
|
|
9088
9178
|
const cfg = deps.config;
|
|
9089
9179
|
const age = await deps.modelsRegistry.ageSeconds();
|
|
@@ -9166,7 +9256,7 @@ var doctorCmd = async (_args, deps) => {
|
|
|
9166
9256
|
});
|
|
9167
9257
|
}
|
|
9168
9258
|
try {
|
|
9169
|
-
await
|
|
9259
|
+
await fsp4.access(deps.paths.secretsKey);
|
|
9170
9260
|
checks.push({ name: "secret vault", status: "ok", detail: deps.paths.secretsKey });
|
|
9171
9261
|
} catch {
|
|
9172
9262
|
checks.push({
|
|
@@ -9176,10 +9266,10 @@ var doctorCmd = async (_args, deps) => {
|
|
|
9176
9266
|
});
|
|
9177
9267
|
}
|
|
9178
9268
|
try {
|
|
9179
|
-
await
|
|
9269
|
+
await fsp4.mkdir(deps.paths.projectSessions, { recursive: true });
|
|
9180
9270
|
const probe = path8.join(deps.paths.projectSessions, `.probe-${Date.now()}`);
|
|
9181
|
-
await
|
|
9182
|
-
await
|
|
9271
|
+
await fsp4.writeFile(probe, "");
|
|
9272
|
+
await fsp4.unlink(probe);
|
|
9183
9273
|
checks.push({ name: "sessions writable", status: "ok", detail: deps.paths.projectSessions });
|
|
9184
9274
|
} catch (err) {
|
|
9185
9275
|
checks.push({
|
|
@@ -9280,8 +9370,8 @@ var exportCmd = async (args, deps) => {
|
|
|
9280
9370
|
return 1;
|
|
9281
9371
|
}
|
|
9282
9372
|
if (output) {
|
|
9283
|
-
await
|
|
9284
|
-
await
|
|
9373
|
+
await fsp4.mkdir(path8.dirname(path8.resolve(deps.cwd, output)), { recursive: true });
|
|
9374
|
+
await fsp4.writeFile(path8.resolve(deps.cwd, output), rendered, "utf8");
|
|
9285
9375
|
deps.renderer.write(`Wrote ${rendered.length} bytes to ${output}
|
|
9286
9376
|
`);
|
|
9287
9377
|
} else {
|
|
@@ -9348,13 +9438,13 @@ var initCmd = async (_args, deps) => {
|
|
|
9348
9438
|
} else {
|
|
9349
9439
|
deps.renderer.writeInfo(`Found API key in env (${provider.envVars.join(" / ")}).`);
|
|
9350
9440
|
}
|
|
9351
|
-
await
|
|
9441
|
+
await fsp4.mkdir(deps.paths.globalRoot, { recursive: true });
|
|
9352
9442
|
const config = { version: 1, provider: providerId, model: modelId };
|
|
9353
9443
|
if (apiKey) config.apiKey = apiKey;
|
|
9354
9444
|
const vault = new DefaultSecretVault({ keyFile: deps.paths.secretsKey });
|
|
9355
9445
|
const encrypted = encryptConfigSecrets(config, vault);
|
|
9356
9446
|
await atomicWrite(deps.paths.globalConfig, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
9357
|
-
await
|
|
9447
|
+
await fsp4.mkdir(path8.join(deps.projectRoot, ".wrongstack"), { recursive: true });
|
|
9358
9448
|
const agentsFile = path8.join(deps.projectRoot, ".wrongstack", "AGENTS.md");
|
|
9359
9449
|
const projectFacts = await detectProjectFacts(deps.projectRoot);
|
|
9360
9450
|
await atomicWrite(agentsFile, renderAgentsTemplate(projectFacts));
|
|
@@ -9494,8 +9584,8 @@ async function serveMcpStdio(deps) {
|
|
|
9494
9584
|
log(
|
|
9495
9585
|
`wrongstack MCP server ready at ${handle2.url} \u2014 exposing ${allowed.length} tool(s) (${mode})${token ? " [token auth]" : ""}.`
|
|
9496
9586
|
);
|
|
9497
|
-
await new Promise((
|
|
9498
|
-
const stop = () =>
|
|
9587
|
+
await new Promise((resolve5) => {
|
|
9588
|
+
const stop = () => resolve5();
|
|
9499
9589
|
process.once("SIGINT", stop);
|
|
9500
9590
|
process.once("SIGTERM", stop);
|
|
9501
9591
|
});
|
|
@@ -9580,7 +9670,7 @@ async function addMcpServer(args, deps) {
|
|
|
9580
9670
|
serverCfg.enabled = enable;
|
|
9581
9671
|
let existing = {};
|
|
9582
9672
|
try {
|
|
9583
|
-
existing = JSON.parse(await
|
|
9673
|
+
existing = JSON.parse(await fsp4.readFile(deps.paths.globalConfig, "utf8"));
|
|
9584
9674
|
} catch {
|
|
9585
9675
|
}
|
|
9586
9676
|
const mcpServers = existing.mcpServers ?? {};
|
|
@@ -9600,7 +9690,7 @@ async function addMcpServer(args, deps) {
|
|
|
9600
9690
|
async function removeMcpServer(name, deps) {
|
|
9601
9691
|
let existing = {};
|
|
9602
9692
|
try {
|
|
9603
|
-
existing = JSON.parse(await
|
|
9693
|
+
existing = JSON.parse(await fsp4.readFile(deps.paths.globalConfig, "utf8"));
|
|
9604
9694
|
} catch {
|
|
9605
9695
|
deps.renderer.writeError("No config file found.\n");
|
|
9606
9696
|
return 1;
|
|
@@ -9721,7 +9811,7 @@ function renderConfiguredPlugins(config) {
|
|
|
9721
9811
|
}
|
|
9722
9812
|
async function readConfig2(file) {
|
|
9723
9813
|
try {
|
|
9724
|
-
return JSON.parse(await
|
|
9814
|
+
return JSON.parse(await fsp4.readFile(file, "utf8"));
|
|
9725
9815
|
} catch {
|
|
9726
9816
|
return {};
|
|
9727
9817
|
}
|
|
@@ -9814,7 +9904,7 @@ var usageCmd = async (_args, deps) => {
|
|
|
9814
9904
|
var projectsCmd = async (_args, deps) => {
|
|
9815
9905
|
const projectsRoot = path8.join(deps.paths.globalRoot, "projects");
|
|
9816
9906
|
try {
|
|
9817
|
-
const entries = await
|
|
9907
|
+
const entries = await fsp4.readdir(projectsRoot);
|
|
9818
9908
|
if (entries.length === 0) {
|
|
9819
9909
|
deps.renderer.write("No projects tracked.\n");
|
|
9820
9910
|
return 0;
|
|
@@ -9822,7 +9912,7 @@ var projectsCmd = async (_args, deps) => {
|
|
|
9822
9912
|
for (const hash of entries) {
|
|
9823
9913
|
try {
|
|
9824
9914
|
const meta = JSON.parse(
|
|
9825
|
-
await
|
|
9915
|
+
await fsp4.readFile(path8.join(projectsRoot, hash, "meta.json"), "utf8")
|
|
9826
9916
|
);
|
|
9827
9917
|
deps.renderer.write(
|
|
9828
9918
|
` ${color.dim(hash)} ${color.dim(meta.lastSeen ?? "")} ${meta.root ?? "?"}
|
|
@@ -10032,7 +10122,7 @@ async function mutateModelsConfig(deps, mutator) {
|
|
|
10032
10122
|
let fileExists = true;
|
|
10033
10123
|
let raw;
|
|
10034
10124
|
try {
|
|
10035
|
-
raw = await
|
|
10125
|
+
raw = await fsp4.readFile(configPath2, "utf8");
|
|
10036
10126
|
} catch (err) {
|
|
10037
10127
|
if (err.code !== "ENOENT") throw err;
|
|
10038
10128
|
fileExists = false;
|
|
@@ -10193,7 +10283,7 @@ var sessionsFleetCmd = async (args, deps) => {
|
|
|
10193
10283
|
async function listFleetRuns(deps) {
|
|
10194
10284
|
let entries = [];
|
|
10195
10285
|
try {
|
|
10196
|
-
entries = await
|
|
10286
|
+
entries = await fsp4.readdir(deps.paths.projectSessions);
|
|
10197
10287
|
} catch {
|
|
10198
10288
|
deps.renderer.writeError(`Cannot read projectSessions: ${deps.paths.projectSessions}
|
|
10199
10289
|
`);
|
|
@@ -10204,7 +10294,7 @@ async function listFleetRuns(deps) {
|
|
|
10204
10294
|
const runDir = path8.join(deps.paths.projectSessions, id);
|
|
10205
10295
|
let stat4;
|
|
10206
10296
|
try {
|
|
10207
|
-
stat4 = await
|
|
10297
|
+
stat4 = await fsp4.stat(runDir);
|
|
10208
10298
|
} catch {
|
|
10209
10299
|
continue;
|
|
10210
10300
|
}
|
|
@@ -10214,18 +10304,18 @@ async function listFleetRuns(deps) {
|
|
|
10214
10304
|
let subagentCount = 0;
|
|
10215
10305
|
let subagentsDir;
|
|
10216
10306
|
try {
|
|
10217
|
-
await
|
|
10307
|
+
await fsp4.access(path8.join(runDir, "fleet.json"));
|
|
10218
10308
|
manifest = true;
|
|
10219
10309
|
} catch {
|
|
10220
10310
|
}
|
|
10221
10311
|
try {
|
|
10222
|
-
await
|
|
10312
|
+
await fsp4.access(path8.join(runDir, "checkpoint.json"));
|
|
10223
10313
|
checkpoint = true;
|
|
10224
10314
|
} catch {
|
|
10225
10315
|
}
|
|
10226
10316
|
try {
|
|
10227
10317
|
subagentsDir = path8.join(runDir, "subagents");
|
|
10228
|
-
const files = await
|
|
10318
|
+
const files = await fsp4.readdir(subagentsDir);
|
|
10229
10319
|
subagentCount = files.filter((f) => f.endsWith(".jsonl")).length;
|
|
10230
10320
|
} catch {
|
|
10231
10321
|
}
|
|
@@ -10256,7 +10346,7 @@ async function showFleetRun(runId, deps) {
|
|
|
10256
10346
|
const runDir = path8.join(deps.paths.projectSessions, runId);
|
|
10257
10347
|
let stat4;
|
|
10258
10348
|
try {
|
|
10259
|
-
stat4 = await
|
|
10349
|
+
stat4 = await fsp4.stat(runDir);
|
|
10260
10350
|
} catch {
|
|
10261
10351
|
deps.renderer.writeError(`Fleet run not found: ${runId}
|
|
10262
10352
|
`);
|
|
@@ -10273,7 +10363,7 @@ Fleet Run: ${runId}
|
|
|
10273
10363
|
const manifestPath = path8.join(runDir, "fleet.json");
|
|
10274
10364
|
let manifestData = null;
|
|
10275
10365
|
try {
|
|
10276
|
-
manifestData = await
|
|
10366
|
+
manifestData = await fsp4.readFile(manifestPath, "utf8");
|
|
10277
10367
|
const manifest = JSON.parse(manifestData);
|
|
10278
10368
|
const subagents = manifest.subagents ?? [];
|
|
10279
10369
|
const tasks = manifest.tasks ?? [];
|
|
@@ -10289,12 +10379,12 @@ Fleet Run: ${runId}
|
|
|
10289
10379
|
const checkpointPath = path8.join(runDir, "checkpoint.json");
|
|
10290
10380
|
let checkpointData = null;
|
|
10291
10381
|
try {
|
|
10292
|
-
checkpointData = await
|
|
10382
|
+
checkpointData = await fsp4.readFile(checkpointPath, "utf8");
|
|
10293
10383
|
const snap = JSON.parse(checkpointData);
|
|
10294
10384
|
const lockPath = `${checkpointPath}.lock`;
|
|
10295
10385
|
let lockStatus = color.dim("\u25CB no lock");
|
|
10296
10386
|
try {
|
|
10297
|
-
const lockRaw = await
|
|
10387
|
+
const lockRaw = await fsp4.readFile(lockPath, "utf8");
|
|
10298
10388
|
const lock = JSON.parse(lockRaw);
|
|
10299
10389
|
lockStatus = `${color.yellow("\u25B8")} lock held by pid ${lock.pid} on ${lock.hostname} (started ${lock.startedAt})`;
|
|
10300
10390
|
} catch {
|
|
@@ -10336,7 +10426,7 @@ Fleet Run: ${runId}
|
|
|
10336
10426
|
const subagentsDir = path8.join(runDir, "subagents");
|
|
10337
10427
|
let subagentFiles = [];
|
|
10338
10428
|
try {
|
|
10339
|
-
subagentFiles = await
|
|
10429
|
+
subagentFiles = await fsp4.readdir(subagentsDir);
|
|
10340
10430
|
subagentFiles = subagentFiles.filter((f) => f.endsWith(".jsonl"));
|
|
10341
10431
|
} catch {
|
|
10342
10432
|
}
|
|
@@ -10348,7 +10438,7 @@ Fleet Run: ${runId}
|
|
|
10348
10438
|
const filePath = path8.join(subagentsDir, f);
|
|
10349
10439
|
let size;
|
|
10350
10440
|
try {
|
|
10351
|
-
const s = await
|
|
10441
|
+
const s = await fsp4.stat(filePath);
|
|
10352
10442
|
size = s.size;
|
|
10353
10443
|
} catch {
|
|
10354
10444
|
size = 0;
|
|
@@ -10364,7 +10454,7 @@ Fleet Run: ${runId}
|
|
|
10364
10454
|
}
|
|
10365
10455
|
const sharedDir = path8.join(runDir, "shared");
|
|
10366
10456
|
try {
|
|
10367
|
-
const files = await
|
|
10457
|
+
const files = await fsp4.readdir(sharedDir);
|
|
10368
10458
|
deps.renderer.write(`
|
|
10369
10459
|
Shared scratchpad: ${files.length} file(s)
|
|
10370
10460
|
`);
|
|
@@ -10764,10 +10854,10 @@ var auditCmd = async (args, deps) => {
|
|
|
10764
10854
|
return verify.ok ? 0 : 1;
|
|
10765
10855
|
};
|
|
10766
10856
|
async function listAudits(log, dir, deps) {
|
|
10767
|
-
const
|
|
10857
|
+
const fs26 = await import('fs/promises');
|
|
10768
10858
|
let entries;
|
|
10769
10859
|
try {
|
|
10770
|
-
entries = await
|
|
10860
|
+
entries = await fs26.readdir(dir);
|
|
10771
10861
|
} catch {
|
|
10772
10862
|
deps.renderer.write(
|
|
10773
10863
|
color.dim(`No sessions dir found at ${dir}. Run a session first.`) + "\n"
|
|
@@ -10918,22 +11008,22 @@ function fmtDuration(ms) {
|
|
|
10918
11008
|
const remMin = m - h * 60;
|
|
10919
11009
|
return `${h}h${remMin}m`;
|
|
10920
11010
|
}
|
|
10921
|
-
function fmtTaskResultLine(r,
|
|
11011
|
+
function fmtTaskResultLine(r, color49) {
|
|
10922
11012
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
10923
11013
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
10924
11014
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
10925
11015
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
10926
|
-
const errKindChip = errKind ?
|
|
10927
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
11016
|
+
const errKindChip = errKind ? color49.dim(` [${errKind}]`) : "";
|
|
11017
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color49.dim(errTail)}` : "";
|
|
10928
11018
|
switch (r.status) {
|
|
10929
11019
|
case "success":
|
|
10930
|
-
return { mark:
|
|
11020
|
+
return { mark: color49.green("\u2713"), stats, tail: "" };
|
|
10931
11021
|
case "timeout":
|
|
10932
|
-
return { mark:
|
|
11022
|
+
return { mark: color49.yellow("\u23F1"), stats: `${color49.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
10933
11023
|
case "stopped":
|
|
10934
|
-
return { mark:
|
|
11024
|
+
return { mark: color49.dim("\u2298"), stats: `${color49.dim("stopped")} ${stats}`, tail: errSnip };
|
|
10935
11025
|
case "failed":
|
|
10936
|
-
return { mark:
|
|
11026
|
+
return { mark: color49.red("\u2717"), stats: `${color49.red("failed")} ${stats}`, tail: errSnip };
|
|
10937
11027
|
}
|
|
10938
11028
|
}
|
|
10939
11029
|
|
|
@@ -11057,20 +11147,51 @@ async function boot(argv) {
|
|
|
11057
11147
|
const modelFlag = typeof flags["model"] === "string" ? flags["model"] : void 0;
|
|
11058
11148
|
if (!(!!providerFlag && !!modelFlag)) {
|
|
11059
11149
|
if (isStdinTTY()) {
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11067
|
-
|
|
11068
|
-
|
|
11150
|
+
let picked;
|
|
11151
|
+
let skipPicker = false;
|
|
11152
|
+
const savedProvider = config.provider;
|
|
11153
|
+
const savedModel = config.model;
|
|
11154
|
+
if (savedProvider && savedModel) {
|
|
11155
|
+
renderer.write(
|
|
11156
|
+
`
|
|
11157
|
+
${color.dim("Last settings:")} ${color.bold(savedProvider)} / ${color.bold(savedModel)}
|
|
11158
|
+
`
|
|
11159
|
+
);
|
|
11160
|
+
const answer = (await reader.readLine(
|
|
11161
|
+
` ${color.amber("?")} Continue with these? ${color.dim("[Y/n/q]")} `
|
|
11162
|
+
)).trim().toLowerCase();
|
|
11163
|
+
if (answer === "q") {
|
|
11164
|
+
renderer.write(color.dim(" Goodbye!\n"));
|
|
11165
|
+
await reader.close();
|
|
11166
|
+
return 0;
|
|
11167
|
+
}
|
|
11168
|
+
if (answer !== "n" && answer !== "no") {
|
|
11169
|
+
skipPicker = true;
|
|
11170
|
+
renderer.write(
|
|
11171
|
+
`
|
|
11172
|
+
${color.green("\u25B6")} ${color.bold(savedProvider)} / ${color.bold(savedModel)}
|
|
11173
|
+
|
|
11174
|
+
`
|
|
11175
|
+
);
|
|
11176
|
+
}
|
|
11177
|
+
}
|
|
11178
|
+
if (!skipPicker) {
|
|
11179
|
+
picked = await runPicker({
|
|
11180
|
+
modelsRegistry,
|
|
11181
|
+
renderer,
|
|
11182
|
+
reader,
|
|
11183
|
+
config,
|
|
11184
|
+
defaultProvider: providerFlag ?? config.provider,
|
|
11185
|
+
defaultModel: modelFlag ?? config.model
|
|
11186
|
+
});
|
|
11187
|
+
}
|
|
11188
|
+
if (!picked && !skipPicker) {
|
|
11069
11189
|
if (!config.provider || !config.model) {
|
|
11070
11190
|
await reader.close();
|
|
11071
11191
|
return 2;
|
|
11072
11192
|
}
|
|
11073
|
-
}
|
|
11193
|
+
}
|
|
11194
|
+
if (picked) {
|
|
11074
11195
|
const prevProvider = config.provider;
|
|
11075
11196
|
const prevModel = config.model;
|
|
11076
11197
|
config = patchConfig(config, { provider: picked.provider, model: picked.model });
|
|
@@ -11080,8 +11201,15 @@ async function boot(argv) {
|
|
|
11080
11201
|
picked.provider,
|
|
11081
11202
|
picked.model
|
|
11082
11203
|
);
|
|
11083
|
-
if (saved)
|
|
11204
|
+
if (saved) {
|
|
11205
|
+
renderer.writeInfo(`Saved ${picked.provider}/${picked.model} as default.
|
|
11084
11206
|
`);
|
|
11207
|
+
} else {
|
|
11208
|
+
renderer.writeWarning(
|
|
11209
|
+
`Could not save ${picked.provider}/${picked.model} to config. Check permissions or disk space.
|
|
11210
|
+
`
|
|
11211
|
+
);
|
|
11212
|
+
}
|
|
11085
11213
|
}
|
|
11086
11214
|
}
|
|
11087
11215
|
} else if (!config.provider || !config.model) {
|
|
@@ -11114,6 +11242,12 @@ async function boot(argv) {
|
|
|
11114
11242
|
} else if (flags["autonomy"] === true) {
|
|
11115
11243
|
autonomyPinned = "auto";
|
|
11116
11244
|
}
|
|
11245
|
+
const lastChoices = config.launch ? {
|
|
11246
|
+
mode: config.launch.mode ?? "tui",
|
|
11247
|
+
yolo: config.yolo ?? true,
|
|
11248
|
+
director: config.launch.director ?? true,
|
|
11249
|
+
autonomy: config.launch.autonomy ?? "auto"
|
|
11250
|
+
} : void 0;
|
|
11117
11251
|
let choices;
|
|
11118
11252
|
try {
|
|
11119
11253
|
choices = await runLaunchPrompts({
|
|
@@ -11122,7 +11256,8 @@ async function boot(argv) {
|
|
|
11122
11256
|
modePinned,
|
|
11123
11257
|
yoloPinned,
|
|
11124
11258
|
directorPinned,
|
|
11125
|
-
autonomyPinned
|
|
11259
|
+
autonomyPinned,
|
|
11260
|
+
lastChoices
|
|
11126
11261
|
});
|
|
11127
11262
|
} catch (err) {
|
|
11128
11263
|
if (err instanceof LaunchAbortedError) {
|
|
@@ -11141,6 +11276,10 @@ async function boot(argv) {
|
|
|
11141
11276
|
if (choices.yolo !== config.yolo) config = patchConfig(config, { yolo: choices.yolo });
|
|
11142
11277
|
if (choices.director) flags["director"] = true;
|
|
11143
11278
|
flags["autonomy"] = choices.autonomy;
|
|
11279
|
+
try {
|
|
11280
|
+
await persistLaunchChoices(wpaths.globalConfig, choices);
|
|
11281
|
+
} catch {
|
|
11282
|
+
}
|
|
11144
11283
|
printLaunchHints(renderer, flags, {
|
|
11145
11284
|
cursorFile: path8.join(wpaths.cacheDir, "hint-cursor")
|
|
11146
11285
|
});
|
|
@@ -11534,7 +11673,7 @@ async function runRepl(opts) {
|
|
|
11534
11673
|
`[eternal] ${err instanceof Error ? err.message : String(err)}`
|
|
11535
11674
|
);
|
|
11536
11675
|
}
|
|
11537
|
-
await new Promise((
|
|
11676
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
11538
11677
|
continue;
|
|
11539
11678
|
}
|
|
11540
11679
|
} else if (opts.getAutonomy?.() === "eternal-parallel") {
|
|
@@ -11580,7 +11719,7 @@ async function runRepl(opts) {
|
|
|
11580
11719
|
`[parallel] ${err instanceof Error ? err.message : String(err)}`
|
|
11581
11720
|
);
|
|
11582
11721
|
}
|
|
11583
|
-
await new Promise((
|
|
11722
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
11584
11723
|
continue;
|
|
11585
11724
|
}
|
|
11586
11725
|
}
|
|
@@ -12059,10 +12198,10 @@ var EMPTY = "\u2591";
|
|
|
12059
12198
|
function renderContextChip(used, max) {
|
|
12060
12199
|
const ratio = Math.max(0, Math.min(1, used / max));
|
|
12061
12200
|
const pct2 = Math.round(ratio * 100);
|
|
12062
|
-
const bar =
|
|
12201
|
+
const bar = renderProgress3(ratio, 6);
|
|
12063
12202
|
return `${bar} ${pct2}% (${fmtTok(used)}/${fmtTok(max)})`;
|
|
12064
12203
|
}
|
|
12065
|
-
function
|
|
12204
|
+
function renderProgress3(ratio, width) {
|
|
12066
12205
|
const clamped = Math.max(0, Math.min(1, ratio));
|
|
12067
12206
|
const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
|
|
12068
12207
|
const capped = Math.min(width, filled);
|
|
@@ -12348,15 +12487,10 @@ async function execute(deps) {
|
|
|
12348
12487
|
},
|
|
12349
12488
|
effectiveMaxContext,
|
|
12350
12489
|
// Default OFF so the terminal's native scrollback works for chat
|
|
12351
|
-
// history out of the box
|
|
12352
|
-
//
|
|
12353
|
-
// `--
|
|
12490
|
+
// history out of the box. Users who hit resize/overlay-leak
|
|
12491
|
+
// artifacts can opt back into alt-screen with `--alt-screen`.
|
|
12492
|
+
// `--no-alt-screen` still wins when both are passed.
|
|
12354
12493
|
altScreen: flags["alt-screen"] === true && flags["no-alt-screen"] !== true,
|
|
12355
|
-
// Mouse mode is DISABLED. It was unreliable on Windows consoles
|
|
12356
|
-
// (freezes / constant repaint in the managed viewport) and is not
|
|
12357
|
-
// wanted, so `--mouse` is intentionally ignored and never engages —
|
|
12358
|
-
// the TUI stays keyboard-only. Do not re-wire `flags.mouse` here.
|
|
12359
|
-
mouse: false,
|
|
12360
12494
|
director,
|
|
12361
12495
|
fleetRoster,
|
|
12362
12496
|
onAfterExit: () => {
|
|
@@ -12502,6 +12636,22 @@ async function execute(deps) {
|
|
|
12502
12636
|
}
|
|
12503
12637
|
return code;
|
|
12504
12638
|
}
|
|
12639
|
+
function buildRoutingRunner(config, host) {
|
|
12640
|
+
const standardRunner = makeAgentSubagentRunner({
|
|
12641
|
+
factory: host.makeSubagentFactory(config),
|
|
12642
|
+
fleetBus: host.getDirector()?.fleet ?? NULL_FLEET_BUS
|
|
12643
|
+
});
|
|
12644
|
+
return async (task, ctx) => {
|
|
12645
|
+
const subCfg = ctx.config;
|
|
12646
|
+
if (subCfg.provider === "acp") {
|
|
12647
|
+
const cacheKey = subCfg.role ?? subCfg.name ?? subCfg.id;
|
|
12648
|
+
return host.buildACPRunner(cacheKey).then((r) => r(task, ctx));
|
|
12649
|
+
}
|
|
12650
|
+
return standardRunner(task, ctx);
|
|
12651
|
+
};
|
|
12652
|
+
}
|
|
12653
|
+
|
|
12654
|
+
// src/fleet/host.ts
|
|
12505
12655
|
var MultiAgentHost = class {
|
|
12506
12656
|
constructor(deps, opts = {}) {
|
|
12507
12657
|
this.deps = deps;
|
|
@@ -12703,8 +12853,10 @@ var MultiAgentHost = class {
|
|
|
12703
12853
|
// meaningless to a single delegated subtask.
|
|
12704
12854
|
subagent: true
|
|
12705
12855
|
});
|
|
12706
|
-
|
|
12707
|
-
|
|
12856
|
+
baseSystem.unshift({ type: "text", text: DEFAULT_SUBAGENT_BASELINE });
|
|
12857
|
+
const rolePrompt = subCfg.systemPromptOverride ?? (subCfg.role ? FLEET_ROSTER[subCfg.role]?.prompt : void 0);
|
|
12858
|
+
if (rolePrompt) {
|
|
12859
|
+
baseSystem.push({ type: "text", text: rolePrompt });
|
|
12708
12860
|
}
|
|
12709
12861
|
let subSession;
|
|
12710
12862
|
if (this.sessionFactory) {
|
|
@@ -13133,20 +13285,6 @@ var MultiAgentHost = class {
|
|
|
13133
13285
|
}
|
|
13134
13286
|
}
|
|
13135
13287
|
};
|
|
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
13288
|
function makePromptDelegate(reader) {
|
|
13151
13289
|
return async (tool, input, suggestedPattern) => {
|
|
13152
13290
|
writeOut("\x07");
|
|
@@ -13248,11 +13386,11 @@ var SessionStats = class {
|
|
|
13248
13386
|
if (e.name === "bash") this.bashCommands++;
|
|
13249
13387
|
else if (e.name === "fetch") this.fetches++;
|
|
13250
13388
|
if (!e.ok) return;
|
|
13251
|
-
const
|
|
13252
|
-
if (e.name === "read" &&
|
|
13253
|
-
else if (e.name === "edit" &&
|
|
13254
|
-
else if (e.name === "write" &&
|
|
13255
|
-
this.writtenPaths.add(
|
|
13389
|
+
const path26 = typeof input?.path === "string" ? input.path : void 0;
|
|
13390
|
+
if (e.name === "read" && path26) this.readPaths.add(path26);
|
|
13391
|
+
else if (e.name === "edit" && path26) this.editedPaths.add(path26);
|
|
13392
|
+
else if (e.name === "write" && path26) {
|
|
13393
|
+
this.writtenPaths.add(path26);
|
|
13256
13394
|
const content = typeof input?.content === "string" ? input.content : "";
|
|
13257
13395
|
this.bytesWritten += Buffer.byteLength(content, "utf8");
|
|
13258
13396
|
}
|
|
@@ -13358,7 +13496,7 @@ function samplePaths(set) {
|
|
|
13358
13496
|
}
|
|
13359
13497
|
var WORKTREE_PHASE_CONCURRENCY = 4;
|
|
13360
13498
|
function gitText(args, cwd) {
|
|
13361
|
-
return new Promise((
|
|
13499
|
+
return new Promise((resolve5) => {
|
|
13362
13500
|
let out = "";
|
|
13363
13501
|
const child = spawn("git", args, {
|
|
13364
13502
|
cwd,
|
|
@@ -13371,8 +13509,8 @@ function gitText(args, cwd) {
|
|
|
13371
13509
|
child.stderr?.on("data", (c) => {
|
|
13372
13510
|
out += c.toString();
|
|
13373
13511
|
});
|
|
13374
|
-
child.on("error", () =>
|
|
13375
|
-
child.on("close", (code) =>
|
|
13512
|
+
child.on("error", () => resolve5({ code: 1, out }));
|
|
13513
|
+
child.on("close", (code) => resolve5({ code: code ?? 1, out: out.trim() }));
|
|
13376
13514
|
});
|
|
13377
13515
|
}
|
|
13378
13516
|
async function isGitRepo(cwd) {
|
|
@@ -13380,7 +13518,7 @@ async function isGitRepo(cwd) {
|
|
|
13380
13518
|
return code === 0 && out.trim() === "true";
|
|
13381
13519
|
}
|
|
13382
13520
|
function runCmd(cmd, args, cwd, shell = false) {
|
|
13383
|
-
return new Promise((
|
|
13521
|
+
return new Promise((resolve5) => {
|
|
13384
13522
|
let out = "";
|
|
13385
13523
|
const child = spawn(cmd, args, {
|
|
13386
13524
|
cwd,
|
|
@@ -13394,8 +13532,8 @@ function runCmd(cmd, args, cwd, shell = false) {
|
|
|
13394
13532
|
child.stderr?.on("data", (c) => {
|
|
13395
13533
|
out += c.toString();
|
|
13396
13534
|
});
|
|
13397
|
-
child.on("error", (e) =>
|
|
13398
|
-
child.on("close", (code) =>
|
|
13535
|
+
child.on("error", (e) => resolve5({ code: 1, out: `${out}${String(e)}` }));
|
|
13536
|
+
child.on("close", (code) => resolve5({ code: code ?? 1, out: out.trim() }));
|
|
13399
13537
|
});
|
|
13400
13538
|
}
|
|
13401
13539
|
function detectPackageManager2(root) {
|
|
@@ -13779,10 +13917,10 @@ function renderContextChip2(ctx) {
|
|
|
13779
13917
|
const ratio = Math.max(0, Math.min(1, ctx.used / ctx.max));
|
|
13780
13918
|
const pct2 = Math.round(ratio * 100);
|
|
13781
13919
|
const chipColor = ratio >= 0.85 ? color.red : ratio >= 0.65 ? color.yellow : color.cyan;
|
|
13782
|
-
const bar =
|
|
13920
|
+
const bar = renderProgress4(ratio, 8);
|
|
13783
13921
|
return color.dim("ctx ") + chipColor(bar) + chipColor(` ${pct2}%`) + color.dim(` (${fmtTok(ctx.used)}/${fmtTok(ctx.max)})`);
|
|
13784
13922
|
}
|
|
13785
|
-
function
|
|
13923
|
+
function renderProgress4(ratio, width) {
|
|
13786
13924
|
const clamped = Math.max(0, Math.min(1, ratio));
|
|
13787
13925
|
const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped * width));
|
|
13788
13926
|
const capped = Math.min(width, filled);
|
|
@@ -14042,7 +14180,7 @@ function setupMetrics(params) {
|
|
|
14042
14180
|
name: "session-store",
|
|
14043
14181
|
check: async () => {
|
|
14044
14182
|
try {
|
|
14045
|
-
await
|
|
14183
|
+
await fsp4.access(wpaths.projectSessions);
|
|
14046
14184
|
return { status: "healthy" };
|
|
14047
14185
|
} catch (e) {
|
|
14048
14186
|
return { status: "unhealthy", detail: e instanceof Error ? e.message : "access denied" };
|
|
@@ -14089,6 +14227,91 @@ function setupMetrics(params) {
|
|
|
14089
14227
|
}
|
|
14090
14228
|
return { metricsSink, healthRegistry, metricsServerHandle };
|
|
14091
14229
|
}
|
|
14230
|
+
var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "multi-edit", "notebook-edit"]);
|
|
14231
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
14232
|
+
"node_modules",
|
|
14233
|
+
".git",
|
|
14234
|
+
"dist",
|
|
14235
|
+
"build",
|
|
14236
|
+
".next",
|
|
14237
|
+
"coverage",
|
|
14238
|
+
".turbo",
|
|
14239
|
+
"__snapshots__",
|
|
14240
|
+
".nyc_output"
|
|
14241
|
+
]);
|
|
14242
|
+
function isIgnored(rel) {
|
|
14243
|
+
return rel.split(/[/\\]/).some((seg) => IGNORE_DIRS.has(seg));
|
|
14244
|
+
}
|
|
14245
|
+
async function setupCodebaseIndexing(deps) {
|
|
14246
|
+
const { config, pipelines, projectRoot, logger } = deps;
|
|
14247
|
+
const idx = config.indexing;
|
|
14248
|
+
if (!idx) return () => {
|
|
14249
|
+
};
|
|
14250
|
+
const debounceMs = idx.debounceMs ?? 400;
|
|
14251
|
+
const onError = (err) => logger.debug(`codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
14252
|
+
if (idx.onSessionStart) {
|
|
14253
|
+
void runStartupIndex({ projectRoot }).then((r) => {
|
|
14254
|
+
const summary = `${color.green("\u2713")} codebase index ready ${color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`)}`;
|
|
14255
|
+
process.stderr.write(`
|
|
14256
|
+
${summary}
|
|
14257
|
+
`);
|
|
14258
|
+
}).catch((err) => {
|
|
14259
|
+
logger.warn(
|
|
14260
|
+
`codebase index (startup) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
14261
|
+
);
|
|
14262
|
+
});
|
|
14263
|
+
}
|
|
14264
|
+
if (idx.onEdit) {
|
|
14265
|
+
pipelines.toolCall.use({
|
|
14266
|
+
name: "CodebaseAutoIndex",
|
|
14267
|
+
// Non-core owner → the pipeline error boundary swallows failures instead
|
|
14268
|
+
// of failing the turn (see wiring/pipeline.ts).
|
|
14269
|
+
owner: "codebase-index",
|
|
14270
|
+
handler: async (payload, next) => {
|
|
14271
|
+
try {
|
|
14272
|
+
const tool = payload.tool;
|
|
14273
|
+
if (tool?.mutating && FILE_EDIT_TOOLS.has(tool.name)) {
|
|
14274
|
+
const fp = payload.toolUse.input?.file_path;
|
|
14275
|
+
if (typeof fp === "string" && fp.length > 0) {
|
|
14276
|
+
const abs = path8.resolve(payload.ctx.cwd, fp);
|
|
14277
|
+
if (isIndexableFile(abs)) {
|
|
14278
|
+
enqueueReindex({ projectRoot, files: [abs], debounceMs, onError });
|
|
14279
|
+
}
|
|
14280
|
+
}
|
|
14281
|
+
}
|
|
14282
|
+
} catch {
|
|
14283
|
+
}
|
|
14284
|
+
return next(payload);
|
|
14285
|
+
}
|
|
14286
|
+
});
|
|
14287
|
+
}
|
|
14288
|
+
let watcher;
|
|
14289
|
+
if (idx.watchExternal) {
|
|
14290
|
+
try {
|
|
14291
|
+
watcher = fs12.watch(projectRoot, { recursive: true }, (_event, filename) => {
|
|
14292
|
+
if (!filename) return;
|
|
14293
|
+
const rel = filename.toString();
|
|
14294
|
+
if (isIgnored(rel)) return;
|
|
14295
|
+
const abs = path8.resolve(projectRoot, rel);
|
|
14296
|
+
if (!isIndexableFile(abs)) return;
|
|
14297
|
+
enqueueReindex({ projectRoot, files: [abs], debounceMs, onError });
|
|
14298
|
+
});
|
|
14299
|
+
watcher.on("error", (err) => logger.debug(`codebase index watcher error: ${err}`));
|
|
14300
|
+
watcher.unref?.();
|
|
14301
|
+
} catch (err) {
|
|
14302
|
+
logger.debug(
|
|
14303
|
+
`codebase index watcher unavailable: ${err instanceof Error ? err.message : String(err)}`
|
|
14304
|
+
);
|
|
14305
|
+
}
|
|
14306
|
+
}
|
|
14307
|
+
return () => {
|
|
14308
|
+
try {
|
|
14309
|
+
watcher?.close();
|
|
14310
|
+
} catch {
|
|
14311
|
+
}
|
|
14312
|
+
cancelPendingReindexes();
|
|
14313
|
+
};
|
|
14314
|
+
}
|
|
14092
14315
|
function createApi(ownerName, base) {
|
|
14093
14316
|
return new DefaultPluginAPI({ ownerName, ...base });
|
|
14094
14317
|
}
|
|
@@ -14425,21 +14648,6 @@ async function promptRecovery(reader, renderer, abandoned, autoRecover) {
|
|
|
14425
14648
|
);
|
|
14426
14649
|
return answer;
|
|
14427
14650
|
}
|
|
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
14651
|
async function launchEternalFromFlag(deps) {
|
|
14444
14652
|
const { eternalFlag } = deps;
|
|
14445
14653
|
if (eternalFlag.length === 0) return false;
|
|
@@ -14475,7 +14683,7 @@ async function launchEternalFromFlag(deps) {
|
|
|
14475
14683
|
return true;
|
|
14476
14684
|
}
|
|
14477
14685
|
|
|
14478
|
-
// src/
|
|
14686
|
+
// src/cli-main.ts
|
|
14479
14687
|
async function main(argv) {
|
|
14480
14688
|
const ctx = await boot(argv);
|
|
14481
14689
|
if (typeof ctx === "number") return ctx;
|
|
@@ -14912,7 +15120,8 @@ async function main(argv) {
|
|
|
14912
15120
|
const directorMode = flags["director"] === true || typeof flags["resume"] === "string";
|
|
14913
15121
|
const maxConcurrentFromFlag = typeof flags["max-concurrent"] === "string" ? Number.parseInt(flags["max-concurrent"], 10) : void 0;
|
|
14914
15122
|
const maxConcurrentFromEnv = typeof process.env["WRONGSTACK_MAX_CONCURRENT"] === "string" ? Number.parseInt(process.env["WRONGSTACK_MAX_CONCURRENT"], 10) : void 0;
|
|
14915
|
-
const
|
|
15123
|
+
const maxConcurrentFromConfig = typeof config.maxConcurrent === "number" && config.maxConcurrent > 0 ? config.maxConcurrent : void 0;
|
|
15124
|
+
const maxConcurrent = Number.isFinite(maxConcurrentFromFlag) && maxConcurrentFromFlag > 0 ? maxConcurrentFromFlag : Number.isFinite(maxConcurrentFromEnv) && maxConcurrentFromEnv > 0 ? maxConcurrentFromEnv : Number.isFinite(maxConcurrentFromConfig) && maxConcurrentFromConfig > 0 ? maxConcurrentFromConfig : void 0;
|
|
14916
15125
|
let director = null;
|
|
14917
15126
|
let autonomyMode = (() => {
|
|
14918
15127
|
const v = flags["autonomy"];
|
|
@@ -15242,6 +15451,7 @@ async function main(argv) {
|
|
|
15242
15451
|
}
|
|
15243
15452
|
try {
|
|
15244
15453
|
multiAgentHost.setMaxConcurrent(n);
|
|
15454
|
+
events.emit("concurrency.changed", { n });
|
|
15245
15455
|
} catch (err) {
|
|
15246
15456
|
return err instanceof Error ? err.message : String(err);
|
|
15247
15457
|
}
|
|
@@ -15296,7 +15506,7 @@ async function main(argv) {
|
|
|
15296
15506
|
const subagentsRoot = path8.join(fleetRootForPromotion, "subagents");
|
|
15297
15507
|
let runDirs;
|
|
15298
15508
|
try {
|
|
15299
|
-
runDirs = await
|
|
15509
|
+
runDirs = await fsp4.readdir(subagentsRoot);
|
|
15300
15510
|
} catch {
|
|
15301
15511
|
return "No fleet transcripts on disk \u2014 no subagents have been spawned for this session.";
|
|
15302
15512
|
}
|
|
@@ -15305,7 +15515,7 @@ async function main(argv) {
|
|
|
15305
15515
|
const runDir = path8.join(subagentsRoot, runId);
|
|
15306
15516
|
let files;
|
|
15307
15517
|
try {
|
|
15308
|
-
files = await
|
|
15518
|
+
files = await fsp4.readdir(runDir);
|
|
15309
15519
|
} catch {
|
|
15310
15520
|
continue;
|
|
15311
15521
|
}
|
|
@@ -15313,7 +15523,7 @@ async function main(argv) {
|
|
|
15313
15523
|
if (!f.endsWith(".jsonl")) continue;
|
|
15314
15524
|
const full = path8.join(runDir, f);
|
|
15315
15525
|
try {
|
|
15316
|
-
const stat4 = await
|
|
15526
|
+
const stat4 = await fsp4.stat(full);
|
|
15317
15527
|
found.push({
|
|
15318
15528
|
runId,
|
|
15319
15529
|
subagentId: f.replace(/\.jsonl$/, ""),
|
|
@@ -15354,7 +15564,7 @@ async function main(argv) {
|
|
|
15354
15564
|
].join("\n");
|
|
15355
15565
|
}
|
|
15356
15566
|
const t = matches[0];
|
|
15357
|
-
const raw = await
|
|
15567
|
+
const raw = await fsp4.readFile(t.file, "utf8");
|
|
15358
15568
|
if (mode === "raw") return raw;
|
|
15359
15569
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
15360
15570
|
const counts = {};
|
|
@@ -15610,7 +15820,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15610
15820
|
const { spawn: spawn3 } = await import('child_process');
|
|
15611
15821
|
const cwd2 = projectRoot;
|
|
15612
15822
|
const statusResult = await new Promise(
|
|
15613
|
-
(
|
|
15823
|
+
(resolve5, reject) => {
|
|
15614
15824
|
const child = spawn3("git", ["status", "--porcelain"], {
|
|
15615
15825
|
cwd: cwd2,
|
|
15616
15826
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -15620,7 +15830,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15620
15830
|
stdout += d;
|
|
15621
15831
|
});
|
|
15622
15832
|
child.on("error", reject);
|
|
15623
|
-
child.on("close", (code) =>
|
|
15833
|
+
child.on("close", (code) => resolve5({ stdout, code: code ?? 0 }));
|
|
15624
15834
|
}
|
|
15625
15835
|
);
|
|
15626
15836
|
if (statusResult.stdout.trim().length > 0) {
|
|
@@ -15746,6 +15956,13 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15746
15956
|
if (eternalFlag.length > 0) {
|
|
15747
15957
|
autonomyMode = "eternal";
|
|
15748
15958
|
}
|
|
15959
|
+
const disposeIndexing = await setupCodebaseIndexing({
|
|
15960
|
+
config,
|
|
15961
|
+
pipelines,
|
|
15962
|
+
projectRoot,
|
|
15963
|
+
logger
|
|
15964
|
+
});
|
|
15965
|
+
process.once("exit", disposeIndexing);
|
|
15749
15966
|
const savedProviderCfg = config.providers?.[config.provider];
|
|
15750
15967
|
return execute({
|
|
15751
15968
|
agent,
|
|
@@ -15805,6 +16022,23 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15805
16022
|
skillLoader: config.features.skills ? skillLoader : void 0
|
|
15806
16023
|
});
|
|
15807
16024
|
}
|
|
16025
|
+
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");
|
|
16026
|
+
function runAsMain(mainFn) {
|
|
16027
|
+
if (!isMain) return;
|
|
16028
|
+
mainFn(process.argv.slice(2)).then(
|
|
16029
|
+
(c) => {
|
|
16030
|
+
process.exitCode = c;
|
|
16031
|
+
setTimeout(() => process.exit(c), 500).unref();
|
|
16032
|
+
},
|
|
16033
|
+
(err) => {
|
|
16034
|
+
writeErr((err instanceof Error ? err.stack : String(err)) + "\n");
|
|
16035
|
+
process.exitCode = 1;
|
|
16036
|
+
setTimeout(() => process.exit(1), 500).unref();
|
|
16037
|
+
}
|
|
16038
|
+
);
|
|
16039
|
+
}
|
|
16040
|
+
|
|
16041
|
+
// src/index.ts
|
|
15808
16042
|
runAsMain(main);
|
|
15809
16043
|
|
|
15810
16044
|
export { CLI_VERSION, main };
|