@wrongstack/cli 0.77.0 → 0.82.6
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/README.md +1 -2
- package/dist/index.js +453 -114
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$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, InputBuilder, FsError } from '@wrongstack/core';
|
|
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, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, bootConfig as bootConfig$1, setOutputLineGuard, 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, InputBuilder, FsError } from '@wrongstack/core';
|
|
3
3
|
import * as path8 from 'path';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import * as fsp4 from 'fs/promises';
|
|
@@ -132,6 +132,12 @@ var init_state = __esm({
|
|
|
132
132
|
sddState = new SDDState();
|
|
133
133
|
}
|
|
134
134
|
});
|
|
135
|
+
function expectDefined3(value) {
|
|
136
|
+
if (value === null || value === void 0) {
|
|
137
|
+
throw new Error("Expected value to be defined");
|
|
138
|
+
}
|
|
139
|
+
return value;
|
|
140
|
+
}
|
|
135
141
|
function formatElapsed(ms) {
|
|
136
142
|
if (ms < 1e3) return `${ms}ms`;
|
|
137
143
|
const s = Math.floor(ms / 1e3);
|
|
@@ -195,7 +201,7 @@ function getCurrentTask() {
|
|
|
195
201
|
if (!tracker) return null;
|
|
196
202
|
const nodes = tracker.getAllNodes({ status: ["in_progress"] });
|
|
197
203
|
if (nodes.length === 0) return null;
|
|
198
|
-
const n = nodes[0];
|
|
204
|
+
const n = expectDefined3(nodes[0]);
|
|
199
205
|
return { id: n.id, title: n.title, description: n.description, priority: n.priority, estimateHours: n.estimateHours ?? 0, tags: n.tags ?? [], startedAt: n.startedAt };
|
|
200
206
|
}
|
|
201
207
|
function advanceToNextTask() {
|
|
@@ -234,7 +240,7 @@ function renderTaskListWithProgress() {
|
|
|
234
240
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
235
241
|
});
|
|
236
242
|
for (let i = 0; i < sorted.length; i++) {
|
|
237
|
-
const n = sorted[i];
|
|
243
|
+
const n = expectDefined3(sorted[i]);
|
|
238
244
|
const status = n.status === "completed" ? "\u2705" : n.status === "in_progress" ? "\u{1F504}" : n.status === "failed" ? "\u274C" : n.status === "blocked" ? "\u{1F6AB}" : n.status === "review" ? "\u{1F441}" : "\u23F3";
|
|
239
245
|
const title = n.title.length > 50 ? n.title.slice(0, 49) + "\u2026" : n.title;
|
|
240
246
|
let elapsed = "";
|
|
@@ -248,7 +254,7 @@ function getCurrentExecutingContext() {
|
|
|
248
254
|
if (!tracker) return null;
|
|
249
255
|
const nodes = tracker.getAllNodes({ status: ["in_progress"] });
|
|
250
256
|
if (nodes.length === 0) return null;
|
|
251
|
-
const n = nodes[0];
|
|
257
|
+
const n = expectDefined3(nodes[0]);
|
|
252
258
|
const elapsed = n.startedAt ? ` \xB7 elapsed: ${formatElapsed(Date.now() - n.startedAt)}` : "";
|
|
253
259
|
const progress = tracker.getProgress();
|
|
254
260
|
return [
|
|
@@ -556,6 +562,12 @@ __export(sdd_exports, {
|
|
|
556
562
|
trySaveSpecFromAIOutput: () => trySaveSpecFromAIOutput,
|
|
557
563
|
trySaveTasksFromAIOutput: () => trySaveTasksFromAIOutput
|
|
558
564
|
});
|
|
565
|
+
function expectDefined4(value) {
|
|
566
|
+
if (value === null || value === void 0) {
|
|
567
|
+
throw new Error("Expected value to be defined");
|
|
568
|
+
}
|
|
569
|
+
return value;
|
|
570
|
+
}
|
|
559
571
|
function getTaskTracker() {
|
|
560
572
|
return getTaskTrackerExport();
|
|
561
573
|
}
|
|
@@ -563,6 +575,7 @@ function buildSddCommand(opts) {
|
|
|
563
575
|
const sessionState = getSessionState(opts.context);
|
|
564
576
|
return {
|
|
565
577
|
name: "sdd",
|
|
578
|
+
category: "Agent",
|
|
566
579
|
description: "AI-driven SDD: /sdd [new|approve|execute|cancel|status|list|show|templates]",
|
|
567
580
|
async run(args) {
|
|
568
581
|
if (!opts.paths) return { message: "SDD not available \u2014 paths not configured." };
|
|
@@ -620,7 +633,7 @@ function buildSddCommand(opts) {
|
|
|
620
633
|
}));
|
|
621
634
|
sddState.setSessionStartTime(Date.now());
|
|
622
635
|
sddState.setPhaseStartTime(Date.now());
|
|
623
|
-
const builder = sddState.getBuilder();
|
|
636
|
+
const builder = expectDefined4(sddState.getBuilder());
|
|
624
637
|
builder.startSession(title);
|
|
625
638
|
const aiPrompt = builder.getAIPrompt();
|
|
626
639
|
return {
|
|
@@ -862,7 +875,7 @@ Start executing the tasks one by one.`
|
|
|
862
875
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
863
876
|
});
|
|
864
877
|
for (let i = 0; i < sorted.length; i++) {
|
|
865
|
-
const n = sorted[i];
|
|
878
|
+
const n = expectDefined4(sorted[i]);
|
|
866
879
|
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";
|
|
867
880
|
const num = `${i + 1}`.padStart(3);
|
|
868
881
|
const prio = n.priority.slice(0, 4).padEnd(5);
|
|
@@ -870,7 +883,7 @@ Start executing the tasks one by one.`
|
|
|
870
883
|
const elapsed = n.status === "in_progress" && n.startedAt ? ` (${formatElapsed(Date.now() - n.startedAt)})` : "";
|
|
871
884
|
lines.push(` ${num} ${status} ${prio} ${title}${elapsed}`);
|
|
872
885
|
if (n.description && n.status !== "completed") {
|
|
873
|
-
const first = n.description.split("\n")[0];
|
|
886
|
+
const first = expectDefined4(n.description.split("\n")[0]);
|
|
874
887
|
const truncated = first.length > 42 ? first.slice(0, 41) + "\u2026" : first;
|
|
875
888
|
lines.push(` \u21B3 ${truncated}`);
|
|
876
889
|
}
|
|
@@ -1037,7 +1050,7 @@ Start executing the tasks one by one.`
|
|
|
1037
1050
|
if (completed.length === 0) {
|
|
1038
1051
|
return { message: "No completed tasks to undo." };
|
|
1039
1052
|
}
|
|
1040
|
-
const last = completed[completed.length - 1];
|
|
1053
|
+
const last = expectDefined4(completed[completed.length - 1]);
|
|
1041
1054
|
undoTracker.updateNodeStatus(last.id, "pending");
|
|
1042
1055
|
const progress = undoTracker.getProgress();
|
|
1043
1056
|
return {
|
|
@@ -1087,7 +1100,7 @@ Start executing the tasks one by one.`
|
|
|
1087
1100
|
` \u{1F504} ${next.title}`
|
|
1088
1101
|
];
|
|
1089
1102
|
if (next.description) {
|
|
1090
|
-
const first = next.description.split("\n")[0];
|
|
1103
|
+
const first = expectDefined4(next.description.split("\n")[0]);
|
|
1091
1104
|
lines.push(` \u21B3 ${first}`);
|
|
1092
1105
|
}
|
|
1093
1106
|
const taskElapsed = next.startedAt ? ` \u23F1 ${formatElapsed(Date.now() - next.startedAt)}` : "";
|
|
@@ -1199,7 +1212,7 @@ Start executing the tasks one by one.`
|
|
|
1199
1212
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
1200
1213
|
});
|
|
1201
1214
|
for (let i = 0; i < sorted2.length; i++) {
|
|
1202
|
-
const n = sorted2[i];
|
|
1215
|
+
const n = expectDefined4(sorted2[i]);
|
|
1203
1216
|
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";
|
|
1204
1217
|
lines2.push(`${i + 1}. ${status} [${n.priority}] ${n.title}`);
|
|
1205
1218
|
}
|
|
@@ -1224,7 +1237,7 @@ Start executing the tasks one by one.`
|
|
|
1224
1237
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
1225
1238
|
});
|
|
1226
1239
|
for (let i = 0; i < sorted.length; i++) {
|
|
1227
|
-
const n = sorted[i];
|
|
1240
|
+
const n = expectDefined4(sorted[i]);
|
|
1228
1241
|
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";
|
|
1229
1242
|
lines.push(`${i + 1}. ${status} [${n.priority}] ${n.title}`);
|
|
1230
1243
|
}
|
|
@@ -1272,7 +1285,7 @@ Start executing the tasks one by one.`
|
|
|
1272
1285
|
maxQuestions: 10,
|
|
1273
1286
|
sessionPath
|
|
1274
1287
|
}));
|
|
1275
|
-
const resumeBuilder = sddState.getBuilder();
|
|
1288
|
+
const resumeBuilder = expectDefined4(sddState.getBuilder());
|
|
1276
1289
|
const loaded = await resumeBuilder.loadSession();
|
|
1277
1290
|
if (!loaded) {
|
|
1278
1291
|
sddState.setBuilder(null);
|
|
@@ -1506,6 +1519,12 @@ var init_sdd = __esm({
|
|
|
1506
1519
|
init_rendering();
|
|
1507
1520
|
}
|
|
1508
1521
|
});
|
|
1522
|
+
function expectDefined7(value) {
|
|
1523
|
+
if (value === null || value === void 0) {
|
|
1524
|
+
throw new Error("Expected value to be defined");
|
|
1525
|
+
}
|
|
1526
|
+
return value;
|
|
1527
|
+
}
|
|
1509
1528
|
function normalizeKeys(cfg) {
|
|
1510
1529
|
if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
|
|
1511
1530
|
return cfg.apiKeys.map((k) => ({ ...k }));
|
|
@@ -1523,7 +1542,7 @@ function writeKeysBack(cfg, keys) {
|
|
|
1523
1542
|
return;
|
|
1524
1543
|
}
|
|
1525
1544
|
cfg.apiKeys = keys;
|
|
1526
|
-
const active = keys.find((k) => k.label === cfg.activeKey) ?? keys[0];
|
|
1545
|
+
const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined7(keys[0]);
|
|
1527
1546
|
cfg.apiKey = active.apiKey;
|
|
1528
1547
|
if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {
|
|
1529
1548
|
cfg.activeKey = active.label;
|
|
@@ -1677,6 +1696,12 @@ var webui_server_exports = {};
|
|
|
1677
1696
|
__export(webui_server_exports, {
|
|
1678
1697
|
runWebUI: () => runWebUI
|
|
1679
1698
|
});
|
|
1699
|
+
function expectDefined16(value) {
|
|
1700
|
+
if (value === null || value === void 0) {
|
|
1701
|
+
throw new Error("Expected value to be defined");
|
|
1702
|
+
}
|
|
1703
|
+
return value;
|
|
1704
|
+
}
|
|
1680
1705
|
async function runWebUI(opts) {
|
|
1681
1706
|
const host = "127.0.0.1";
|
|
1682
1707
|
const requestedWsPort = opts.port ?? 3457;
|
|
@@ -2263,7 +2288,7 @@ async function runWebUI(opts) {
|
|
|
2263
2288
|
const keys = normalizeKeys(existing);
|
|
2264
2289
|
const existingIdx = keys.findIndex((k) => k.label === label);
|
|
2265
2290
|
if (existingIdx >= 0) {
|
|
2266
|
-
keys[existingIdx] = { ...keys[existingIdx], apiKey, createdAt: nowIso() };
|
|
2291
|
+
keys[existingIdx] = { ...expectDefined16(keys[existingIdx]), apiKey, createdAt: nowIso() };
|
|
2267
2292
|
} else {
|
|
2268
2293
|
keys.push({ label, apiKey, createdAt: nowIso() });
|
|
2269
2294
|
}
|
|
@@ -2290,7 +2315,7 @@ async function runWebUI(opts) {
|
|
|
2290
2315
|
} else {
|
|
2291
2316
|
writeKeysBack(existing, keys);
|
|
2292
2317
|
if (existing.activeKey === label) {
|
|
2293
|
-
existing.activeKey = keys[0]
|
|
2318
|
+
existing.activeKey = keys[0]?.label;
|
|
2294
2319
|
}
|
|
2295
2320
|
providers[providerId] = existing;
|
|
2296
2321
|
}
|
|
@@ -2437,6 +2462,12 @@ try {
|
|
|
2437
2462
|
}
|
|
2438
2463
|
|
|
2439
2464
|
// src/slash-commands/commit-llm.ts
|
|
2465
|
+
function expectDefined(value) {
|
|
2466
|
+
if (value === null || value === void 0) {
|
|
2467
|
+
throw new Error("Expected value to be defined");
|
|
2468
|
+
}
|
|
2469
|
+
return value;
|
|
2470
|
+
}
|
|
2440
2471
|
async function generateCommitMessageWithLLM(diff, opts) {
|
|
2441
2472
|
const systemPrompt = "You are a helpful assistant that generates concise, conventional-commit-formatted git commit messages. Analyze the provided diff and output ONLY the commit message (no explanation, no quotes). Format: <type>(<scope>): <short description> \u2014 <type> is one of: feat, fix, docs, style, refactor, test, chore, perf, ci, build, temp. If the diff contains multiple unrelated changes, pick the most important one. Keep the description under 72 characters. Example: feat(cli): add /commit LLM integration";
|
|
2442
2473
|
const userPrompt = `Here is the git diff:
|
|
@@ -2458,7 +2489,7 @@ ${diff}`;
|
|
|
2458
2489
|
clearTimeout(timeout);
|
|
2459
2490
|
const rawContent = resp.content;
|
|
2460
2491
|
const text = Array.isArray(rawContent) ? rawContent[0]?.text ?? "" : typeof rawContent === "object" && rawContent !== null ? rawContent.text ?? "" : String(rawContent);
|
|
2461
|
-
const message = text.trim().split("\n")[0];
|
|
2492
|
+
const message = expectDefined(text.trim().split("\n")[0]);
|
|
2462
2493
|
if (message.length > 0 && message.length < 200) {
|
|
2463
2494
|
return message;
|
|
2464
2495
|
}
|
|
@@ -2564,8 +2595,6 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
2564
2595
|
"no-tui",
|
|
2565
2596
|
"no-recovery",
|
|
2566
2597
|
"recover",
|
|
2567
|
-
"no-alt-screen",
|
|
2568
|
-
"alt-screen",
|
|
2569
2598
|
"output-json",
|
|
2570
2599
|
"prompt",
|
|
2571
2600
|
"metrics",
|
|
@@ -2665,7 +2694,7 @@ function parseSpawnFlags(input) {
|
|
|
2665
2694
|
else {
|
|
2666
2695
|
m = consume(/^--tools=(\S+)\s*/);
|
|
2667
2696
|
if (m)
|
|
2668
|
-
opts.tools = m[1]
|
|
2697
|
+
opts.tools = m[1]?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
2669
2698
|
else {
|
|
2670
2699
|
m = consume(/^-p\s+(\S+)\s*/);
|
|
2671
2700
|
if (m) opts.provider = m[1];
|
|
@@ -2888,6 +2917,7 @@ function estimateTokens(messages) {
|
|
|
2888
2917
|
function buildAutonomyCommand(opts) {
|
|
2889
2918
|
return {
|
|
2890
2919
|
name: "autonomy",
|
|
2920
|
+
category: "Agent",
|
|
2891
2921
|
description: "Toggle or query autonomy mode (self-driving agent).",
|
|
2892
2922
|
help: [
|
|
2893
2923
|
"Usage:",
|
|
@@ -3146,6 +3176,7 @@ async function gatherProjectContext(projectRoot) {
|
|
|
3146
3176
|
function buildAutoPhaseCommand(opts) {
|
|
3147
3177
|
return {
|
|
3148
3178
|
name: "autophase",
|
|
3179
|
+
category: "Agent",
|
|
3149
3180
|
description: "Autonomous phase-based workflow \u2014 plans a project into phases of todos and builds it with the LLM.",
|
|
3150
3181
|
help: [
|
|
3151
3182
|
"Usage:",
|
|
@@ -3253,6 +3284,7 @@ function buildAutoPhaseCommand(opts) {
|
|
|
3253
3284
|
function buildBtwCommand(opts) {
|
|
3254
3285
|
return {
|
|
3255
3286
|
name: "btw",
|
|
3287
|
+
category: "Agent",
|
|
3256
3288
|
description: 'Drop a "by the way" note for the running agent without interrupting it \u2014 delivered at the next step',
|
|
3257
3289
|
argsHint: "<note>",
|
|
3258
3290
|
help: [
|
|
@@ -3287,6 +3319,7 @@ function buildBtwCommand(opts) {
|
|
|
3287
3319
|
function buildClearCommand(opts) {
|
|
3288
3320
|
return {
|
|
3289
3321
|
name: "clear",
|
|
3322
|
+
category: "Session",
|
|
3290
3323
|
description: "Reset the session and start a new one.",
|
|
3291
3324
|
help: [
|
|
3292
3325
|
"Usage:",
|
|
@@ -3323,6 +3356,7 @@ function buildClearCommand(opts) {
|
|
|
3323
3356
|
function buildCodebaseReindexCommand(opts) {
|
|
3324
3357
|
return {
|
|
3325
3358
|
name: "codebase-reindex",
|
|
3359
|
+
category: "Inspect",
|
|
3326
3360
|
aliases: ["reindex"],
|
|
3327
3361
|
description: "Rebuild the codebase symbol index used by codebase-search.",
|
|
3328
3362
|
argsHint: "[force]",
|
|
@@ -3354,6 +3388,7 @@ ${color.yellow(` ${r.errors.length} file(s) had errors`)}` : "");
|
|
|
3354
3388
|
function buildCollabCommand(opts) {
|
|
3355
3389
|
return {
|
|
3356
3390
|
name: "collab",
|
|
3391
|
+
category: "Agent",
|
|
3357
3392
|
description: "Live collaboration helpers (status / invite / history).",
|
|
3358
3393
|
async run(args, ctx) {
|
|
3359
3394
|
const parts = args.split(/\s+/).filter(Boolean);
|
|
@@ -3545,6 +3580,7 @@ function helpCommand() {
|
|
|
3545
3580
|
function buildCompactCommand(opts) {
|
|
3546
3581
|
return {
|
|
3547
3582
|
name: "compact",
|
|
3583
|
+
category: "Session",
|
|
3548
3584
|
description: "Compact the context window.",
|
|
3549
3585
|
help: [
|
|
3550
3586
|
"Usage:",
|
|
@@ -3572,6 +3608,7 @@ function buildCompactCommand(opts) {
|
|
|
3572
3608
|
function buildContextCommand(opts) {
|
|
3573
3609
|
return {
|
|
3574
3610
|
name: "context",
|
|
3611
|
+
category: "Inspect",
|
|
3575
3612
|
aliases: ["ctx"],
|
|
3576
3613
|
description: "Show context window summary.",
|
|
3577
3614
|
help: [
|
|
@@ -3818,6 +3855,7 @@ function pct(n) {
|
|
|
3818
3855
|
function buildDiagCommand(opts) {
|
|
3819
3856
|
return {
|
|
3820
3857
|
name: "diag",
|
|
3858
|
+
category: "Inspect",
|
|
3821
3859
|
description: "Show runtime diagnostics (provider, tokens, tools, MCP).",
|
|
3822
3860
|
async run() {
|
|
3823
3861
|
if (!opts.onDiag) return { message: "Diag not available in this context." };
|
|
@@ -3828,6 +3866,7 @@ function buildDiagCommand(opts) {
|
|
|
3828
3866
|
function buildStatsCommand(opts) {
|
|
3829
3867
|
return {
|
|
3830
3868
|
name: "stats",
|
|
3869
|
+
category: "Inspect",
|
|
3831
3870
|
description: "Show session report: tokens, requests, tools, files, cost.",
|
|
3832
3871
|
async run() {
|
|
3833
3872
|
if (!opts.onStats) return { message: "Stats not available in this context." };
|
|
@@ -3865,6 +3904,33 @@ async function persistAutonomySetting(deps, mutator) {
|
|
|
3865
3904
|
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3866
3905
|
deps.configStore.update({ autonomy: decrypted.autonomy });
|
|
3867
3906
|
}
|
|
3907
|
+
async function persistConfigSetting(deps, mutator) {
|
|
3908
|
+
let raw;
|
|
3909
|
+
let fileExists = true;
|
|
3910
|
+
try {
|
|
3911
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
3912
|
+
} catch (err) {
|
|
3913
|
+
if (err.code !== "ENOENT") {
|
|
3914
|
+
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
3915
|
+
}
|
|
3916
|
+
fileExists = false;
|
|
3917
|
+
raw = "{}";
|
|
3918
|
+
}
|
|
3919
|
+
let parsed;
|
|
3920
|
+
try {
|
|
3921
|
+
parsed = JSON.parse(raw);
|
|
3922
|
+
} catch (err) {
|
|
3923
|
+
if (fileExists) {
|
|
3924
|
+
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
3925
|
+
}
|
|
3926
|
+
parsed = {};
|
|
3927
|
+
}
|
|
3928
|
+
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
3929
|
+
mutator(decrypted);
|
|
3930
|
+
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
3931
|
+
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3932
|
+
deps.configStore.update(decrypted);
|
|
3933
|
+
}
|
|
3868
3934
|
async function persistTelegramConfig(deps, mutator) {
|
|
3869
3935
|
let raw;
|
|
3870
3936
|
let fileExists = true;
|
|
@@ -3907,6 +3973,7 @@ function buildEnhanceCommand(opts) {
|
|
|
3907
3973
|
const controller = opts.enhanceController;
|
|
3908
3974
|
return {
|
|
3909
3975
|
name: "enhance",
|
|
3976
|
+
category: "Config",
|
|
3910
3977
|
description: 'Toggle prompt refinement ("did you mean this?") before sending.',
|
|
3911
3978
|
help: [
|
|
3912
3979
|
"Usage:",
|
|
@@ -4635,6 +4702,7 @@ function categoryLabel(cli) {
|
|
|
4635
4702
|
function buildFixCommand(opts) {
|
|
4636
4703
|
return {
|
|
4637
4704
|
name: "fix",
|
|
4705
|
+
category: "Agent",
|
|
4638
4706
|
description: "Classify a bug/error (any language), activate the right skill, and fix it \u2014 inline or via subagent.",
|
|
4639
4707
|
argsHint: "<error message or problem description>",
|
|
4640
4708
|
help: `
|
|
@@ -4800,6 +4868,7 @@ var PHASE_ORDER = [
|
|
|
4800
4868
|
function buildFleetCommand(opts) {
|
|
4801
4869
|
return {
|
|
4802
4870
|
name: "fleet",
|
|
4871
|
+
category: "Agent",
|
|
4803
4872
|
description: "Inspect and control the agent fleet (subagents, parallel slots).",
|
|
4804
4873
|
help: [
|
|
4805
4874
|
"Usage:",
|
|
@@ -5104,6 +5173,7 @@ var KNOWN_VERBS = /* @__PURE__ */ new Set([
|
|
|
5104
5173
|
function buildGoalCommand(opts) {
|
|
5105
5174
|
return {
|
|
5106
5175
|
name: "goal",
|
|
5176
|
+
category: "Agent",
|
|
5107
5177
|
description: "Set, inspect, or clear the long-running autonomous mission used by /autonomy eternal.",
|
|
5108
5178
|
help: [
|
|
5109
5179
|
"Usage:",
|
|
@@ -5257,6 +5327,7 @@ ${lines.join("\n")}`;
|
|
|
5257
5327
|
function buildHelpCommand(opts) {
|
|
5258
5328
|
return {
|
|
5259
5329
|
name: "help",
|
|
5330
|
+
category: "App",
|
|
5260
5331
|
description: "Show available slash commands. Pass a name for detailed help.",
|
|
5261
5332
|
help: [
|
|
5262
5333
|
"Usage:",
|
|
@@ -5317,6 +5388,7 @@ function buildHelpCommand(opts) {
|
|
|
5317
5388
|
function buildInitCommand(opts) {
|
|
5318
5389
|
return {
|
|
5319
5390
|
name: "init",
|
|
5391
|
+
category: "Config",
|
|
5320
5392
|
description: "Create or update .wrongstack/AGENTS.md project context for the system prompt.",
|
|
5321
5393
|
async run(_args, ctx) {
|
|
5322
5394
|
const dir = path8.join(ctx.projectRoot, ".wrongstack");
|
|
@@ -5341,11 +5413,17 @@ No project type auto-detected. Edit the file with project context and instructio
|
|
|
5341
5413
|
}
|
|
5342
5414
|
};
|
|
5343
5415
|
}
|
|
5416
|
+
function expectDefined2(value) {
|
|
5417
|
+
if (value === null || value === void 0) {
|
|
5418
|
+
throw new Error("Expected value to be defined");
|
|
5419
|
+
}
|
|
5420
|
+
return value;
|
|
5421
|
+
}
|
|
5344
5422
|
function parseMcpArgs(args) {
|
|
5345
5423
|
const trimmed = args.trim();
|
|
5346
5424
|
if (!trimmed || trimmed === "list") return { action: "list", name: "" };
|
|
5347
5425
|
const parts = trimmed.split(/\s+/);
|
|
5348
|
-
const action = parts[0];
|
|
5426
|
+
const action = expectDefined2(parts[0]);
|
|
5349
5427
|
const name = parts[1] ?? "";
|
|
5350
5428
|
const enable = parts.includes("--enable") || parts.includes("-e");
|
|
5351
5429
|
switch (action) {
|
|
@@ -5483,7 +5561,7 @@ async function runEnable(name, configured, configPath2, mcpRegistry) {
|
|
|
5483
5561
|
const mcpServers = {
|
|
5484
5562
|
...full.mcpServers ?? {}
|
|
5485
5563
|
};
|
|
5486
|
-
mcpServers[name] = { ...mcpServers[name], enabled: true };
|
|
5564
|
+
mcpServers[name] = { ...cfg, ...mcpServers[name] ?? {}, enabled: true };
|
|
5487
5565
|
full.mcpServers = mcpServers;
|
|
5488
5566
|
await writeConfig(configPath2, full);
|
|
5489
5567
|
try {
|
|
@@ -5502,7 +5580,7 @@ async function runDisable(name, configured, configPath2, mcpRegistry) {
|
|
|
5502
5580
|
const mcpServers = {
|
|
5503
5581
|
...full.mcpServers ?? {}
|
|
5504
5582
|
};
|
|
5505
|
-
mcpServers[name] = { ...mcpServers[name], enabled: false };
|
|
5583
|
+
mcpServers[name] = { ...cfg, ...mcpServers[name] ?? {}, enabled: false };
|
|
5506
5584
|
full.mcpServers = mcpServers;
|
|
5507
5585
|
await writeConfig(configPath2, full);
|
|
5508
5586
|
return `${color.yellow("Disabled")} "${name}" and stopped.`;
|
|
@@ -5556,6 +5634,7 @@ async function writeConfig(path26, cfg) {
|
|
|
5556
5634
|
function buildMcpSlashCommand(opts) {
|
|
5557
5635
|
return {
|
|
5558
5636
|
name: "mcp",
|
|
5637
|
+
category: "Config",
|
|
5559
5638
|
description: "Manage MCP servers: /mcp [list|add <name>|remove <name>|enable <name>|disable <name>|restart <name>]",
|
|
5560
5639
|
aliases: ["mcp-servers"],
|
|
5561
5640
|
argsHint: "[list|add <name>|remove <name>|enable <name>|disable <name>|restart <name>]",
|
|
@@ -5590,6 +5669,7 @@ function buildMcpSlashCommand(opts) {
|
|
|
5590
5669
|
function buildMemoryCommand(opts) {
|
|
5591
5670
|
return {
|
|
5592
5671
|
name: "memory",
|
|
5672
|
+
category: "Inspect",
|
|
5593
5673
|
description: "Inspect or edit persistent memory: /memory [show|remember <text>|forget <query>|clear]",
|
|
5594
5674
|
async run(args) {
|
|
5595
5675
|
const store = opts.memoryStore;
|
|
@@ -5643,8 +5723,7 @@ ${color.bold(color.amber("WrongStack") + color.dim(" \u2014 Mode Selection"))}
|
|
|
5643
5723
|
`);
|
|
5644
5724
|
lines.push(color.dim(" \u2191\u2193 navigate Enter select q quit\n"));
|
|
5645
5725
|
lines.push("");
|
|
5646
|
-
for (
|
|
5647
|
-
const m = modes[i];
|
|
5726
|
+
for (const [i, m] of modes.entries()) {
|
|
5648
5727
|
const mark = m.id === active?.id ? color.green(" [active]") : "";
|
|
5649
5728
|
const prefix = i === currentCursor ? color.bold("\u276F ") : " ";
|
|
5650
5729
|
const name = i === currentCursor ? color.bold(m.name) : m.name;
|
|
@@ -5676,6 +5755,7 @@ ${color.bold(color.amber("WrongStack") + color.dim(" \u2014 Mode Selection"))}
|
|
|
5676
5755
|
function buildModeCommand(opts) {
|
|
5677
5756
|
return {
|
|
5678
5757
|
name: "mode",
|
|
5758
|
+
category: "Config",
|
|
5679
5759
|
description: "Switch or view the current mode",
|
|
5680
5760
|
help: [
|
|
5681
5761
|
"Usage:",
|
|
@@ -5794,7 +5874,7 @@ function parseFlags(tokens) {
|
|
|
5794
5874
|
let maxOutput;
|
|
5795
5875
|
let i = 0;
|
|
5796
5876
|
while (i < tokens.length) {
|
|
5797
|
-
const t = tokens[i];
|
|
5877
|
+
const t = tokens[i] ?? "";
|
|
5798
5878
|
if (t.startsWith("--")) {
|
|
5799
5879
|
const key = t.slice(2);
|
|
5800
5880
|
switch (key) {
|
|
@@ -5864,6 +5944,7 @@ function buildModelsCommand(opts) {
|
|
|
5864
5944
|
].join("\n");
|
|
5865
5945
|
return {
|
|
5866
5946
|
name: "models",
|
|
5947
|
+
category: "Config",
|
|
5867
5948
|
description: "Manage custom model definitions.",
|
|
5868
5949
|
help,
|
|
5869
5950
|
async run(args) {
|
|
@@ -5890,7 +5971,10 @@ function buildModelsCommand(opts) {
|
|
|
5890
5971
|
return {
|
|
5891
5972
|
message: [
|
|
5892
5973
|
`${color.bold("Custom Models")} ${color.dim(`(${ids.length})`)}`,
|
|
5893
|
-
...ids.sort().map((id) =>
|
|
5974
|
+
...ids.sort().map((id) => {
|
|
5975
|
+
const def = models[id];
|
|
5976
|
+
return def ? fmtModel(id, def) : void 0;
|
|
5977
|
+
}).filter((line) => line !== void 0)
|
|
5894
5978
|
].join("\n")
|
|
5895
5979
|
};
|
|
5896
5980
|
}
|
|
@@ -5955,6 +6039,7 @@ function buildModelsCommand(opts) {
|
|
|
5955
6039
|
function buildNextCommand(opts) {
|
|
5956
6040
|
return {
|
|
5957
6041
|
name: "next",
|
|
6042
|
+
category: "Config",
|
|
5958
6043
|
description: "Toggle next-task prediction \u2014 show likely next steps after each turn.",
|
|
5959
6044
|
argsHint: "[on|off|toggle]",
|
|
5960
6045
|
help: [
|
|
@@ -6006,6 +6091,7 @@ function buildNextCommand(opts) {
|
|
|
6006
6091
|
function buildPluginCommand(opts) {
|
|
6007
6092
|
return {
|
|
6008
6093
|
name: "plugin",
|
|
6094
|
+
category: "Config",
|
|
6009
6095
|
aliases: ["plugins"],
|
|
6010
6096
|
description: "Manage plugins: /plugin [list|status|official|install <alias>|enable <name>|disable <name>|remove <name>]",
|
|
6011
6097
|
argsHint: "[list|status|official|install <alias>|enable <name>|disable <name>|remove <name>]",
|
|
@@ -6033,12 +6119,86 @@ function buildPluginCommand(opts) {
|
|
|
6033
6119
|
}
|
|
6034
6120
|
};
|
|
6035
6121
|
}
|
|
6122
|
+
function buildPruneCommand(opts) {
|
|
6123
|
+
return {
|
|
6124
|
+
name: "prune",
|
|
6125
|
+
category: "Session",
|
|
6126
|
+
description: "Delete old sessions. /prune (default 30d), /prune 7, /prune --rebuild-index.",
|
|
6127
|
+
help: "Usage:\n /prune Delete sessions older than 30 days.\n /prune 14 Delete sessions older than 14 days.\n /prune --dry-run Show what would be deleted without deleting.\n /prune --rebuild-index Rebuild the session index from disk.",
|
|
6128
|
+
async run(args) {
|
|
6129
|
+
const parts = args.split(/\s+/).filter(Boolean);
|
|
6130
|
+
const rebuildIndex = parts.includes("--rebuild-index") || parts.includes("--rebuild");
|
|
6131
|
+
const dryRun = parts.includes("--dry-run");
|
|
6132
|
+
if (rebuildIndex) {
|
|
6133
|
+
if (!opts.sessionStore?.rebuildIndex) {
|
|
6134
|
+
return {
|
|
6135
|
+
message: color.yellow(
|
|
6136
|
+
"Session store does not support index rebuild."
|
|
6137
|
+
)
|
|
6138
|
+
};
|
|
6139
|
+
}
|
|
6140
|
+
const count = await opts.sessionStore.rebuildIndex();
|
|
6141
|
+
return {
|
|
6142
|
+
message: count === 0 ? color.dim("No sessions found to index.") : `Session index rebuilt: ${color.green(String(count))} session${count === 1 ? "" : "s"} indexed.`
|
|
6143
|
+
};
|
|
6144
|
+
}
|
|
6145
|
+
let maxAgeDays = 30;
|
|
6146
|
+
const numPart = parts.find((p) => /^\d+$/.test(p));
|
|
6147
|
+
if (numPart) {
|
|
6148
|
+
maxAgeDays = Math.max(1, Math.min(365, Number.parseInt(numPart, 10)));
|
|
6149
|
+
}
|
|
6150
|
+
if (dryRun) {
|
|
6151
|
+
if (!opts.sessionStore) {
|
|
6152
|
+
return { message: color.yellow("No session store configured.") };
|
|
6153
|
+
}
|
|
6154
|
+
const cutoff = Date.now() - maxAgeDays * 864e5;
|
|
6155
|
+
const list = await opts.sessionStore.list(1e3);
|
|
6156
|
+
const stale = list.filter((s) => new Date(s.startedAt).getTime() < cutoff);
|
|
6157
|
+
if (stale.length === 0) {
|
|
6158
|
+
return {
|
|
6159
|
+
message: color.dim(
|
|
6160
|
+
`No sessions older than ${maxAgeDays} day${maxAgeDays === 1 ? "" : "s"}.`
|
|
6161
|
+
)
|
|
6162
|
+
};
|
|
6163
|
+
}
|
|
6164
|
+
const lines = stale.map(
|
|
6165
|
+
(s) => ` ${color.dim(s.id)} ${color.dim(s.startedAt.slice(0, 10))} ${s.title}`
|
|
6166
|
+
);
|
|
6167
|
+
return {
|
|
6168
|
+
message: [
|
|
6169
|
+
color.bold(
|
|
6170
|
+
`Would delete ${stale.length} session${stale.length === 1 ? "" : "s"} (dry run, maxAge=${maxAgeDays}d):`
|
|
6171
|
+
),
|
|
6172
|
+
...lines,
|
|
6173
|
+
"",
|
|
6174
|
+
color.dim("Run /prune without --dry-run to actually delete.")
|
|
6175
|
+
].join("\n")
|
|
6176
|
+
};
|
|
6177
|
+
}
|
|
6178
|
+
if (!opts.sessionStore) {
|
|
6179
|
+
return { message: color.yellow("No session store configured.") };
|
|
6180
|
+
}
|
|
6181
|
+
const deleted = await opts.sessionStore.prune(maxAgeDays);
|
|
6182
|
+
if (deleted === 0) {
|
|
6183
|
+
return {
|
|
6184
|
+
message: color.dim(
|
|
6185
|
+
`No sessions older than ${maxAgeDays} day${maxAgeDays === 1 ? "" : "s"}.`
|
|
6186
|
+
)
|
|
6187
|
+
};
|
|
6188
|
+
}
|
|
6189
|
+
return {
|
|
6190
|
+
message: `Pruned ${color.green(String(deleted))} session${deleted === 1 ? "" : "s"} older than ${color.cyan(String(maxAgeDays))} day${maxAgeDays === 1 ? "" : "s"}.`
|
|
6191
|
+
};
|
|
6192
|
+
}
|
|
6193
|
+
};
|
|
6194
|
+
}
|
|
6036
6195
|
|
|
6037
6196
|
// src/slash-commands/index.ts
|
|
6038
6197
|
init_sdd();
|
|
6039
6198
|
function buildSaveCommand(opts) {
|
|
6040
6199
|
return {
|
|
6041
6200
|
name: "save",
|
|
6201
|
+
category: "Session",
|
|
6042
6202
|
description: "Save current session (auto by default; this forces flush).",
|
|
6043
6203
|
async run(_args, ctx) {
|
|
6044
6204
|
await ctx.session.append({
|
|
@@ -6053,6 +6213,7 @@ function buildSaveCommand(opts) {
|
|
|
6053
6213
|
function buildLoadCommand(opts) {
|
|
6054
6214
|
return {
|
|
6055
6215
|
name: "resume",
|
|
6216
|
+
category: "Session",
|
|
6056
6217
|
aliases: ["load", "sessions"],
|
|
6057
6218
|
description: "List recent sessions, show incomplete ones (--incomplete), or plan a recovery (--recover <id>).",
|
|
6058
6219
|
async run(args) {
|
|
@@ -6136,15 +6297,30 @@ function buildLoadCommand(opts) {
|
|
|
6136
6297
|
if (!opts.sessionStore) return { message: "No session store configured." };
|
|
6137
6298
|
const list = await opts.sessionStore.list(10);
|
|
6138
6299
|
if (list.length === 0) return { message: "No saved sessions." };
|
|
6139
|
-
const lines = list.map(
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
${
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
`)
|
|
6147
|
-
|
|
6300
|
+
const lines = list.map((s) => {
|
|
6301
|
+
const parts2 = [];
|
|
6302
|
+
parts2.push(color.dim(`${s.tokenTotal.toLocaleString()} tok`));
|
|
6303
|
+
if (s.toolCallCount) {
|
|
6304
|
+
const toolStr = `${s.toolCallCount} call${s.toolCallCount === 1 ? "" : "s"}`;
|
|
6305
|
+
parts2.push(s.toolErrorCount ? color.yellow(toolStr) : color.cyan(toolStr));
|
|
6306
|
+
}
|
|
6307
|
+
if (s.iterationCount) parts2.push(color.dim(`${s.iterationCount} iter`));
|
|
6308
|
+
if (s.outcome) {
|
|
6309
|
+
const badge = s.outcome === "completed" ? color.green("\u2713") : s.outcome === "aborted" ? color.yellow("\u26A0") : s.outcome === "error" ? color.red("\u2717") : color.dim("?");
|
|
6310
|
+
parts2.push(badge);
|
|
6311
|
+
}
|
|
6312
|
+
const stat4 = parts2.join(" ");
|
|
6313
|
+
const date = color.dim(s.startedAt.slice(0, 16).replace("T", " "));
|
|
6314
|
+
return ` ${s.id.padEnd(42)} ${date} ${stat4}
|
|
6315
|
+
${color.dim(s.title)}`;
|
|
6316
|
+
});
|
|
6317
|
+
const msg = [
|
|
6318
|
+
color.bold(`Recent sessions (${list.length}):`),
|
|
6319
|
+
...lines,
|
|
6320
|
+
"",
|
|
6321
|
+
color.dim(`Resume: wstack resume ${list[0]?.id ?? "<id>"}`),
|
|
6322
|
+
color.dim("Tip: /resume --incomplete \u2014 list crashed sessions")
|
|
6323
|
+
].join("\n");
|
|
6148
6324
|
opts.renderer.write(msg);
|
|
6149
6325
|
return { message: msg };
|
|
6150
6326
|
}
|
|
@@ -6153,6 +6329,7 @@ ${color.dim("Tip: /resume --incomplete \u2014 list sessions that crashed mid-ite
|
|
|
6153
6329
|
function buildExitCommand(opts) {
|
|
6154
6330
|
return {
|
|
6155
6331
|
name: "exit",
|
|
6332
|
+
category: "App",
|
|
6156
6333
|
aliases: ["quit", "q"],
|
|
6157
6334
|
description: "Exit the REPL.",
|
|
6158
6335
|
async run() {
|
|
@@ -6209,6 +6386,12 @@ function summariseEvent(ev) {
|
|
|
6209
6386
|
return color.dim("\u2026");
|
|
6210
6387
|
}
|
|
6211
6388
|
}
|
|
6389
|
+
function expectDefined5(value) {
|
|
6390
|
+
if (value === null || value === void 0) {
|
|
6391
|
+
throw new Error("Expected value to be defined");
|
|
6392
|
+
}
|
|
6393
|
+
return value;
|
|
6394
|
+
}
|
|
6212
6395
|
var noOpVault3 = {
|
|
6213
6396
|
encrypt: (v) => v,
|
|
6214
6397
|
decrypt: (v) => v,
|
|
@@ -6301,7 +6484,7 @@ function buildSetModelCommand(opts) {
|
|
|
6301
6484
|
for (const k of keys.sort()) {
|
|
6302
6485
|
const kind = matrixKeyKind(k);
|
|
6303
6486
|
const tag = kind === "unknown" ? color.red("?") : color.dim(kind);
|
|
6304
|
-
lines.push(` ${color.amber(k.padEnd(22))} \u2192 ${fmtEntry(matrix[k])} ${tag}`);
|
|
6487
|
+
lines.push(` ${color.amber(k.padEnd(22))} \u2192 ${fmtEntry(expectDefined5(matrix[k]))} ${tag}`);
|
|
6305
6488
|
}
|
|
6306
6489
|
}
|
|
6307
6490
|
lines.push("", color.dim(" /setmodel list for valid keys \xB7 /setmodel help for usage"));
|
|
@@ -6309,6 +6492,7 @@ function buildSetModelCommand(opts) {
|
|
|
6309
6492
|
}
|
|
6310
6493
|
return {
|
|
6311
6494
|
name: "setmodel",
|
|
6495
|
+
category: "Config",
|
|
6312
6496
|
description: "View or change the leader model and the per-task model matrix.",
|
|
6313
6497
|
help,
|
|
6314
6498
|
async run(args) {
|
|
@@ -6439,6 +6623,7 @@ function buildSettingsCommand(opts) {
|
|
|
6439
6623
|
" /settings Show current settings",
|
|
6440
6624
|
" /settings delay <seconds> Auto-proceed delay in auto mode (0 disables)",
|
|
6441
6625
|
" /settings mode <off|suggest|auto> Default autonomy mode at startup",
|
|
6626
|
+
" /settings hints on|off Show or suppress rotating launch hints",
|
|
6442
6627
|
" /settings defaults Show built-in default values",
|
|
6443
6628
|
"",
|
|
6444
6629
|
"Settings are persisted to ~/.wrongstack/config.json."
|
|
@@ -6447,18 +6632,21 @@ function buildSettingsCommand(opts) {
|
|
|
6447
6632
|
const autonomy = opts.configStore.get().autonomy;
|
|
6448
6633
|
const delay = autonomy?.autoProceedDelayMs ?? 45e3;
|
|
6449
6634
|
const mode = autonomy?.defaultMode ?? "off";
|
|
6635
|
+
const hints = opts.configStore.get().hints !== false;
|
|
6450
6636
|
return [
|
|
6451
6637
|
`${color.bold("WrongStack")} ${color.dim("\u2014 Settings")}`,
|
|
6452
6638
|
"",
|
|
6453
6639
|
` auto-proceed delay: ${color.cyan(formatDelay(delay))} ${color.dim("change: /settings delay <seconds>")}`,
|
|
6454
6640
|
` default autonomy mode: ${color.cyan(mode)} ${color.dim("change: /settings mode off|suggest|auto")}`,
|
|
6641
|
+
` launch hints: ${hints ? color.cyan("on") : color.dim("off")} ${color.dim("change: /settings hints on|off")}`,
|
|
6455
6642
|
"",
|
|
6456
6643
|
color.dim(" Persisted to ~/.wrongstack/config.json \xB7 /settings help for more")
|
|
6457
6644
|
].join("\n");
|
|
6458
6645
|
}
|
|
6459
6646
|
return {
|
|
6460
6647
|
name: "settings",
|
|
6461
|
-
|
|
6648
|
+
category: "Config",
|
|
6649
|
+
description: "View or change settings (auto-proceed delay, default autonomy mode, launch hints).",
|
|
6462
6650
|
help,
|
|
6463
6651
|
async run(args) {
|
|
6464
6652
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
@@ -6479,6 +6667,7 @@ function buildSettingsCommand(opts) {
|
|
|
6479
6667
|
"",
|
|
6480
6668
|
` auto-proceed delay: ${color.cyan("45s")} ${color.dim("(WRONGSTACK_AUTO_PROCEED_DELAY_MS env)")}`,
|
|
6481
6669
|
` default autonomy mode: ${color.cyan("off")}`,
|
|
6670
|
+
` launch hints: ${color.cyan("on")}`,
|
|
6482
6671
|
` iteration timeout: ${color.cyan("5 min")}`,
|
|
6483
6672
|
` session timeout: ${color.cyan("30 min")}`,
|
|
6484
6673
|
` max iterations: ${color.cyan("100")}`
|
|
@@ -6521,8 +6710,19 @@ function buildSettingsCommand(opts) {
|
|
|
6521
6710
|
});
|
|
6522
6711
|
return { message: `${color.green("\u2713")} default autonomy \u2192 ${color.bold(raw)}` };
|
|
6523
6712
|
}
|
|
6713
|
+
if (sub === "hints") {
|
|
6714
|
+
const raw = (parts[1] ?? "").toLowerCase();
|
|
6715
|
+
if (!["on", "off"].includes(raw)) {
|
|
6716
|
+
return { message: `${color.amber("Usage:")} /settings hints on|off` };
|
|
6717
|
+
}
|
|
6718
|
+
const on = raw === "on";
|
|
6719
|
+
await persistConfigSetting(persistDeps, (cfg) => {
|
|
6720
|
+
cfg.hints = on;
|
|
6721
|
+
});
|
|
6722
|
+
return { message: `${color.green("\u2713")} launch hints \u2192 ${on ? color.cyan("on") : color.dim("off")}` };
|
|
6723
|
+
}
|
|
6524
6724
|
return {
|
|
6525
|
-
message: `${color.red("Unknown setting")} "${sub}". Try ${color.dim("/settings")}, ${color.dim("/settings delay <s>")},
|
|
6725
|
+
message: `${color.red("Unknown setting")} "${sub}". Try ${color.dim("/settings")}, ${color.dim("/settings delay <s>")}, ${color.dim("/settings mode <m>")}, or ${color.dim("/settings hints on|off")}.`
|
|
6526
6726
|
};
|
|
6527
6727
|
} catch (err) {
|
|
6528
6728
|
return {
|
|
@@ -6556,6 +6756,7 @@ var HELP = [
|
|
|
6556
6756
|
function buildTelegramSetupCommand(opts) {
|
|
6557
6757
|
return {
|
|
6558
6758
|
name: "telegram-setup",
|
|
6759
|
+
category: "Config",
|
|
6559
6760
|
aliases: ["tg-setup"],
|
|
6560
6761
|
description: "Configure Telegram bot token and default chat. /telegram-setup <token> [chatId]",
|
|
6561
6762
|
argsHint: "[botToken] [chatId]",
|
|
@@ -6594,7 +6795,7 @@ function buildTelegramSetupCommand(opts) {
|
|
|
6594
6795
|
);
|
|
6595
6796
|
return { message: lines.join("\n") };
|
|
6596
6797
|
}
|
|
6597
|
-
const botToken = parts[0];
|
|
6798
|
+
const botToken = parts[0] ?? "";
|
|
6598
6799
|
const chatId = parts[1];
|
|
6599
6800
|
if (!/^\d+:[A-Za-z0-9_-]+$/.test(botToken)) {
|
|
6600
6801
|
return {
|
|
@@ -6688,6 +6889,7 @@ ${color.dim("No default chat set. You can add it later: /telegram-setup <token>
|
|
|
6688
6889
|
function buildSpawnCommand(opts) {
|
|
6689
6890
|
return {
|
|
6690
6891
|
name: "spawn",
|
|
6892
|
+
category: "Agent",
|
|
6691
6893
|
description: "Spawn an isolated subagent to handle a task.",
|
|
6692
6894
|
async run(args) {
|
|
6693
6895
|
const { description, opts: parsed } = parseSpawnFlags(args.trim());
|
|
@@ -6708,6 +6910,7 @@ function buildSpawnCommand(opts) {
|
|
|
6708
6910
|
function buildAgentsCommand(opts) {
|
|
6709
6911
|
return {
|
|
6710
6912
|
name: "agents",
|
|
6913
|
+
category: "Agent",
|
|
6711
6914
|
description: "Show status of spawned subagents. /agents monitor opens the agents monitor overlay. /agents on|off toggles the overlay.",
|
|
6712
6915
|
help: [
|
|
6713
6916
|
"Usage: /agents [monitor|on|off|stream on|stream off]",
|
|
@@ -6745,6 +6948,7 @@ function buildAgentsCommand(opts) {
|
|
|
6745
6948
|
function buildDirectorCommand(opts) {
|
|
6746
6949
|
return {
|
|
6747
6950
|
name: "director",
|
|
6951
|
+
category: "Agent",
|
|
6748
6952
|
description: "Promote this session to director mode, enabling fleet orchestration tools. Only works before any subagents are spawned.",
|
|
6749
6953
|
async run() {
|
|
6750
6954
|
if (!opts.onDirector) return { message: "Director promotion is not available in this session." };
|
|
@@ -6797,6 +7001,7 @@ async function saveStatuslineConfig(cfg) {
|
|
|
6797
7001
|
function buildStatuslineCommand(deps) {
|
|
6798
7002
|
return {
|
|
6799
7003
|
name: "statusline",
|
|
7004
|
+
category: "Config",
|
|
6800
7005
|
aliases: ["sl"],
|
|
6801
7006
|
description: "Customize status bar chips: /statusline [item] [on|off] or /statusline reset",
|
|
6802
7007
|
help: [
|
|
@@ -6874,15 +7079,22 @@ function findTodo(todos, query) {
|
|
|
6874
7079
|
if (item) return { idx, item };
|
|
6875
7080
|
}
|
|
6876
7081
|
const byId = todos.findIndex((t) => t.id === query);
|
|
6877
|
-
if (byId >= 0)
|
|
7082
|
+
if (byId >= 0) {
|
|
7083
|
+
const item = todos[byId];
|
|
7084
|
+
if (item) return { idx: byId, item };
|
|
7085
|
+
}
|
|
6878
7086
|
const q = query.toLowerCase();
|
|
6879
7087
|
const byContent = todos.findIndex((t) => t.content.toLowerCase().includes(q));
|
|
6880
|
-
if (byContent >= 0)
|
|
7088
|
+
if (byContent >= 0) {
|
|
7089
|
+
const item = todos[byContent];
|
|
7090
|
+
if (item) return { idx: byContent, item };
|
|
7091
|
+
}
|
|
6881
7092
|
return null;
|
|
6882
7093
|
}
|
|
6883
7094
|
function buildTodosCommand(opts) {
|
|
6884
7095
|
return {
|
|
6885
7096
|
name: "todos",
|
|
7097
|
+
category: "Inspect",
|
|
6886
7098
|
description: "Inspect or edit the live todo list: /todos [show|clear|add|done|remove|rm <id|index>]",
|
|
6887
7099
|
async run(args) {
|
|
6888
7100
|
const ctx = opts.context;
|
|
@@ -6949,6 +7161,7 @@ function buildTodosCommand(opts) {
|
|
|
6949
7161
|
function buildToolsCommand(opts) {
|
|
6950
7162
|
return {
|
|
6951
7163
|
name: "tools",
|
|
7164
|
+
category: "Inspect",
|
|
6952
7165
|
description: "List registered tools.",
|
|
6953
7166
|
async run() {
|
|
6954
7167
|
const all = opts.toolRegistry.listWithOwner();
|
|
@@ -6968,6 +7181,7 @@ ${lines.join("\n")}
|
|
|
6968
7181
|
function buildWorktreeCommand(opts) {
|
|
6969
7182
|
return {
|
|
6970
7183
|
name: "worktree",
|
|
7184
|
+
category: "Config",
|
|
6971
7185
|
aliases: ["wt"],
|
|
6972
7186
|
description: "Inspect/manage git worktrees used for AutoPhase per-phase isolation.",
|
|
6973
7187
|
argsHint: "[list | merge <branch> | prune | clean]",
|
|
@@ -7011,6 +7225,7 @@ function buildWorktreeCommand(opts) {
|
|
|
7011
7225
|
function buildYoloCommand(opts) {
|
|
7012
7226
|
return {
|
|
7013
7227
|
name: "yolo",
|
|
7228
|
+
category: "Config",
|
|
7014
7229
|
description: "Toggle or query YOLO (auto-approve) mode.",
|
|
7015
7230
|
help: [
|
|
7016
7231
|
"Usage:",
|
|
@@ -7068,6 +7283,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
7068
7283
|
buildCodebaseReindexCommand(opts),
|
|
7069
7284
|
buildToolsCommand(opts),
|
|
7070
7285
|
buildPluginCommand(opts),
|
|
7286
|
+
buildPruneCommand(opts),
|
|
7071
7287
|
buildMcpSlashCommand(opts),
|
|
7072
7288
|
buildDiagCommand(opts),
|
|
7073
7289
|
buildStatsCommand(opts),
|
|
@@ -7424,15 +7640,20 @@ var ReadlineInputReader = class {
|
|
|
7424
7640
|
});
|
|
7425
7641
|
}
|
|
7426
7642
|
const fresh = this.ensure();
|
|
7643
|
+
this.installPromptGuard(fresh);
|
|
7427
7644
|
return new Promise((resolve5) => {
|
|
7645
|
+
const settle = (line) => {
|
|
7646
|
+
setOutputLineGuard(null);
|
|
7647
|
+
resolve5(line);
|
|
7648
|
+
};
|
|
7428
7649
|
fresh.question(prompt ?? "> ", (line) => {
|
|
7429
7650
|
if (line.trim()) {
|
|
7430
7651
|
this.history.push(line);
|
|
7431
7652
|
void this.saveHistory();
|
|
7432
7653
|
}
|
|
7433
|
-
|
|
7654
|
+
settle(line);
|
|
7434
7655
|
});
|
|
7435
|
-
fresh.once("close", () =>
|
|
7656
|
+
fresh.once("close", () => settle(""));
|
|
7436
7657
|
}).then((result) => {
|
|
7437
7658
|
this.rl?.close();
|
|
7438
7659
|
return result;
|
|
@@ -7441,7 +7662,38 @@ var ReadlineInputReader = class {
|
|
|
7441
7662
|
this.pending = false;
|
|
7442
7663
|
}
|
|
7443
7664
|
}
|
|
7665
|
+
/**
|
|
7666
|
+
* Install the out-of-band write guard for the active prompt. When a log
|
|
7667
|
+
* line or other async output lands while the user is mid-type, the guard
|
|
7668
|
+
* clears the draft row, lets the message print, then repaints the prompt
|
|
7669
|
+
* and the in-progress draft (cursor preserved) via readline's own
|
|
7670
|
+
* refresh. Without it, each async write leaves the half-typed line
|
|
7671
|
+
* stranded as a fresh scrollback row.
|
|
7672
|
+
*
|
|
7673
|
+
* No-op on non-TTY output (piped/redirected) — there's no draft to
|
|
7674
|
+
* protect and the ANSI clear/repaint would be noise in a file.
|
|
7675
|
+
*/
|
|
7676
|
+
installPromptGuard(rl) {
|
|
7677
|
+
const out = process.stdout;
|
|
7678
|
+
if (!out.isTTY) {
|
|
7679
|
+
setOutputLineGuard(null);
|
|
7680
|
+
return;
|
|
7681
|
+
}
|
|
7682
|
+
setOutputLineGuard({
|
|
7683
|
+
suspend() {
|
|
7684
|
+
readline.cursorTo(out, 0);
|
|
7685
|
+
readline.clearLine(out, 0);
|
|
7686
|
+
},
|
|
7687
|
+
resume() {
|
|
7688
|
+
try {
|
|
7689
|
+
rl.prompt(true);
|
|
7690
|
+
} catch {
|
|
7691
|
+
}
|
|
7692
|
+
}
|
|
7693
|
+
});
|
|
7694
|
+
}
|
|
7444
7695
|
async readKey(prompt, options) {
|
|
7696
|
+
setOutputLineGuard(null);
|
|
7445
7697
|
writeOut(prompt);
|
|
7446
7698
|
return new Promise((resolve5) => {
|
|
7447
7699
|
const stdin = process.stdin;
|
|
@@ -7494,6 +7746,7 @@ var ReadlineInputReader = class {
|
|
|
7494
7746
|
async readSecret(prompt) {
|
|
7495
7747
|
const stdin = process.stdin;
|
|
7496
7748
|
if (!stdin.isTTY) return this.readLine(prompt);
|
|
7749
|
+
setOutputLineGuard(null);
|
|
7497
7750
|
this.rl?.close();
|
|
7498
7751
|
this.rl = void 0;
|
|
7499
7752
|
writeOut(prompt);
|
|
@@ -7556,6 +7809,7 @@ var ReadlineInputReader = class {
|
|
|
7556
7809
|
});
|
|
7557
7810
|
}
|
|
7558
7811
|
async close() {
|
|
7812
|
+
setOutputLineGuard(null);
|
|
7559
7813
|
await this.saveHistory();
|
|
7560
7814
|
this.rl?.close();
|
|
7561
7815
|
this.rl = void 0;
|
|
@@ -7874,6 +8128,12 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
7874
8128
|
}
|
|
7875
8129
|
|
|
7876
8130
|
// src/picker.ts
|
|
8131
|
+
function expectDefined6(value) {
|
|
8132
|
+
if (value === null || value === void 0) {
|
|
8133
|
+
throw new Error("Expected value to be defined");
|
|
8134
|
+
}
|
|
8135
|
+
return value;
|
|
8136
|
+
}
|
|
7877
8137
|
var theme = { primary: color.amber };
|
|
7878
8138
|
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os2__default.homedir()) {
|
|
7879
8139
|
try {
|
|
@@ -7995,7 +8255,7 @@ ${color.bold(theme.primary("WrongStack") + color.dim(" \u2014 Provider & Model S
|
|
|
7995
8255
|
for (const p of list) {
|
|
7996
8256
|
const envFound = p.envVars.some((v) => !!process.env[v]);
|
|
7997
8257
|
const entry = config?.providers?.[p.id];
|
|
7998
|
-
const configKey = typeof entry?.apiKey === "string" && entry.apiKey.length > 0 || Array.isArray(entry?.apiKeys) && entry
|
|
8258
|
+
const configKey = typeof entry?.apiKey === "string" && entry.apiKey.length > 0 || Array.isArray(entry?.apiKeys) && entry?.apiKeys?.some((k) => k?.apiKey);
|
|
7999
8259
|
const marker = envFound ? color.green("\u25CF") : configKey ? color.cyan("\u25C9") : color.dim("\u25CB");
|
|
8000
8260
|
const isDefault = p.id === defaultProvider;
|
|
8001
8261
|
if (isDefault) defaultIdx = idx;
|
|
@@ -8069,7 +8329,7 @@ async function pickModel(provider, registry, renderer, reader, defaultModel) {
|
|
|
8069
8329
|
while (offset < models.length) {
|
|
8070
8330
|
const page = models.slice(offset, offset + pageSize);
|
|
8071
8331
|
for (let i = 0; i < page.length; i++) {
|
|
8072
|
-
const m = page[i];
|
|
8332
|
+
const m = expectDefined6(page[i]);
|
|
8073
8333
|
const num = offset + i + 1;
|
|
8074
8334
|
const ctx = m.limit?.context ? `${(m.limit.context / 1e3).toFixed(0)}k`.padStart(6) : " ?";
|
|
8075
8335
|
const cost = m.cost?.input !== void 0 ? `$${m.cost.input}/$${m.cost.output ?? "?"}` : "";
|
|
@@ -8126,7 +8386,7 @@ async function resolveModelSelection(answer, models, provider, _registry, render
|
|
|
8126
8386
|
const idx = Number.parseInt(answer, 10);
|
|
8127
8387
|
let modelId;
|
|
8128
8388
|
if (!Number.isNaN(idx) && idx >= 1 && idx <= models.length) {
|
|
8129
|
-
modelId = models[idx - 1]
|
|
8389
|
+
modelId = models[idx - 1]?.id;
|
|
8130
8390
|
} else {
|
|
8131
8391
|
const lower = answer.toLowerCase();
|
|
8132
8392
|
const match = models.find((m) => m.id.toLowerCase() === lower);
|
|
@@ -8135,7 +8395,7 @@ async function resolveModelSelection(answer, models, provider, _registry, render
|
|
|
8135
8395
|
} else {
|
|
8136
8396
|
const partial = models.filter((m) => m.id.toLowerCase().includes(lower));
|
|
8137
8397
|
if (partial.length === 1) {
|
|
8138
|
-
modelId = partial[0]
|
|
8398
|
+
modelId = partial[0]?.id;
|
|
8139
8399
|
} else if (partial.length > 1) {
|
|
8140
8400
|
renderer.writeError(`"${answer}" matches multiple models. Be more specific.`);
|
|
8141
8401
|
return void 0;
|
|
@@ -8460,6 +8720,7 @@ var TerminalRenderer = class {
|
|
|
8460
8720
|
if (this.silent) return;
|
|
8461
8721
|
if (result.delegateSummaries) {
|
|
8462
8722
|
for (const { summary, ok } of result.delegateSummaries) {
|
|
8723
|
+
if (!summary) continue;
|
|
8463
8724
|
this.writeAgentSummary(summary, ok);
|
|
8464
8725
|
}
|
|
8465
8726
|
return;
|
|
@@ -8731,6 +8992,12 @@ async function spawnACPAgent(args, deps) {
|
|
|
8731
8992
|
|
|
8732
8993
|
// src/auth-menu.ts
|
|
8733
8994
|
init_provider_config_utils();
|
|
8995
|
+
function expectDefined8(value) {
|
|
8996
|
+
if (value === null || value === void 0) {
|
|
8997
|
+
throw new Error("Expected value to be defined");
|
|
8998
|
+
}
|
|
8999
|
+
return value;
|
|
9000
|
+
}
|
|
8734
9001
|
async function runAuthMenu(deps) {
|
|
8735
9002
|
for (; ; ) {
|
|
8736
9003
|
const providers = await loadProviders(deps);
|
|
@@ -8752,7 +9019,7 @@ ${color.amber("?")} Pick: `)).trim().toLowerCase();
|
|
|
8752
9019
|
}
|
|
8753
9020
|
const idx = Number.parseInt(choice, 10);
|
|
8754
9021
|
if (!Number.isNaN(idx) && idx >= 1 && idx <= ids.length) {
|
|
8755
|
-
const pid = ids[idx - 1];
|
|
9022
|
+
const pid = expectDefined8(ids[idx - 1]);
|
|
8756
9023
|
await manageProvider(pid, deps);
|
|
8757
9024
|
continue;
|
|
8758
9025
|
}
|
|
@@ -8778,9 +9045,11 @@ ${color.bold("WrongStack")} ${color.dim("\u2014 API keys")}
|
|
|
8778
9045
|
let idx = 1;
|
|
8779
9046
|
for (const id of ids) {
|
|
8780
9047
|
const cfg = providers[id];
|
|
9048
|
+
if (!cfg) continue;
|
|
8781
9049
|
const keys = normalizeKeys(cfg);
|
|
8782
9050
|
const active = activeLabel(cfg, keys);
|
|
8783
|
-
const
|
|
9051
|
+
const firstKey = keys[0];
|
|
9052
|
+
const summary = keys.length === 0 ? color.dim("(no keys)") : keys.length === 1 ? maskedKey(firstKey?.apiKey ?? "") : `${color.dim(`${keys.length} keys`)} ${color.dim("active:")} ${color.bold(active ?? "?")} ${maskedKey(keys.find((k) => k.label === active)?.apiKey ?? firstKey?.apiKey ?? "")}`;
|
|
8784
9053
|
const fam = cfg.family ? color.dim(`[${cfg.family}]`) : "";
|
|
8785
9054
|
const aliasHint = cfg.type && cfg.type !== id ? color.dim(`\u2192 ${cfg.type}`) : "";
|
|
8786
9055
|
renderer.write(
|
|
@@ -8840,7 +9109,7 @@ ${color.bold(providerId)} ${cfg.family ? color.dim(`[${cfg.family}]`) : color.am
|
|
|
8840
9109
|
deps.renderer.write(color.dim(" (no keys saved)\n"));
|
|
8841
9110
|
} else {
|
|
8842
9111
|
for (let i = 0; i < keys.length; i++) {
|
|
8843
|
-
const k = keys[i];
|
|
9112
|
+
const k = expectDefined8(keys[i]);
|
|
8844
9113
|
const marker = k.label === active ? color.green("\u25CF") : color.dim("\u25CB");
|
|
8845
9114
|
deps.renderer.write(
|
|
8846
9115
|
` ${color.dim(`${i + 1}.`.padStart(4))} ${marker} ${k.label.padEnd(20)} ${maskedKey(k.apiKey)} ${color.dim(k.createdAt)}
|
|
@@ -8902,7 +9171,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
8902
9171
|
deps.renderer.writeError(`Usage: u <1-${keys.length}>`);
|
|
8903
9172
|
continue;
|
|
8904
9173
|
}
|
|
8905
|
-
const target = keys[arg - 1];
|
|
9174
|
+
const target = expectDefined8(keys[arg - 1]);
|
|
8906
9175
|
const newKey = await readKeyInput(deps, `Updated key for ${target.label}`);
|
|
8907
9176
|
if (!newKey) continue;
|
|
8908
9177
|
await mutateProviders(deps, (all) => {
|
|
@@ -8922,7 +9191,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
8922
9191
|
deps.renderer.writeError(`Usage: d <1-${keys.length}>`);
|
|
8923
9192
|
continue;
|
|
8924
9193
|
}
|
|
8925
|
-
const target = keys[arg - 1];
|
|
9194
|
+
const target = expectDefined8(keys[arg - 1]);
|
|
8926
9195
|
const confirm = (await deps.reader.readLine(
|
|
8927
9196
|
` ${color.amber("?")} Delete key "${target.label}" (${maskedKey(target.apiKey)})? ${color.dim("[y/N/q]")} `
|
|
8928
9197
|
)).trim().toLowerCase();
|
|
@@ -8998,7 +9267,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
8998
9267
|
deps.renderer.writeError(`Usage: s <1-${keys.length}>`);
|
|
8999
9268
|
continue;
|
|
9000
9269
|
}
|
|
9001
|
-
const target = keys[arg - 1];
|
|
9270
|
+
const target = expectDefined8(keys[arg - 1]);
|
|
9002
9271
|
await mutateProviders(deps, (all) => {
|
|
9003
9272
|
const p = all[providerId];
|
|
9004
9273
|
if (!p) return;
|
|
@@ -9381,6 +9650,12 @@ async function mutateProviders(deps, mutator) {
|
|
|
9381
9650
|
}
|
|
9382
9651
|
|
|
9383
9652
|
// src/subcommands/handlers/auth.ts
|
|
9653
|
+
function expectDefined9(value) {
|
|
9654
|
+
if (value === null || value === void 0) {
|
|
9655
|
+
throw new Error("Expected value to be defined");
|
|
9656
|
+
}
|
|
9657
|
+
return value;
|
|
9658
|
+
}
|
|
9384
9659
|
var authCmd = async (args, deps) => {
|
|
9385
9660
|
const flags = parseAuthFlags(args);
|
|
9386
9661
|
const menuDeps = {
|
|
@@ -9392,7 +9667,7 @@ var authCmd = async (args, deps) => {
|
|
|
9392
9667
|
};
|
|
9393
9668
|
if (flags.positional.length === 0) return runAuthMenu(menuDeps);
|
|
9394
9669
|
return runAuthDirect(menuDeps, {
|
|
9395
|
-
providerId: flags.positional[0],
|
|
9670
|
+
providerId: expectDefined9(flags.positional[0]),
|
|
9396
9671
|
label: flags.label,
|
|
9397
9672
|
family: flags.family,
|
|
9398
9673
|
baseUrl: flags.baseUrl,
|
|
@@ -9615,6 +9890,12 @@ var doctorCmd = async (_args, deps) => {
|
|
|
9615
9890
|
deps.renderer.write(color.green("All checks passed.\n"));
|
|
9616
9891
|
return 0;
|
|
9617
9892
|
};
|
|
9893
|
+
function expectDefined10(value) {
|
|
9894
|
+
if (value === null || value === void 0) {
|
|
9895
|
+
throw new Error("Expected value to be defined");
|
|
9896
|
+
}
|
|
9897
|
+
return value;
|
|
9898
|
+
}
|
|
9618
9899
|
var exportCmd = async (args, deps) => {
|
|
9619
9900
|
if (!deps.sessionStore) {
|
|
9620
9901
|
deps.renderer.writeError("No session store configured.");
|
|
@@ -9626,7 +9907,7 @@ var exportCmd = async (args, deps) => {
|
|
|
9626
9907
|
let includeDiagnostics = true;
|
|
9627
9908
|
let sessionId;
|
|
9628
9909
|
for (let i = 0; i < args.length; i++) {
|
|
9629
|
-
const a = args[i];
|
|
9910
|
+
const a = expectDefined10(args[i]);
|
|
9630
9911
|
if (a === "--format" || a === "-f") {
|
|
9631
9912
|
const v = args[++i];
|
|
9632
9913
|
if (v !== "markdown" && v !== "json" && v !== "text") {
|
|
@@ -9888,6 +10169,12 @@ async function serveMcpStdio(deps) {
|
|
|
9888
10169
|
}
|
|
9889
10170
|
|
|
9890
10171
|
// src/subcommands/handlers/mcp.ts
|
|
10172
|
+
function expectDefined11(value) {
|
|
10173
|
+
if (value === null || value === void 0) {
|
|
10174
|
+
throw new Error("Expected value to be defined");
|
|
10175
|
+
}
|
|
10176
|
+
return value;
|
|
10177
|
+
}
|
|
9891
10178
|
var BUILT_IN_MCP = allServers();
|
|
9892
10179
|
var mcpCmd = async (args, deps) => {
|
|
9893
10180
|
const sub = args[0];
|
|
@@ -9938,7 +10225,7 @@ async function addMcpServer(args, deps) {
|
|
|
9938
10225
|
`);
|
|
9939
10226
|
if (Object.keys(deps.config.mcpServers ?? {}).length === 0)
|
|
9940
10227
|
for (const k of Object.keys(BUILT_IN_MCP)) {
|
|
9941
|
-
const s = BUILT_IN_MCP[k];
|
|
10228
|
+
const s = expectDefined11(BUILT_IN_MCP[k]);
|
|
9942
10229
|
deps.renderer.write(` ${k.padEnd(20)} ${s.description}
|
|
9943
10230
|
`);
|
|
9944
10231
|
}
|
|
@@ -10216,6 +10503,12 @@ var projectsCmd = async (_args, deps) => {
|
|
|
10216
10503
|
return 0;
|
|
10217
10504
|
}
|
|
10218
10505
|
};
|
|
10506
|
+
function expectDefined12(value) {
|
|
10507
|
+
if (value === null || value === void 0) {
|
|
10508
|
+
throw new Error("Expected value to be defined");
|
|
10509
|
+
}
|
|
10510
|
+
return value;
|
|
10511
|
+
}
|
|
10219
10512
|
var providersCmd = async (args, deps) => {
|
|
10220
10513
|
const showAll = args.includes("--all");
|
|
10221
10514
|
const showUnsupported = args.includes("--unsupported");
|
|
@@ -10263,14 +10556,14 @@ ${color.dim(`Current: ${deps.config.provider ?? "<unset>"} / ${deps.config.model
|
|
|
10263
10556
|
function parseFlags2(args) {
|
|
10264
10557
|
const flags = {};
|
|
10265
10558
|
for (let i = 0; i < args.length; i++) {
|
|
10266
|
-
const a = args[i];
|
|
10559
|
+
const a = expectDefined12(args[i]);
|
|
10267
10560
|
if (a.startsWith("--")) {
|
|
10268
10561
|
const eq = a.indexOf("=");
|
|
10269
10562
|
if (eq !== -1) {
|
|
10270
10563
|
flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
10271
10564
|
} else {
|
|
10272
10565
|
const name = a.slice(2);
|
|
10273
|
-
if (i + 1 < args.length && !args[i + 1]
|
|
10566
|
+
if (i + 1 < args.length && !args[i + 1]?.startsWith("--")) {
|
|
10274
10567
|
flags[name] = args[++i] ?? "";
|
|
10275
10568
|
} else {
|
|
10276
10569
|
flags[name] = true;
|
|
@@ -10283,11 +10576,11 @@ function parseFlags2(args) {
|
|
|
10283
10576
|
function positionals(args) {
|
|
10284
10577
|
const out = [];
|
|
10285
10578
|
for (let i = 0; i < args.length; i++) {
|
|
10286
|
-
const a = args[i];
|
|
10579
|
+
const a = expectDefined12(args[i]);
|
|
10287
10580
|
if (a.startsWith("--")) {
|
|
10288
10581
|
const eq = a.indexOf("=");
|
|
10289
10582
|
if (eq === -1) {
|
|
10290
|
-
if (i + 1 < args.length && !args[i + 1]
|
|
10583
|
+
if (i + 1 < args.length && !args[i + 1]?.startsWith("--")) {
|
|
10291
10584
|
i++;
|
|
10292
10585
|
}
|
|
10293
10586
|
}
|
|
@@ -10438,7 +10731,7 @@ function parseSizeFlag(raw) {
|
|
|
10438
10731
|
const s = raw.trim().toLowerCase();
|
|
10439
10732
|
const match = /^(\d+(?:\.\d+)?)\s*(k|m|b)?$/.exec(s);
|
|
10440
10733
|
if (!match) return void 0;
|
|
10441
|
-
const num = Number.parseFloat(match[1]);
|
|
10734
|
+
const num = Number.parseFloat(expectDefined12(match[1]));
|
|
10442
10735
|
const unit = match[2];
|
|
10443
10736
|
if (unit === "b") return Math.round(num * 1e9);
|
|
10444
10737
|
if (unit === "m") return Math.round(num * 1e6);
|
|
@@ -10759,6 +11052,12 @@ Fleet Run: ${runId}
|
|
|
10759
11052
|
}
|
|
10760
11053
|
|
|
10761
11054
|
// src/subcommands/handlers/sessions-config.ts
|
|
11055
|
+
function expectDefined13(value) {
|
|
11056
|
+
if (value === null || value === void 0) {
|
|
11057
|
+
throw new Error("Expected value to be defined");
|
|
11058
|
+
}
|
|
11059
|
+
return value;
|
|
11060
|
+
}
|
|
10762
11061
|
var sessionsCmd = async (args, deps) => {
|
|
10763
11062
|
const sub = args[0];
|
|
10764
11063
|
if (sub === "fleet") {
|
|
@@ -10804,7 +11103,7 @@ var configCmd = async (args, deps) => {
|
|
|
10804
11103
|
};
|
|
10805
11104
|
function extractArg(args, key) {
|
|
10806
11105
|
const idx = args.indexOf(key);
|
|
10807
|
-
if (idx !== -1 && args[idx + 1] !== void 0) return args[idx + 1];
|
|
11106
|
+
if (idx !== -1 && args[idx + 1] !== void 0) return expectDefined13(args[idx + 1]);
|
|
10808
11107
|
const eq = key.startsWith("--") ? args.find((a) => a.startsWith(`${key}=`)) : null;
|
|
10809
11108
|
if (eq) return eq.slice(eq.indexOf("=") + 1);
|
|
10810
11109
|
return null;
|
|
@@ -10855,7 +11154,7 @@ async function runHistory(args, deps) {
|
|
|
10855
11154
|
}
|
|
10856
11155
|
async function runRestore(args, deps) {
|
|
10857
11156
|
const latest = args.includes("--latest") || args.includes("-l");
|
|
10858
|
-
const id = extractArg(args, "--id") ?? (args[0] && !args[0]
|
|
11157
|
+
const id = extractArg(args, "--id") ?? (args[0] && !args[0]?.startsWith("-") ? args[0] : null);
|
|
10859
11158
|
if (latest) {
|
|
10860
11159
|
const result2 = await restoreLast();
|
|
10861
11160
|
if (!result2.ok) {
|
|
@@ -10880,6 +11179,12 @@ async function runRestore(args, deps) {
|
|
|
10880
11179
|
`);
|
|
10881
11180
|
return 0;
|
|
10882
11181
|
}
|
|
11182
|
+
function expectDefined14(value) {
|
|
11183
|
+
if (value === null || value === void 0) {
|
|
11184
|
+
throw new Error("Expected value to be defined");
|
|
11185
|
+
}
|
|
11186
|
+
return value;
|
|
11187
|
+
}
|
|
10883
11188
|
function parseRewindFlags(args) {
|
|
10884
11189
|
const flags = {};
|
|
10885
11190
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -10894,7 +11199,7 @@ function parseRewindFlags(args) {
|
|
|
10894
11199
|
}
|
|
10895
11200
|
function findSessionId(args) {
|
|
10896
11201
|
for (let i = 0; i < args.length; i++) {
|
|
10897
|
-
const a = args[i];
|
|
11202
|
+
const a = expectDefined14(args[i]);
|
|
10898
11203
|
if (a === "--last" || a === "--to") {
|
|
10899
11204
|
i++;
|
|
10900
11205
|
continue;
|
|
@@ -10919,13 +11224,18 @@ var rewindCmd = async (args, deps) => {
|
|
|
10919
11224
|
deps.renderer.writeError("No sessions found.");
|
|
10920
11225
|
return 1;
|
|
10921
11226
|
}
|
|
10922
|
-
sessionId = sessions[0]
|
|
11227
|
+
sessionId = sessions[0]?.id;
|
|
10923
11228
|
}
|
|
11229
|
+
if (!sessionId) {
|
|
11230
|
+
deps.renderer.writeError("No sessions found.");
|
|
11231
|
+
return 1;
|
|
11232
|
+
}
|
|
11233
|
+
const targetSessionId = sessionId;
|
|
10924
11234
|
if (flags.list) {
|
|
10925
|
-
deps.renderer.write(`Session: ${color.bold(
|
|
11235
|
+
deps.renderer.write(`Session: ${color.bold(targetSessionId)}
|
|
10926
11236
|
|
|
10927
11237
|
`);
|
|
10928
|
-
const checkpoints = await rewind.listCheckpoints(
|
|
11238
|
+
const checkpoints = await rewind.listCheckpoints(targetSessionId);
|
|
10929
11239
|
if (checkpoints.length === 0) {
|
|
10930
11240
|
deps.renderer.write("No checkpoints in this session.\n");
|
|
10931
11241
|
return 0;
|
|
@@ -10942,7 +11252,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10942
11252
|
let result;
|
|
10943
11253
|
if (flags.all) {
|
|
10944
11254
|
deps.renderer.write("Rewinding to session start...\n");
|
|
10945
|
-
result = await rewind.rewindToStart(
|
|
11255
|
+
result = await rewind.rewindToStart(targetSessionId);
|
|
10946
11256
|
} else if (flags.last) {
|
|
10947
11257
|
const n = Number.parseInt(flags.last, 10);
|
|
10948
11258
|
if (Number.isNaN(n) || n < 1) {
|
|
@@ -10951,7 +11261,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10951
11261
|
}
|
|
10952
11262
|
deps.renderer.write(`Rewinding last ${n} prompt(s)...
|
|
10953
11263
|
`);
|
|
10954
|
-
result = await rewind.rewindLastN(
|
|
11264
|
+
result = await rewind.rewindLastN(targetSessionId, n);
|
|
10955
11265
|
} else if (flags.to) {
|
|
10956
11266
|
const idx = Number.parseInt(flags.to, 10);
|
|
10957
11267
|
if (Number.isNaN(idx) || idx < 0) {
|
|
@@ -10960,7 +11270,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10960
11270
|
}
|
|
10961
11271
|
deps.renderer.write(`Rewinding to checkpoint ${idx}...
|
|
10962
11272
|
`);
|
|
10963
|
-
result = await rewind.rewindToCheckpoint(
|
|
11273
|
+
result = await rewind.rewindToCheckpoint(targetSessionId, idx);
|
|
10964
11274
|
} else {
|
|
10965
11275
|
deps.renderer.write("Usage: ws rewind --all | --last N | --to <index> [--list] [--resume]\n");
|
|
10966
11276
|
deps.renderer.write(" --all Rewind to session start\n");
|
|
@@ -10974,7 +11284,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10974
11284
|
deps.renderer.write("No files to revert.\n");
|
|
10975
11285
|
if (flags.resume) {
|
|
10976
11286
|
const store = new DefaultSessionStore({ dir: sessionsDir });
|
|
10977
|
-
const resumed = await store.resume(
|
|
11287
|
+
const resumed = await store.resume(targetSessionId);
|
|
10978
11288
|
const toIdx = result.toPromptIndex;
|
|
10979
11289
|
await resumed.writer.truncateToCheckpoint(toIdx);
|
|
10980
11290
|
await resumed.writer.close();
|
|
@@ -10992,7 +11302,7 @@ Reverted ${result.revertedFiles.length} file(s):
|
|
|
10992
11302
|
}
|
|
10993
11303
|
if (flags.resume) {
|
|
10994
11304
|
const store = new DefaultSessionStore({ dir: sessionsDir });
|
|
10995
|
-
const resumed = await store.resume(
|
|
11305
|
+
const resumed = await store.resume(targetSessionId);
|
|
10996
11306
|
const toIdx = result.toPromptIndex;
|
|
10997
11307
|
const removed = await resumed.writer.truncateToCheckpoint(toIdx);
|
|
10998
11308
|
await resumed.writer.close();
|
|
@@ -11295,22 +11605,22 @@ function fmtDuration(ms) {
|
|
|
11295
11605
|
const remMin = m - h * 60;
|
|
11296
11606
|
return `${h}h${remMin}m`;
|
|
11297
11607
|
}
|
|
11298
|
-
function fmtTaskResultLine(r,
|
|
11608
|
+
function fmtTaskResultLine(r, color52) {
|
|
11299
11609
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
11300
11610
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
11301
11611
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
11302
11612
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
11303
|
-
const errKindChip = errKind ?
|
|
11304
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
11613
|
+
const errKindChip = errKind ? color52.dim(` [${errKind}]`) : "";
|
|
11614
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color52.dim(errTail)}` : "";
|
|
11305
11615
|
switch (r.status) {
|
|
11306
11616
|
case "success":
|
|
11307
|
-
return { mark:
|
|
11617
|
+
return { mark: color52.green("\u2713"), stats, tail: "" };
|
|
11308
11618
|
case "timeout":
|
|
11309
|
-
return { mark:
|
|
11619
|
+
return { mark: color52.yellow("\u23F1"), stats: `${color52.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
11310
11620
|
case "stopped":
|
|
11311
|
-
return { mark:
|
|
11621
|
+
return { mark: color52.dim("\u2298"), stats: `${color52.dim("stopped")} ${stats}`, tail: errSnip };
|
|
11312
11622
|
case "failed":
|
|
11313
|
-
return { mark:
|
|
11623
|
+
return { mark: color52.red("\u2717"), stats: `${color52.red("failed")} ${stats}`, tail: errSnip };
|
|
11314
11624
|
}
|
|
11315
11625
|
}
|
|
11316
11626
|
|
|
@@ -11359,8 +11669,8 @@ async function boot(argv) {
|
|
|
11359
11669
|
file: wpaths.logFile,
|
|
11360
11670
|
// Suppress stderr output in TUI mode: plugin/library log messages
|
|
11361
11671
|
// (e.g. Telegram "getUpdates failed") write directly to stderr and
|
|
11362
|
-
// bypass Ink, which breaks the Static/live boundary
|
|
11363
|
-
//
|
|
11672
|
+
// bypass Ink, which breaks the Static/live boundary.
|
|
11673
|
+
// Logs still go to the disk file for post-hoc debugging.
|
|
11364
11674
|
stderr: !flags.tui
|
|
11365
11675
|
});
|
|
11366
11676
|
const renderer = new TerminalRenderer();
|
|
@@ -11411,7 +11721,7 @@ async function boot(argv) {
|
|
|
11411
11721
|
[...builtinToolsPack.tools ?? []],
|
|
11412
11722
|
builtinToolsPack.name
|
|
11413
11723
|
);
|
|
11414
|
-
const code = await subcommands[first](positional.slice(1), {
|
|
11724
|
+
const code = await subcommands[first]?.(positional.slice(1), {
|
|
11415
11725
|
config,
|
|
11416
11726
|
renderer,
|
|
11417
11727
|
reader,
|
|
@@ -11903,6 +12213,12 @@ async function predictNextTasks(input, opts) {
|
|
|
11903
12213
|
}
|
|
11904
12214
|
}
|
|
11905
12215
|
init_sdd();
|
|
12216
|
+
function expectDefined15(value) {
|
|
12217
|
+
if (value === null || value === void 0) {
|
|
12218
|
+
throw new Error("Expected value to be defined");
|
|
12219
|
+
}
|
|
12220
|
+
return value;
|
|
12221
|
+
}
|
|
11906
12222
|
async function runRepl(opts) {
|
|
11907
12223
|
if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
|
|
11908
12224
|
await renderGoalBanner(opts);
|
|
@@ -12418,7 +12734,7 @@ async function renderGoalBanner(opts) {
|
|
|
12418
12734
|
color.dim("Goal: ") + stateColor(summary) + color.dim(` [${goal.goalState}] (iter ${goal.iterations})`) + "\n"
|
|
12419
12735
|
);
|
|
12420
12736
|
if (goal.journal.length > 0) {
|
|
12421
|
-
const lastEntry = goal.journal[goal.journal.length - 1];
|
|
12737
|
+
const lastEntry = expectDefined15(goal.journal[goal.journal.length - 1]);
|
|
12422
12738
|
const statusIcon = lastEntry.status === "success" ? "\u2713" : lastEntry.status === "failure" ? "\u2717" : lastEntry.status === "aborted" ? "\u2298" : lastEntry.status === "skipped" ? "\u229D" : "\xB7";
|
|
12423
12739
|
opts.renderer.write(
|
|
12424
12740
|
color.dim(` Last: ${statusIcon} ${lastEntry.task} (${lastEntry.status})`) + "\n"
|
|
@@ -12872,20 +13188,10 @@ async function execute(deps) {
|
|
|
12872
13188
|
titleAnimation: config.autonomy?.["terminalTitleAnimation"] ?? true,
|
|
12873
13189
|
// Completion chime: terminal bell when agent finishes.
|
|
12874
13190
|
chime: config.autonomy?.["chime"] ?? false,
|
|
12875
|
-
//
|
|
13191
|
+
// Normal exit.
|
|
12876
13192
|
confirmExit: config.autonomy?.["confirmExit"] ?? true,
|
|
12877
|
-
// Default OFF so the terminal's native scrollback works for chat
|
|
12878
|
-
// history out of the box. Users who hit resize/overlay-leak
|
|
12879
|
-
// artifacts can opt back into alt-screen with `--alt-screen`.
|
|
12880
|
-
// `--no-alt-screen` still wins when both are passed.
|
|
12881
|
-
altScreen: flags["alt-screen"] === true && flags["no-alt-screen"] !== true,
|
|
12882
13193
|
director,
|
|
12883
13194
|
fleetRoster,
|
|
12884
|
-
onAfterExit: () => {
|
|
12885
|
-
writeOut(
|
|
12886
|
-
color.dim(`Session saved: ${session.id} \u2014 resume with `) + color.cyan(`wstack resume ${session.id}`) + "\n"
|
|
12887
|
-
);
|
|
12888
|
-
},
|
|
12889
13195
|
onClearHistory: (dispatch) => {
|
|
12890
13196
|
dispatch({ type: "clearHistory" });
|
|
12891
13197
|
dispatch({ type: "resetContextChip" });
|
|
@@ -13030,6 +13336,12 @@ async function execute(deps) {
|
|
|
13030
13336
|
}
|
|
13031
13337
|
return code;
|
|
13032
13338
|
}
|
|
13339
|
+
function expectDefined17(value) {
|
|
13340
|
+
if (value === null || value === void 0) {
|
|
13341
|
+
throw new Error("Expected value to be defined");
|
|
13342
|
+
}
|
|
13343
|
+
return value;
|
|
13344
|
+
}
|
|
13033
13345
|
function buildRoutingRunner(config, host) {
|
|
13034
13346
|
const standardRunner = makeAgentSubagentRunner({
|
|
13035
13347
|
factory: host.makeSubagentFactory(config),
|
|
@@ -13038,7 +13350,7 @@ function buildRoutingRunner(config, host) {
|
|
|
13038
13350
|
return async (task, ctx) => {
|
|
13039
13351
|
const subCfg = ctx.config;
|
|
13040
13352
|
if (subCfg.provider === "acp") {
|
|
13041
|
-
const cacheKey = subCfg.role ?? subCfg.name ?? subCfg.id;
|
|
13353
|
+
const cacheKey = subCfg.role ?? subCfg.name ?? expectDefined17(subCfg.id);
|
|
13042
13354
|
return host.buildACPRunner(cacheKey).then((r) => r(task, ctx));
|
|
13043
13355
|
}
|
|
13044
13356
|
return standardRunner(task, ctx);
|
|
@@ -13481,6 +13793,7 @@ var MultiAgentHost = class {
|
|
|
13481
13793
|
*/
|
|
13482
13794
|
async _spawnAndAssign(subagentConfig) {
|
|
13483
13795
|
const taskId = randomUUID();
|
|
13796
|
+
if (!this.director) throw new Error("Director is not initialized");
|
|
13484
13797
|
const subagentId = await this.director.spawn(subagentConfig);
|
|
13485
13798
|
await this.director.assign({ id: taskId, description: "", subagentId });
|
|
13486
13799
|
return { subagentId, taskId };
|
|
@@ -14259,9 +14572,18 @@ var Spinner = class {
|
|
|
14259
14572
|
context;
|
|
14260
14573
|
out;
|
|
14261
14574
|
enabled;
|
|
14262
|
-
|
|
14575
|
+
/**
|
|
14576
|
+
* @param out Stream the spinner writes to (default stderr).
|
|
14577
|
+
* @param opts.enabled Hard override. When `false`, every method becomes a
|
|
14578
|
+
* no-op regardless of TTY state — used to silence the spinner when the Ink
|
|
14579
|
+
* TUI owns the screen (the spinner writes to stderr on an 80ms timer, which
|
|
14580
|
+
* interleaves with Ink's stdout cursor math and corrupts the live region:
|
|
14581
|
+
* it leaks the input row into scrollback and paints a stray
|
|
14582
|
+
* "thinking… ctx" tracker at the very bottom). Defaults to TTY detection.
|
|
14583
|
+
*/
|
|
14584
|
+
constructor(out = process.stderr, opts) {
|
|
14263
14585
|
this.out = out;
|
|
14264
|
-
this.enabled = Boolean(out.isTTY) && !process.env.NO_COLOR;
|
|
14586
|
+
this.enabled = (opts?.enabled ?? Boolean(out.isTTY)) && !process.env.NO_COLOR;
|
|
14265
14587
|
}
|
|
14266
14588
|
start(label) {
|
|
14267
14589
|
if (!this.enabled || this.active) return;
|
|
@@ -14917,8 +15239,17 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
14917
15239
|
}
|
|
14918
15240
|
return { resolvedProvider, provider, providerRegistry };
|
|
14919
15241
|
}
|
|
15242
|
+
function expectDefined18(value) {
|
|
15243
|
+
if (value === null || value === void 0) {
|
|
15244
|
+
throw new Error("Expected value to be defined");
|
|
15245
|
+
}
|
|
15246
|
+
return value;
|
|
15247
|
+
}
|
|
14920
15248
|
async function setupSession(params) {
|
|
14921
15249
|
const { config, wpaths, projectRoot, cwd, sessionStore, systemPrompt, provider, tokenCounter, renderer, flags, onRecovery } = params;
|
|
15250
|
+
sessionStore.prune(30).then((count) => {
|
|
15251
|
+
if (count > 0) renderer.writeInfo(`Pruned ${count} old session${count === 1 ? "" : "s"}.`);
|
|
15252
|
+
}).catch(() => void 0);
|
|
14922
15253
|
let resumeId = typeof flags["resume"] === "string" ? flags["resume"] : void 0;
|
|
14923
15254
|
const recoveryLock = new RecoveryLock({ dir: wpaths.projectSessions, sessionStore });
|
|
14924
15255
|
if (!resumeId && !flags["no-recovery"]) {
|
|
@@ -14951,13 +15282,13 @@ async function setupSession(params) {
|
|
|
14951
15282
|
session = await sessionStore.create({ id: "", title: "", model: config.model, provider: config.provider });
|
|
14952
15283
|
}
|
|
14953
15284
|
const sessionRef = { current: session };
|
|
14954
|
-
await recoveryLock.write(session
|
|
14955
|
-
const attachments = new DefaultAttachmentStore({ spoolDir: path8.join(wpaths.projectSessions, session
|
|
14956
|
-
const queueStore = new QueueStore({ dir: path8.join(wpaths.projectSessions, session
|
|
15285
|
+
await recoveryLock.write(session?.id).catch(() => void 0);
|
|
15286
|
+
const attachments = new DefaultAttachmentStore({ spoolDir: path8.join(wpaths.projectSessions, session?.id, "attachments") });
|
|
15287
|
+
const queueStore = new QueueStore({ dir: path8.join(wpaths.projectSessions, session?.id) });
|
|
14957
15288
|
const ctxSignal = new AbortController().signal;
|
|
14958
|
-
const context = new Context({ systemPrompt, provider, session, signal: ctxSignal, tokenCounter, cwd, projectRoot, model: config.model });
|
|
15289
|
+
const context = new Context({ systemPrompt, provider, session: expectDefined18(session), signal: ctxSignal, tokenCounter, cwd, projectRoot, model: config.model });
|
|
14959
15290
|
if (restoredMessages.length > 0) context.state.replaceMessages(restoredMessages);
|
|
14960
|
-
const todosCheckpointPath = path8.join(wpaths.projectSessions, `${session
|
|
15291
|
+
const todosCheckpointPath = path8.join(wpaths.projectSessions, `${session?.id}.todos.json`);
|
|
14961
15292
|
if (resumeId) {
|
|
14962
15293
|
try {
|
|
14963
15294
|
const restoredTodos = await loadTodosCheckpoint(todosCheckpointPath);
|
|
@@ -14968,13 +15299,13 @@ async function setupSession(params) {
|
|
|
14968
15299
|
} catch {
|
|
14969
15300
|
}
|
|
14970
15301
|
}
|
|
14971
|
-
const detachTodosCheckpoint = attachTodosCheckpoint(context.state, todosCheckpointPath, session
|
|
14972
|
-
const planPath = path8.join(wpaths.projectSessions, `${session
|
|
15302
|
+
const detachTodosCheckpoint = attachTodosCheckpoint(context.state, todosCheckpointPath, session?.id);
|
|
15303
|
+
const planPath = path8.join(wpaths.projectSessions, `${session?.id}.plan.json`);
|
|
14973
15304
|
context.state.setMeta("plan.path", planPath);
|
|
14974
15305
|
let dirState;
|
|
14975
15306
|
if (resumeId) {
|
|
14976
15307
|
try {
|
|
14977
|
-
const fleetRoot = path8.join(wpaths.projectSessions, session
|
|
15308
|
+
const fleetRoot = path8.join(wpaths.projectSessions, session?.id);
|
|
14978
15309
|
dirState = await loadDirectorState(path8.join(fleetRoot, "director-state.json"));
|
|
14979
15310
|
if (dirState) {
|
|
14980
15311
|
const tCounts = {};
|
|
@@ -14994,7 +15325,7 @@ async function setupSession(params) {
|
|
|
14994
15325
|
} catch {
|
|
14995
15326
|
}
|
|
14996
15327
|
}
|
|
14997
|
-
return { session, sessionRef, context, restoredMessages, attachments, recoveryLock, queueStore, planPath, detachTodosCheckpoint, priorFleetState: dirState ?? void 0 };
|
|
15328
|
+
return { session: expectDefined18(session), sessionRef, context, restoredMessages, attachments, recoveryLock, queueStore, planPath, detachTodosCheckpoint, priorFleetState: dirState ?? void 0 };
|
|
14998
15329
|
}
|
|
14999
15330
|
function resolveBundledSkillsDir2() {
|
|
15000
15331
|
try {
|
|
@@ -15093,6 +15424,12 @@ async function launchEternalFromFlag(deps) {
|
|
|
15093
15424
|
}
|
|
15094
15425
|
|
|
15095
15426
|
// src/cli-main.ts
|
|
15427
|
+
function expectDefined19(value) {
|
|
15428
|
+
if (value === null || value === void 0) {
|
|
15429
|
+
throw new Error("Expected value to be defined");
|
|
15430
|
+
}
|
|
15431
|
+
return value;
|
|
15432
|
+
}
|
|
15096
15433
|
async function main(argv) {
|
|
15097
15434
|
const ctx = await boot(argv);
|
|
15098
15435
|
if (typeof ctx === "number") return ctx;
|
|
@@ -15228,7 +15565,8 @@ async function main(argv) {
|
|
|
15228
15565
|
});
|
|
15229
15566
|
return ms;
|
|
15230
15567
|
})();
|
|
15231
|
-
const
|
|
15568
|
+
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
15569
|
+
const spinner = new Spinner(process.stderr, { enabled: !tuiOwnsScreen });
|
|
15232
15570
|
let lastInputTokens = 0;
|
|
15233
15571
|
events.on("provider.response", (e) => {
|
|
15234
15572
|
lastInputTokens = e.usage?.input ?? 0;
|
|
@@ -15310,7 +15648,9 @@ async function main(argv) {
|
|
|
15310
15648
|
const planPath = sessResult.planPath;
|
|
15311
15649
|
const detachTodosCheckpoint = sessResult.detachTodosCheckpoint;
|
|
15312
15650
|
const priorFleetState = sessResult.priorFleetState;
|
|
15313
|
-
const sessionConfig = resolveSessionLoggingConfig(
|
|
15651
|
+
const sessionConfig = resolveSessionLoggingConfig(
|
|
15652
|
+
config
|
|
15653
|
+
);
|
|
15314
15654
|
const sessionBridge = createSessionEventBridge(
|
|
15315
15655
|
session,
|
|
15316
15656
|
sessionConfig.auditLevel,
|
|
@@ -15360,7 +15700,6 @@ async function main(argv) {
|
|
|
15360
15700
|
}).catch(() => {
|
|
15361
15701
|
});
|
|
15362
15702
|
});
|
|
15363
|
-
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
15364
15703
|
if (!tuiOwnsScreen) {
|
|
15365
15704
|
events.on("delegate.started", (e) => {
|
|
15366
15705
|
const task = e.task.length > 100 ? `${e.task.slice(0, 99)}\u2026` : e.task;
|
|
@@ -15571,10 +15910,10 @@ async function main(argv) {
|
|
|
15571
15910
|
}
|
|
15572
15911
|
};
|
|
15573
15912
|
const fleetRoot = directorMode ? path8.join(wpaths.projectSessions, session.id) : void 0;
|
|
15574
|
-
const manifestPath = directorMode ? typeof process.env["WRONGSTACK_FLEET_MANIFEST"] === "string" ? process.env["WRONGSTACK_FLEET_MANIFEST"] : path8.join(fleetRoot, "fleet.json") : void 0;
|
|
15575
|
-
const sharedScratchpadPath = directorMode ? path8.join(fleetRoot, "shared") : void 0;
|
|
15576
|
-
const subagentSessionsRoot = directorMode ? path8.join(fleetRoot, "subagents") : void 0;
|
|
15577
|
-
const stateCheckpointPath = directorMode ? path8.join(fleetRoot, "director-state.json") : void 0;
|
|
15913
|
+
const manifestPath = directorMode ? typeof process.env["WRONGSTACK_FLEET_MANIFEST"] === "string" ? process.env["WRONGSTACK_FLEET_MANIFEST"] : path8.join(expectDefined19(fleetRoot), "fleet.json") : void 0;
|
|
15914
|
+
const sharedScratchpadPath = directorMode ? path8.join(expectDefined19(fleetRoot), "shared") : void 0;
|
|
15915
|
+
const subagentSessionsRoot = directorMode ? path8.join(expectDefined19(fleetRoot), "subagents") : void 0;
|
|
15916
|
+
const stateCheckpointPath = directorMode ? path8.join(expectDefined19(fleetRoot), "director-state.json") : void 0;
|
|
15578
15917
|
const fleetRootForPromotion = path8.join(wpaths.projectSessions, session.id);
|
|
15579
15918
|
const brainQueue = new BrainDecisionQueue(events);
|
|
15580
15919
|
const brain = new ObservableBrainArbiter(
|
|
@@ -15993,7 +16332,7 @@ async function main(argv) {
|
|
|
15993
16332
|
...matches.map((m) => ` ${m.subagentId} (${m.runId})`)
|
|
15994
16333
|
].join("\n");
|
|
15995
16334
|
}
|
|
15996
|
-
const t = matches[0];
|
|
16335
|
+
const t = expectDefined19(matches[0]);
|
|
15997
16336
|
const raw = await fsp4.readFile(t.file, "utf8");
|
|
15998
16337
|
if (mode === "raw") return raw;
|
|
15999
16338
|
const lines = raw.split("\n").filter((l) => l.trim());
|