@wrongstack/cli 0.73.1 → 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 +951 -180
- package/dist/index.js.map +1 -1
- package/package.json +12 -11
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, 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,
|
|
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." };
|
|
@@ -3836,6 +3875,169 @@ function buildStatsCommand(opts) {
|
|
|
3836
3875
|
}
|
|
3837
3876
|
};
|
|
3838
3877
|
}
|
|
3878
|
+
async function persistAutonomySetting(deps, mutator) {
|
|
3879
|
+
let raw;
|
|
3880
|
+
let fileExists = true;
|
|
3881
|
+
try {
|
|
3882
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
3883
|
+
} catch (err) {
|
|
3884
|
+
if (err.code !== "ENOENT") {
|
|
3885
|
+
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
3886
|
+
}
|
|
3887
|
+
fileExists = false;
|
|
3888
|
+
raw = "{}";
|
|
3889
|
+
}
|
|
3890
|
+
let parsed;
|
|
3891
|
+
try {
|
|
3892
|
+
parsed = JSON.parse(raw);
|
|
3893
|
+
} catch (err) {
|
|
3894
|
+
if (fileExists) {
|
|
3895
|
+
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
3896
|
+
}
|
|
3897
|
+
parsed = {};
|
|
3898
|
+
}
|
|
3899
|
+
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
3900
|
+
const autonomy = decrypted.autonomy ?? {};
|
|
3901
|
+
mutator(autonomy);
|
|
3902
|
+
decrypted.autonomy = autonomy;
|
|
3903
|
+
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
3904
|
+
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3905
|
+
deps.configStore.update({ autonomy: decrypted.autonomy });
|
|
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
|
+
}
|
|
3934
|
+
async function persistTelegramConfig(deps, mutator) {
|
|
3935
|
+
let raw;
|
|
3936
|
+
let fileExists = true;
|
|
3937
|
+
try {
|
|
3938
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
3939
|
+
} catch (err) {
|
|
3940
|
+
if (err.code !== "ENOENT") {
|
|
3941
|
+
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
3942
|
+
}
|
|
3943
|
+
fileExists = false;
|
|
3944
|
+
raw = "{}";
|
|
3945
|
+
}
|
|
3946
|
+
let parsed;
|
|
3947
|
+
try {
|
|
3948
|
+
parsed = JSON.parse(raw);
|
|
3949
|
+
} catch (err) {
|
|
3950
|
+
if (fileExists) {
|
|
3951
|
+
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
3952
|
+
}
|
|
3953
|
+
parsed = {};
|
|
3954
|
+
}
|
|
3955
|
+
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
3956
|
+
const extensions = decrypted.extensions ?? {};
|
|
3957
|
+
const telegram = extensions.telegram ?? {};
|
|
3958
|
+
mutator(telegram);
|
|
3959
|
+
extensions.telegram = telegram;
|
|
3960
|
+
decrypted.extensions = extensions;
|
|
3961
|
+
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
3962
|
+
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3963
|
+
deps.configStore.update({ extensions: decrypted.extensions });
|
|
3964
|
+
}
|
|
3965
|
+
|
|
3966
|
+
// src/slash-commands/enhance.ts
|
|
3967
|
+
var noOpVault = {
|
|
3968
|
+
encrypt: (v) => v,
|
|
3969
|
+
decrypt: (v) => v,
|
|
3970
|
+
isEncrypted: () => false
|
|
3971
|
+
};
|
|
3972
|
+
function buildEnhanceCommand(opts) {
|
|
3973
|
+
const controller = opts.enhanceController;
|
|
3974
|
+
return {
|
|
3975
|
+
name: "enhance",
|
|
3976
|
+
category: "Config",
|
|
3977
|
+
description: 'Toggle prompt refinement ("did you mean this?") before sending.',
|
|
3978
|
+
help: [
|
|
3979
|
+
"Usage:",
|
|
3980
|
+
" /enhance Show current prompt-refinement status",
|
|
3981
|
+
" /enhance on Enable \u2014 refine free-text prompts before sending",
|
|
3982
|
+
" /enhance off Disable \u2014 send prompts verbatim",
|
|
3983
|
+
" /enhance toggle Flip the current state",
|
|
3984
|
+
"",
|
|
3985
|
+
"When on, each free-text message is rewritten into a clearer instruction",
|
|
3986
|
+
"by a separate LLM call and briefly previewed (auto-sends after a short",
|
|
3987
|
+
"countdown; Enter sends now, Esc keeps your original, e edits). Persisted",
|
|
3988
|
+
"to ~/.wrongstack/config.json (autonomy.enhance)."
|
|
3989
|
+
].join("\n"),
|
|
3990
|
+
async run(args) {
|
|
3991
|
+
if (!controller) {
|
|
3992
|
+
const msg2 = "Prompt refinement is not available in this session.";
|
|
3993
|
+
opts.renderer.writeWarning(msg2);
|
|
3994
|
+
return { message: msg2 };
|
|
3995
|
+
}
|
|
3996
|
+
const arg = args.trim().toLowerCase();
|
|
3997
|
+
if (!arg) {
|
|
3998
|
+
const status = controller.enabled ? `${color.cyan("ON")} ${color.dim("(prompts are refined before sending)")}` : `${color.green("OFF")} ${color.dim("(prompts are sent verbatim)")}`;
|
|
3999
|
+
const msg2 = `Prompt refinement: ${status}`;
|
|
4000
|
+
opts.renderer.write(msg2);
|
|
4001
|
+
return { message: msg2 };
|
|
4002
|
+
}
|
|
4003
|
+
let newState;
|
|
4004
|
+
if (arg === "on" || arg === "enable" || arg === "true" || arg === "1") {
|
|
4005
|
+
newState = true;
|
|
4006
|
+
} else if (arg === "off" || arg === "disable" || arg === "false" || arg === "0") {
|
|
4007
|
+
newState = false;
|
|
4008
|
+
} else if (arg === "toggle") {
|
|
4009
|
+
newState = !controller.enabled;
|
|
4010
|
+
} else {
|
|
4011
|
+
const msg2 = `Unknown argument: ${arg}. Use /enhance on, /enhance off, or /enhance toggle.`;
|
|
4012
|
+
opts.renderer.writeWarning(msg2);
|
|
4013
|
+
return { message: msg2 };
|
|
4014
|
+
}
|
|
4015
|
+
controller.setEnabled(newState);
|
|
4016
|
+
if (opts.configStore && opts.paths) {
|
|
4017
|
+
try {
|
|
4018
|
+
await persistAutonomySetting(
|
|
4019
|
+
{
|
|
4020
|
+
configStore: opts.configStore,
|
|
4021
|
+
globalConfigPath: opts.paths.globalConfig,
|
|
4022
|
+
vault: noOpVault
|
|
4023
|
+
},
|
|
4024
|
+
(autonomy) => {
|
|
4025
|
+
autonomy.enhance = newState;
|
|
4026
|
+
}
|
|
4027
|
+
);
|
|
4028
|
+
} catch (err) {
|
|
4029
|
+
opts.renderer.writeWarning(
|
|
4030
|
+
`Toggle applied for this session but could not be saved: ${err.message}`
|
|
4031
|
+
);
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4034
|
+
const label = newState ? `${color.cyan("ENABLED")} \u2014 free-text prompts will be refined before sending` : `${color.green("DISABLED")} \u2014 prompts are sent verbatim`;
|
|
4035
|
+
const msg = `Prompt refinement: ${label}`;
|
|
4036
|
+
opts.renderer.write(msg);
|
|
4037
|
+
return { message: msg };
|
|
4038
|
+
}
|
|
4039
|
+
};
|
|
4040
|
+
}
|
|
3839
4041
|
|
|
3840
4042
|
// src/slash-commands/fix-classifier.ts
|
|
3841
4043
|
var TS = ["typescript-strict"];
|
|
@@ -4500,6 +4702,7 @@ function categoryLabel(cli) {
|
|
|
4500
4702
|
function buildFixCommand(opts) {
|
|
4501
4703
|
return {
|
|
4502
4704
|
name: "fix",
|
|
4705
|
+
category: "Agent",
|
|
4503
4706
|
description: "Classify a bug/error (any language), activate the right skill, and fix it \u2014 inline or via subagent.",
|
|
4504
4707
|
argsHint: "<error message or problem description>",
|
|
4505
4708
|
help: `
|
|
@@ -4665,6 +4868,7 @@ var PHASE_ORDER = [
|
|
|
4665
4868
|
function buildFleetCommand(opts) {
|
|
4666
4869
|
return {
|
|
4667
4870
|
name: "fleet",
|
|
4871
|
+
category: "Agent",
|
|
4668
4872
|
description: "Inspect and control the agent fleet (subagents, parallel slots).",
|
|
4669
4873
|
help: [
|
|
4670
4874
|
"Usage:",
|
|
@@ -4969,6 +5173,7 @@ var KNOWN_VERBS = /* @__PURE__ */ new Set([
|
|
|
4969
5173
|
function buildGoalCommand(opts) {
|
|
4970
5174
|
return {
|
|
4971
5175
|
name: "goal",
|
|
5176
|
+
category: "Agent",
|
|
4972
5177
|
description: "Set, inspect, or clear the long-running autonomous mission used by /autonomy eternal.",
|
|
4973
5178
|
help: [
|
|
4974
5179
|
"Usage:",
|
|
@@ -5122,6 +5327,7 @@ ${lines.join("\n")}`;
|
|
|
5122
5327
|
function buildHelpCommand(opts) {
|
|
5123
5328
|
return {
|
|
5124
5329
|
name: "help",
|
|
5330
|
+
category: "App",
|
|
5125
5331
|
description: "Show available slash commands. Pass a name for detailed help.",
|
|
5126
5332
|
help: [
|
|
5127
5333
|
"Usage:",
|
|
@@ -5182,6 +5388,7 @@ function buildHelpCommand(opts) {
|
|
|
5182
5388
|
function buildInitCommand(opts) {
|
|
5183
5389
|
return {
|
|
5184
5390
|
name: "init",
|
|
5391
|
+
category: "Config",
|
|
5185
5392
|
description: "Create or update .wrongstack/AGENTS.md project context for the system prompt.",
|
|
5186
5393
|
async run(_args, ctx) {
|
|
5187
5394
|
const dir = path8.join(ctx.projectRoot, ".wrongstack");
|
|
@@ -5206,11 +5413,17 @@ No project type auto-detected. Edit the file with project context and instructio
|
|
|
5206
5413
|
}
|
|
5207
5414
|
};
|
|
5208
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
|
+
}
|
|
5209
5422
|
function parseMcpArgs(args) {
|
|
5210
5423
|
const trimmed = args.trim();
|
|
5211
5424
|
if (!trimmed || trimmed === "list") return { action: "list", name: "" };
|
|
5212
5425
|
const parts = trimmed.split(/\s+/);
|
|
5213
|
-
const action = parts[0];
|
|
5426
|
+
const action = expectDefined2(parts[0]);
|
|
5214
5427
|
const name = parts[1] ?? "";
|
|
5215
5428
|
const enable = parts.includes("--enable") || parts.includes("-e");
|
|
5216
5429
|
switch (action) {
|
|
@@ -5348,7 +5561,7 @@ async function runEnable(name, configured, configPath2, mcpRegistry) {
|
|
|
5348
5561
|
const mcpServers = {
|
|
5349
5562
|
...full.mcpServers ?? {}
|
|
5350
5563
|
};
|
|
5351
|
-
mcpServers[name] = { ...mcpServers[name], enabled: true };
|
|
5564
|
+
mcpServers[name] = { ...cfg, ...mcpServers[name] ?? {}, enabled: true };
|
|
5352
5565
|
full.mcpServers = mcpServers;
|
|
5353
5566
|
await writeConfig(configPath2, full);
|
|
5354
5567
|
try {
|
|
@@ -5367,7 +5580,7 @@ async function runDisable(name, configured, configPath2, mcpRegistry) {
|
|
|
5367
5580
|
const mcpServers = {
|
|
5368
5581
|
...full.mcpServers ?? {}
|
|
5369
5582
|
};
|
|
5370
|
-
mcpServers[name] = { ...mcpServers[name], enabled: false };
|
|
5583
|
+
mcpServers[name] = { ...cfg, ...mcpServers[name] ?? {}, enabled: false };
|
|
5371
5584
|
full.mcpServers = mcpServers;
|
|
5372
5585
|
await writeConfig(configPath2, full);
|
|
5373
5586
|
return `${color.yellow("Disabled")} "${name}" and stopped.`;
|
|
@@ -5421,6 +5634,7 @@ async function writeConfig(path26, cfg) {
|
|
|
5421
5634
|
function buildMcpSlashCommand(opts) {
|
|
5422
5635
|
return {
|
|
5423
5636
|
name: "mcp",
|
|
5637
|
+
category: "Config",
|
|
5424
5638
|
description: "Manage MCP servers: /mcp [list|add <name>|remove <name>|enable <name>|disable <name>|restart <name>]",
|
|
5425
5639
|
aliases: ["mcp-servers"],
|
|
5426
5640
|
argsHint: "[list|add <name>|remove <name>|enable <name>|disable <name>|restart <name>]",
|
|
@@ -5455,6 +5669,7 @@ function buildMcpSlashCommand(opts) {
|
|
|
5455
5669
|
function buildMemoryCommand(opts) {
|
|
5456
5670
|
return {
|
|
5457
5671
|
name: "memory",
|
|
5672
|
+
category: "Inspect",
|
|
5458
5673
|
description: "Inspect or edit persistent memory: /memory [show|remember <text>|forget <query>|clear]",
|
|
5459
5674
|
async run(args) {
|
|
5460
5675
|
const store = opts.memoryStore;
|
|
@@ -5508,8 +5723,7 @@ ${color.bold(color.amber("WrongStack") + color.dim(" \u2014 Mode Selection"))}
|
|
|
5508
5723
|
`);
|
|
5509
5724
|
lines.push(color.dim(" \u2191\u2193 navigate Enter select q quit\n"));
|
|
5510
5725
|
lines.push("");
|
|
5511
|
-
for (
|
|
5512
|
-
const m = modes[i];
|
|
5726
|
+
for (const [i, m] of modes.entries()) {
|
|
5513
5727
|
const mark = m.id === active?.id ? color.green(" [active]") : "";
|
|
5514
5728
|
const prefix = i === currentCursor ? color.bold("\u276F ") : " ";
|
|
5515
5729
|
const name = i === currentCursor ? color.bold(m.name) : m.name;
|
|
@@ -5541,6 +5755,7 @@ ${color.bold(color.amber("WrongStack") + color.dim(" \u2014 Mode Selection"))}
|
|
|
5541
5755
|
function buildModeCommand(opts) {
|
|
5542
5756
|
return {
|
|
5543
5757
|
name: "mode",
|
|
5758
|
+
category: "Config",
|
|
5544
5759
|
description: "Switch or view the current mode",
|
|
5545
5760
|
help: [
|
|
5546
5761
|
"Usage:",
|
|
@@ -5557,7 +5772,7 @@ function buildModeCommand(opts) {
|
|
|
5557
5772
|
" /mode brief Switch to brief mode",
|
|
5558
5773
|
" /mode teach Switch to teach mode"
|
|
5559
5774
|
].join("\n"),
|
|
5560
|
-
async run(args,
|
|
5775
|
+
async run(args, ctx) {
|
|
5561
5776
|
const modeStore = opts.modeStore;
|
|
5562
5777
|
if (!modeStore) {
|
|
5563
5778
|
return { message: "Mode store not available in this context." };
|
|
@@ -5571,6 +5786,7 @@ function buildModeCommand(opts) {
|
|
|
5571
5786
|
return { message: "Mode selection cancelled." };
|
|
5572
5787
|
}
|
|
5573
5788
|
await modeStore.setActiveMode(selected.id);
|
|
5789
|
+
ctx?.state?.setMeta?.("mode", selected.id);
|
|
5574
5790
|
return {
|
|
5575
5791
|
message: `Switched to "${selected.name}" mode.
|
|
5576
5792
|
${selected.description}`
|
|
@@ -5590,6 +5806,7 @@ ${selected.description}`
|
|
|
5590
5806
|
return { message: `Unknown mode "${target}". Available: ${available}` };
|
|
5591
5807
|
}
|
|
5592
5808
|
await modeStore.setActiveMode(targetMode.id);
|
|
5809
|
+
ctx?.state?.setMeta?.("mode", targetMode.id);
|
|
5593
5810
|
return {
|
|
5594
5811
|
message: `Switched to "${targetMode.name}" mode.
|
|
5595
5812
|
${targetMode.description}`
|
|
@@ -5597,7 +5814,7 @@ ${targetMode.description}`
|
|
|
5597
5814
|
}
|
|
5598
5815
|
};
|
|
5599
5816
|
}
|
|
5600
|
-
var
|
|
5817
|
+
var noOpVault2 = {
|
|
5601
5818
|
encrypt: (v) => v,
|
|
5602
5819
|
decrypt: (v) => v,
|
|
5603
5820
|
isEncrypted: () => false
|
|
@@ -5620,9 +5837,9 @@ async function patchGlobalConfig(globalConfigPath, mutate) {
|
|
|
5620
5837
|
}
|
|
5621
5838
|
parsed = {};
|
|
5622
5839
|
}
|
|
5623
|
-
const decrypted = decryptConfigSecrets$1(parsed,
|
|
5840
|
+
const decrypted = decryptConfigSecrets$1(parsed, noOpVault2);
|
|
5624
5841
|
mutate(decrypted);
|
|
5625
|
-
const encrypted = encryptConfigSecrets$1(decrypted,
|
|
5842
|
+
const encrypted = encryptConfigSecrets$1(decrypted, noOpVault2);
|
|
5626
5843
|
await atomicWrite(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
5627
5844
|
return decrypted;
|
|
5628
5845
|
}
|
|
@@ -5657,7 +5874,7 @@ function parseFlags(tokens) {
|
|
|
5657
5874
|
let maxOutput;
|
|
5658
5875
|
let i = 0;
|
|
5659
5876
|
while (i < tokens.length) {
|
|
5660
|
-
const t = tokens[i];
|
|
5877
|
+
const t = tokens[i] ?? "";
|
|
5661
5878
|
if (t.startsWith("--")) {
|
|
5662
5879
|
const key = t.slice(2);
|
|
5663
5880
|
switch (key) {
|
|
@@ -5727,6 +5944,7 @@ function buildModelsCommand(opts) {
|
|
|
5727
5944
|
].join("\n");
|
|
5728
5945
|
return {
|
|
5729
5946
|
name: "models",
|
|
5947
|
+
category: "Config",
|
|
5730
5948
|
description: "Manage custom model definitions.",
|
|
5731
5949
|
help,
|
|
5732
5950
|
async run(args) {
|
|
@@ -5753,7 +5971,10 @@ function buildModelsCommand(opts) {
|
|
|
5753
5971
|
return {
|
|
5754
5972
|
message: [
|
|
5755
5973
|
`${color.bold("Custom Models")} ${color.dim(`(${ids.length})`)}`,
|
|
5756
|
-
...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)
|
|
5757
5978
|
].join("\n")
|
|
5758
5979
|
};
|
|
5759
5980
|
}
|
|
@@ -5818,6 +6039,7 @@ function buildModelsCommand(opts) {
|
|
|
5818
6039
|
function buildNextCommand(opts) {
|
|
5819
6040
|
return {
|
|
5820
6041
|
name: "next",
|
|
6042
|
+
category: "Config",
|
|
5821
6043
|
description: "Toggle next-task prediction \u2014 show likely next steps after each turn.",
|
|
5822
6044
|
argsHint: "[on|off|toggle]",
|
|
5823
6045
|
help: [
|
|
@@ -5869,6 +6091,7 @@ function buildNextCommand(opts) {
|
|
|
5869
6091
|
function buildPluginCommand(opts) {
|
|
5870
6092
|
return {
|
|
5871
6093
|
name: "plugin",
|
|
6094
|
+
category: "Config",
|
|
5872
6095
|
aliases: ["plugins"],
|
|
5873
6096
|
description: "Manage plugins: /plugin [list|status|official|install <alias>|enable <name>|disable <name>|remove <name>]",
|
|
5874
6097
|
argsHint: "[list|status|official|install <alias>|enable <name>|disable <name>|remove <name>]",
|
|
@@ -5896,12 +6119,86 @@ function buildPluginCommand(opts) {
|
|
|
5896
6119
|
}
|
|
5897
6120
|
};
|
|
5898
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
|
+
}
|
|
5899
6195
|
|
|
5900
6196
|
// src/slash-commands/index.ts
|
|
5901
6197
|
init_sdd();
|
|
5902
6198
|
function buildSaveCommand(opts) {
|
|
5903
6199
|
return {
|
|
5904
6200
|
name: "save",
|
|
6201
|
+
category: "Session",
|
|
5905
6202
|
description: "Save current session (auto by default; this forces flush).",
|
|
5906
6203
|
async run(_args, ctx) {
|
|
5907
6204
|
await ctx.session.append({
|
|
@@ -5916,6 +6213,7 @@ function buildSaveCommand(opts) {
|
|
|
5916
6213
|
function buildLoadCommand(opts) {
|
|
5917
6214
|
return {
|
|
5918
6215
|
name: "resume",
|
|
6216
|
+
category: "Session",
|
|
5919
6217
|
aliases: ["load", "sessions"],
|
|
5920
6218
|
description: "List recent sessions, show incomplete ones (--incomplete), or plan a recovery (--recover <id>).",
|
|
5921
6219
|
async run(args) {
|
|
@@ -5999,15 +6297,30 @@ function buildLoadCommand(opts) {
|
|
|
5999
6297
|
if (!opts.sessionStore) return { message: "No session store configured." };
|
|
6000
6298
|
const list = await opts.sessionStore.list(10);
|
|
6001
6299
|
if (list.length === 0) return { message: "No saved sessions." };
|
|
6002
|
-
const lines = list.map(
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
${
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
`)
|
|
6010
|
-
|
|
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");
|
|
6011
6324
|
opts.renderer.write(msg);
|
|
6012
6325
|
return { message: msg };
|
|
6013
6326
|
}
|
|
@@ -6016,6 +6329,7 @@ ${color.dim("Tip: /resume --incomplete \u2014 list sessions that crashed mid-ite
|
|
|
6016
6329
|
function buildExitCommand(opts) {
|
|
6017
6330
|
return {
|
|
6018
6331
|
name: "exit",
|
|
6332
|
+
category: "App",
|
|
6019
6333
|
aliases: ["quit", "q"],
|
|
6020
6334
|
description: "Exit the REPL.",
|
|
6021
6335
|
async run() {
|
|
@@ -6072,7 +6386,13 @@ function summariseEvent(ev) {
|
|
|
6072
6386
|
return color.dim("\u2026");
|
|
6073
6387
|
}
|
|
6074
6388
|
}
|
|
6075
|
-
|
|
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
|
+
}
|
|
6395
|
+
var noOpVault3 = {
|
|
6076
6396
|
encrypt: (v) => v,
|
|
6077
6397
|
decrypt: (v) => v,
|
|
6078
6398
|
isEncrypted: () => false
|
|
@@ -6124,9 +6444,9 @@ async function patchGlobalConfig2(globalConfigPath, mutate) {
|
|
|
6124
6444
|
throw new Error(`Config at ${globalConfigPath} is not valid JSON: ${err.message}`);
|
|
6125
6445
|
parsed = {};
|
|
6126
6446
|
}
|
|
6127
|
-
const decrypted = decryptConfigSecrets$1(parsed,
|
|
6447
|
+
const decrypted = decryptConfigSecrets$1(parsed, noOpVault3);
|
|
6128
6448
|
mutate(decrypted);
|
|
6129
|
-
const encrypted = encryptConfigSecrets$1(decrypted,
|
|
6449
|
+
const encrypted = encryptConfigSecrets$1(decrypted, noOpVault3);
|
|
6130
6450
|
await atomicWrite(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
6131
6451
|
return decrypted;
|
|
6132
6452
|
}
|
|
@@ -6164,7 +6484,7 @@ function buildSetModelCommand(opts) {
|
|
|
6164
6484
|
for (const k of keys.sort()) {
|
|
6165
6485
|
const kind = matrixKeyKind(k);
|
|
6166
6486
|
const tag = kind === "unknown" ? color.red("?") : color.dim(kind);
|
|
6167
|
-
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}`);
|
|
6168
6488
|
}
|
|
6169
6489
|
}
|
|
6170
6490
|
lines.push("", color.dim(" /setmodel list for valid keys \xB7 /setmodel help for usage"));
|
|
@@ -6172,6 +6492,7 @@ function buildSetModelCommand(opts) {
|
|
|
6172
6492
|
}
|
|
6173
6493
|
return {
|
|
6174
6494
|
name: "setmodel",
|
|
6495
|
+
category: "Config",
|
|
6175
6496
|
description: "View or change the leader model and the per-task model matrix.",
|
|
6176
6497
|
help,
|
|
6177
6498
|
async run(args) {
|
|
@@ -6286,38 +6607,7 @@ function buildSetModelCommand(opts) {
|
|
|
6286
6607
|
}
|
|
6287
6608
|
};
|
|
6288
6609
|
}
|
|
6289
|
-
|
|
6290
|
-
let raw;
|
|
6291
|
-
let fileExists = true;
|
|
6292
|
-
try {
|
|
6293
|
-
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
6294
|
-
} catch (err) {
|
|
6295
|
-
if (err.code !== "ENOENT") {
|
|
6296
|
-
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
6297
|
-
}
|
|
6298
|
-
fileExists = false;
|
|
6299
|
-
raw = "{}";
|
|
6300
|
-
}
|
|
6301
|
-
let parsed;
|
|
6302
|
-
try {
|
|
6303
|
-
parsed = JSON.parse(raw);
|
|
6304
|
-
} catch (err) {
|
|
6305
|
-
if (fileExists) {
|
|
6306
|
-
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
6307
|
-
}
|
|
6308
|
-
parsed = {};
|
|
6309
|
-
}
|
|
6310
|
-
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
6311
|
-
const autonomy = decrypted.autonomy ?? {};
|
|
6312
|
-
mutator(autonomy);
|
|
6313
|
-
decrypted.autonomy = autonomy;
|
|
6314
|
-
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
6315
|
-
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
6316
|
-
deps.configStore.update({ autonomy: decrypted.autonomy });
|
|
6317
|
-
}
|
|
6318
|
-
|
|
6319
|
-
// src/slash-commands/settings.ts
|
|
6320
|
-
var noOpVault3 = {
|
|
6610
|
+
var noOpVault4 = {
|
|
6321
6611
|
encrypt: (v) => v,
|
|
6322
6612
|
decrypt: (v) => v,
|
|
6323
6613
|
isEncrypted: () => false
|
|
@@ -6333,6 +6623,7 @@ function buildSettingsCommand(opts) {
|
|
|
6333
6623
|
" /settings Show current settings",
|
|
6334
6624
|
" /settings delay <seconds> Auto-proceed delay in auto mode (0 disables)",
|
|
6335
6625
|
" /settings mode <off|suggest|auto> Default autonomy mode at startup",
|
|
6626
|
+
" /settings hints on|off Show or suppress rotating launch hints",
|
|
6336
6627
|
" /settings defaults Show built-in default values",
|
|
6337
6628
|
"",
|
|
6338
6629
|
"Settings are persisted to ~/.wrongstack/config.json."
|
|
@@ -6341,18 +6632,21 @@ function buildSettingsCommand(opts) {
|
|
|
6341
6632
|
const autonomy = opts.configStore.get().autonomy;
|
|
6342
6633
|
const delay = autonomy?.autoProceedDelayMs ?? 45e3;
|
|
6343
6634
|
const mode = autonomy?.defaultMode ?? "off";
|
|
6635
|
+
const hints = opts.configStore.get().hints !== false;
|
|
6344
6636
|
return [
|
|
6345
6637
|
`${color.bold("WrongStack")} ${color.dim("\u2014 Settings")}`,
|
|
6346
6638
|
"",
|
|
6347
6639
|
` auto-proceed delay: ${color.cyan(formatDelay(delay))} ${color.dim("change: /settings delay <seconds>")}`,
|
|
6348
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")}`,
|
|
6349
6642
|
"",
|
|
6350
6643
|
color.dim(" Persisted to ~/.wrongstack/config.json \xB7 /settings help for more")
|
|
6351
6644
|
].join("\n");
|
|
6352
6645
|
}
|
|
6353
6646
|
return {
|
|
6354
6647
|
name: "settings",
|
|
6355
|
-
|
|
6648
|
+
category: "Config",
|
|
6649
|
+
description: "View or change settings (auto-proceed delay, default autonomy mode, launch hints).",
|
|
6356
6650
|
help,
|
|
6357
6651
|
async run(args) {
|
|
6358
6652
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
@@ -6373,6 +6667,7 @@ function buildSettingsCommand(opts) {
|
|
|
6373
6667
|
"",
|
|
6374
6668
|
` auto-proceed delay: ${color.cyan("45s")} ${color.dim("(WRONGSTACK_AUTO_PROCEED_DELAY_MS env)")}`,
|
|
6375
6669
|
` default autonomy mode: ${color.cyan("off")}`,
|
|
6670
|
+
` launch hints: ${color.cyan("on")}`,
|
|
6376
6671
|
` iteration timeout: ${color.cyan("5 min")}`,
|
|
6377
6672
|
` session timeout: ${color.cyan("30 min")}`,
|
|
6378
6673
|
` max iterations: ${color.cyan("100")}`
|
|
@@ -6382,7 +6677,7 @@ function buildSettingsCommand(opts) {
|
|
|
6382
6677
|
const persistDeps = {
|
|
6383
6678
|
configStore: opts.configStore,
|
|
6384
6679
|
globalConfigPath: opts.paths.globalConfig,
|
|
6385
|
-
vault:
|
|
6680
|
+
vault: noOpVault4
|
|
6386
6681
|
};
|
|
6387
6682
|
try {
|
|
6388
6683
|
if (sub === "delay") {
|
|
@@ -6415,8 +6710,19 @@ function buildSettingsCommand(opts) {
|
|
|
6415
6710
|
});
|
|
6416
6711
|
return { message: `${color.green("\u2713")} default autonomy \u2192 ${color.bold(raw)}` };
|
|
6417
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
|
+
}
|
|
6418
6724
|
return {
|
|
6419
|
-
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")}.`
|
|
6420
6726
|
};
|
|
6421
6727
|
} catch (err) {
|
|
6422
6728
|
return {
|
|
@@ -6426,11 +6732,164 @@ function buildSettingsCommand(opts) {
|
|
|
6426
6732
|
}
|
|
6427
6733
|
};
|
|
6428
6734
|
}
|
|
6735
|
+
var noOpVault5 = {
|
|
6736
|
+
encrypt: (v) => v,
|
|
6737
|
+
decrypt: (v) => v,
|
|
6738
|
+
isEncrypted: () => false
|
|
6739
|
+
};
|
|
6740
|
+
var HELP = [
|
|
6741
|
+
"Usage:",
|
|
6742
|
+
" /telegram-setup Show setup instructions",
|
|
6743
|
+
" /telegram-setup <botToken> Validate and save bot token",
|
|
6744
|
+
" /telegram-setup <botToken> <chatId> Save token and default chat ID",
|
|
6745
|
+
"",
|
|
6746
|
+
"Aliases: /tg-setup",
|
|
6747
|
+
"",
|
|
6748
|
+
"Quick start:",
|
|
6749
|
+
" 1. Message @BotFather on Telegram \u2192 /newbot \u2192 copy the token",
|
|
6750
|
+
" 2. Message your new bot, then visit:",
|
|
6751
|
+
" https://api.telegram.org/bot<TOKEN>/getUpdates",
|
|
6752
|
+
" Copy the chat.id from the JSON response.",
|
|
6753
|
+
" 3. Run: /telegram-setup <botToken> <chatId>",
|
|
6754
|
+
" 4. Restart WrongStack to activate the plugin."
|
|
6755
|
+
].join("\n");
|
|
6756
|
+
function buildTelegramSetupCommand(opts) {
|
|
6757
|
+
return {
|
|
6758
|
+
name: "telegram-setup",
|
|
6759
|
+
category: "Config",
|
|
6760
|
+
aliases: ["tg-setup"],
|
|
6761
|
+
description: "Configure Telegram bot token and default chat. /telegram-setup <token> [chatId]",
|
|
6762
|
+
argsHint: "[botToken] [chatId]",
|
|
6763
|
+
help: HELP,
|
|
6764
|
+
async run(args) {
|
|
6765
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
6766
|
+
const sub = (parts[0] ?? "").toLowerCase();
|
|
6767
|
+
if (sub === "help" || sub === "--help" || sub === "-h") {
|
|
6768
|
+
return { message: HELP };
|
|
6769
|
+
}
|
|
6770
|
+
if (!sub) {
|
|
6771
|
+
const config = opts.configStore.get();
|
|
6772
|
+
const hasTelegram = (config.plugins ?? []).some((p) => {
|
|
6773
|
+
const name = typeof p === "string" ? p : p.name;
|
|
6774
|
+
return name === "@wrongstack/telegram" || name === "telegram";
|
|
6775
|
+
});
|
|
6776
|
+
const lines = [
|
|
6777
|
+
`${color.bold("Telegram Setup")}`,
|
|
6778
|
+
""
|
|
6779
|
+
];
|
|
6780
|
+
if (!hasTelegram) {
|
|
6781
|
+
lines.push(
|
|
6782
|
+
`${color.amber("\u26A0")} Telegram plugin is not installed.`,
|
|
6783
|
+
` Run: ${color.cyan("/plugin install telegram")}`,
|
|
6784
|
+
` Then run ${color.cyan("/telegram-setup <botToken>")} to configure it.`,
|
|
6785
|
+
""
|
|
6786
|
+
);
|
|
6787
|
+
}
|
|
6788
|
+
lines.push(
|
|
6789
|
+
"1. Create a bot: message @BotFather \u2192 /newbot \u2192 copy the token",
|
|
6790
|
+
"2. Get your chat ID: message your bot, then open in browser:",
|
|
6791
|
+
` ${color.dim("https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates")}`,
|
|
6792
|
+
" Find chat.id in the JSON response.",
|
|
6793
|
+
"3. Configure: /telegram-setup <botToken> <chatId>",
|
|
6794
|
+
"4. Restart WrongStack."
|
|
6795
|
+
);
|
|
6796
|
+
return { message: lines.join("\n") };
|
|
6797
|
+
}
|
|
6798
|
+
const botToken = parts[0] ?? "";
|
|
6799
|
+
const chatId = parts[1];
|
|
6800
|
+
if (!/^\d+:[A-Za-z0-9_-]+$/.test(botToken)) {
|
|
6801
|
+
return {
|
|
6802
|
+
message: [
|
|
6803
|
+
`${color.red("\u2717")} Invalid token format.`,
|
|
6804
|
+
`Expected: ${color.dim("123456789:ABCdefGHIjkl...")}`,
|
|
6805
|
+
`Got: ${botToken.slice(0, 20)}...`,
|
|
6806
|
+
"",
|
|
6807
|
+
"Get a valid token from @BotFather on Telegram."
|
|
6808
|
+
].join("\n")
|
|
6809
|
+
};
|
|
6810
|
+
}
|
|
6811
|
+
let botInfo;
|
|
6812
|
+
try {
|
|
6813
|
+
const res = await fetch(`https://api.telegram.org/bot${botToken}/getMe`, {
|
|
6814
|
+
signal: AbortSignal.timeout(1e4)
|
|
6815
|
+
});
|
|
6816
|
+
botInfo = await res.json();
|
|
6817
|
+
} catch (err) {
|
|
6818
|
+
return {
|
|
6819
|
+
message: [
|
|
6820
|
+
`${color.red("\u2717")} Could not reach Telegram API.`,
|
|
6821
|
+
`Error: ${err.message}`,
|
|
6822
|
+
"",
|
|
6823
|
+
"Check your network connection and try again."
|
|
6824
|
+
].join("\n")
|
|
6825
|
+
};
|
|
6826
|
+
}
|
|
6827
|
+
if (!botInfo.ok || !botInfo.result) {
|
|
6828
|
+
return {
|
|
6829
|
+
message: [
|
|
6830
|
+
`${color.red("\u2717")} Invalid bot token.`,
|
|
6831
|
+
`Telegram says: ${botInfo.description ?? "Unknown error"}`,
|
|
6832
|
+
"",
|
|
6833
|
+
"Get a valid token from @BotFather on Telegram."
|
|
6834
|
+
].join("\n")
|
|
6835
|
+
};
|
|
6836
|
+
}
|
|
6837
|
+
const bot = botInfo.result;
|
|
6838
|
+
const persistDeps = {
|
|
6839
|
+
configStore: opts.configStore,
|
|
6840
|
+
globalConfigPath: opts.paths?.globalConfig ?? "",
|
|
6841
|
+
vault: noOpVault5
|
|
6842
|
+
};
|
|
6843
|
+
if (!persistDeps.globalConfigPath) {
|
|
6844
|
+
return {
|
|
6845
|
+
message: `${color.red("\u2717")} Config path not available. Cannot persist settings.`
|
|
6846
|
+
};
|
|
6847
|
+
}
|
|
6848
|
+
try {
|
|
6849
|
+
await persistTelegramConfig(persistDeps, (telegram) => {
|
|
6850
|
+
telegram.botToken = botToken;
|
|
6851
|
+
if (chatId) {
|
|
6852
|
+
telegram.notifyChatId = /^\d+$/.test(chatId) ? Number(chatId) : chatId;
|
|
6853
|
+
}
|
|
6854
|
+
if (telegram.notifyOnSessionEnd === void 0) {
|
|
6855
|
+
telegram.notifyOnSessionEnd = true;
|
|
6856
|
+
}
|
|
6857
|
+
});
|
|
6858
|
+
const chatLine = chatId ? `
|
|
6859
|
+
Default chat: ${color.green(chatId)}` : `
|
|
6860
|
+
${color.dim("No default chat set. You can add it later: /telegram-setup <token> <chatId>")}`;
|
|
6861
|
+
return {
|
|
6862
|
+
message: [
|
|
6863
|
+
`${color.green("\u2713")} Telegram configured successfully!`,
|
|
6864
|
+
"",
|
|
6865
|
+
`Bot: ${color.bold(`@${bot.username ?? bot.first_name}`)} ${color.dim(`(id=${bot.id})`)}`,
|
|
6866
|
+
`Name: ${bot.first_name}`,
|
|
6867
|
+
chatLine,
|
|
6868
|
+
"",
|
|
6869
|
+
`${color.amber("\u26A0")} Restart WrongStack for the plugin to pick up the new config.`,
|
|
6870
|
+
"",
|
|
6871
|
+
"After restart, try:",
|
|
6872
|
+
` ${color.cyan("/telegram:status")} \u2014 check bot connection`,
|
|
6873
|
+
` ${color.cyan("/telegram:send")} \u2014 send a test message`
|
|
6874
|
+
].join("\n")
|
|
6875
|
+
};
|
|
6876
|
+
} catch (err) {
|
|
6877
|
+
return {
|
|
6878
|
+
message: [
|
|
6879
|
+
`${color.red("\u2717")} Failed to save config.`,
|
|
6880
|
+
`Error: ${err.message}`
|
|
6881
|
+
].join("\n")
|
|
6882
|
+
};
|
|
6883
|
+
}
|
|
6884
|
+
}
|
|
6885
|
+
};
|
|
6886
|
+
}
|
|
6429
6887
|
|
|
6430
6888
|
// src/slash-commands/spawn-agents.ts
|
|
6431
6889
|
function buildSpawnCommand(opts) {
|
|
6432
6890
|
return {
|
|
6433
6891
|
name: "spawn",
|
|
6892
|
+
category: "Agent",
|
|
6434
6893
|
description: "Spawn an isolated subagent to handle a task.",
|
|
6435
6894
|
async run(args) {
|
|
6436
6895
|
const { description, opts: parsed } = parseSpawnFlags(args.trim());
|
|
@@ -6451,6 +6910,7 @@ function buildSpawnCommand(opts) {
|
|
|
6451
6910
|
function buildAgentsCommand(opts) {
|
|
6452
6911
|
return {
|
|
6453
6912
|
name: "agents",
|
|
6913
|
+
category: "Agent",
|
|
6454
6914
|
description: "Show status of spawned subagents. /agents monitor opens the agents monitor overlay. /agents on|off toggles the overlay.",
|
|
6455
6915
|
help: [
|
|
6456
6916
|
"Usage: /agents [monitor|on|off|stream on|stream off]",
|
|
@@ -6488,6 +6948,7 @@ function buildAgentsCommand(opts) {
|
|
|
6488
6948
|
function buildDirectorCommand(opts) {
|
|
6489
6949
|
return {
|
|
6490
6950
|
name: "director",
|
|
6951
|
+
category: "Agent",
|
|
6491
6952
|
description: "Promote this session to director mode, enabling fleet orchestration tools. Only works before any subagents are spawned.",
|
|
6492
6953
|
async run() {
|
|
6493
6954
|
if (!opts.onDirector) return { message: "Director promotion is not available in this session." };
|
|
@@ -6540,6 +7001,7 @@ async function saveStatuslineConfig(cfg) {
|
|
|
6540
7001
|
function buildStatuslineCommand(deps) {
|
|
6541
7002
|
return {
|
|
6542
7003
|
name: "statusline",
|
|
7004
|
+
category: "Config",
|
|
6543
7005
|
aliases: ["sl"],
|
|
6544
7006
|
description: "Customize status bar chips: /statusline [item] [on|off] or /statusline reset",
|
|
6545
7007
|
help: [
|
|
@@ -6609,10 +7071,31 @@ function buildStatuslineCommand(deps) {
|
|
|
6609
7071
|
}
|
|
6610
7072
|
};
|
|
6611
7073
|
}
|
|
7074
|
+
function findTodo(todos, query) {
|
|
7075
|
+
const asIndex = Number.parseInt(query, 10);
|
|
7076
|
+
if (!Number.isNaN(asIndex)) {
|
|
7077
|
+
const idx = asIndex - 1;
|
|
7078
|
+
const item = todos[idx];
|
|
7079
|
+
if (item) return { idx, item };
|
|
7080
|
+
}
|
|
7081
|
+
const byId = todos.findIndex((t) => t.id === query);
|
|
7082
|
+
if (byId >= 0) {
|
|
7083
|
+
const item = todos[byId];
|
|
7084
|
+
if (item) return { idx: byId, item };
|
|
7085
|
+
}
|
|
7086
|
+
const q = query.toLowerCase();
|
|
7087
|
+
const byContent = todos.findIndex((t) => t.content.toLowerCase().includes(q));
|
|
7088
|
+
if (byContent >= 0) {
|
|
7089
|
+
const item = todos[byContent];
|
|
7090
|
+
if (item) return { idx: byContent, item };
|
|
7091
|
+
}
|
|
7092
|
+
return null;
|
|
7093
|
+
}
|
|
6612
7094
|
function buildTodosCommand(opts) {
|
|
6613
7095
|
return {
|
|
6614
7096
|
name: "todos",
|
|
6615
|
-
|
|
7097
|
+
category: "Inspect",
|
|
7098
|
+
description: "Inspect or edit the live todo list: /todos [show|clear|add|done|remove|rm <id|index>]",
|
|
6616
7099
|
async run(args) {
|
|
6617
7100
|
const ctx = opts.context;
|
|
6618
7101
|
if (!ctx) return { message: "No active context." };
|
|
@@ -6626,36 +7109,50 @@ function buildTodosCommand(opts) {
|
|
|
6626
7109
|
}
|
|
6627
7110
|
case "clear": {
|
|
6628
7111
|
const n = ctx.todos.length;
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
};
|
|
7112
|
+
if (n === 0) return { message: "Todos were already empty." };
|
|
7113
|
+
ctx.state.replaceTodos([]);
|
|
7114
|
+
return { message: `Cleared ${n} todo${n === 1 ? "" : "s"}.` };
|
|
6633
7115
|
}
|
|
6634
7116
|
case "add": {
|
|
6635
7117
|
if (!restJoined) return { message: "Usage: /todos add <text>" };
|
|
6636
|
-
|
|
7118
|
+
const item = {
|
|
6637
7119
|
id: `todo_${Date.now()}_${randomUUID().slice(0, 7)}`,
|
|
6638
7120
|
content: restJoined,
|
|
6639
7121
|
status: "pending"
|
|
6640
|
-
}
|
|
7122
|
+
};
|
|
7123
|
+
ctx.state.replaceTodos([...ctx.todos, item]);
|
|
6641
7124
|
return { message: `Added: ${restJoined}` };
|
|
6642
7125
|
}
|
|
6643
7126
|
case "done":
|
|
6644
7127
|
case "complete": {
|
|
6645
7128
|
if (!restJoined) return { message: "Usage: /todos done <id|index>" };
|
|
6646
|
-
const
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
7129
|
+
const found = findTodo(ctx.todos, restJoined);
|
|
7130
|
+
if (!found) return { message: `No todo matched "${restJoined}".` };
|
|
7131
|
+
const doneItem = { ...found.item, status: "completed" };
|
|
7132
|
+
const nextTodos = [
|
|
7133
|
+
...ctx.todos.slice(0, found.idx),
|
|
7134
|
+
doneItem,
|
|
7135
|
+
...ctx.todos.slice(found.idx + 1)
|
|
7136
|
+
];
|
|
7137
|
+
ctx.state.replaceTodos(nextTodos);
|
|
7138
|
+
return { message: `Marked done: ${doneItem.content}` };
|
|
7139
|
+
}
|
|
7140
|
+
case "remove":
|
|
7141
|
+
case "rm":
|
|
7142
|
+
case "delete": {
|
|
7143
|
+
if (!restJoined) return { message: "Usage: /todos remove <id|index>" };
|
|
7144
|
+
const found = findTodo(ctx.todos, restJoined);
|
|
7145
|
+
if (!found) return { message: `No todo matched "${restJoined}".` };
|
|
7146
|
+
const nextTodos = [
|
|
7147
|
+
...ctx.todos.slice(0, found.idx),
|
|
7148
|
+
...ctx.todos.slice(found.idx + 1)
|
|
7149
|
+
];
|
|
7150
|
+
ctx.state.replaceTodos(nextTodos);
|
|
7151
|
+
return { message: `Removed: ${found.item.content}` };
|
|
6655
7152
|
}
|
|
6656
7153
|
default:
|
|
6657
7154
|
return {
|
|
6658
|
-
message: `Unknown subcommand "${verb}". Try: show | clear | add <text> | done <id|index>`
|
|
7155
|
+
message: `Unknown subcommand "${verb}". Try: show | clear | add <text> | done <id|index> | remove <id|index>`
|
|
6659
7156
|
};
|
|
6660
7157
|
}
|
|
6661
7158
|
}
|
|
@@ -6664,6 +7161,7 @@ function buildTodosCommand(opts) {
|
|
|
6664
7161
|
function buildToolsCommand(opts) {
|
|
6665
7162
|
return {
|
|
6666
7163
|
name: "tools",
|
|
7164
|
+
category: "Inspect",
|
|
6667
7165
|
description: "List registered tools.",
|
|
6668
7166
|
async run() {
|
|
6669
7167
|
const all = opts.toolRegistry.listWithOwner();
|
|
@@ -6683,6 +7181,7 @@ ${lines.join("\n")}
|
|
|
6683
7181
|
function buildWorktreeCommand(opts) {
|
|
6684
7182
|
return {
|
|
6685
7183
|
name: "worktree",
|
|
7184
|
+
category: "Config",
|
|
6686
7185
|
aliases: ["wt"],
|
|
6687
7186
|
description: "Inspect/manage git worktrees used for AutoPhase per-phase isolation.",
|
|
6688
7187
|
argsHint: "[list | merge <branch> | prune | clean]",
|
|
@@ -6726,6 +7225,7 @@ function buildWorktreeCommand(opts) {
|
|
|
6726
7225
|
function buildYoloCommand(opts) {
|
|
6727
7226
|
return {
|
|
6728
7227
|
name: "yolo",
|
|
7228
|
+
category: "Config",
|
|
6729
7229
|
description: "Toggle or query YOLO (auto-approve) mode.",
|
|
6730
7230
|
help: [
|
|
6731
7231
|
"Usage:",
|
|
@@ -6783,6 +7283,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6783
7283
|
buildCodebaseReindexCommand(opts),
|
|
6784
7284
|
buildToolsCommand(opts),
|
|
6785
7285
|
buildPluginCommand(opts),
|
|
7286
|
+
buildPruneCommand(opts),
|
|
6786
7287
|
buildMcpSlashCommand(opts),
|
|
6787
7288
|
buildDiagCommand(opts),
|
|
6788
7289
|
buildStatsCommand(opts),
|
|
@@ -6790,6 +7291,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6790
7291
|
buildAgentsCommand(opts),
|
|
6791
7292
|
buildDirectorCommand(opts),
|
|
6792
7293
|
buildFleetCommand(opts),
|
|
7294
|
+
buildEnhanceCommand(opts),
|
|
6793
7295
|
buildMemoryCommand(opts),
|
|
6794
7296
|
buildTodosCommand(opts),
|
|
6795
7297
|
buildSddCommand(opts),
|
|
@@ -6806,6 +7308,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6806
7308
|
buildAutoPhaseCommand(opts),
|
|
6807
7309
|
buildWorktreeCommand(opts),
|
|
6808
7310
|
buildSettingsCommand(opts),
|
|
7311
|
+
buildTelegramSetupCommand(opts),
|
|
6809
7312
|
buildSetModelCommand(opts),
|
|
6810
7313
|
buildModelsCommand(opts),
|
|
6811
7314
|
buildCollabCommand(opts),
|
|
@@ -6859,7 +7362,7 @@ async function scaffoldAgentsMd(projectRoot) {
|
|
|
6859
7362
|
return file;
|
|
6860
7363
|
}
|
|
6861
7364
|
async function runProjectCheck(opts) {
|
|
6862
|
-
const { projectRoot, renderer, reader } = opts;
|
|
7365
|
+
const { projectRoot, cwd, renderer, reader } = opts;
|
|
6863
7366
|
const kind = await detectProjectKind(projectRoot);
|
|
6864
7367
|
if (kind === "initialized") {
|
|
6865
7368
|
renderer.write(
|
|
@@ -6919,7 +7422,7 @@ async function runProjectCheck(opts) {
|
|
|
6919
7422
|
try {
|
|
6920
7423
|
const { spawn: spawn3 } = await import('child_process');
|
|
6921
7424
|
await new Promise((resolve5, reject) => {
|
|
6922
|
-
const child = spawn3("git", ["init"], { cwd
|
|
7425
|
+
const child = spawn3("git", ["init"], { cwd });
|
|
6923
7426
|
child.on("error", reject);
|
|
6924
7427
|
child.on("close", (code) => code === 0 ? resolve5() : reject(new Error(`git init failed with ${code}`)));
|
|
6925
7428
|
});
|
|
@@ -7137,15 +7640,20 @@ var ReadlineInputReader = class {
|
|
|
7137
7640
|
});
|
|
7138
7641
|
}
|
|
7139
7642
|
const fresh = this.ensure();
|
|
7643
|
+
this.installPromptGuard(fresh);
|
|
7140
7644
|
return new Promise((resolve5) => {
|
|
7645
|
+
const settle = (line) => {
|
|
7646
|
+
setOutputLineGuard(null);
|
|
7647
|
+
resolve5(line);
|
|
7648
|
+
};
|
|
7141
7649
|
fresh.question(prompt ?? "> ", (line) => {
|
|
7142
7650
|
if (line.trim()) {
|
|
7143
7651
|
this.history.push(line);
|
|
7144
7652
|
void this.saveHistory();
|
|
7145
7653
|
}
|
|
7146
|
-
|
|
7654
|
+
settle(line);
|
|
7147
7655
|
});
|
|
7148
|
-
fresh.once("close", () =>
|
|
7656
|
+
fresh.once("close", () => settle(""));
|
|
7149
7657
|
}).then((result) => {
|
|
7150
7658
|
this.rl?.close();
|
|
7151
7659
|
return result;
|
|
@@ -7154,7 +7662,38 @@ var ReadlineInputReader = class {
|
|
|
7154
7662
|
this.pending = false;
|
|
7155
7663
|
}
|
|
7156
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
|
+
}
|
|
7157
7695
|
async readKey(prompt, options) {
|
|
7696
|
+
setOutputLineGuard(null);
|
|
7158
7697
|
writeOut(prompt);
|
|
7159
7698
|
return new Promise((resolve5) => {
|
|
7160
7699
|
const stdin = process.stdin;
|
|
@@ -7207,6 +7746,7 @@ var ReadlineInputReader = class {
|
|
|
7207
7746
|
async readSecret(prompt) {
|
|
7208
7747
|
const stdin = process.stdin;
|
|
7209
7748
|
if (!stdin.isTTY) return this.readLine(prompt);
|
|
7749
|
+
setOutputLineGuard(null);
|
|
7210
7750
|
this.rl?.close();
|
|
7211
7751
|
this.rl = void 0;
|
|
7212
7752
|
writeOut(prompt);
|
|
@@ -7269,6 +7809,7 @@ var ReadlineInputReader = class {
|
|
|
7269
7809
|
});
|
|
7270
7810
|
}
|
|
7271
7811
|
async close() {
|
|
7812
|
+
setOutputLineGuard(null);
|
|
7272
7813
|
await this.saveHistory();
|
|
7273
7814
|
this.rl?.close();
|
|
7274
7815
|
this.rl = void 0;
|
|
@@ -7587,14 +8128,20 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
7587
8128
|
}
|
|
7588
8129
|
|
|
7589
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
|
+
}
|
|
7590
8137
|
var theme = { primary: color.amber };
|
|
7591
8138
|
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os2__default.homedir()) {
|
|
7592
8139
|
try {
|
|
7593
|
-
const { atomicWrite:
|
|
7594
|
-
const
|
|
8140
|
+
const { atomicWrite: atomicWrite15 } = await import('@wrongstack/core');
|
|
8141
|
+
const fs27 = await import('fs/promises');
|
|
7595
8142
|
let existing = {};
|
|
7596
8143
|
try {
|
|
7597
|
-
const raw = await
|
|
8144
|
+
const raw = await fs27.readFile(configPath2, "utf8");
|
|
7598
8145
|
existing = JSON.parse(raw);
|
|
7599
8146
|
} catch {
|
|
7600
8147
|
}
|
|
@@ -7606,7 +8153,7 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
|
|
|
7606
8153
|
} catch (err) {
|
|
7607
8154
|
console.warn("[picker] backupCurrent failed:", err);
|
|
7608
8155
|
}
|
|
7609
|
-
await
|
|
8156
|
+
await atomicWrite15(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7610
8157
|
try {
|
|
7611
8158
|
await appendHistory(
|
|
7612
8159
|
oldCfg,
|
|
@@ -7708,7 +8255,7 @@ ${color.bold(theme.primary("WrongStack") + color.dim(" \u2014 Provider & Model S
|
|
|
7708
8255
|
for (const p of list) {
|
|
7709
8256
|
const envFound = p.envVars.some((v) => !!process.env[v]);
|
|
7710
8257
|
const entry = config?.providers?.[p.id];
|
|
7711
|
-
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);
|
|
7712
8259
|
const marker = envFound ? color.green("\u25CF") : configKey ? color.cyan("\u25C9") : color.dim("\u25CB");
|
|
7713
8260
|
const isDefault = p.id === defaultProvider;
|
|
7714
8261
|
if (isDefault) defaultIdx = idx;
|
|
@@ -7782,7 +8329,7 @@ async function pickModel(provider, registry, renderer, reader, defaultModel) {
|
|
|
7782
8329
|
while (offset < models.length) {
|
|
7783
8330
|
const page = models.slice(offset, offset + pageSize);
|
|
7784
8331
|
for (let i = 0; i < page.length; i++) {
|
|
7785
|
-
const m = page[i];
|
|
8332
|
+
const m = expectDefined6(page[i]);
|
|
7786
8333
|
const num = offset + i + 1;
|
|
7787
8334
|
const ctx = m.limit?.context ? `${(m.limit.context / 1e3).toFixed(0)}k`.padStart(6) : " ?";
|
|
7788
8335
|
const cost = m.cost?.input !== void 0 ? `$${m.cost.input}/$${m.cost.output ?? "?"}` : "";
|
|
@@ -7839,7 +8386,7 @@ async function resolveModelSelection(answer, models, provider, _registry, render
|
|
|
7839
8386
|
const idx = Number.parseInt(answer, 10);
|
|
7840
8387
|
let modelId;
|
|
7841
8388
|
if (!Number.isNaN(idx) && idx >= 1 && idx <= models.length) {
|
|
7842
|
-
modelId = models[idx - 1]
|
|
8389
|
+
modelId = models[idx - 1]?.id;
|
|
7843
8390
|
} else {
|
|
7844
8391
|
const lower = answer.toLowerCase();
|
|
7845
8392
|
const match = models.find((m) => m.id.toLowerCase() === lower);
|
|
@@ -7848,7 +8395,7 @@ async function resolveModelSelection(answer, models, provider, _registry, render
|
|
|
7848
8395
|
} else {
|
|
7849
8396
|
const partial = models.filter((m) => m.id.toLowerCase().includes(lower));
|
|
7850
8397
|
if (partial.length === 1) {
|
|
7851
|
-
modelId = partial[0]
|
|
8398
|
+
modelId = partial[0]?.id;
|
|
7852
8399
|
} else if (partial.length > 1) {
|
|
7853
8400
|
renderer.writeError(`"${answer}" matches multiple models. Be more specific.`);
|
|
7854
8401
|
return void 0;
|
|
@@ -8173,6 +8720,7 @@ var TerminalRenderer = class {
|
|
|
8173
8720
|
if (this.silent) return;
|
|
8174
8721
|
if (result.delegateSummaries) {
|
|
8175
8722
|
for (const { summary, ok } of result.delegateSummaries) {
|
|
8723
|
+
if (!summary) continue;
|
|
8176
8724
|
this.writeAgentSummary(summary, ok);
|
|
8177
8725
|
}
|
|
8178
8726
|
return;
|
|
@@ -8444,6 +8992,12 @@ async function spawnACPAgent(args, deps) {
|
|
|
8444
8992
|
|
|
8445
8993
|
// src/auth-menu.ts
|
|
8446
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
|
+
}
|
|
8447
9001
|
async function runAuthMenu(deps) {
|
|
8448
9002
|
for (; ; ) {
|
|
8449
9003
|
const providers = await loadProviders(deps);
|
|
@@ -8465,7 +9019,7 @@ ${color.amber("?")} Pick: `)).trim().toLowerCase();
|
|
|
8465
9019
|
}
|
|
8466
9020
|
const idx = Number.parseInt(choice, 10);
|
|
8467
9021
|
if (!Number.isNaN(idx) && idx >= 1 && idx <= ids.length) {
|
|
8468
|
-
const pid = ids[idx - 1];
|
|
9022
|
+
const pid = expectDefined8(ids[idx - 1]);
|
|
8469
9023
|
await manageProvider(pid, deps);
|
|
8470
9024
|
continue;
|
|
8471
9025
|
}
|
|
@@ -8491,9 +9045,11 @@ ${color.bold("WrongStack")} ${color.dim("\u2014 API keys")}
|
|
|
8491
9045
|
let idx = 1;
|
|
8492
9046
|
for (const id of ids) {
|
|
8493
9047
|
const cfg = providers[id];
|
|
9048
|
+
if (!cfg) continue;
|
|
8494
9049
|
const keys = normalizeKeys(cfg);
|
|
8495
9050
|
const active = activeLabel(cfg, keys);
|
|
8496
|
-
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 ?? "")}`;
|
|
8497
9053
|
const fam = cfg.family ? color.dim(`[${cfg.family}]`) : "";
|
|
8498
9054
|
const aliasHint = cfg.type && cfg.type !== id ? color.dim(`\u2192 ${cfg.type}`) : "";
|
|
8499
9055
|
renderer.write(
|
|
@@ -8553,7 +9109,7 @@ ${color.bold(providerId)} ${cfg.family ? color.dim(`[${cfg.family}]`) : color.am
|
|
|
8553
9109
|
deps.renderer.write(color.dim(" (no keys saved)\n"));
|
|
8554
9110
|
} else {
|
|
8555
9111
|
for (let i = 0; i < keys.length; i++) {
|
|
8556
|
-
const k = keys[i];
|
|
9112
|
+
const k = expectDefined8(keys[i]);
|
|
8557
9113
|
const marker = k.label === active ? color.green("\u25CF") : color.dim("\u25CB");
|
|
8558
9114
|
deps.renderer.write(
|
|
8559
9115
|
` ${color.dim(`${i + 1}.`.padStart(4))} ${marker} ${k.label.padEnd(20)} ${maskedKey(k.apiKey)} ${color.dim(k.createdAt)}
|
|
@@ -8615,7 +9171,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
8615
9171
|
deps.renderer.writeError(`Usage: u <1-${keys.length}>`);
|
|
8616
9172
|
continue;
|
|
8617
9173
|
}
|
|
8618
|
-
const target = keys[arg - 1];
|
|
9174
|
+
const target = expectDefined8(keys[arg - 1]);
|
|
8619
9175
|
const newKey = await readKeyInput(deps, `Updated key for ${target.label}`);
|
|
8620
9176
|
if (!newKey) continue;
|
|
8621
9177
|
await mutateProviders(deps, (all) => {
|
|
@@ -8635,7 +9191,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
8635
9191
|
deps.renderer.writeError(`Usage: d <1-${keys.length}>`);
|
|
8636
9192
|
continue;
|
|
8637
9193
|
}
|
|
8638
|
-
const target = keys[arg - 1];
|
|
9194
|
+
const target = expectDefined8(keys[arg - 1]);
|
|
8639
9195
|
const confirm = (await deps.reader.readLine(
|
|
8640
9196
|
` ${color.amber("?")} Delete key "${target.label}" (${maskedKey(target.apiKey)})? ${color.dim("[y/N/q]")} `
|
|
8641
9197
|
)).trim().toLowerCase();
|
|
@@ -8711,7 +9267,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
8711
9267
|
deps.renderer.writeError(`Usage: s <1-${keys.length}>`);
|
|
8712
9268
|
continue;
|
|
8713
9269
|
}
|
|
8714
|
-
const target = keys[arg - 1];
|
|
9270
|
+
const target = expectDefined8(keys[arg - 1]);
|
|
8715
9271
|
await mutateProviders(deps, (all) => {
|
|
8716
9272
|
const p = all[providerId];
|
|
8717
9273
|
if (!p) return;
|
|
@@ -9094,6 +9650,12 @@ async function mutateProviders(deps, mutator) {
|
|
|
9094
9650
|
}
|
|
9095
9651
|
|
|
9096
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
|
+
}
|
|
9097
9659
|
var authCmd = async (args, deps) => {
|
|
9098
9660
|
const flags = parseAuthFlags(args);
|
|
9099
9661
|
const menuDeps = {
|
|
@@ -9105,7 +9667,7 @@ var authCmd = async (args, deps) => {
|
|
|
9105
9667
|
};
|
|
9106
9668
|
if (flags.positional.length === 0) return runAuthMenu(menuDeps);
|
|
9107
9669
|
return runAuthDirect(menuDeps, {
|
|
9108
|
-
providerId: flags.positional[0],
|
|
9670
|
+
providerId: expectDefined9(flags.positional[0]),
|
|
9109
9671
|
label: flags.label,
|
|
9110
9672
|
family: flags.family,
|
|
9111
9673
|
baseUrl: flags.baseUrl,
|
|
@@ -9328,6 +9890,12 @@ var doctorCmd = async (_args, deps) => {
|
|
|
9328
9890
|
deps.renderer.write(color.green("All checks passed.\n"));
|
|
9329
9891
|
return 0;
|
|
9330
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
|
+
}
|
|
9331
9899
|
var exportCmd = async (args, deps) => {
|
|
9332
9900
|
if (!deps.sessionStore) {
|
|
9333
9901
|
deps.renderer.writeError("No session store configured.");
|
|
@@ -9339,7 +9907,7 @@ var exportCmd = async (args, deps) => {
|
|
|
9339
9907
|
let includeDiagnostics = true;
|
|
9340
9908
|
let sessionId;
|
|
9341
9909
|
for (let i = 0; i < args.length; i++) {
|
|
9342
|
-
const a = args[i];
|
|
9910
|
+
const a = expectDefined10(args[i]);
|
|
9343
9911
|
if (a === "--format" || a === "-f") {
|
|
9344
9912
|
const v = args[++i];
|
|
9345
9913
|
if (v !== "markdown" && v !== "json" && v !== "text") {
|
|
@@ -9601,6 +10169,12 @@ async function serveMcpStdio(deps) {
|
|
|
9601
10169
|
}
|
|
9602
10170
|
|
|
9603
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
|
+
}
|
|
9604
10178
|
var BUILT_IN_MCP = allServers();
|
|
9605
10179
|
var mcpCmd = async (args, deps) => {
|
|
9606
10180
|
const sub = args[0];
|
|
@@ -9651,7 +10225,7 @@ async function addMcpServer(args, deps) {
|
|
|
9651
10225
|
`);
|
|
9652
10226
|
if (Object.keys(deps.config.mcpServers ?? {}).length === 0)
|
|
9653
10227
|
for (const k of Object.keys(BUILT_IN_MCP)) {
|
|
9654
|
-
const s = BUILT_IN_MCP[k];
|
|
10228
|
+
const s = expectDefined11(BUILT_IN_MCP[k]);
|
|
9655
10229
|
deps.renderer.write(` ${k.padEnd(20)} ${s.description}
|
|
9656
10230
|
`);
|
|
9657
10231
|
}
|
|
@@ -9929,6 +10503,12 @@ var projectsCmd = async (_args, deps) => {
|
|
|
9929
10503
|
return 0;
|
|
9930
10504
|
}
|
|
9931
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
|
+
}
|
|
9932
10512
|
var providersCmd = async (args, deps) => {
|
|
9933
10513
|
const showAll = args.includes("--all");
|
|
9934
10514
|
const showUnsupported = args.includes("--unsupported");
|
|
@@ -9976,14 +10556,14 @@ ${color.dim(`Current: ${deps.config.provider ?? "<unset>"} / ${deps.config.model
|
|
|
9976
10556
|
function parseFlags2(args) {
|
|
9977
10557
|
const flags = {};
|
|
9978
10558
|
for (let i = 0; i < args.length; i++) {
|
|
9979
|
-
const a = args[i];
|
|
10559
|
+
const a = expectDefined12(args[i]);
|
|
9980
10560
|
if (a.startsWith("--")) {
|
|
9981
10561
|
const eq = a.indexOf("=");
|
|
9982
10562
|
if (eq !== -1) {
|
|
9983
10563
|
flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
9984
10564
|
} else {
|
|
9985
10565
|
const name = a.slice(2);
|
|
9986
|
-
if (i + 1 < args.length && !args[i + 1]
|
|
10566
|
+
if (i + 1 < args.length && !args[i + 1]?.startsWith("--")) {
|
|
9987
10567
|
flags[name] = args[++i] ?? "";
|
|
9988
10568
|
} else {
|
|
9989
10569
|
flags[name] = true;
|
|
@@ -9996,11 +10576,11 @@ function parseFlags2(args) {
|
|
|
9996
10576
|
function positionals(args) {
|
|
9997
10577
|
const out = [];
|
|
9998
10578
|
for (let i = 0; i < args.length; i++) {
|
|
9999
|
-
const a = args[i];
|
|
10579
|
+
const a = expectDefined12(args[i]);
|
|
10000
10580
|
if (a.startsWith("--")) {
|
|
10001
10581
|
const eq = a.indexOf("=");
|
|
10002
10582
|
if (eq === -1) {
|
|
10003
|
-
if (i + 1 < args.length && !args[i + 1]
|
|
10583
|
+
if (i + 1 < args.length && !args[i + 1]?.startsWith("--")) {
|
|
10004
10584
|
i++;
|
|
10005
10585
|
}
|
|
10006
10586
|
}
|
|
@@ -10151,7 +10731,7 @@ function parseSizeFlag(raw) {
|
|
|
10151
10731
|
const s = raw.trim().toLowerCase();
|
|
10152
10732
|
const match = /^(\d+(?:\.\d+)?)\s*(k|m|b)?$/.exec(s);
|
|
10153
10733
|
if (!match) return void 0;
|
|
10154
|
-
const num = Number.parseFloat(match[1]);
|
|
10734
|
+
const num = Number.parseFloat(expectDefined12(match[1]));
|
|
10155
10735
|
const unit = match[2];
|
|
10156
10736
|
if (unit === "b") return Math.round(num * 1e9);
|
|
10157
10737
|
if (unit === "m") return Math.round(num * 1e6);
|
|
@@ -10472,6 +11052,12 @@ Fleet Run: ${runId}
|
|
|
10472
11052
|
}
|
|
10473
11053
|
|
|
10474
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
|
+
}
|
|
10475
11061
|
var sessionsCmd = async (args, deps) => {
|
|
10476
11062
|
const sub = args[0];
|
|
10477
11063
|
if (sub === "fleet") {
|
|
@@ -10517,7 +11103,7 @@ var configCmd = async (args, deps) => {
|
|
|
10517
11103
|
};
|
|
10518
11104
|
function extractArg(args, key) {
|
|
10519
11105
|
const idx = args.indexOf(key);
|
|
10520
|
-
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]);
|
|
10521
11107
|
const eq = key.startsWith("--") ? args.find((a) => a.startsWith(`${key}=`)) : null;
|
|
10522
11108
|
if (eq) return eq.slice(eq.indexOf("=") + 1);
|
|
10523
11109
|
return null;
|
|
@@ -10568,7 +11154,7 @@ async function runHistory(args, deps) {
|
|
|
10568
11154
|
}
|
|
10569
11155
|
async function runRestore(args, deps) {
|
|
10570
11156
|
const latest = args.includes("--latest") || args.includes("-l");
|
|
10571
|
-
const id = extractArg(args, "--id") ?? (args[0] && !args[0]
|
|
11157
|
+
const id = extractArg(args, "--id") ?? (args[0] && !args[0]?.startsWith("-") ? args[0] : null);
|
|
10572
11158
|
if (latest) {
|
|
10573
11159
|
const result2 = await restoreLast();
|
|
10574
11160
|
if (!result2.ok) {
|
|
@@ -10593,6 +11179,12 @@ async function runRestore(args, deps) {
|
|
|
10593
11179
|
`);
|
|
10594
11180
|
return 0;
|
|
10595
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
|
+
}
|
|
10596
11188
|
function parseRewindFlags(args) {
|
|
10597
11189
|
const flags = {};
|
|
10598
11190
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -10607,7 +11199,7 @@ function parseRewindFlags(args) {
|
|
|
10607
11199
|
}
|
|
10608
11200
|
function findSessionId(args) {
|
|
10609
11201
|
for (let i = 0; i < args.length; i++) {
|
|
10610
|
-
const a = args[i];
|
|
11202
|
+
const a = expectDefined14(args[i]);
|
|
10611
11203
|
if (a === "--last" || a === "--to") {
|
|
10612
11204
|
i++;
|
|
10613
11205
|
continue;
|
|
@@ -10632,13 +11224,18 @@ var rewindCmd = async (args, deps) => {
|
|
|
10632
11224
|
deps.renderer.writeError("No sessions found.");
|
|
10633
11225
|
return 1;
|
|
10634
11226
|
}
|
|
10635
|
-
sessionId = sessions[0]
|
|
11227
|
+
sessionId = sessions[0]?.id;
|
|
11228
|
+
}
|
|
11229
|
+
if (!sessionId) {
|
|
11230
|
+
deps.renderer.writeError("No sessions found.");
|
|
11231
|
+
return 1;
|
|
10636
11232
|
}
|
|
11233
|
+
const targetSessionId = sessionId;
|
|
10637
11234
|
if (flags.list) {
|
|
10638
|
-
deps.renderer.write(`Session: ${color.bold(
|
|
11235
|
+
deps.renderer.write(`Session: ${color.bold(targetSessionId)}
|
|
10639
11236
|
|
|
10640
11237
|
`);
|
|
10641
|
-
const checkpoints = await rewind.listCheckpoints(
|
|
11238
|
+
const checkpoints = await rewind.listCheckpoints(targetSessionId);
|
|
10642
11239
|
if (checkpoints.length === 0) {
|
|
10643
11240
|
deps.renderer.write("No checkpoints in this session.\n");
|
|
10644
11241
|
return 0;
|
|
@@ -10655,7 +11252,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10655
11252
|
let result;
|
|
10656
11253
|
if (flags.all) {
|
|
10657
11254
|
deps.renderer.write("Rewinding to session start...\n");
|
|
10658
|
-
result = await rewind.rewindToStart(
|
|
11255
|
+
result = await rewind.rewindToStart(targetSessionId);
|
|
10659
11256
|
} else if (flags.last) {
|
|
10660
11257
|
const n = Number.parseInt(flags.last, 10);
|
|
10661
11258
|
if (Number.isNaN(n) || n < 1) {
|
|
@@ -10664,7 +11261,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10664
11261
|
}
|
|
10665
11262
|
deps.renderer.write(`Rewinding last ${n} prompt(s)...
|
|
10666
11263
|
`);
|
|
10667
|
-
result = await rewind.rewindLastN(
|
|
11264
|
+
result = await rewind.rewindLastN(targetSessionId, n);
|
|
10668
11265
|
} else if (flags.to) {
|
|
10669
11266
|
const idx = Number.parseInt(flags.to, 10);
|
|
10670
11267
|
if (Number.isNaN(idx) || idx < 0) {
|
|
@@ -10673,7 +11270,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10673
11270
|
}
|
|
10674
11271
|
deps.renderer.write(`Rewinding to checkpoint ${idx}...
|
|
10675
11272
|
`);
|
|
10676
|
-
result = await rewind.rewindToCheckpoint(
|
|
11273
|
+
result = await rewind.rewindToCheckpoint(targetSessionId, idx);
|
|
10677
11274
|
} else {
|
|
10678
11275
|
deps.renderer.write("Usage: ws rewind --all | --last N | --to <index> [--list] [--resume]\n");
|
|
10679
11276
|
deps.renderer.write(" --all Rewind to session start\n");
|
|
@@ -10687,7 +11284,7 @@ var rewindCmd = async (args, deps) => {
|
|
|
10687
11284
|
deps.renderer.write("No files to revert.\n");
|
|
10688
11285
|
if (flags.resume) {
|
|
10689
11286
|
const store = new DefaultSessionStore({ dir: sessionsDir });
|
|
10690
|
-
const resumed = await store.resume(
|
|
11287
|
+
const resumed = await store.resume(targetSessionId);
|
|
10691
11288
|
const toIdx = result.toPromptIndex;
|
|
10692
11289
|
await resumed.writer.truncateToCheckpoint(toIdx);
|
|
10693
11290
|
await resumed.writer.close();
|
|
@@ -10705,7 +11302,7 @@ Reverted ${result.revertedFiles.length} file(s):
|
|
|
10705
11302
|
}
|
|
10706
11303
|
if (flags.resume) {
|
|
10707
11304
|
const store = new DefaultSessionStore({ dir: sessionsDir });
|
|
10708
|
-
const resumed = await store.resume(
|
|
11305
|
+
const resumed = await store.resume(targetSessionId);
|
|
10709
11306
|
const toIdx = result.toPromptIndex;
|
|
10710
11307
|
const removed = await resumed.writer.truncateToCheckpoint(toIdx);
|
|
10711
11308
|
await resumed.writer.close();
|
|
@@ -10854,10 +11451,10 @@ var auditCmd = async (args, deps) => {
|
|
|
10854
11451
|
return verify.ok ? 0 : 1;
|
|
10855
11452
|
};
|
|
10856
11453
|
async function listAudits(log, dir, deps) {
|
|
10857
|
-
const
|
|
11454
|
+
const fs27 = await import('fs/promises');
|
|
10858
11455
|
let entries;
|
|
10859
11456
|
try {
|
|
10860
|
-
entries = await
|
|
11457
|
+
entries = await fs27.readdir(dir);
|
|
10861
11458
|
} catch {
|
|
10862
11459
|
deps.renderer.write(
|
|
10863
11460
|
color.dim(`No sessions dir found at ${dir}. Run a session first.`) + "\n"
|
|
@@ -11008,22 +11605,22 @@ function fmtDuration(ms) {
|
|
|
11008
11605
|
const remMin = m - h * 60;
|
|
11009
11606
|
return `${h}h${remMin}m`;
|
|
11010
11607
|
}
|
|
11011
|
-
function fmtTaskResultLine(r,
|
|
11608
|
+
function fmtTaskResultLine(r, color52) {
|
|
11012
11609
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
11013
11610
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
11014
11611
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
11015
11612
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
11016
|
-
const errKindChip = errKind ?
|
|
11017
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
11613
|
+
const errKindChip = errKind ? color52.dim(` [${errKind}]`) : "";
|
|
11614
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color52.dim(errTail)}` : "";
|
|
11018
11615
|
switch (r.status) {
|
|
11019
11616
|
case "success":
|
|
11020
|
-
return { mark:
|
|
11617
|
+
return { mark: color52.green("\u2713"), stats, tail: "" };
|
|
11021
11618
|
case "timeout":
|
|
11022
|
-
return { mark:
|
|
11619
|
+
return { mark: color52.yellow("\u23F1"), stats: `${color52.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
11023
11620
|
case "stopped":
|
|
11024
|
-
return { mark:
|
|
11621
|
+
return { mark: color52.dim("\u2298"), stats: `${color52.dim("stopped")} ${stats}`, tail: errSnip };
|
|
11025
11622
|
case "failed":
|
|
11026
|
-
return { mark:
|
|
11623
|
+
return { mark: color52.red("\u2717"), stats: `${color52.red("failed")} ${stats}`, tail: errSnip };
|
|
11027
11624
|
}
|
|
11028
11625
|
}
|
|
11029
11626
|
|
|
@@ -11067,7 +11664,15 @@ async function boot(argv) {
|
|
|
11067
11664
|
const { paths, config: _config, vault } = bootResult;
|
|
11068
11665
|
let config = _config;
|
|
11069
11666
|
const { cwd, projectRoot, userHome, wpaths, pathResolver } = paths;
|
|
11070
|
-
const logger = new DefaultLogger({
|
|
11667
|
+
const logger = new DefaultLogger({
|
|
11668
|
+
level: config.log.level,
|
|
11669
|
+
file: wpaths.logFile,
|
|
11670
|
+
// Suppress stderr output in TUI mode: plugin/library log messages
|
|
11671
|
+
// (e.g. Telegram "getUpdates failed") write directly to stderr and
|
|
11672
|
+
// bypass Ink, which breaks the Static/live boundary.
|
|
11673
|
+
// Logs still go to the disk file for post-hoc debugging.
|
|
11674
|
+
stderr: !flags.tui
|
|
11675
|
+
});
|
|
11071
11676
|
const renderer = new TerminalRenderer();
|
|
11072
11677
|
const reader = new ReadlineInputReader({ historyFile: wpaths.historyFile });
|
|
11073
11678
|
const modelsRegistry = new DefaultModelsRegistry({
|
|
@@ -11116,7 +11721,7 @@ async function boot(argv) {
|
|
|
11116
11721
|
[...builtinToolsPack.tools ?? []],
|
|
11117
11722
|
builtinToolsPack.name
|
|
11118
11723
|
);
|
|
11119
|
-
const code = await subcommands[first](positional.slice(1), {
|
|
11724
|
+
const code = await subcommands[first]?.(positional.slice(1), {
|
|
11120
11725
|
config,
|
|
11121
11726
|
renderer,
|
|
11122
11727
|
reader,
|
|
@@ -11137,7 +11742,7 @@ async function boot(argv) {
|
|
|
11137
11742
|
const isSingleShot = positional.length > 0 || typeof flags["prompt"] === "string";
|
|
11138
11743
|
const isInteractiveTTY = isStdinTTY() && !isSingleShot;
|
|
11139
11744
|
if (isInteractiveTTY) {
|
|
11140
|
-
const cont = await runProjectCheck({ projectRoot, renderer, reader });
|
|
11745
|
+
const cont = await runProjectCheck({ projectRoot, cwd, renderer, reader });
|
|
11141
11746
|
if (!cont) {
|
|
11142
11747
|
await reader.close();
|
|
11143
11748
|
return 0;
|
|
@@ -11608,6 +12213,12 @@ async function predictNextTasks(input, opts) {
|
|
|
11608
12213
|
}
|
|
11609
12214
|
}
|
|
11610
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
|
+
}
|
|
11611
12222
|
async function runRepl(opts) {
|
|
11612
12223
|
if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
|
|
11613
12224
|
await renderGoalBanner(opts);
|
|
@@ -12123,7 +12734,7 @@ async function renderGoalBanner(opts) {
|
|
|
12123
12734
|
color.dim("Goal: ") + stateColor(summary) + color.dim(` [${goal.goalState}] (iter ${goal.iterations})`) + "\n"
|
|
12124
12735
|
);
|
|
12125
12736
|
if (goal.journal.length > 0) {
|
|
12126
|
-
const lastEntry = goal.journal[goal.journal.length - 1];
|
|
12737
|
+
const lastEntry = expectDefined15(goal.journal[goal.journal.length - 1]);
|
|
12127
12738
|
const statusIcon = lastEntry.status === "success" ? "\u2713" : lastEntry.status === "failure" ? "\u2717" : lastEntry.status === "aborted" ? "\u2298" : lastEntry.status === "skipped" ? "\u229D" : "\xB7";
|
|
12128
12739
|
opts.renderer.write(
|
|
12129
12740
|
color.dim(` Last: ${statusIcon} ${lastEntry.task} (${lastEntry.status})`) + "\n"
|
|
@@ -12252,6 +12863,7 @@ async function execute(deps) {
|
|
|
12252
12863
|
director,
|
|
12253
12864
|
fleetRoster,
|
|
12254
12865
|
fleetStreamController,
|
|
12866
|
+
enhanceController,
|
|
12255
12867
|
statuslineHiddenItems,
|
|
12256
12868
|
setStatuslineHiddenItems,
|
|
12257
12869
|
agentsMonitorController,
|
|
@@ -12263,7 +12875,8 @@ async function execute(deps) {
|
|
|
12263
12875
|
getParallelEngine,
|
|
12264
12876
|
subscribeEternalIteration,
|
|
12265
12877
|
subscribeEternalStage,
|
|
12266
|
-
skillLoader
|
|
12878
|
+
skillLoader,
|
|
12879
|
+
modeId
|
|
12267
12880
|
} = deps;
|
|
12268
12881
|
let code = 0;
|
|
12269
12882
|
let fleetStatusLine = null;
|
|
@@ -12462,10 +13075,31 @@ async function execute(deps) {
|
|
|
12462
13075
|
return null;
|
|
12463
13076
|
},
|
|
12464
13077
|
getSettings: () => {
|
|
12465
|
-
const
|
|
13078
|
+
const cfg = configStore.get();
|
|
13079
|
+
const autonomy = cfg.autonomy;
|
|
12466
13080
|
const rawMode = autonomy?.defaultMode;
|
|
12467
13081
|
const mode = rawMode === "suggest" || rawMode === "auto" ? rawMode : "off";
|
|
12468
|
-
return {
|
|
13082
|
+
return {
|
|
13083
|
+
mode,
|
|
13084
|
+
delayMs: autonomy?.autoProceedDelayMs ?? 45e3,
|
|
13085
|
+
titleAnimation: autonomy?.terminalTitleAnimation !== false,
|
|
13086
|
+
yolo: autonomy?.yolo ?? false,
|
|
13087
|
+
streamFleet: autonomy?.streamFleet !== false,
|
|
13088
|
+
chime: autonomy?.chime ?? false,
|
|
13089
|
+
confirmExit: autonomy?.confirmExit !== false,
|
|
13090
|
+
nextPrediction: cfg.nextPrediction ?? false,
|
|
13091
|
+
featureMcp: cfg.features?.mcp !== false,
|
|
13092
|
+
featurePlugins: cfg.features?.plugins !== false,
|
|
13093
|
+
featureMemory: cfg.features?.memory !== false,
|
|
13094
|
+
featureSkills: cfg.features?.skills !== false,
|
|
13095
|
+
featureModelsRegistry: cfg.features?.modelsRegistry !== false,
|
|
13096
|
+
contextAutoCompact: cfg.context?.autoCompact !== false,
|
|
13097
|
+
contextStrategy: cfg.context?.strategy ?? "hybrid",
|
|
13098
|
+
logLevel: cfg.log?.level ?? "info",
|
|
13099
|
+
auditLevel: cfg.session?.auditLevel ?? "standard",
|
|
13100
|
+
indexOnStart: cfg.indexing?.onSessionStart !== false,
|
|
13101
|
+
maxIterations: cfg.tools?.maxIterations ?? 500
|
|
13102
|
+
};
|
|
12469
13103
|
},
|
|
12470
13104
|
async saveSettings(s) {
|
|
12471
13105
|
try {
|
|
@@ -12478,31 +13112,92 @@ async function execute(deps) {
|
|
|
12478
13112
|
(autonomy) => {
|
|
12479
13113
|
autonomy.defaultMode = s.mode;
|
|
12480
13114
|
autonomy.autoProceedDelayMs = s.delayMs;
|
|
13115
|
+
const a = autonomy;
|
|
13116
|
+
a["terminalTitleAnimation"] = s.titleAnimation ?? true;
|
|
13117
|
+
a["yolo"] = s.yolo ?? false;
|
|
13118
|
+
a["streamFleet"] = s.streamFleet ?? true;
|
|
13119
|
+
a["chime"] = s.chime ?? false;
|
|
13120
|
+
a["confirmExit"] = s.confirmExit ?? true;
|
|
12481
13121
|
}
|
|
12482
13122
|
);
|
|
13123
|
+
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.nextPrediction !== void 0) {
|
|
13124
|
+
const raw = await fsp4.readFile(wpaths.globalConfig, "utf8").catch(() => "{}");
|
|
13125
|
+
const parsed = JSON.parse(raw);
|
|
13126
|
+
const vault = { encrypt: (v) => v, decrypt: (v) => v, isEncrypted: () => false };
|
|
13127
|
+
const decrypted = decryptConfigSecrets$1(parsed, vault);
|
|
13128
|
+
if (s.nextPrediction !== void 0) {
|
|
13129
|
+
decrypted.nextPrediction = s.nextPrediction;
|
|
13130
|
+
}
|
|
13131
|
+
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0) {
|
|
13132
|
+
const feats = decrypted.features ?? {};
|
|
13133
|
+
if (s.featureMcp !== void 0) feats.mcp = s.featureMcp;
|
|
13134
|
+
if (s.featurePlugins !== void 0) feats.plugins = s.featurePlugins;
|
|
13135
|
+
if (s.featureMemory !== void 0) feats.memory = s.featureMemory;
|
|
13136
|
+
if (s.featureSkills !== void 0) feats.skills = s.featureSkills;
|
|
13137
|
+
if (s.featureModelsRegistry !== void 0) feats.modelsRegistry = s.featureModelsRegistry;
|
|
13138
|
+
decrypted.features = feats;
|
|
13139
|
+
}
|
|
13140
|
+
if (s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0) {
|
|
13141
|
+
const ctx = decrypted.context ?? {};
|
|
13142
|
+
if (s.contextAutoCompact !== void 0) ctx.autoCompact = s.contextAutoCompact;
|
|
13143
|
+
if (s.contextStrategy !== void 0) ctx.strategy = s.contextStrategy;
|
|
13144
|
+
decrypted.context = ctx;
|
|
13145
|
+
}
|
|
13146
|
+
if (s.logLevel !== void 0) {
|
|
13147
|
+
const log = decrypted.log ?? {};
|
|
13148
|
+
log.level = s.logLevel;
|
|
13149
|
+
decrypted.log = log;
|
|
13150
|
+
}
|
|
13151
|
+
if (s.auditLevel !== void 0) {
|
|
13152
|
+
const sess = decrypted.session ?? {};
|
|
13153
|
+
sess.auditLevel = s.auditLevel;
|
|
13154
|
+
decrypted.session = sess;
|
|
13155
|
+
}
|
|
13156
|
+
if (s.indexOnStart !== void 0) {
|
|
13157
|
+
const idx = decrypted.indexing ?? {};
|
|
13158
|
+
idx.onSessionStart = s.indexOnStart;
|
|
13159
|
+
decrypted.indexing = idx;
|
|
13160
|
+
}
|
|
13161
|
+
if (s.maxIterations !== void 0) {
|
|
13162
|
+
const tools = decrypted.tools ?? {};
|
|
13163
|
+
tools.maxIterations = s.maxIterations;
|
|
13164
|
+
decrypted.tools = tools;
|
|
13165
|
+
}
|
|
13166
|
+
const encrypted = encryptConfigSecrets$1(decrypted, vault);
|
|
13167
|
+
await atomicWrite(wpaths.globalConfig, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
13168
|
+
configStore.update({
|
|
13169
|
+
...s.nextPrediction !== void 0 ? { nextPrediction: s.nextPrediction } : {},
|
|
13170
|
+
...s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 ? { features: decrypted.features } : {},
|
|
13171
|
+
...s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 ? { context: decrypted.context } : {},
|
|
13172
|
+
...s.logLevel !== void 0 ? { log: decrypted.log } : {},
|
|
13173
|
+
...s.auditLevel !== void 0 ? { session: decrypted.session } : {},
|
|
13174
|
+
...s.indexOnStart !== void 0 ? { indexing: decrypted.indexing } : {},
|
|
13175
|
+
...s.maxIterations !== void 0 ? { tools: decrypted.tools } : {}
|
|
13176
|
+
});
|
|
13177
|
+
}
|
|
13178
|
+
if (s.streamFleet !== void 0) {
|
|
13179
|
+
fleetStreamController?.setEnabled(s.streamFleet);
|
|
13180
|
+
}
|
|
12483
13181
|
return null;
|
|
12484
13182
|
} catch (err) {
|
|
12485
13183
|
return err instanceof Error ? err.message : String(err);
|
|
12486
13184
|
}
|
|
12487
13185
|
},
|
|
12488
13186
|
effectiveMaxContext,
|
|
12489
|
-
//
|
|
12490
|
-
|
|
12491
|
-
//
|
|
12492
|
-
|
|
12493
|
-
|
|
13187
|
+
// Terminal title animation: read from config (default on).
|
|
13188
|
+
titleAnimation: config.autonomy?.["terminalTitleAnimation"] ?? true,
|
|
13189
|
+
// Completion chime: terminal bell when agent finishes.
|
|
13190
|
+
chime: config.autonomy?.["chime"] ?? false,
|
|
13191
|
+
// Normal exit.
|
|
13192
|
+
confirmExit: config.autonomy?.["confirmExit"] ?? true,
|
|
12494
13193
|
director,
|
|
12495
13194
|
fleetRoster,
|
|
12496
|
-
onAfterExit: () => {
|
|
12497
|
-
writeOut(
|
|
12498
|
-
color.dim(`Session saved: ${session.id} \u2014 resume with `) + color.cyan(`wstack resume ${session.id}`) + "\n"
|
|
12499
|
-
);
|
|
12500
|
-
},
|
|
12501
13195
|
onClearHistory: (dispatch) => {
|
|
12502
13196
|
dispatch({ type: "clearHistory" });
|
|
12503
13197
|
dispatch({ type: "resetContextChip" });
|
|
12504
13198
|
},
|
|
12505
13199
|
fleetStreamController,
|
|
13200
|
+
enhanceController,
|
|
12506
13201
|
statuslineHiddenItems,
|
|
12507
13202
|
setStatuslineHiddenItems,
|
|
12508
13203
|
agentsMonitorController,
|
|
@@ -12547,6 +13242,11 @@ async function execute(deps) {
|
|
|
12547
13242
|
}
|
|
12548
13243
|
}
|
|
12549
13244
|
return messages;
|
|
13245
|
+
},
|
|
13246
|
+
modeLabel: modeId,
|
|
13247
|
+
getModeLabel: () => {
|
|
13248
|
+
const metaMode = context.meta?.["mode"];
|
|
13249
|
+
return typeof metaMode === "string" ? metaMode : modeId ?? "default";
|
|
12550
13250
|
}
|
|
12551
13251
|
});
|
|
12552
13252
|
} finally {
|
|
@@ -12636,6 +13336,12 @@ async function execute(deps) {
|
|
|
12636
13336
|
}
|
|
12637
13337
|
return code;
|
|
12638
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
|
+
}
|
|
12639
13345
|
function buildRoutingRunner(config, host) {
|
|
12640
13346
|
const standardRunner = makeAgentSubagentRunner({
|
|
12641
13347
|
factory: host.makeSubagentFactory(config),
|
|
@@ -12644,7 +13350,7 @@ function buildRoutingRunner(config, host) {
|
|
|
12644
13350
|
return async (task, ctx) => {
|
|
12645
13351
|
const subCfg = ctx.config;
|
|
12646
13352
|
if (subCfg.provider === "acp") {
|
|
12647
|
-
const cacheKey = subCfg.role ?? subCfg.name ?? subCfg.id;
|
|
13353
|
+
const cacheKey = subCfg.role ?? subCfg.name ?? expectDefined17(subCfg.id);
|
|
12648
13354
|
return host.buildACPRunner(cacheKey).then((r) => r(task, ctx));
|
|
12649
13355
|
}
|
|
12650
13356
|
return standardRunner(task, ctx);
|
|
@@ -13087,6 +13793,7 @@ var MultiAgentHost = class {
|
|
|
13087
13793
|
*/
|
|
13088
13794
|
async _spawnAndAssign(subagentConfig) {
|
|
13089
13795
|
const taskId = randomUUID();
|
|
13796
|
+
if (!this.director) throw new Error("Director is not initialized");
|
|
13090
13797
|
const subagentId = await this.director.spawn(subagentConfig);
|
|
13091
13798
|
await this.director.assign({ id: taskId, description: "", subagentId });
|
|
13092
13799
|
return { subagentId, taskId };
|
|
@@ -13865,9 +14572,18 @@ var Spinner = class {
|
|
|
13865
14572
|
context;
|
|
13866
14573
|
out;
|
|
13867
14574
|
enabled;
|
|
13868
|
-
|
|
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) {
|
|
13869
14585
|
this.out = out;
|
|
13870
|
-
this.enabled = Boolean(out.isTTY) && !process.env.NO_COLOR;
|
|
14586
|
+
this.enabled = (opts?.enabled ?? Boolean(out.isTTY)) && !process.env.NO_COLOR;
|
|
13871
14587
|
}
|
|
13872
14588
|
start(label) {
|
|
13873
14589
|
if (!this.enabled || this.active) return;
|
|
@@ -14345,7 +15061,22 @@ var BUILTIN_PLUGIN_FACTORIES = [
|
|
|
14345
15061
|
async () => {
|
|
14346
15062
|
const { createPlanPlugin } = await import('@wrongstack/core');
|
|
14347
15063
|
return createPlanPlugin();
|
|
14348
|
-
}
|
|
15064
|
+
},
|
|
15065
|
+
// ── Workspace plugins (@wrongstack/plugins subpath exports) ──────────
|
|
15066
|
+
async () => (await import('@wrongstack/plugins/cost-tracker')).default,
|
|
15067
|
+
async () => (await import('@wrongstack/plugins/json-path')).default,
|
|
15068
|
+
async () => (await import('@wrongstack/plugins/web-search')).default,
|
|
15069
|
+
async () => (await import('@wrongstack/plugins/file-watcher')).default,
|
|
15070
|
+
async () => (await import('@wrongstack/plugins/git-autocommit')).default,
|
|
15071
|
+
async () => (await import('@wrongstack/plugins/auto-doc')).default,
|
|
15072
|
+
async () => (await import('@wrongstack/plugins/shell-check')).default,
|
|
15073
|
+
async () => (await import('@wrongstack/plugins/cron')).default,
|
|
15074
|
+
async () => (await import('@wrongstack/plugins/template-engine')).default,
|
|
15075
|
+
async () => (await import('@wrongstack/plugins/semver-bump')).default,
|
|
15076
|
+
// ── LSP plugin ──────────────────────────────────────────────────────
|
|
15077
|
+
async () => (await import('@wrongstack/plug-lsp')).default,
|
|
15078
|
+
// ── Telegram plugin ─────────────────────────────────────────────────
|
|
15079
|
+
async () => (await import('@wrongstack/telegram')).default
|
|
14349
15080
|
];
|
|
14350
15081
|
async function setupPlugins(params) {
|
|
14351
15082
|
const {
|
|
@@ -14508,8 +15239,17 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
14508
15239
|
}
|
|
14509
15240
|
return { resolvedProvider, provider, providerRegistry };
|
|
14510
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
|
+
}
|
|
14511
15248
|
async function setupSession(params) {
|
|
14512
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);
|
|
14513
15253
|
let resumeId = typeof flags["resume"] === "string" ? flags["resume"] : void 0;
|
|
14514
15254
|
const recoveryLock = new RecoveryLock({ dir: wpaths.projectSessions, sessionStore });
|
|
14515
15255
|
if (!resumeId && !flags["no-recovery"]) {
|
|
@@ -14542,13 +15282,13 @@ async function setupSession(params) {
|
|
|
14542
15282
|
session = await sessionStore.create({ id: "", title: "", model: config.model, provider: config.provider });
|
|
14543
15283
|
}
|
|
14544
15284
|
const sessionRef = { current: session };
|
|
14545
|
-
await recoveryLock.write(session
|
|
14546
|
-
const attachments = new DefaultAttachmentStore({ spoolDir: path8.join(wpaths.projectSessions, session
|
|
14547
|
-
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) });
|
|
14548
15288
|
const ctxSignal = new AbortController().signal;
|
|
14549
|
-
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 });
|
|
14550
15290
|
if (restoredMessages.length > 0) context.state.replaceMessages(restoredMessages);
|
|
14551
|
-
const todosCheckpointPath = path8.join(wpaths.projectSessions, `${session
|
|
15291
|
+
const todosCheckpointPath = path8.join(wpaths.projectSessions, `${session?.id}.todos.json`);
|
|
14552
15292
|
if (resumeId) {
|
|
14553
15293
|
try {
|
|
14554
15294
|
const restoredTodos = await loadTodosCheckpoint(todosCheckpointPath);
|
|
@@ -14559,13 +15299,13 @@ async function setupSession(params) {
|
|
|
14559
15299
|
} catch {
|
|
14560
15300
|
}
|
|
14561
15301
|
}
|
|
14562
|
-
const detachTodosCheckpoint = attachTodosCheckpoint(context.state, todosCheckpointPath, session
|
|
14563
|
-
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`);
|
|
14564
15304
|
context.state.setMeta("plan.path", planPath);
|
|
14565
15305
|
let dirState;
|
|
14566
15306
|
if (resumeId) {
|
|
14567
15307
|
try {
|
|
14568
|
-
const fleetRoot = path8.join(wpaths.projectSessions, session
|
|
15308
|
+
const fleetRoot = path8.join(wpaths.projectSessions, session?.id);
|
|
14569
15309
|
dirState = await loadDirectorState(path8.join(fleetRoot, "director-state.json"));
|
|
14570
15310
|
if (dirState) {
|
|
14571
15311
|
const tCounts = {};
|
|
@@ -14585,7 +15325,7 @@ async function setupSession(params) {
|
|
|
14585
15325
|
} catch {
|
|
14586
15326
|
}
|
|
14587
15327
|
}
|
|
14588
|
-
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 };
|
|
14589
15329
|
}
|
|
14590
15330
|
function resolveBundledSkillsDir2() {
|
|
14591
15331
|
try {
|
|
@@ -14684,6 +15424,12 @@ async function launchEternalFromFlag(deps) {
|
|
|
14684
15424
|
}
|
|
14685
15425
|
|
|
14686
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
|
+
}
|
|
14687
15433
|
async function main(argv) {
|
|
14688
15434
|
const ctx = await boot(argv);
|
|
14689
15435
|
if (typeof ctx === "number") return ctx;
|
|
@@ -14819,7 +15565,8 @@ async function main(argv) {
|
|
|
14819
15565
|
});
|
|
14820
15566
|
return ms;
|
|
14821
15567
|
})();
|
|
14822
|
-
const
|
|
15568
|
+
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
15569
|
+
const spinner = new Spinner(process.stderr, { enabled: !tuiOwnsScreen });
|
|
14823
15570
|
let lastInputTokens = 0;
|
|
14824
15571
|
events.on("provider.response", (e) => {
|
|
14825
15572
|
lastInputTokens = e.usage?.input ?? 0;
|
|
@@ -14901,7 +15648,9 @@ async function main(argv) {
|
|
|
14901
15648
|
const planPath = sessResult.planPath;
|
|
14902
15649
|
const detachTodosCheckpoint = sessResult.detachTodosCheckpoint;
|
|
14903
15650
|
const priorFleetState = sessResult.priorFleetState;
|
|
14904
|
-
const sessionConfig = resolveSessionLoggingConfig(
|
|
15651
|
+
const sessionConfig = resolveSessionLoggingConfig(
|
|
15652
|
+
config
|
|
15653
|
+
);
|
|
14905
15654
|
const sessionBridge = createSessionEventBridge(
|
|
14906
15655
|
session,
|
|
14907
15656
|
sessionConfig.auditLevel,
|
|
@@ -14951,6 +15700,16 @@ async function main(argv) {
|
|
|
14951
15700
|
}).catch(() => {
|
|
14952
15701
|
});
|
|
14953
15702
|
});
|
|
15703
|
+
if (!tuiOwnsScreen) {
|
|
15704
|
+
events.on("delegate.started", (e) => {
|
|
15705
|
+
const task = e.task.length > 100 ? `${e.task.slice(0, 99)}\u2026` : e.task;
|
|
15706
|
+
renderer.writeInfo(`\u{1F91D} Delegating \u2192 ${e.target}: ${task}`);
|
|
15707
|
+
});
|
|
15708
|
+
events.on("delegate.completed", (e) => {
|
|
15709
|
+
const cost = e.costUsd && e.costUsd > 0 ? ` \xB7 $${e.costUsd.toFixed(3)}` : "";
|
|
15710
|
+
renderer.writeInfo(`${e.ok ? "\u2705" : "\u274C"} ${e.summary}${cost}`);
|
|
15711
|
+
});
|
|
15712
|
+
}
|
|
14954
15713
|
events.on("tool.progress", (e) => {
|
|
14955
15714
|
sessionBridge.append({
|
|
14956
15715
|
type: "tool_progress",
|
|
@@ -15151,10 +15910,10 @@ async function main(argv) {
|
|
|
15151
15910
|
}
|
|
15152
15911
|
};
|
|
15153
15912
|
const fleetRoot = directorMode ? path8.join(wpaths.projectSessions, session.id) : void 0;
|
|
15154
|
-
const manifestPath = directorMode ? typeof process.env["WRONGSTACK_FLEET_MANIFEST"] === "string" ? process.env["WRONGSTACK_FLEET_MANIFEST"] : path8.join(fleetRoot, "fleet.json") : void 0;
|
|
15155
|
-
const sharedScratchpadPath = directorMode ? path8.join(fleetRoot, "shared") : void 0;
|
|
15156
|
-
const subagentSessionsRoot = directorMode ? path8.join(fleetRoot, "subagents") : void 0;
|
|
15157
|
-
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;
|
|
15158
15917
|
const fleetRootForPromotion = path8.join(wpaths.projectSessions, session.id);
|
|
15159
15918
|
const brainQueue = new BrainDecisionQueue(events);
|
|
15160
15919
|
const brain = new ObservableBrainArbiter(
|
|
@@ -15199,7 +15958,10 @@ async function main(argv) {
|
|
|
15199
15958
|
// this, a subagent that hit its iteration cap returns an empty
|
|
15200
15959
|
// result and the host LLM has no idea what work was done.
|
|
15201
15960
|
sessionsRoot: subagentSessionsRoot,
|
|
15202
|
-
directorRunId: session.id
|
|
15961
|
+
directorRunId: session.id,
|
|
15962
|
+
// Host bus so `delegate` can emit start/finish events that the TUI,
|
|
15963
|
+
// plain CLI, and Telegram bridge render as readable lines.
|
|
15964
|
+
events
|
|
15203
15965
|
})
|
|
15204
15966
|
);
|
|
15205
15967
|
toolRegistry.register(
|
|
@@ -15231,6 +15993,12 @@ async function main(argv) {
|
|
|
15231
15993
|
this.enabled = enabled;
|
|
15232
15994
|
}
|
|
15233
15995
|
};
|
|
15996
|
+
const enhanceController = {
|
|
15997
|
+
enabled: config.autonomy?.["enhance"] ?? true,
|
|
15998
|
+
setEnabled(enabled) {
|
|
15999
|
+
this.enabled = enabled;
|
|
16000
|
+
}
|
|
16001
|
+
};
|
|
15234
16002
|
const statuslineConfigDeps = {
|
|
15235
16003
|
get: () => loadStatuslineConfig(),
|
|
15236
16004
|
set: (cfg) => saveStatuslineConfig(cfg)
|
|
@@ -15281,6 +16049,7 @@ async function main(argv) {
|
|
|
15281
16049
|
planPath,
|
|
15282
16050
|
modeStore,
|
|
15283
16051
|
fleetStreamController,
|
|
16052
|
+
enhanceController,
|
|
15284
16053
|
llmProvider: provider,
|
|
15285
16054
|
llmModel: config.model,
|
|
15286
16055
|
statuslineConfig: statuslineConfigDeps,
|
|
@@ -15563,7 +16332,7 @@ async function main(argv) {
|
|
|
15563
16332
|
...matches.map((m) => ` ${m.subagentId} (${m.runId})`)
|
|
15564
16333
|
].join("\n");
|
|
15565
16334
|
}
|
|
15566
|
-
const t = matches[0];
|
|
16335
|
+
const t = expectDefined19(matches[0]);
|
|
15567
16336
|
const raw = await fsp4.readFile(t.file, "utf8");
|
|
15568
16337
|
if (mode === "raw") return raw;
|
|
15569
16338
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
@@ -15994,6 +16763,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15994
16763
|
director: director ?? null,
|
|
15995
16764
|
fleetRoster: FLEET_ROSTER,
|
|
15996
16765
|
fleetStreamController,
|
|
16766
|
+
enhanceController,
|
|
15997
16767
|
statuslineHiddenItems,
|
|
15998
16768
|
setStatuslineHiddenItems,
|
|
15999
16769
|
getYolo: () => {
|
|
@@ -16019,7 +16789,8 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
16019
16789
|
stageListeners.add(fn);
|
|
16020
16790
|
return () => stageListeners.delete(fn);
|
|
16021
16791
|
},
|
|
16022
|
-
skillLoader: config.features.skills ? skillLoader : void 0
|
|
16792
|
+
skillLoader: config.features.skills ? skillLoader : void 0,
|
|
16793
|
+
modeId
|
|
16023
16794
|
});
|
|
16024
16795
|
}
|
|
16025
16796
|
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");
|