@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 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, EventBus, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, 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';
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 = expectDefined3(nodes[0]);
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 = expectDefined3(sorted[i]);
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 = expectDefined3(nodes[0]);
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 = expectDefined4(sddState.getBuilder());
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 = expectDefined4(sorted[i]);
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 = expectDefined4(n.description.split("\n")[0]);
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 = expectDefined4(completed[completed.length - 1]);
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 = expectDefined4(next.description.split("\n")[0]);
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 = expectDefined4(sorted2[i]);
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 = expectDefined4(sorted[i]);
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 = expectDefined4(sddState.getBuilder());
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) ?? expectDefined7(keys[0]);
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] = { ...expectDefined7(keys[existingIdx]), apiKey, createdAt: nowIso() };
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 = expectDefined2(parts[0]);
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(expectDefined5(matrix[k]))} ${tag}`);
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 fs26 = await import('fs/promises');
8433
+ const fs27 = await import('fs/promises');
8153
8434
  let existing = {};
8154
8435
  try {
8155
- const raw = await fs26.readFile(configPath2, "utf8");
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 = expectDefined6(page[i]);
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 = expectDefined7(ids[idx - 1]);
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 = expectDefined7(keys[i]);
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 = expectDefined7(keys[arg - 1]);
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 = expectDefined7(keys[arg - 1]);
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 = expectDefined7(keys[arg - 1]);
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: expectDefined8(flags.positional[0]),
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 = expectDefined9(args[i]);
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 = expectDefined10(BUILT_IN_MCP[k]);
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 = expectDefined11(args[i]);
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 = expectDefined11(args[i]);
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(expectDefined11(match[1]));
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 expectDefined12(args[idx + 1]);
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 = expectDefined13(args[i]);
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 fs26 = await import('fs/promises');
11655
+ const fs27 = await import('fs/promises');
11410
11656
  let entries;
11411
11657
  try {
11412
- entries = await fs26.readdir(dir);
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, color52) {
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 ? color52.dim(` [${errKind}]`) : "";
11569
- const errSnip = errMsg || errKind ? `${errKindChip}${color52.dim(errTail)}` : "";
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: color52.green("\u2713"), stats, tail: "" };
11818
+ return { mark: color51.green("\u2713"), stats, tail: "" };
11573
11819
  case "timeout":
11574
- return { mark: color52.yellow("\u23F1"), stats: `${color52.yellow("timeout")} ${stats}`, tail: errSnip };
11820
+ return { mark: color51.yellow("\u23F1"), stats: `${color51.yellow("timeout")} ${stats}`, tail: errSnip };
11575
11821
  case "stopped":
11576
- return { mark: color52.dim("\u2298"), stats: `${color52.dim("stopped")} ${stats}`, tail: errSnip };
11822
+ return { mark: color51.dim("\u2298"), stats: `${color51.dim("stopped")} ${stats}`, tail: errSnip };
11577
11823
  case "failed":
11578
- return { mark: color52.red("\u2717"), stats: `${color52.red("failed")} ${stats}`, tail: errSnip };
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 = expectDefined14(goal.journal[goal.journal.length - 1]);
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(), __toCommonJS(sdd_exports));
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(), __toCommonJS(sdd_exports));
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 ?? expectDefined15(subCfg.id);
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
- const summary = `${color.green("\u2713")} codebase index ready ${color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`)}`;
14926
- process.stderr.write(`
14927
- ${summary}
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: expectDefined16(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: expectDefined16(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
- events.on("provider.response", (e) => {
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
- events.on("iteration.started", () => {
15868
+ evOn("iteration.started", () => {
15582
15869
  updateSpinnerContext();
15583
15870
  spinner.start(color.dim(`${config.provider}/${config.model} thinking\u2026`));
15584
15871
  });
15585
- events.on("provider.response", () => {
15872
+ evOn("provider.response", () => {
15586
15873
  spinner.stop();
15587
15874
  });
15588
- events.on("error", () => {
15875
+ evOn("error", () => {
15589
15876
  spinner.stop();
15590
15877
  });
15591
15878
  let streamingActive = false;
15592
- events.on("provider.text_delta", (p) => {
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
- events.on("iteration.completed", () => {
15886
+ evOn("iteration.completed", () => {
15600
15887
  if (streamingActive) {
15601
15888
  renderer.write("\n");
15602
15889
  streamingActive = false;
15603
15890
  }
15604
15891
  });
15605
- events.on("provider.retry", (p) => {
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
- events.on("provider.error", (p) => {
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
- events.on("error", (e) => {
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
- events.on("tool.started", (e) => {
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
- events.on("tool.executed", (e) => {
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
- events.on("delegate.started", (e) => {
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
- events.on("delegate.completed", (e) => {
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
- events.on("tool.progress", (e) => {
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
- events.on("provider.retry", (e) => {
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
- events.on("provider.error", (e) => {
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(expectDefined17(fleetRoot), "fleet.json") : void 0;
15920
- const sharedScratchpadPath = directorMode ? path8.join(expectDefined17(fleetRoot), "shared") : void 0;
15921
- const subagentSessionsRoot = directorMode ? path8.join(expectDefined17(fleetRoot), "subagents") : void 0;
15922
- const stateCheckpointPath = directorMode ? path8.join(expectDefined17(fleetRoot), "director-state.json") : void 0;
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 = expectDefined17(matches[0]);
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) => {