@wrongstack/cli 0.89.1 → 0.89.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +495 -198
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { color, writeErr, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool,
|
|
2
|
+
import { color, writeErr, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, DefaultPathResolver, EventBus, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, SpecVersioning, atomicWrite, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, DEFAULT_SESSION_PRUNE_DAYS, 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';
|
|
@@ -15,7 +15,7 @@ import { spawn } from 'child_process';
|
|
|
15
15
|
import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
|
|
16
16
|
import { capabilitiesFor, buildProviderFactoriesFromRegistry, makeProviderFromConfig } from '@wrongstack/providers';
|
|
17
17
|
import { createDefaultContainer, routeImagesForModel, readClipboardImage } from '@wrongstack/runtime';
|
|
18
|
-
import { builtinToolsPack, rememberTool, forgetTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes } from '@wrongstack/tools';
|
|
18
|
+
import { builtinToolsPack, rememberTool, forgetTool, searchMemoryTool, relatedMemoryTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes } from '@wrongstack/tools';
|
|
19
19
|
import { fileURLToPath } from 'url';
|
|
20
20
|
import * as readline from 'readline';
|
|
21
21
|
import * as fs12 from 'fs';
|
|
@@ -28,9 +28,7 @@ import { ToolExecutor } from '@wrongstack/core/execution';
|
|
|
28
28
|
import { createToolVisionAdapters } from '@wrongstack/runtime/vision';
|
|
29
29
|
|
|
30
30
|
var __defProp = Object.defineProperty;
|
|
31
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
32
31
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
33
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
34
32
|
var __esm = (fn, res) => function __init() {
|
|
35
33
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
36
34
|
};
|
|
@@ -38,15 +36,6 @@ var __export = (target, all) => {
|
|
|
38
36
|
for (var name in all)
|
|
39
37
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
40
38
|
};
|
|
41
|
-
var __copyProps = (to, from, except, desc) => {
|
|
42
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
43
|
-
for (let key of __getOwnPropNames(from))
|
|
44
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
45
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
46
|
-
}
|
|
47
|
-
return to;
|
|
48
|
-
};
|
|
49
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
50
39
|
function getSessionState(ctx) {
|
|
51
40
|
if (!ctx) return sddState;
|
|
52
41
|
let state = ctx.meta[SDD_META_KEY];
|
|
@@ -132,12 +121,6 @@ var init_state = __esm({
|
|
|
132
121
|
sddState = new SDDState();
|
|
133
122
|
}
|
|
134
123
|
});
|
|
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
|
-
}
|
|
141
124
|
function formatElapsed(ms) {
|
|
142
125
|
if (ms < 1e3) return `${ms}ms`;
|
|
143
126
|
const s = Math.floor(ms / 1e3);
|
|
@@ -201,7 +184,7 @@ function getCurrentTask() {
|
|
|
201
184
|
if (!tracker) return null;
|
|
202
185
|
const nodes = tracker.getAllNodes({ status: ["in_progress"] });
|
|
203
186
|
if (nodes.length === 0) return null;
|
|
204
|
-
const n =
|
|
187
|
+
const n = expectDefined(nodes[0]);
|
|
205
188
|
return { id: n.id, title: n.title, description: n.description, priority: n.priority, estimateHours: n.estimateHours ?? 0, tags: n.tags ?? [], startedAt: n.startedAt };
|
|
206
189
|
}
|
|
207
190
|
function advanceToNextTask() {
|
|
@@ -240,7 +223,7 @@ function renderTaskListWithProgress() {
|
|
|
240
223
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
241
224
|
});
|
|
242
225
|
for (let i = 0; i < sorted.length; i++) {
|
|
243
|
-
const n =
|
|
226
|
+
const n = expectDefined(sorted[i]);
|
|
244
227
|
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";
|
|
245
228
|
const title = n.title.length > 50 ? n.title.slice(0, 49) + "\u2026" : n.title;
|
|
246
229
|
let elapsed = "";
|
|
@@ -254,7 +237,7 @@ function getCurrentExecutingContext() {
|
|
|
254
237
|
if (!tracker) return null;
|
|
255
238
|
const nodes = tracker.getAllNodes({ status: ["in_progress"] });
|
|
256
239
|
if (nodes.length === 0) return null;
|
|
257
|
-
const n =
|
|
240
|
+
const n = expectDefined(nodes[0]);
|
|
258
241
|
const elapsed = n.startedAt ? ` \xB7 elapsed: ${formatElapsed(Date.now() - n.startedAt)}` : "";
|
|
259
242
|
const progress = tracker.getProgress();
|
|
260
243
|
return [
|
|
@@ -562,12 +545,6 @@ __export(sdd_exports, {
|
|
|
562
545
|
trySaveSpecFromAIOutput: () => trySaveSpecFromAIOutput,
|
|
563
546
|
trySaveTasksFromAIOutput: () => trySaveTasksFromAIOutput
|
|
564
547
|
});
|
|
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
|
-
}
|
|
571
548
|
function getTaskTracker() {
|
|
572
549
|
return getTaskTrackerExport();
|
|
573
550
|
}
|
|
@@ -633,7 +610,7 @@ function buildSddCommand(opts) {
|
|
|
633
610
|
}));
|
|
634
611
|
sddState.setSessionStartTime(Date.now());
|
|
635
612
|
sddState.setPhaseStartTime(Date.now());
|
|
636
|
-
const builder =
|
|
613
|
+
const builder = expectDefined(sddState.getBuilder());
|
|
637
614
|
builder.startSession(title);
|
|
638
615
|
const aiPrompt = builder.getAIPrompt();
|
|
639
616
|
return {
|
|
@@ -875,7 +852,7 @@ Start executing the tasks one by one.`
|
|
|
875
852
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
876
853
|
});
|
|
877
854
|
for (let i = 0; i < sorted.length; i++) {
|
|
878
|
-
const n =
|
|
855
|
+
const n = expectDefined(sorted[i]);
|
|
879
856
|
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";
|
|
880
857
|
const num = `${i + 1}`.padStart(3);
|
|
881
858
|
const prio = n.priority.slice(0, 4).padEnd(5);
|
|
@@ -883,7 +860,7 @@ Start executing the tasks one by one.`
|
|
|
883
860
|
const elapsed = n.status === "in_progress" && n.startedAt ? ` (${formatElapsed(Date.now() - n.startedAt)})` : "";
|
|
884
861
|
lines.push(` ${num} ${status} ${prio} ${title}${elapsed}`);
|
|
885
862
|
if (n.description && n.status !== "completed") {
|
|
886
|
-
const first =
|
|
863
|
+
const first = expectDefined(n.description.split("\n")[0]);
|
|
887
864
|
const truncated = first.length > 42 ? first.slice(0, 41) + "\u2026" : first;
|
|
888
865
|
lines.push(` \u21B3 ${truncated}`);
|
|
889
866
|
}
|
|
@@ -1050,7 +1027,7 @@ Start executing the tasks one by one.`
|
|
|
1050
1027
|
if (completed.length === 0) {
|
|
1051
1028
|
return { message: "No completed tasks to undo." };
|
|
1052
1029
|
}
|
|
1053
|
-
const last =
|
|
1030
|
+
const last = expectDefined(completed[completed.length - 1]);
|
|
1054
1031
|
undoTracker.updateNodeStatus(last.id, "pending");
|
|
1055
1032
|
const progress = undoTracker.getProgress();
|
|
1056
1033
|
return {
|
|
@@ -1100,7 +1077,7 @@ Start executing the tasks one by one.`
|
|
|
1100
1077
|
` \u{1F504} ${next.title}`
|
|
1101
1078
|
];
|
|
1102
1079
|
if (next.description) {
|
|
1103
|
-
const first =
|
|
1080
|
+
const first = expectDefined(next.description.split("\n")[0]);
|
|
1104
1081
|
lines.push(` \u21B3 ${first}`);
|
|
1105
1082
|
}
|
|
1106
1083
|
const taskElapsed = next.startedAt ? ` \u23F1 ${formatElapsed(Date.now() - next.startedAt)}` : "";
|
|
@@ -1212,7 +1189,7 @@ Start executing the tasks one by one.`
|
|
|
1212
1189
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
1213
1190
|
});
|
|
1214
1191
|
for (let i = 0; i < sorted2.length; i++) {
|
|
1215
|
-
const n =
|
|
1192
|
+
const n = expectDefined(sorted2[i]);
|
|
1216
1193
|
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";
|
|
1217
1194
|
lines2.push(`${i + 1}. ${status} [${n.priority}] ${n.title}`);
|
|
1218
1195
|
}
|
|
@@ -1237,7 +1214,7 @@ Start executing the tasks one by one.`
|
|
|
1237
1214
|
return (order[a.status] ?? 6) - (order[b.status] ?? 6);
|
|
1238
1215
|
});
|
|
1239
1216
|
for (let i = 0; i < sorted.length; i++) {
|
|
1240
|
-
const n =
|
|
1217
|
+
const n = expectDefined(sorted[i]);
|
|
1241
1218
|
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";
|
|
1242
1219
|
lines.push(`${i + 1}. ${status} [${n.priority}] ${n.title}`);
|
|
1243
1220
|
}
|
|
@@ -1285,7 +1262,7 @@ Start executing the tasks one by one.`
|
|
|
1285
1262
|
maxQuestions: 10,
|
|
1286
1263
|
sessionPath
|
|
1287
1264
|
}));
|
|
1288
|
-
const resumeBuilder =
|
|
1265
|
+
const resumeBuilder = expectDefined(sddState.getBuilder());
|
|
1289
1266
|
const loaded = await resumeBuilder.loadSession();
|
|
1290
1267
|
if (!loaded) {
|
|
1291
1268
|
sddState.setBuilder(null);
|
|
@@ -1519,12 +1496,6 @@ var init_sdd = __esm({
|
|
|
1519
1496
|
init_rendering();
|
|
1520
1497
|
}
|
|
1521
1498
|
});
|
|
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
|
-
}
|
|
1528
1499
|
function normalizeKeys(cfg) {
|
|
1529
1500
|
if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
|
|
1530
1501
|
return cfg.apiKeys.map((k) => ({ ...k }));
|
|
@@ -1542,7 +1513,7 @@ function writeKeysBack(cfg, keys) {
|
|
|
1542
1513
|
return;
|
|
1543
1514
|
}
|
|
1544
1515
|
cfg.apiKeys = keys;
|
|
1545
|
-
const active = keys.find((k) => k.label === cfg.activeKey) ??
|
|
1516
|
+
const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);
|
|
1546
1517
|
cfg.apiKey = active.apiKey;
|
|
1547
1518
|
if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {
|
|
1548
1519
|
cfg.activeKey = active.label;
|
|
@@ -2337,7 +2308,7 @@ async function runWebUI(opts) {
|
|
|
2337
2308
|
const keys = normalizeKeys(existing);
|
|
2338
2309
|
const existingIdx = keys.findIndex((k) => k.label === label);
|
|
2339
2310
|
if (existingIdx >= 0) {
|
|
2340
|
-
keys[existingIdx] = { ...
|
|
2311
|
+
keys[existingIdx] = { ...expectDefined(keys[existingIdx]), apiKey, createdAt: nowIso() };
|
|
2341
2312
|
} else {
|
|
2342
2313
|
keys.push({ label, apiKey, createdAt: nowIso() });
|
|
2343
2314
|
}
|
|
@@ -2471,14 +2442,6 @@ try {
|
|
|
2471
2442
|
if (corePkg.wrongstackApiVersion) API_VERSION = corePkg.wrongstackApiVersion;
|
|
2472
2443
|
} catch {
|
|
2473
2444
|
}
|
|
2474
|
-
|
|
2475
|
-
// src/slash-commands/commit-llm.ts
|
|
2476
|
-
function expectDefined(value) {
|
|
2477
|
-
if (value === null || value === void 0) {
|
|
2478
|
-
throw new Error("Expected value to be defined");
|
|
2479
|
-
}
|
|
2480
|
-
return value;
|
|
2481
|
-
}
|
|
2482
2445
|
async function generateCommitMessageWithLLM(diff, opts) {
|
|
2483
2446
|
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";
|
|
2484
2447
|
const userPrompt = `Here is the git diff:
|
|
@@ -5424,17 +5387,11 @@ No project type auto-detected. Edit the file with project context and instructio
|
|
|
5424
5387
|
}
|
|
5425
5388
|
};
|
|
5426
5389
|
}
|
|
5427
|
-
function expectDefined2(value) {
|
|
5428
|
-
if (value === null || value === void 0) {
|
|
5429
|
-
throw new Error("Expected value to be defined");
|
|
5430
|
-
}
|
|
5431
|
-
return value;
|
|
5432
|
-
}
|
|
5433
5390
|
function parseMcpArgs(args) {
|
|
5434
5391
|
const trimmed = args.trim();
|
|
5435
5392
|
if (!trimmed || trimmed === "list") return { action: "list", name: "" };
|
|
5436
5393
|
const parts = trimmed.split(/\s+/);
|
|
5437
|
-
const action =
|
|
5394
|
+
const action = expectDefined(parts[0]);
|
|
5438
5395
|
const name = parts[1] ?? "";
|
|
5439
5396
|
const enable = parts.includes("--enable") || parts.includes("-e");
|
|
5440
5397
|
switch (action) {
|
|
@@ -5681,7 +5638,7 @@ function buildMemoryCommand(opts) {
|
|
|
5681
5638
|
return {
|
|
5682
5639
|
name: "memory",
|
|
5683
5640
|
category: "Inspect",
|
|
5684
|
-
description: "Inspect or edit persistent memory: /memory [show|remember <text>|forget <query>|clear]",
|
|
5641
|
+
description: "Inspect or edit persistent memory: /memory [show|remember <text>|forget <query>|clear|compact|stats]",
|
|
5685
5642
|
async run(args) {
|
|
5686
5643
|
const store = opts.memoryStore;
|
|
5687
5644
|
if (!store) return { message: "No memory store configured." };
|
|
@@ -5714,14 +5671,350 @@ function buildMemoryCommand(opts) {
|
|
|
5714
5671
|
await store.clear();
|
|
5715
5672
|
return { message: "Cleared all memory scopes." };
|
|
5716
5673
|
}
|
|
5674
|
+
case "compact": {
|
|
5675
|
+
return runCompact(opts);
|
|
5676
|
+
}
|
|
5677
|
+
case "stats": {
|
|
5678
|
+
return runStats(opts);
|
|
5679
|
+
}
|
|
5717
5680
|
default:
|
|
5718
5681
|
return {
|
|
5719
|
-
message: `Unknown subcommand "${verb}". Try: show | remember <text> | forget <query> | clear`
|
|
5682
|
+
message: `Unknown subcommand "${verb}". Try: show | remember <text> | forget <query> | clear | compact | stats`
|
|
5720
5683
|
};
|
|
5721
5684
|
}
|
|
5722
5685
|
}
|
|
5723
5686
|
};
|
|
5724
5687
|
}
|
|
5688
|
+
function buildCompactPrompt(entries) {
|
|
5689
|
+
const entriesBlock = entries.map(
|
|
5690
|
+
(e, i) => `${i + 1}. [${e.ts.slice(0, 10)}] ${e.id}
|
|
5691
|
+
${e.text}${e.tags ? `
|
|
5692
|
+
tags: ${e.tags.join(", ")}` : ""}${e.type ? `
|
|
5693
|
+
type: ${e.type}` : ""}${e.priority ? `
|
|
5694
|
+
priority: ${e.priority}` : ""}`
|
|
5695
|
+
).join("\n\n");
|
|
5696
|
+
return `You are a memory curator. Your task is to review, deduplicate, and improve a set of long-term memory entries.
|
|
5697
|
+
|
|
5698
|
+
These entries are injected into the context of an AI coding agent. Every token counts. The memory must be concise, accurate, and free of noise.
|
|
5699
|
+
|
|
5700
|
+
## Current Memory Entries
|
|
5701
|
+
|
|
5702
|
+
${entriesBlock}
|
|
5703
|
+
|
|
5704
|
+
## Your Task
|
|
5705
|
+
|
|
5706
|
+
Review each entry and return a JSON object with an "operations" array. Each operation targets one or more entries:
|
|
5707
|
+
|
|
5708
|
+
### Actions
|
|
5709
|
+
|
|
5710
|
+
- **"keep"** \u2014 The entry is valuable as-is. Include it in the operations so I know you reviewed it.
|
|
5711
|
+
- **"rewrite"** \u2014 The entry has value but needs better wording. Provide improved "newText". Target a single entry.
|
|
5712
|
+
- **"merge"** \u2014 Two or more entries say essentially the same thing. Combine them into one concise entry. The "targets" should list all entries being merged. Provide the combined "newText".
|
|
5713
|
+
- **"delete"** \u2014 The entry is obsolete, redundant, too vague, or not useful for future sessions. Target one or more entries.
|
|
5714
|
+
|
|
5715
|
+
### Rules
|
|
5716
|
+
|
|
5717
|
+
1. **Be ruthless about noise.** If an entry won't help a future AI agent do its job better, delete it.
|
|
5718
|
+
2. **Deduplicate aggressively.** Similar entries should be merged. Identical entries MUST be merged.
|
|
5719
|
+
3. **Keep entries concise.** Each entry should be one clear sentence. Remove filler words.
|
|
5720
|
+
4. **Preserve factual accuracy.** Don't change the meaning of entries unless they're wrong.
|
|
5721
|
+
5. **Handle every entry.** Every entry must appear in at least one operation (keep, rewrite, merge, or delete).
|
|
5722
|
+
6. **Prefer quality over quantity.** 10 excellent entries > 30 mediocre ones.
|
|
5723
|
+
7. **Tag entries appropriately.** If an entry mentions a technology or concept that could be tagged, suggest tags in the newText using #hashtag syntax.
|
|
5724
|
+
|
|
5725
|
+
### Response Format
|
|
5726
|
+
|
|
5727
|
+
Return ONLY valid JSON with this structure:
|
|
5728
|
+
|
|
5729
|
+
{
|
|
5730
|
+
"operations": [
|
|
5731
|
+
{ "action": "keep", "targets": ["mem_1234_abcd"], "reason": "Clear and useful" },
|
|
5732
|
+
{ "action": "rewrite", "targets": ["mem_5678_ef01"], "newText": "Project uses pnpm v9 with ESM-only modules #pnpm #esm", "reason": "Added version and ESM detail" },
|
|
5733
|
+
{ "action": "merge", "targets": ["mem_aaaa_1111", "mem_bbbb_2222"], "newText": "All packages use TypeScript strict mode with noUncheckedIndexedAccess #typescript", "reason": "Two entries about TS config, merged" },
|
|
5734
|
+
{ "action": "delete", "targets": ["mem_cccc_3333"], "reason": "Obsolete \u2014 was a temporary debug note" }
|
|
5735
|
+
],
|
|
5736
|
+
"summary": "Merged 2 TS entries, rewrote 1 for clarity, deleted 1 obsolete note. 12 entries \u2192 10 entries."
|
|
5737
|
+
}
|
|
5738
|
+
|
|
5739
|
+
Use the EXACT entry IDs from the list above for "targets". No markdown, no explanation outside the JSON.`;
|
|
5740
|
+
}
|
|
5741
|
+
async function runCompact(opts) {
|
|
5742
|
+
const store = opts.memoryStore;
|
|
5743
|
+
if (!store) return { message: "No memory store configured." };
|
|
5744
|
+
const entries = await store.list("project-memory");
|
|
5745
|
+
if (entries.length === 0) {
|
|
5746
|
+
return { message: "Memory is empty \u2014 nothing to compact." };
|
|
5747
|
+
}
|
|
5748
|
+
const raw = await store.read("project-memory");
|
|
5749
|
+
const compactEntries = parseCompactEntries(raw);
|
|
5750
|
+
if (compactEntries.length === 0) {
|
|
5751
|
+
return { message: "No parseable entries found." };
|
|
5752
|
+
}
|
|
5753
|
+
const provider = opts.llmProvider;
|
|
5754
|
+
if (!provider || !provider.complete) {
|
|
5755
|
+
return { message: "No LLM provider available. /memory compact requires an active session with a configured provider." };
|
|
5756
|
+
}
|
|
5757
|
+
const prompt = buildCompactPrompt(compactEntries);
|
|
5758
|
+
let responseText;
|
|
5759
|
+
try {
|
|
5760
|
+
const signal = AbortSignal.timeout(3e4);
|
|
5761
|
+
const response = await provider.complete(
|
|
5762
|
+
{
|
|
5763
|
+
model: opts.llmModel ?? "",
|
|
5764
|
+
system: [{ type: "text", text: prompt }],
|
|
5765
|
+
messages: [
|
|
5766
|
+
{
|
|
5767
|
+
role: "user",
|
|
5768
|
+
content: `Review the ${compactEntries.length} memory entries above and return operations as JSON.`
|
|
5769
|
+
}
|
|
5770
|
+
],
|
|
5771
|
+
maxTokens: 2e3,
|
|
5772
|
+
temperature: 0.1
|
|
5773
|
+
// low temperature for deterministic curation
|
|
5774
|
+
},
|
|
5775
|
+
{ signal }
|
|
5776
|
+
);
|
|
5777
|
+
responseText = response.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
|
|
5778
|
+
} catch (err) {
|
|
5779
|
+
return {
|
|
5780
|
+
message: `LLM call failed: ${err instanceof Error ? err.message : String(err)}`
|
|
5781
|
+
};
|
|
5782
|
+
}
|
|
5783
|
+
if (!responseText) {
|
|
5784
|
+
return { message: "LLM returned empty response." };
|
|
5785
|
+
}
|
|
5786
|
+
let parsed;
|
|
5787
|
+
try {
|
|
5788
|
+
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
|
|
5789
|
+
if (!jsonMatch) {
|
|
5790
|
+
return { message: `LLM response is not valid JSON:
|
|
5791
|
+
${responseText.slice(0, 500)}` };
|
|
5792
|
+
}
|
|
5793
|
+
parsed = JSON.parse(jsonMatch[0]);
|
|
5794
|
+
} catch (err) {
|
|
5795
|
+
return {
|
|
5796
|
+
message: `Failed to parse LLM response: ${err instanceof Error ? err.message : String(err)}
|
|
5797
|
+
|
|
5798
|
+
Raw response:
|
|
5799
|
+
${responseText.slice(0, 500)}`
|
|
5800
|
+
};
|
|
5801
|
+
}
|
|
5802
|
+
if (!Array.isArray(parsed.operations) || parsed.operations.length === 0) {
|
|
5803
|
+
return { message: "LLM returned no operations." };
|
|
5804
|
+
}
|
|
5805
|
+
let kept = 0;
|
|
5806
|
+
let rewritten = 0;
|
|
5807
|
+
let merged = 0;
|
|
5808
|
+
let deleted = 0;
|
|
5809
|
+
const errors = [];
|
|
5810
|
+
for (const op of parsed.operations) {
|
|
5811
|
+
try {
|
|
5812
|
+
switch (op.action) {
|
|
5813
|
+
case "keep": {
|
|
5814
|
+
kept += op.targets.length;
|
|
5815
|
+
break;
|
|
5816
|
+
}
|
|
5817
|
+
case "rewrite": {
|
|
5818
|
+
if (!op.newText) {
|
|
5819
|
+
errors.push(`rewrite missing newText for targets: ${op.targets.join(", ")}`);
|
|
5820
|
+
continue;
|
|
5821
|
+
}
|
|
5822
|
+
for (const target of op.targets) {
|
|
5823
|
+
await store.forget(target);
|
|
5824
|
+
}
|
|
5825
|
+
await store.remember(op.newText);
|
|
5826
|
+
rewritten++;
|
|
5827
|
+
break;
|
|
5828
|
+
}
|
|
5829
|
+
case "merge": {
|
|
5830
|
+
if (!op.newText) {
|
|
5831
|
+
errors.push(`merge missing newText for targets: ${op.targets.join(", ")}`);
|
|
5832
|
+
continue;
|
|
5833
|
+
}
|
|
5834
|
+
for (const target of op.targets) {
|
|
5835
|
+
await store.forget(target);
|
|
5836
|
+
}
|
|
5837
|
+
await store.remember(op.newText);
|
|
5838
|
+
merged++;
|
|
5839
|
+
break;
|
|
5840
|
+
}
|
|
5841
|
+
case "delete": {
|
|
5842
|
+
for (const target of op.targets) {
|
|
5843
|
+
await store.forget(target);
|
|
5844
|
+
}
|
|
5845
|
+
deleted += op.targets.length;
|
|
5846
|
+
break;
|
|
5847
|
+
}
|
|
5848
|
+
default: {
|
|
5849
|
+
errors.push(`unknown action "${op.action}"`);
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
} catch (err) {
|
|
5853
|
+
errors.push(
|
|
5854
|
+
`${op.action} failed for ${op.targets.join(", ")}: ${err instanceof Error ? err.message : String(err)}`
|
|
5855
|
+
);
|
|
5856
|
+
}
|
|
5857
|
+
}
|
|
5858
|
+
const lines = ["## Memory Compact \u2014 Complete"];
|
|
5859
|
+
const stats = [];
|
|
5860
|
+
if (kept > 0) stats.push(`${kept} kept`);
|
|
5861
|
+
if (rewritten > 0) stats.push(`${rewritten} rewritten`);
|
|
5862
|
+
if (merged > 0) stats.push(`${merged} merged`);
|
|
5863
|
+
if (deleted > 0) stats.push(`${deleted} deleted`);
|
|
5864
|
+
lines.push(`**Result:** ${stats.join(", ")}`);
|
|
5865
|
+
lines.push(`**Before:** ${compactEntries.length} entries \u2192 **After:** ${kept + rewritten + merged} entries`);
|
|
5866
|
+
if (parsed.summary) {
|
|
5867
|
+
lines.push("");
|
|
5868
|
+
lines.push(parsed.summary);
|
|
5869
|
+
}
|
|
5870
|
+
lines.push("");
|
|
5871
|
+
lines.push("### Operations");
|
|
5872
|
+
for (const op of parsed.operations) {
|
|
5873
|
+
const icon = op.action === "keep" ? "\u2713" : op.action === "rewrite" ? "\u270F\uFE0F" : op.action === "merge" ? "\u{1F500}" : op.action === "delete" ? "\u2717" : "?";
|
|
5874
|
+
const detail = op.newText ? ` \u2192 "${op.newText}"` : "";
|
|
5875
|
+
lines.push(`- ${icon} **${op.action}** ${op.targets.join(", ")}${detail}`);
|
|
5876
|
+
if (op.reason) lines.push(` _${op.reason}_`);
|
|
5877
|
+
}
|
|
5878
|
+
if (errors.length > 0) {
|
|
5879
|
+
lines.push("");
|
|
5880
|
+
lines.push("### Errors");
|
|
5881
|
+
for (const err of errors) {
|
|
5882
|
+
lines.push(`- \u26A0\uFE0F ${err}`);
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
return { message: lines.join("\n") };
|
|
5886
|
+
}
|
|
5887
|
+
function parseCompactEntries(raw) {
|
|
5888
|
+
const entries = [];
|
|
5889
|
+
for (const line of raw.split("\n")) {
|
|
5890
|
+
const trimmed = line.trim();
|
|
5891
|
+
if (!trimmed.startsWith("- [")) continue;
|
|
5892
|
+
const idMatch = trimmed.match(/mem_(\d+_\w+)/);
|
|
5893
|
+
if (!idMatch) continue;
|
|
5894
|
+
const id = idMatch[0] ?? "";
|
|
5895
|
+
const afterId = trimmed.slice((idMatch.index ?? 0) + id.length).trim();
|
|
5896
|
+
const tsMatch = trimmed.match(/^-\s*\[([^\]]+)\]/);
|
|
5897
|
+
const ts = tsMatch?.[1] ?? "";
|
|
5898
|
+
const tags = [];
|
|
5899
|
+
const tagRe = /#([\w-]+)/g;
|
|
5900
|
+
let tm;
|
|
5901
|
+
while ((tm = tagRe.exec(afterId)) !== null) {
|
|
5902
|
+
tags.push(tm[1] ?? "");
|
|
5903
|
+
}
|
|
5904
|
+
const text = afterId.replace(tagRe, "").replace(/\s{2,}/g, " ").trim();
|
|
5905
|
+
if (!text) continue;
|
|
5906
|
+
entries.push({ id, text, ts, tags: tags.length > 0 ? tags : void 0 });
|
|
5907
|
+
}
|
|
5908
|
+
return entries;
|
|
5909
|
+
}
|
|
5910
|
+
async function runStats(opts) {
|
|
5911
|
+
const store = opts.memoryStore;
|
|
5912
|
+
if (!store) return { message: "No memory store configured." };
|
|
5913
|
+
const entries = await store.list("project-memory");
|
|
5914
|
+
if (entries.length === 0) {
|
|
5915
|
+
return { message: "\u{1F4CA} Memory is empty. Start adding entries with `/memory remember <text>`." };
|
|
5916
|
+
}
|
|
5917
|
+
const now = Date.now();
|
|
5918
|
+
const lines = ["## \u{1F4CA} Memory Stats"];
|
|
5919
|
+
const raw = await store.read("project-memory");
|
|
5920
|
+
const byteSize = Buffer.byteLength(raw, "utf8");
|
|
5921
|
+
const kbSize = (byteSize / 1024).toFixed(1);
|
|
5922
|
+
const maxKb = (32e3 / 1024).toFixed(1);
|
|
5923
|
+
const pctFull = (byteSize / 32e3 * 100).toFixed(0);
|
|
5924
|
+
lines.push(`**Total:** ${entries.length} entries \xB7 ${kbSize} KB / ${maxKb} KB (${pctFull}%)`);
|
|
5925
|
+
const byType = /* @__PURE__ */ new Map();
|
|
5926
|
+
for (const e of entries) {
|
|
5927
|
+
const t = e.type ?? "untyped";
|
|
5928
|
+
byType.set(t, (byType.get(t) ?? 0) + 1);
|
|
5929
|
+
}
|
|
5930
|
+
if (byType.size > 0) {
|
|
5931
|
+
lines.push("");
|
|
5932
|
+
lines.push("### By Type");
|
|
5933
|
+
const typeOrder = ["convention", "decision", "fact", "preference", "reference", "anti_pattern", "untyped"];
|
|
5934
|
+
for (const t of typeOrder) {
|
|
5935
|
+
const count = byType.get(t);
|
|
5936
|
+
if (count) {
|
|
5937
|
+
const bar = "\u2588".repeat(Math.min(count, 20));
|
|
5938
|
+
lines.push(`- \`${t}\` ${bar} ${count}`);
|
|
5939
|
+
}
|
|
5940
|
+
}
|
|
5941
|
+
}
|
|
5942
|
+
const byPriority = /* @__PURE__ */ new Map();
|
|
5943
|
+
for (const e of entries) {
|
|
5944
|
+
const p = e.priority ?? "unset";
|
|
5945
|
+
byPriority.set(p, (byPriority.get(p) ?? 0) + 1);
|
|
5946
|
+
}
|
|
5947
|
+
if (byPriority.size > 0) {
|
|
5948
|
+
lines.push("");
|
|
5949
|
+
lines.push("### By Priority");
|
|
5950
|
+
const icon = { critical: "\u26A1", high: "\u25B2", medium: "\u25CF", low: "\u25CB", unset: "\xB7" };
|
|
5951
|
+
for (const [p, count] of [...byPriority.entries()].sort((a, b) => b[1] - a[1])) {
|
|
5952
|
+
lines.push(`- ${icon[p] ?? "\xB7"} \`${p}\`: ${count}`);
|
|
5953
|
+
}
|
|
5954
|
+
}
|
|
5955
|
+
const ages = entries.map((e) => {
|
|
5956
|
+
const ageDays = (now - new Date(e.ts).getTime()) / (1e3 * 60 * 60 * 24);
|
|
5957
|
+
if (ageDays < 1) return "<1d";
|
|
5958
|
+
if (ageDays < 7) return "<7d";
|
|
5959
|
+
if (ageDays < 30) return "<30d";
|
|
5960
|
+
return ">30d";
|
|
5961
|
+
});
|
|
5962
|
+
const byAge = /* @__PURE__ */ new Map();
|
|
5963
|
+
for (const a of ages) byAge.set(a, (byAge.get(a) ?? 0) + 1);
|
|
5964
|
+
lines.push("");
|
|
5965
|
+
lines.push("### By Age");
|
|
5966
|
+
for (const age of ["<1d", "<7d", "<30d", ">30d"]) {
|
|
5967
|
+
const actual = byAge.get(age) ?? 0;
|
|
5968
|
+
if (actual > 0 || age === "<7d") {
|
|
5969
|
+
lines.push(`- ${age}: ${actual}`);
|
|
5970
|
+
}
|
|
5971
|
+
}
|
|
5972
|
+
const tagCounts = /* @__PURE__ */ new Map();
|
|
5973
|
+
for (const e of entries) {
|
|
5974
|
+
for (const t of e.tags ?? []) {
|
|
5975
|
+
tagCounts.set(t, (tagCounts.get(t) ?? 0) + 1);
|
|
5976
|
+
}
|
|
5977
|
+
}
|
|
5978
|
+
if (tagCounts.size > 0) {
|
|
5979
|
+
lines.push("");
|
|
5980
|
+
lines.push("### Top Tags");
|
|
5981
|
+
const sorted = [...tagCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10);
|
|
5982
|
+
for (const [tag, count] of sorted) {
|
|
5983
|
+
lines.push(`- \`#${tag}\`: ${count}`);
|
|
5984
|
+
}
|
|
5985
|
+
}
|
|
5986
|
+
lines.push("");
|
|
5987
|
+
lines.push("### Health");
|
|
5988
|
+
const untyped = byType.get("untyped") ?? 0;
|
|
5989
|
+
const unsetPriority = byPriority.get("unset") ?? 0;
|
|
5990
|
+
const old = byAge.get(">30d") ?? 0;
|
|
5991
|
+
if (untyped > entries.length * 0.5) {
|
|
5992
|
+
lines.push(`- \u26A0\uFE0F ${untyped}/${entries.length} entries have no type \u2014 run \`/memory compact\` to categorize`);
|
|
5993
|
+
} else if (untyped > 0) {
|
|
5994
|
+
lines.push(`- \u2139\uFE0F ${untyped} entries untyped \u2014 consider categorizing`);
|
|
5995
|
+
} else {
|
|
5996
|
+
lines.push("- \u2705 All entries have types");
|
|
5997
|
+
}
|
|
5998
|
+
if (unsetPriority > entries.length * 0.5) {
|
|
5999
|
+
lines.push(`- \u26A0\uFE0F ${unsetPriority}/${entries.length} entries have no priority`);
|
|
6000
|
+
} else if (unsetPriority > 0) {
|
|
6001
|
+
lines.push(`- \u2139\uFE0F ${unsetPriority} entries have no priority set`);
|
|
6002
|
+
} else {
|
|
6003
|
+
lines.push("- \u2705 All entries have priorities");
|
|
6004
|
+
}
|
|
6005
|
+
if (old > 5) {
|
|
6006
|
+
lines.push(`- \u26A0\uFE0F ${old} entries older than 30 days \u2014 run \`/memory compact\` to review`);
|
|
6007
|
+
}
|
|
6008
|
+
const pct2 = Number.parseInt(pctFull);
|
|
6009
|
+
if (pct2 > 80) {
|
|
6010
|
+
lines.push(`- \u26A0\uFE0F Storage ${pct2}% full \u2014 run \`/memory compact\` to free space`);
|
|
6011
|
+
} else {
|
|
6012
|
+
lines.push(`- \u2705 Storage ${pct2}% full \u2014 healthy`);
|
|
6013
|
+
}
|
|
6014
|
+
lines.push("");
|
|
6015
|
+
lines.push("**Commands:** `/memory show` \xB7 `/memory compact` \xB7 `/memory remember <text>`");
|
|
6016
|
+
return { message: lines.join("\n") };
|
|
6017
|
+
}
|
|
5725
6018
|
async function runModePicker(modeStore, reader) {
|
|
5726
6019
|
const modes = await modeStore.listModes();
|
|
5727
6020
|
const active = await modeStore.getActiveMode();
|
|
@@ -6397,12 +6690,6 @@ function summariseEvent(ev) {
|
|
|
6397
6690
|
return color.dim("\u2026");
|
|
6398
6691
|
}
|
|
6399
6692
|
}
|
|
6400
|
-
function expectDefined5(value) {
|
|
6401
|
-
if (value === null || value === void 0) {
|
|
6402
|
-
throw new Error("Expected value to be defined");
|
|
6403
|
-
}
|
|
6404
|
-
return value;
|
|
6405
|
-
}
|
|
6406
6693
|
var noOpVault3 = {
|
|
6407
6694
|
encrypt: (v) => v,
|
|
6408
6695
|
decrypt: (v) => v,
|
|
@@ -6495,7 +6782,7 @@ function buildSetModelCommand(opts) {
|
|
|
6495
6782
|
for (const k of keys.sort()) {
|
|
6496
6783
|
const kind = matrixKeyKind(k);
|
|
6497
6784
|
const tag = kind === "unknown" ? color.red("?") : color.dim(kind);
|
|
6498
|
-
lines.push(` ${color.amber(k.padEnd(22))} \u2192 ${fmtEntry(
|
|
6785
|
+
lines.push(` ${color.amber(k.padEnd(22))} \u2192 ${fmtEntry(expectDefined(matrix[k]))} ${tag}`);
|
|
6499
6786
|
}
|
|
6500
6787
|
}
|
|
6501
6788
|
lines.push("", color.dim(" /setmodel list for valid keys \xB7 /setmodel help for usage"));
|
|
@@ -7433,7 +7720,7 @@ async function runProjectCheck(opts) {
|
|
|
7433
7720
|
try {
|
|
7434
7721
|
const { spawn: spawn4 } = await import('child_process');
|
|
7435
7722
|
await new Promise((resolve5, reject) => {
|
|
7436
|
-
const child = spawn4("git", ["init"], { cwd });
|
|
7723
|
+
const child = spawn4("git", ["init"], { cwd, signal: AbortSignal.timeout(1e4) });
|
|
7437
7724
|
child.on("error", reject);
|
|
7438
7725
|
child.on("close", (code) => code === 0 ? resolve5() : reject(new Error(`git init failed with ${code}`)));
|
|
7439
7726
|
});
|
|
@@ -8139,20 +8426,14 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
8139
8426
|
}
|
|
8140
8427
|
|
|
8141
8428
|
// src/picker.ts
|
|
8142
|
-
function expectDefined6(value) {
|
|
8143
|
-
if (value === null || value === void 0) {
|
|
8144
|
-
throw new Error("Expected value to be defined");
|
|
8145
|
-
}
|
|
8146
|
-
return value;
|
|
8147
|
-
}
|
|
8148
8429
|
var theme = { primary: color.amber };
|
|
8149
8430
|
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os2__default.homedir()) {
|
|
8150
8431
|
try {
|
|
8151
8432
|
const { atomicWrite: atomicWrite14 } = await import('@wrongstack/core');
|
|
8152
|
-
const
|
|
8433
|
+
const fs27 = await import('fs/promises');
|
|
8153
8434
|
let existing = {};
|
|
8154
8435
|
try {
|
|
8155
|
-
const raw = await
|
|
8436
|
+
const raw = await fs27.readFile(configPath2, "utf8");
|
|
8156
8437
|
existing = JSON.parse(raw);
|
|
8157
8438
|
} catch {
|
|
8158
8439
|
}
|
|
@@ -8340,7 +8621,7 @@ async function pickModel(provider, registry, renderer, reader, defaultModel) {
|
|
|
8340
8621
|
while (offset < models.length) {
|
|
8341
8622
|
const page = models.slice(offset, offset + pageSize);
|
|
8342
8623
|
for (let i = 0; i < page.length; i++) {
|
|
8343
|
-
const m =
|
|
8624
|
+
const m = expectDefined(page[i]);
|
|
8344
8625
|
const num = offset + i + 1;
|
|
8345
8626
|
const ctx = m.limit?.context ? `${(m.limit.context / 1e3).toFixed(0)}k`.padStart(6) : " ?";
|
|
8346
8627
|
const cost = m.cost?.input !== void 0 ? `$${m.cost.input}/$${m.cost.output ?? "?"}` : "";
|
|
@@ -9024,7 +9305,7 @@ ${color.amber("?")} Pick: `)).trim().toLowerCase();
|
|
|
9024
9305
|
}
|
|
9025
9306
|
const idx = Number.parseInt(choice, 10);
|
|
9026
9307
|
if (!Number.isNaN(idx) && idx >= 1 && idx <= ids.length) {
|
|
9027
|
-
const pid =
|
|
9308
|
+
const pid = expectDefined(ids[idx - 1]);
|
|
9028
9309
|
await manageProvider(pid, deps);
|
|
9029
9310
|
continue;
|
|
9030
9311
|
}
|
|
@@ -9114,7 +9395,7 @@ ${color.bold(providerId)} ${cfg.family ? color.dim(`[${cfg.family}]`) : color.am
|
|
|
9114
9395
|
deps.renderer.write(color.dim(" (no keys saved)\n"));
|
|
9115
9396
|
} else {
|
|
9116
9397
|
for (let i = 0; i < keys.length; i++) {
|
|
9117
|
-
const k =
|
|
9398
|
+
const k = expectDefined(keys[i]);
|
|
9118
9399
|
const marker = k.label === active ? color.green("\u25CF") : color.dim("\u25CB");
|
|
9119
9400
|
deps.renderer.write(
|
|
9120
9401
|
` ${color.dim(`${i + 1}.`.padStart(4))} ${marker} ${k.label.padEnd(20)} ${maskedKey(k.apiKey)} ${color.dim(k.createdAt)}
|
|
@@ -9176,7 +9457,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
9176
9457
|
deps.renderer.writeError(`Usage: u <1-${keys.length}>`);
|
|
9177
9458
|
continue;
|
|
9178
9459
|
}
|
|
9179
|
-
const target =
|
|
9460
|
+
const target = expectDefined(keys[arg - 1]);
|
|
9180
9461
|
const newKey = await readKeyInput(deps, `Updated key for ${target.label}`);
|
|
9181
9462
|
if (!newKey) continue;
|
|
9182
9463
|
await mutateProviders(deps, (all) => {
|
|
@@ -9196,7 +9477,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
9196
9477
|
deps.renderer.writeError(`Usage: d <1-${keys.length}>`);
|
|
9197
9478
|
continue;
|
|
9198
9479
|
}
|
|
9199
|
-
const target =
|
|
9480
|
+
const target = expectDefined(keys[arg - 1]);
|
|
9200
9481
|
const confirm = (await deps.reader.readLine(
|
|
9201
9482
|
` ${color.amber("?")} Delete key "${target.label}" (${maskedKey(target.apiKey)})? ${color.dim("[y/N/q]")} `
|
|
9202
9483
|
)).trim().toLowerCase();
|
|
@@ -9272,7 +9553,7 @@ ${color.amber("?")} ${providerId} > `)).trim();
|
|
|
9272
9553
|
deps.renderer.writeError(`Usage: s <1-${keys.length}>`);
|
|
9273
9554
|
continue;
|
|
9274
9555
|
}
|
|
9275
|
-
const target =
|
|
9556
|
+
const target = expectDefined(keys[arg - 1]);
|
|
9276
9557
|
await mutateProviders(deps, (all) => {
|
|
9277
9558
|
const p = all[providerId];
|
|
9278
9559
|
if (!p) return;
|
|
@@ -9605,12 +9886,6 @@ function mutateProviders(deps, mutator) {
|
|
|
9605
9886
|
}
|
|
9606
9887
|
|
|
9607
9888
|
// src/subcommands/handlers/auth.ts
|
|
9608
|
-
function expectDefined8(value) {
|
|
9609
|
-
if (value === null || value === void 0) {
|
|
9610
|
-
throw new Error("Expected value to be defined");
|
|
9611
|
-
}
|
|
9612
|
-
return value;
|
|
9613
|
-
}
|
|
9614
9889
|
var authCmd = async (args, deps) => {
|
|
9615
9890
|
const flags = parseAuthFlags(args);
|
|
9616
9891
|
const menuDeps = {
|
|
@@ -9622,7 +9897,7 @@ var authCmd = async (args, deps) => {
|
|
|
9622
9897
|
};
|
|
9623
9898
|
if (flags.positional.length === 0) return runAuthMenu(menuDeps);
|
|
9624
9899
|
return runAuthDirect(menuDeps, {
|
|
9625
|
-
providerId:
|
|
9900
|
+
providerId: expectDefined(flags.positional[0]),
|
|
9626
9901
|
label: flags.label,
|
|
9627
9902
|
family: flags.family,
|
|
9628
9903
|
baseUrl: flags.baseUrl,
|
|
@@ -9658,7 +9933,8 @@ var updateCmd = async (args, deps) => {
|
|
|
9658
9933
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
9659
9934
|
const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
|
|
9660
9935
|
cwd,
|
|
9661
|
-
stdio: "pipe"
|
|
9936
|
+
stdio: "pipe",
|
|
9937
|
+
signal: AbortSignal.timeout(12e4)
|
|
9662
9938
|
});
|
|
9663
9939
|
let _stderr = "";
|
|
9664
9940
|
child.stderr?.on("data", (d) => {
|
|
@@ -9845,12 +10121,6 @@ var doctorCmd = async (_args, deps) => {
|
|
|
9845
10121
|
deps.renderer.write(color.green("All checks passed.\n"));
|
|
9846
10122
|
return 0;
|
|
9847
10123
|
};
|
|
9848
|
-
function expectDefined9(value) {
|
|
9849
|
-
if (value === null || value === void 0) {
|
|
9850
|
-
throw new Error("Expected value to be defined");
|
|
9851
|
-
}
|
|
9852
|
-
return value;
|
|
9853
|
-
}
|
|
9854
10124
|
var exportCmd = async (args, deps) => {
|
|
9855
10125
|
if (!deps.sessionStore) {
|
|
9856
10126
|
deps.renderer.writeError("No session store configured.");
|
|
@@ -9862,7 +10132,7 @@ var exportCmd = async (args, deps) => {
|
|
|
9862
10132
|
let includeDiagnostics = true;
|
|
9863
10133
|
let sessionId;
|
|
9864
10134
|
for (let i = 0; i < args.length; i++) {
|
|
9865
|
-
const a =
|
|
10135
|
+
const a = expectDefined(args[i]);
|
|
9866
10136
|
if (a === "--format" || a === "-f") {
|
|
9867
10137
|
const v = args[++i];
|
|
9868
10138
|
if (v !== "markdown" && v !== "json" && v !== "text") {
|
|
@@ -10124,12 +10394,6 @@ async function serveMcpStdio(deps) {
|
|
|
10124
10394
|
}
|
|
10125
10395
|
|
|
10126
10396
|
// src/subcommands/handlers/mcp.ts
|
|
10127
|
-
function expectDefined10(value) {
|
|
10128
|
-
if (value === null || value === void 0) {
|
|
10129
|
-
throw new Error("Expected value to be defined");
|
|
10130
|
-
}
|
|
10131
|
-
return value;
|
|
10132
|
-
}
|
|
10133
10397
|
var BUILT_IN_MCP = allServers();
|
|
10134
10398
|
var mcpCmd = async (args, deps) => {
|
|
10135
10399
|
const sub = args[0];
|
|
@@ -10180,7 +10444,7 @@ async function addMcpServer(args, deps) {
|
|
|
10180
10444
|
`);
|
|
10181
10445
|
if (Object.keys(deps.config.mcpServers ?? {}).length === 0)
|
|
10182
10446
|
for (const k of Object.keys(BUILT_IN_MCP)) {
|
|
10183
|
-
const s =
|
|
10447
|
+
const s = expectDefined(BUILT_IN_MCP[k]);
|
|
10184
10448
|
deps.renderer.write(` ${k.padEnd(20)} ${s.description}
|
|
10185
10449
|
`);
|
|
10186
10450
|
}
|
|
@@ -10458,12 +10722,6 @@ var projectsCmd = async (_args, deps) => {
|
|
|
10458
10722
|
return 0;
|
|
10459
10723
|
}
|
|
10460
10724
|
};
|
|
10461
|
-
function expectDefined11(value) {
|
|
10462
|
-
if (value === null || value === void 0) {
|
|
10463
|
-
throw new Error("Expected value to be defined");
|
|
10464
|
-
}
|
|
10465
|
-
return value;
|
|
10466
|
-
}
|
|
10467
10725
|
var providersCmd = async (args, deps) => {
|
|
10468
10726
|
const showAll = args.includes("--all");
|
|
10469
10727
|
const showUnsupported = args.includes("--unsupported");
|
|
@@ -10511,7 +10769,7 @@ ${color.dim(`Current: ${deps.config.provider ?? "<unset>"} / ${deps.config.model
|
|
|
10511
10769
|
function parseFlags2(args) {
|
|
10512
10770
|
const flags = {};
|
|
10513
10771
|
for (let i = 0; i < args.length; i++) {
|
|
10514
|
-
const a =
|
|
10772
|
+
const a = expectDefined(args[i]);
|
|
10515
10773
|
if (a.startsWith("--")) {
|
|
10516
10774
|
const eq = a.indexOf("=");
|
|
10517
10775
|
if (eq !== -1) {
|
|
@@ -10531,7 +10789,7 @@ function parseFlags2(args) {
|
|
|
10531
10789
|
function positionals(args) {
|
|
10532
10790
|
const out = [];
|
|
10533
10791
|
for (let i = 0; i < args.length; i++) {
|
|
10534
|
-
const a =
|
|
10792
|
+
const a = expectDefined(args[i]);
|
|
10535
10793
|
if (a.startsWith("--")) {
|
|
10536
10794
|
const eq = a.indexOf("=");
|
|
10537
10795
|
if (eq === -1) {
|
|
@@ -10686,7 +10944,7 @@ function parseSizeFlag(raw) {
|
|
|
10686
10944
|
const s = raw.trim().toLowerCase();
|
|
10687
10945
|
const match = /^(\d+(?:\.\d+)?)\s*(k|m|b)?$/.exec(s);
|
|
10688
10946
|
if (!match) return void 0;
|
|
10689
|
-
const num = Number.parseFloat(
|
|
10947
|
+
const num = Number.parseFloat(expectDefined(match[1]));
|
|
10690
10948
|
const unit = match[2];
|
|
10691
10949
|
if (unit === "b") return Math.round(num * 1e9);
|
|
10692
10950
|
if (unit === "m") return Math.round(num * 1e6);
|
|
@@ -11007,12 +11265,6 @@ Fleet Run: ${runId}
|
|
|
11007
11265
|
}
|
|
11008
11266
|
|
|
11009
11267
|
// src/subcommands/handlers/sessions-config.ts
|
|
11010
|
-
function expectDefined12(value) {
|
|
11011
|
-
if (value === null || value === void 0) {
|
|
11012
|
-
throw new Error("Expected value to be defined");
|
|
11013
|
-
}
|
|
11014
|
-
return value;
|
|
11015
|
-
}
|
|
11016
11268
|
var sessionsCmd = async (args, deps) => {
|
|
11017
11269
|
const sub = args[0];
|
|
11018
11270
|
if (sub === "fleet") {
|
|
@@ -11058,7 +11310,7 @@ var configCmd = async (args, deps) => {
|
|
|
11058
11310
|
};
|
|
11059
11311
|
function extractArg(args, key) {
|
|
11060
11312
|
const idx = args.indexOf(key);
|
|
11061
|
-
if (idx !== -1 && args[idx + 1] !== void 0) return
|
|
11313
|
+
if (idx !== -1 && args[idx + 1] !== void 0) return expectDefined(args[idx + 1]);
|
|
11062
11314
|
const eq = key.startsWith("--") ? args.find((a) => a.startsWith(`${key}=`)) : null;
|
|
11063
11315
|
if (eq) return eq.slice(eq.indexOf("=") + 1);
|
|
11064
11316
|
return null;
|
|
@@ -11134,12 +11386,6 @@ async function runRestore(args, deps) {
|
|
|
11134
11386
|
`);
|
|
11135
11387
|
return 0;
|
|
11136
11388
|
}
|
|
11137
|
-
function expectDefined13(value) {
|
|
11138
|
-
if (value === null || value === void 0) {
|
|
11139
|
-
throw new Error("Expected value to be defined");
|
|
11140
|
-
}
|
|
11141
|
-
return value;
|
|
11142
|
-
}
|
|
11143
11389
|
function parseRewindFlags(args) {
|
|
11144
11390
|
const flags = {};
|
|
11145
11391
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -11154,7 +11400,7 @@ function parseRewindFlags(args) {
|
|
|
11154
11400
|
}
|
|
11155
11401
|
function findSessionId(args) {
|
|
11156
11402
|
for (let i = 0; i < args.length; i++) {
|
|
11157
|
-
const a =
|
|
11403
|
+
const a = expectDefined(args[i]);
|
|
11158
11404
|
if (a === "--last" || a === "--to") {
|
|
11159
11405
|
i++;
|
|
11160
11406
|
continue;
|
|
@@ -11406,10 +11652,10 @@ var auditCmd = async (args, deps) => {
|
|
|
11406
11652
|
return verify.ok ? 0 : 1;
|
|
11407
11653
|
};
|
|
11408
11654
|
async function listAudits(log, dir, deps) {
|
|
11409
|
-
const
|
|
11655
|
+
const fs27 = await import('fs/promises');
|
|
11410
11656
|
let entries;
|
|
11411
11657
|
try {
|
|
11412
|
-
entries = await
|
|
11658
|
+
entries = await fs27.readdir(dir);
|
|
11413
11659
|
} catch {
|
|
11414
11660
|
deps.renderer.write(
|
|
11415
11661
|
color.dim(`No sessions dir found at ${dir}. Run a session first.`) + "\n"
|
|
@@ -11560,22 +11806,22 @@ function fmtDuration(ms) {
|
|
|
11560
11806
|
const remMin = m - h * 60;
|
|
11561
11807
|
return `${h}h${remMin}m`;
|
|
11562
11808
|
}
|
|
11563
|
-
function fmtTaskResultLine(r,
|
|
11809
|
+
function fmtTaskResultLine(r, color51) {
|
|
11564
11810
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
11565
11811
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
11566
11812
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
11567
11813
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
11568
|
-
const errKindChip = errKind ?
|
|
11569
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
11814
|
+
const errKindChip = errKind ? color51.dim(` [${errKind}]`) : "";
|
|
11815
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color51.dim(errTail)}` : "";
|
|
11570
11816
|
switch (r.status) {
|
|
11571
11817
|
case "success":
|
|
11572
|
-
return { mark:
|
|
11818
|
+
return { mark: color51.green("\u2713"), stats, tail: "" };
|
|
11573
11819
|
case "timeout":
|
|
11574
|
-
return { mark:
|
|
11820
|
+
return { mark: color51.yellow("\u23F1"), stats: `${color51.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
11575
11821
|
case "stopped":
|
|
11576
|
-
return { mark:
|
|
11822
|
+
return { mark: color51.dim("\u2298"), stats: `${color51.dim("stopped")} ${stats}`, tail: errSnip };
|
|
11577
11823
|
case "failed":
|
|
11578
|
-
return { mark:
|
|
11824
|
+
return { mark: color51.red("\u2717"), stats: `${color51.red("failed")} ${stats}`, tail: errSnip };
|
|
11579
11825
|
}
|
|
11580
11826
|
}
|
|
11581
11827
|
|
|
@@ -11697,6 +11943,7 @@ async function boot(argv) {
|
|
|
11697
11943
|
const isSingleShot = positional.length > 0 || typeof flags["prompt"] === "string";
|
|
11698
11944
|
const isInteractiveTTY = isStdinTTY() && !isSingleShot;
|
|
11699
11945
|
if (isInteractiveTTY) {
|
|
11946
|
+
await checkGitInCwd({ cwd, renderer, reader });
|
|
11700
11947
|
const cont = await runProjectCheck({ projectRoot, cwd, renderer, reader });
|
|
11701
11948
|
if (!cont) {
|
|
11702
11949
|
await reader.close();
|
|
@@ -11860,6 +12107,61 @@ async function boot(argv) {
|
|
|
11860
12107
|
updateInfo
|
|
11861
12108
|
};
|
|
11862
12109
|
}
|
|
12110
|
+
async function checkGitInCwd(opts) {
|
|
12111
|
+
const { cwd, renderer, reader } = opts;
|
|
12112
|
+
const cwdGit = path8.join(cwd, ".git");
|
|
12113
|
+
let hasCwdGit = false;
|
|
12114
|
+
try {
|
|
12115
|
+
await fsp4.access(cwdGit);
|
|
12116
|
+
hasCwdGit = true;
|
|
12117
|
+
} catch {
|
|
12118
|
+
}
|
|
12119
|
+
if (!hasCwdGit) {
|
|
12120
|
+
renderer.write(
|
|
12121
|
+
`
|
|
12122
|
+
${color.amber("\u25CB")} This folder has no ${color.bold(".git")} repository.
|
|
12123
|
+
`
|
|
12124
|
+
);
|
|
12125
|
+
const answer = (await reader.readLine(
|
|
12126
|
+
` ${color.amber("?")} Initialize one here? ${color.dim("[y/N]")} `
|
|
12127
|
+
)).trim().toLowerCase();
|
|
12128
|
+
if (answer === "y" || answer === "yes") {
|
|
12129
|
+
try {
|
|
12130
|
+
const { spawn: spawn4 } = await import('child_process');
|
|
12131
|
+
await new Promise((resolve5, reject) => {
|
|
12132
|
+
const child = spawn4("git", ["init"], {
|
|
12133
|
+
cwd,
|
|
12134
|
+
signal: AbortSignal.timeout(1e4)
|
|
12135
|
+
});
|
|
12136
|
+
child.on("error", reject);
|
|
12137
|
+
child.on(
|
|
12138
|
+
"close",
|
|
12139
|
+
(code) => code === 0 ? resolve5() : reject(new Error(`git init failed with ${code}`))
|
|
12140
|
+
);
|
|
12141
|
+
});
|
|
12142
|
+
renderer.write(` ${color.green("\u2713")} Git repository initialized
|
|
12143
|
+
`);
|
|
12144
|
+
hasCwdGit = true;
|
|
12145
|
+
} catch (err) {
|
|
12146
|
+
renderer.writeError(
|
|
12147
|
+
`git init failed: ${err instanceof Error ? err.message : String(err)}
|
|
12148
|
+
`
|
|
12149
|
+
);
|
|
12150
|
+
}
|
|
12151
|
+
}
|
|
12152
|
+
}
|
|
12153
|
+
const parentDir = path8.dirname(cwd);
|
|
12154
|
+
if (parentDir !== cwd) {
|
|
12155
|
+
try {
|
|
12156
|
+
await fsp4.access(path8.join(parentDir, ".git"));
|
|
12157
|
+
renderer.write(
|
|
12158
|
+
` ${color.dim("\u2139")} A ${color.bold(".git")} repo exists in the parent directory: ${color.dim(parentDir)}
|
|
12159
|
+
`
|
|
12160
|
+
);
|
|
12161
|
+
} catch {
|
|
12162
|
+
}
|
|
12163
|
+
}
|
|
12164
|
+
}
|
|
11863
12165
|
var CONTEXT_OVERFLOW_RE = /context window|exceeds the context|too many tokens|context.*tokens/i;
|
|
11864
12166
|
function contextOverflowHint(err) {
|
|
11865
12167
|
const structured = err.code === ERROR_CODES.PROVIDER_CONTEXT_OVERFLOW || err.code === ERROR_CODES.AGENT_CONTEXT_OVERFLOW;
|
|
@@ -12168,12 +12470,6 @@ async function predictNextTasks(input, opts) {
|
|
|
12168
12470
|
}
|
|
12169
12471
|
}
|
|
12170
12472
|
init_sdd();
|
|
12171
|
-
function expectDefined14(value) {
|
|
12172
|
-
if (value === null || value === void 0) {
|
|
12173
|
-
throw new Error("Expected value to be defined");
|
|
12174
|
-
}
|
|
12175
|
-
return value;
|
|
12176
|
-
}
|
|
12177
12473
|
async function runRepl(opts) {
|
|
12178
12474
|
if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
|
|
12179
12475
|
await renderGoalBanner(opts);
|
|
@@ -12689,7 +12985,7 @@ async function renderGoalBanner(opts) {
|
|
|
12689
12985
|
color.dim("Goal: ") + stateColor(summary) + color.dim(` [${goal.goalState}] (iter ${goal.iterations})`) + "\n"
|
|
12690
12986
|
);
|
|
12691
12987
|
if (goal.journal.length > 0) {
|
|
12692
|
-
const lastEntry =
|
|
12988
|
+
const lastEntry = expectDefined(goal.journal[goal.journal.length - 1]);
|
|
12693
12989
|
const statusIcon = lastEntry.status === "success" ? "\u2713" : lastEntry.status === "failure" ? "\u2717" : lastEntry.status === "aborted" ? "\u2298" : lastEntry.status === "skipped" ? "\u229D" : "\xB7";
|
|
12694
12990
|
opts.renderer.write(
|
|
12695
12991
|
color.dim(` Last: ${statusIcon} ${lastEntry.task} (${lastEntry.status})`) + "\n"
|
|
@@ -13159,8 +13455,8 @@ async function execute(deps) {
|
|
|
13159
13455
|
initialGoal: goalFlag,
|
|
13160
13456
|
initialAsk: askFlag,
|
|
13161
13457
|
projectRoot,
|
|
13162
|
-
getSDDContext: () => {
|
|
13163
|
-
const { getActiveSDDContext: getActiveSDDContext2 } = (init_sdd(),
|
|
13458
|
+
getSDDContext: async () => {
|
|
13459
|
+
const { getActiveSDDContext: getActiveSDDContext2 } = await Promise.resolve().then(() => (init_sdd(), sdd_exports));
|
|
13164
13460
|
return getActiveSDDContext2();
|
|
13165
13461
|
},
|
|
13166
13462
|
onSDDOutput: async (output) => {
|
|
@@ -13171,7 +13467,7 @@ async function execute(deps) {
|
|
|
13171
13467
|
autoDetectTaskCompletion: autoDetectTaskCompletion2,
|
|
13172
13468
|
getTaskProgress: getTaskProgress2,
|
|
13173
13469
|
getActiveSDDPhase: getActiveSDDPhase2
|
|
13174
|
-
} = (init_sdd(),
|
|
13470
|
+
} = await Promise.resolve().then(() => (init_sdd(), sdd_exports));
|
|
13175
13471
|
const messages = [];
|
|
13176
13472
|
const specSaved = await trySaveSpecFromAIOutput2(output);
|
|
13177
13473
|
if (specSaved)
|
|
@@ -13291,12 +13587,6 @@ async function execute(deps) {
|
|
|
13291
13587
|
}
|
|
13292
13588
|
return code;
|
|
13293
13589
|
}
|
|
13294
|
-
function expectDefined15(value) {
|
|
13295
|
-
if (value === null || value === void 0) {
|
|
13296
|
-
throw new Error("Expected value to be defined");
|
|
13297
|
-
}
|
|
13298
|
-
return value;
|
|
13299
|
-
}
|
|
13300
13590
|
function buildRoutingRunner(config, host) {
|
|
13301
13591
|
const standardRunner = makeAgentSubagentRunner({
|
|
13302
13592
|
factory: host.makeSubagentFactory(config),
|
|
@@ -13305,7 +13595,7 @@ function buildRoutingRunner(config, host) {
|
|
|
13305
13595
|
return async (task, ctx) => {
|
|
13306
13596
|
const subCfg = ctx.config;
|
|
13307
13597
|
if (subCfg.provider === "acp") {
|
|
13308
|
-
const cacheKey = subCfg.role ?? subCfg.name ??
|
|
13598
|
+
const cacheKey = subCfg.role ?? subCfg.name ?? expectDefined(subCfg.id);
|
|
13309
13599
|
return host.buildACPRunner(cacheKey).then((r) => r(task, ctx));
|
|
13310
13600
|
}
|
|
13311
13601
|
return standardRunner(task, ctx);
|
|
@@ -14163,7 +14453,8 @@ function gitText(args, cwd) {
|
|
|
14163
14453
|
const child = spawn("git", args, {
|
|
14164
14454
|
cwd,
|
|
14165
14455
|
env: buildChildEnv(),
|
|
14166
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
14456
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
14457
|
+
signal: AbortSignal.timeout(1e4)
|
|
14167
14458
|
});
|
|
14168
14459
|
child.stdout?.on("data", (c) => {
|
|
14169
14460
|
out += c.toString();
|
|
@@ -14186,7 +14477,8 @@ function runCmd(cmd, args, cwd, shell = false) {
|
|
|
14186
14477
|
cwd,
|
|
14187
14478
|
env: buildChildEnv(),
|
|
14188
14479
|
stdio: ["ignore", "pipe", "pipe"],
|
|
14189
|
-
shell: shell || process.platform === "win32"
|
|
14480
|
+
shell: shell || process.platform === "win32",
|
|
14481
|
+
signal: AbortSignal.timeout(3e4)
|
|
14190
14482
|
});
|
|
14191
14483
|
child.stdout?.on("data", (c) => {
|
|
14192
14484
|
out += c.toString();
|
|
@@ -14922,10 +15214,9 @@ async function setupCodebaseIndexing(deps) {
|
|
|
14922
15214
|
const onError = (err) => logger.debug(`codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
14923
15215
|
if (idx.onSessionStart) {
|
|
14924
15216
|
void runStartupIndex({ projectRoot }).then((r) => {
|
|
14925
|
-
|
|
14926
|
-
|
|
14927
|
-
|
|
14928
|
-
`);
|
|
15217
|
+
logger.info(
|
|
15218
|
+
`codebase index ready: ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`
|
|
15219
|
+
);
|
|
14929
15220
|
}).catch((err) => {
|
|
14930
15221
|
logger.warn(
|
|
14931
15222
|
`codebase index (startup) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -15194,12 +15485,6 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
15194
15485
|
}
|
|
15195
15486
|
return { resolvedProvider, provider, providerRegistry };
|
|
15196
15487
|
}
|
|
15197
|
-
function expectDefined16(value) {
|
|
15198
|
-
if (value === null || value === void 0) {
|
|
15199
|
-
throw new Error("Expected value to be defined");
|
|
15200
|
-
}
|
|
15201
|
-
return value;
|
|
15202
|
-
}
|
|
15203
15488
|
async function setupSession(params) {
|
|
15204
15489
|
const {
|
|
15205
15490
|
config,
|
|
@@ -15265,7 +15550,7 @@ async function setupSession(params) {
|
|
|
15265
15550
|
const context = new Context({
|
|
15266
15551
|
systemPrompt,
|
|
15267
15552
|
provider,
|
|
15268
|
-
session:
|
|
15553
|
+
session: expectDefined(session),
|
|
15269
15554
|
signal: ctxSignal,
|
|
15270
15555
|
tokenCounter,
|
|
15271
15556
|
cwd,
|
|
@@ -15321,7 +15606,7 @@ async function setupSession(params) {
|
|
|
15321
15606
|
}
|
|
15322
15607
|
}
|
|
15323
15608
|
return {
|
|
15324
|
-
session:
|
|
15609
|
+
session: expectDefined(session),
|
|
15325
15610
|
sessionRef,
|
|
15326
15611
|
context,
|
|
15327
15612
|
restoredMessages,
|
|
@@ -15430,12 +15715,6 @@ async function launchEternalFromFlag(deps) {
|
|
|
15430
15715
|
}
|
|
15431
15716
|
|
|
15432
15717
|
// src/cli-main.ts
|
|
15433
|
-
function expectDefined17(value) {
|
|
15434
|
-
if (value === null || value === void 0) {
|
|
15435
|
-
throw new Error("Expected value to be defined");
|
|
15436
|
-
}
|
|
15437
|
-
return value;
|
|
15438
|
-
}
|
|
15439
15718
|
async function main(argv) {
|
|
15440
15719
|
const ctx = await boot(argv);
|
|
15441
15720
|
if (typeof ctx === "number") return ctx;
|
|
@@ -15455,11 +15734,14 @@ async function main(argv) {
|
|
|
15455
15734
|
} = ctx;
|
|
15456
15735
|
updateInfo = await printUpdateNotice(updateInfo);
|
|
15457
15736
|
const pathResolver = new DefaultPathResolver(cwd);
|
|
15737
|
+
const events = new EventBus();
|
|
15738
|
+
events.setLogger(logger);
|
|
15458
15739
|
const container = createDefaultContainer({
|
|
15459
15740
|
config,
|
|
15460
15741
|
wpaths,
|
|
15461
15742
|
logger,
|
|
15462
15743
|
modelsRegistry,
|
|
15744
|
+
events,
|
|
15463
15745
|
permission: {
|
|
15464
15746
|
yolo: config.yolo,
|
|
15465
15747
|
yoloDestructive: flags["yolo-destructive"] === true || flags["force-all-yolo"] === true,
|
|
@@ -15558,9 +15840,9 @@ async function main(argv) {
|
|
|
15558
15840
|
if (config.features.memory) {
|
|
15559
15841
|
toolRegistry.register(rememberTool(memoryStore));
|
|
15560
15842
|
toolRegistry.register(forgetTool(memoryStore));
|
|
15843
|
+
toolRegistry.register(searchMemoryTool(memoryStore));
|
|
15844
|
+
toolRegistry.register(relatedMemoryTool(memoryStore));
|
|
15561
15845
|
}
|
|
15562
|
-
const events = new EventBus();
|
|
15563
|
-
events.setLogger(logger);
|
|
15564
15846
|
const { metricsSink, healthRegistry } = (() => {
|
|
15565
15847
|
const ms = setupMetrics({
|
|
15566
15848
|
flags,
|
|
@@ -15574,35 +15856,40 @@ async function main(argv) {
|
|
|
15574
15856
|
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
15575
15857
|
const spinner = new Spinner(process.stderr, { enabled: !tuiOwnsScreen });
|
|
15576
15858
|
let lastInputTokens = 0;
|
|
15577
|
-
|
|
15859
|
+
const teardownHandlers = [];
|
|
15860
|
+
const evOn = (event, handler) => {
|
|
15861
|
+
events.on(event, handler);
|
|
15862
|
+
teardownHandlers.push(() => events.off(event, handler));
|
|
15863
|
+
};
|
|
15864
|
+
evOn("provider.response", (e) => {
|
|
15578
15865
|
lastInputTokens = e.usage?.input ?? 0;
|
|
15579
15866
|
updateSpinnerContext();
|
|
15580
15867
|
});
|
|
15581
|
-
|
|
15868
|
+
evOn("iteration.started", () => {
|
|
15582
15869
|
updateSpinnerContext();
|
|
15583
15870
|
spinner.start(color.dim(`${config.provider}/${config.model} thinking\u2026`));
|
|
15584
15871
|
});
|
|
15585
|
-
|
|
15872
|
+
evOn("provider.response", () => {
|
|
15586
15873
|
spinner.stop();
|
|
15587
15874
|
});
|
|
15588
|
-
|
|
15875
|
+
evOn("error", () => {
|
|
15589
15876
|
spinner.stop();
|
|
15590
15877
|
});
|
|
15591
15878
|
let streamingActive = false;
|
|
15592
|
-
|
|
15879
|
+
evOn("provider.text_delta", (p) => {
|
|
15593
15880
|
if (!streamingActive) {
|
|
15594
15881
|
spinner.stop();
|
|
15595
15882
|
streamingActive = true;
|
|
15596
15883
|
}
|
|
15597
15884
|
renderer.write(p.text);
|
|
15598
15885
|
});
|
|
15599
|
-
|
|
15886
|
+
evOn("iteration.completed", () => {
|
|
15600
15887
|
if (streamingActive) {
|
|
15601
15888
|
renderer.write("\n");
|
|
15602
15889
|
streamingActive = false;
|
|
15603
15890
|
}
|
|
15604
15891
|
});
|
|
15605
|
-
|
|
15892
|
+
evOn("provider.retry", (p) => {
|
|
15606
15893
|
spinner.stop();
|
|
15607
15894
|
if (streamingActive) {
|
|
15608
15895
|
renderer.write("\n");
|
|
@@ -15613,7 +15900,7 @@ async function main(argv) {
|
|
|
15613
15900
|
`));
|
|
15614
15901
|
spinner.start(color.dim(`${config.provider}/${config.model} thinking\u2026`));
|
|
15615
15902
|
});
|
|
15616
|
-
|
|
15903
|
+
evOn("provider.error", (p) => {
|
|
15617
15904
|
spinner.stop();
|
|
15618
15905
|
if (streamingActive) {
|
|
15619
15906
|
renderer.write("\n");
|
|
@@ -15666,7 +15953,7 @@ async function main(argv) {
|
|
|
15666
15953
|
);
|
|
15667
15954
|
const stats = new SessionStats(events, tokenCounter);
|
|
15668
15955
|
const errorRing = [];
|
|
15669
|
-
|
|
15956
|
+
evOn("error", (e) => {
|
|
15670
15957
|
const err = e.err;
|
|
15671
15958
|
const code = err && typeof err === "object" && "code" in err && typeof err.code === "string" ? err.code : "UNKNOWN";
|
|
15672
15959
|
const message = e.err instanceof Error ? e.err.message : String(e.err);
|
|
@@ -15681,7 +15968,7 @@ async function main(argv) {
|
|
|
15681
15968
|
}).catch(() => {
|
|
15682
15969
|
});
|
|
15683
15970
|
});
|
|
15684
|
-
|
|
15971
|
+
evOn("tool.started", (e) => {
|
|
15685
15972
|
sessionBridge.append({
|
|
15686
15973
|
type: "tool_call_start",
|
|
15687
15974
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15691,7 +15978,7 @@ async function main(argv) {
|
|
|
15691
15978
|
}).catch(() => {
|
|
15692
15979
|
});
|
|
15693
15980
|
});
|
|
15694
|
-
|
|
15981
|
+
evOn("tool.executed", (e) => {
|
|
15695
15982
|
sessionBridge.append({
|
|
15696
15983
|
type: "tool_call_end",
|
|
15697
15984
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15707,16 +15994,16 @@ async function main(argv) {
|
|
|
15707
15994
|
});
|
|
15708
15995
|
});
|
|
15709
15996
|
if (!tuiOwnsScreen) {
|
|
15710
|
-
|
|
15997
|
+
evOn("delegate.started", (e) => {
|
|
15711
15998
|
const task = e.task.length > 100 ? `${e.task.slice(0, 99)}\u2026` : e.task;
|
|
15712
15999
|
renderer.writeInfo(`\u{1F91D} Delegating \u2192 ${e.target}: ${task}`);
|
|
15713
16000
|
});
|
|
15714
|
-
|
|
16001
|
+
evOn("delegate.completed", (e) => {
|
|
15715
16002
|
const cost = e.costUsd && e.costUsd > 0 ? ` \xB7 $${e.costUsd.toFixed(4)}` : "";
|
|
15716
16003
|
renderer.writeInfo(`${e.ok ? "\u2705" : "\u274C"} ${e.summary}${cost}`);
|
|
15717
16004
|
});
|
|
15718
16005
|
}
|
|
15719
|
-
|
|
16006
|
+
evOn("tool.progress", (e) => {
|
|
15720
16007
|
sessionBridge.append({
|
|
15721
16008
|
type: "tool_progress",
|
|
15722
16009
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15726,7 +16013,7 @@ async function main(argv) {
|
|
|
15726
16013
|
}).catch(() => {
|
|
15727
16014
|
});
|
|
15728
16015
|
});
|
|
15729
|
-
|
|
16016
|
+
evOn("provider.retry", (e) => {
|
|
15730
16017
|
sessionBridge.append({
|
|
15731
16018
|
type: "provider_retry",
|
|
15732
16019
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15738,7 +16025,7 @@ async function main(argv) {
|
|
|
15738
16025
|
}).catch(() => {
|
|
15739
16026
|
});
|
|
15740
16027
|
});
|
|
15741
|
-
|
|
16028
|
+
evOn("provider.error", (e) => {
|
|
15742
16029
|
sessionBridge.append({
|
|
15743
16030
|
type: "provider_error",
|
|
15744
16031
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -15870,6 +16157,13 @@ async function main(argv) {
|
|
|
15870
16157
|
logger
|
|
15871
16158
|
});
|
|
15872
16159
|
if (fallbackExtension) agent.extensions.register(fallbackExtension);
|
|
16160
|
+
if (config.features.memory && config.features.memoryConsolidation !== false) {
|
|
16161
|
+
agent.extensions.register(
|
|
16162
|
+
new SessionMemoryConsolidator({
|
|
16163
|
+
memoryStore
|
|
16164
|
+
})
|
|
16165
|
+
);
|
|
16166
|
+
}
|
|
15873
16167
|
const switchProviderAndModel = (providerId, modelId) => {
|
|
15874
16168
|
try {
|
|
15875
16169
|
context.provider = buildProviderForId(providerId);
|
|
@@ -15916,10 +16210,10 @@ async function main(argv) {
|
|
|
15916
16210
|
}
|
|
15917
16211
|
};
|
|
15918
16212
|
const fleetRoot = directorMode ? path8.join(wpaths.projectSessions, session.id) : void 0;
|
|
15919
|
-
const manifestPath = directorMode ? typeof process.env["WRONGSTACK_FLEET_MANIFEST"] === "string" ? process.env["WRONGSTACK_FLEET_MANIFEST"] : path8.join(
|
|
15920
|
-
const sharedScratchpadPath = directorMode ? path8.join(
|
|
15921
|
-
const subagentSessionsRoot = directorMode ? path8.join(
|
|
15922
|
-
const stateCheckpointPath = directorMode ? path8.join(
|
|
16213
|
+
const manifestPath = directorMode ? typeof process.env["WRONGSTACK_FLEET_MANIFEST"] === "string" ? process.env["WRONGSTACK_FLEET_MANIFEST"] : path8.join(expectDefined(fleetRoot), "fleet.json") : void 0;
|
|
16214
|
+
const sharedScratchpadPath = directorMode ? path8.join(expectDefined(fleetRoot), "shared") : void 0;
|
|
16215
|
+
const subagentSessionsRoot = directorMode ? path8.join(expectDefined(fleetRoot), "subagents") : void 0;
|
|
16216
|
+
const stateCheckpointPath = directorMode ? path8.join(expectDefined(fleetRoot), "director-state.json") : void 0;
|
|
15923
16217
|
const fleetRootForPromotion = path8.join(wpaths.projectSessions, session.id);
|
|
15924
16218
|
const brainQueue = new BrainDecisionQueue(events);
|
|
15925
16219
|
const brain = new ObservableBrainArbiter(
|
|
@@ -16338,7 +16632,7 @@ async function main(argv) {
|
|
|
16338
16632
|
...matches.map((m) => ` ${m.subagentId} (${m.runId})`)
|
|
16339
16633
|
].join("\n");
|
|
16340
16634
|
}
|
|
16341
|
-
const t =
|
|
16635
|
+
const t = expectDefined(matches[0]);
|
|
16342
16636
|
const raw = await fsp4.readFile(t.file, "utf8");
|
|
16343
16637
|
if (mode === "raw") return raw;
|
|
16344
16638
|
const lines = raw.split("\n").filter((l) => l.trim());
|
|
@@ -16588,6 +16882,8 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
16588
16882
|
parallelEngine?.stop();
|
|
16589
16883
|
},
|
|
16590
16884
|
onExit: () => {
|
|
16885
|
+
for (const teardown of teardownHandlers) teardown();
|
|
16886
|
+
teardownHandlers.length = 0;
|
|
16591
16887
|
brainQueue.dispose();
|
|
16592
16888
|
void mcpRegistry.stopAll();
|
|
16593
16889
|
},
|
|
@@ -16597,7 +16893,8 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
16597
16893
|
(resolve5, reject) => {
|
|
16598
16894
|
const child = spawn("git", ["status", "--porcelain"], {
|
|
16599
16895
|
cwd: cwd2,
|
|
16600
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
16896
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
16897
|
+
signal: AbortSignal.timeout(5e3)
|
|
16601
16898
|
});
|
|
16602
16899
|
let stdout = "";
|
|
16603
16900
|
child.stdout?.on("data", (d) => {
|