@wrongstack/cli 0.309.0 → 0.310.0

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.
Files changed (83) hide show
  1. package/dist/{acp-5ZLGFHWP.js → acp-EA57GUFB.js} +6 -4
  2. package/dist/acp-server-agent.d.ts +1 -1
  3. package/dist/{audit-BBR22QH3.js → audit-ZPCLCC3C.js} +1 -1
  4. package/dist/{auth-WOKC2RVG.js → auth-VQMSZGKE.js} +4 -4
  5. package/dist/auth-menu/loopback-server.d.ts +0 -12
  6. package/dist/{bench-XNDUJOSZ.js → bench-XYG56AMO.js} +1 -1
  7. package/dist/boot/tui-session-stub-enrich.d.ts +20 -0
  8. package/dist/{chronicle-63MFCZN6.js → chronicle-6EPPMUC5.js} +1 -1
  9. package/dist/{chunk-53STH6CX.js → chunk-63GFD62R.js} +3 -2
  10. package/dist/{chunk-SZ42FYPT.js → chunk-BXFYBQKR.js} +4 -6
  11. package/dist/{chunk-JQURRYU4.js → chunk-CHZZEEIP.js} +2 -2
  12. package/dist/{chunk-CB35UVXO.js → chunk-KQNYSZG2.js} +34 -9
  13. package/dist/{chunk-XSG33WHN.js → chunk-QAC263FZ.js} +4 -2
  14. package/dist/{chunk-SSSJQVUY.js → chunk-QYIIOMLE.js} +15 -2
  15. package/dist/{chunk-7JOMY3HO.js → chunk-USYOJIV2.js} +3 -3
  16. package/dist/{chunk-DOJLAULS.js → chunk-WOTGMHAH.js} +36 -26
  17. package/dist/{chunk-T6YAVFXA.js → chunk-X3N5TS2S.js} +2 -1
  18. package/dist/{cli-main-RG2PTQ6S.js → cli-main-RFEZAJ4U.js} +3190 -2839
  19. package/dist/{diag-doctor-WTBHPOMB.js → diag-doctor-HJKFUY6B.js} +1 -1
  20. package/dist/diff-renderer.d.ts +17 -0
  21. package/dist/{execution-TYUXABWI.js → execution-WA2UCXNM.js} +180 -61
  22. package/dist/{export-CCUXRJOU.js → export-ROG3DKTZ.js} +1 -1
  23. package/dist/{hq-PA6RH2UW.js → hq-AG4VW4XO.js} +18 -10
  24. package/dist/hq-server/handle-types.d.ts +32 -0
  25. package/dist/hq-server/login-attempt-store.d.ts +5 -0
  26. package/dist/{hq-server-PBRU275L.js → hq-server-GZGM4BHA.js} +2 -2
  27. package/dist/hq-server.d.ts +2 -20
  28. package/dist/index.js +105 -76
  29. package/dist/{init-E2NDDOHI.js → init-4JQSG66Q.js} +1 -1
  30. package/dist/{mailbox-serve-V3QIJBDH.js → mailbox-serve-5S3PHG5D.js} +1 -1
  31. package/dist/{mcp-CMLFHRG2.js → mcp-RRPKNRSN.js} +3 -1
  32. package/dist/mcp-serve.d.ts +1 -1
  33. package/dist/{modeldiag-ICMPHT5L.js → modeldiag-H6DKWJ2N.js} +6 -12
  34. package/dist/{plugin-usage-26LIIW3P.js → plugin-usage-GCTYOZPH.js} +1 -1
  35. package/dist/{projects-XE76NFNZ.js → projects-5J727S4L.js} +1 -1
  36. package/dist/provider-config-utils.d.ts +1 -2
  37. package/dist/{providers-models-D23WUD74.js → providers-models-663NDPRQ.js} +2 -2
  38. package/dist/{quick-VIO2BEHS.js → quick-XLYLZX4B.js} +1 -1
  39. package/dist/{replay-WBRMEWQ5.js → replay-RZXZKP2U.js} +1 -1
  40. package/dist/{rewind-7RE6ONIC.js → rewind-2FFNOOKS.js} +1 -1
  41. package/dist/{sessions-config-YX2ZPAFM.js → sessions-config-7Q7QJBKJ.js} +1 -1
  42. package/dist/slash-commands/dev.d.ts +50 -0
  43. package/dist/subcommands/handlers/acp.d.ts +1 -1
  44. package/dist/subcommands/handlers/audit.d.ts +1 -1
  45. package/dist/subcommands/handlers/auth.d.ts +1 -1
  46. package/dist/subcommands/handlers/bench.d.ts +1 -1
  47. package/dist/subcommands/handlers/chronicle.d.ts +1 -1
  48. package/dist/subcommands/handlers/config-history.d.ts +1 -1
  49. package/dist/subcommands/handlers/diag-doctor.d.ts +1 -1
  50. package/dist/subcommands/handlers/export.d.ts +1 -1
  51. package/dist/subcommands/handlers/hq.d.ts +1 -1
  52. package/dist/subcommands/handlers/init.d.ts +1 -1
  53. package/dist/subcommands/handlers/mailbox-serve.d.ts +1 -1
  54. package/dist/subcommands/handlers/mcp.d.ts +1 -1
  55. package/dist/subcommands/handlers/modeldiag-bench.d.ts +1 -1
  56. package/dist/subcommands/handlers/modeldiag-eval.d.ts +1 -1
  57. package/dist/subcommands/handlers/modeldiag-test.d.ts +1 -1
  58. package/dist/subcommands/handlers/modeldiag.d.ts +1 -1
  59. package/dist/subcommands/handlers/plugin-usage.d.ts +1 -1
  60. package/dist/subcommands/handlers/projects.d.ts +1 -1
  61. package/dist/subcommands/handlers/providers-models.d.ts +1 -1
  62. package/dist/subcommands/handlers/quick.d.ts +1 -1
  63. package/dist/subcommands/handlers/replay.d.ts +1 -1
  64. package/dist/subcommands/handlers/rewind.d.ts +1 -1
  65. package/dist/subcommands/handlers/sessions-config.d.ts +1 -1
  66. package/dist/subcommands/handlers/sessions-fleet.d.ts +1 -1
  67. package/dist/subcommands/handlers/tools-skills.d.ts +1 -1
  68. package/dist/subcommands/handlers/update.d.ts +1 -1
  69. package/dist/subcommands/handlers/version-help.d.ts +1 -1
  70. package/dist/subcommands/index.d.ts +2 -3
  71. package/dist/{tools-skills-UNKLOB7M.js → tools-skills-Q4P27URS.js} +1 -1
  72. package/dist/{update-VZSOZGYC.js → update-RATFF63M.js} +2 -2
  73. package/dist/{version-help-TFD6VPF3.js → version-help-WMPSEL4U.js} +2 -2
  74. package/dist/{webui-server-JXJ4CGIX.js → webui-server-3DU6BVTB.js} +7 -10
  75. package/dist/wiring/cli-execute-builder.d.ts +110 -85
  76. package/dist/wiring/cli-slash-commands-setup.d.ts +102 -72
  77. package/dist/wiring/director-announcement.d.ts +31 -0
  78. package/dist/wiring/session-establishment.d.ts +45 -0
  79. package/dist/wiring/session-registry.d.ts +1 -1
  80. package/dist/wiring/session-runtime.d.ts +64 -0
  81. package/dist/wiring/teardown-registrar.d.ts +41 -0
  82. package/dist/wiring/vector-memory-setup.d.ts +30 -0
  83. package/package.json +27 -25
@@ -326,4 +326,4 @@ export {
326
326
  diagCmd,
327
327
  doctorCmd
328
328
  };
329
- //# sourceMappingURL=diag-doctor-WTBHPOMB.js.map
329
+ //# sourceMappingURL=diag-doctor-HJKFUY6B.js.map
@@ -1,2 +1,19 @@
1
+ /**
2
+ * Colorize a single already-sanitized diff line.
3
+ *
4
+ * Exported so callers that must sanitize untrusted text themselves can apply
5
+ * the styling AFTER sanitizing — sanitizing colorized text would strip the
6
+ * colors, and colorizing before sanitizing would leave the untrusted escape
7
+ * sequences in place. See `permission-prompt.ts`.
8
+ */
9
+ export declare function diffLineStyle(line: string): string;
10
+ /**
11
+ * Render a diff for terminal display.
12
+ *
13
+ * The diff body can carry model-supplied or file-supplied text, so it is
14
+ * sanitized before styling: a raw `\x1b[2J\x1b[H` in a diff line clears the
15
+ * screen and lets a payload repaint the surrounding UI — including an approval
16
+ * prompt's header.
17
+ */
1
18
  export declare function renderDiff(diff: string): string;
2
19
  //# sourceMappingURL=diff-renderer.d.ts.map
@@ -8,7 +8,7 @@ import {
8
8
  runGit,
9
9
  setAutoSuggestions,
10
10
  setSuggestions
11
- } from "./chunk-T6YAVFXA.js";
11
+ } from "./chunk-X3N5TS2S.js";
12
12
  import {
13
13
  startCliHqConnection
14
14
  } from "./chunk-FKWHSFX4.js";
@@ -49,11 +49,11 @@ import {
49
49
  } from "./chunk-YMXXOOFN.js";
50
50
  import {
51
51
  resolveActiveApiKey
52
- } from "./chunk-SZ42FYPT.js";
52
+ } from "./chunk-BXFYBQKR.js";
53
53
  import "./chunk-7OCVIDC7.js";
54
54
 
55
55
  // src/execution.ts
56
- import * as path13 from "node:path";
56
+ import * as path14 from "node:path";
57
57
  import { effectiveFallbackChain as effectiveFallbackChain2, setQueuedMessagesSnapshot as setQueuedMessagesSnapshot2 } from "@wrongstack/core/agent";
58
58
  import { updateReviewReportEvidence } from "@wrongstack/core/plugin";
59
59
  import { attachTodosCheckpoint as attachTodosCheckpoint2 } from "@wrongstack/core/storage";
@@ -207,7 +207,7 @@ async function runWebUIDispatch(ctx) {
207
207
  const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
208
208
  agent.disableInteractiveConfirmation();
209
209
  renderer.setSilent(true);
210
- const { runWebUI } = await import("./webui-server-JXJ4CGIX.js");
210
+ const { runWebUI } = await import("./webui-server-3DU6BVTB.js");
211
211
  const flagValue = (names) => {
212
212
  for (const name of names) {
213
213
  if (!Object.hasOwn(flags, name)) continue;
@@ -406,14 +406,14 @@ async function runWebUIDispatch(ctx) {
406
406
  applyLiveSettings?.({ yolo: enabled });
407
407
  }
408
408
  });
409
- const webuiExit = new Promise((resolve3) => {
409
+ const webuiExit = new Promise((resolve4) => {
410
410
  webuiPromise.then(() => {
411
411
  renderer.setSilent(false);
412
412
  renderer.write("\n");
413
413
  renderer.writeInfo(
414
414
  color2.yellow(` Shutting down ${isSimpleUi ? "SimpleUI" : "WebUI"} server\u2026`)
415
415
  );
416
- resolve3(0);
416
+ resolve4(0);
417
417
  }).catch((err) => {
418
418
  if (webuiSessionChild) {
419
419
  void writeWebuiSessionChildError(webuiSessionChild.readyFile, {
@@ -431,7 +431,7 @@ async function runWebUIDispatch(ctx) {
431
431
  ` \u2717 ${isSimpleUi ? "SimpleUI" : "WebUI"} failed to start: ${err instanceof Error ? err.message : String(err)}`
432
432
  )
433
433
  );
434
- resolve3(1);
434
+ resolve4(1);
435
435
  });
436
436
  });
437
437
  return webuiExit;
@@ -1013,8 +1013,8 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1013
1013
  attachTodosCheckpoint: attachTodosCheckpoint3
1014
1014
  } = ctx;
1015
1015
  const resolved = path6.resolve(targetRoot);
1016
- const stat2 = await fs2.stat(resolved).catch(() => null);
1017
- if (!stat2?.isDirectory()) return `Cannot switch: not a directory: ${resolved}`;
1016
+ const stat3 = await fs2.stat(resolved).catch(() => null);
1017
+ if (!stat3?.isDirectory()) return `Cannot switch: not a directory: ${resolved}`;
1018
1018
  const oldWriter = context.session;
1019
1019
  const oldSessionStore = state.activeSessionStore;
1020
1020
  const oldUsage = tokenCounter.total();
@@ -1136,12 +1136,12 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1136
1136
  modeStore,
1137
1137
  modeId: modeId ?? "default",
1138
1138
  modePrompt: switchMode?.prompt ?? "",
1139
- tokenSavingMode: config.features.tokenSavingMode,
1139
+ tokenSavingMode: config.features?.tokenSavingMode,
1140
1140
  modelCapabilities: {
1141
- maxContextTokens: context.provider.capabilities.maxContext,
1142
- supportsTools: !!context.provider.capabilities.tools,
1143
- supportsVision: !!context.provider.capabilities.vision,
1144
- supportsReasoning: !!context.provider.capabilities.reasoning
1141
+ maxContextTokens: context.provider?.capabilities?.maxContext,
1142
+ supportsTools: !!context.provider?.capabilities?.tools,
1143
+ supportsVision: !!context.provider?.capabilities?.vision,
1144
+ supportsReasoning: !!context.provider?.capabilities?.reasoning
1145
1145
  },
1146
1146
  instructionPaths: {
1147
1147
  globalDir: nextWpaths.globalInstructions,
@@ -1152,12 +1152,12 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1152
1152
  context.systemPrompt = await switchBuilder.build({
1153
1153
  cwd: resolved,
1154
1154
  projectRoot: resolved,
1155
- tools: agent.tools.listForProvider(),
1156
- catalogTools: agent.tools.list(),
1155
+ tools: typeof agent.tools?.listForProvider === "function" ? agent.tools.listForProvider() : typeof agent.tools?.list === "function" ? agent.tools.list() : [],
1156
+ catalogTools: typeof agent.tools?.list === "function" ? agent.tools.list() : [],
1157
1157
  provider: context.provider.id,
1158
1158
  model: context.model
1159
1159
  });
1160
- if (agent.container.has(TOKENS.SystemPromptBuilder)) {
1160
+ if (agent.container?.has?.(TOKENS.SystemPromptBuilder)) {
1161
1161
  agent.container.override(TOKENS.SystemPromptBuilder, () => switchBuilder, {
1162
1162
  owner: "tui-project-switch"
1163
1163
  });
@@ -1482,9 +1482,124 @@ async function resumeSession(ctx, sessionId) {
1482
1482
  }
1483
1483
  }
1484
1484
 
1485
- // src/boot/tui-settings-adapter.ts
1485
+ // src/boot/tui-session-stub-enrich.ts
1486
1486
  import * as fs3 from "node:fs/promises";
1487
1487
  import * as path8 from "node:path";
1488
+ var SLICE_BYTES = 256 * 1024;
1489
+ var MAX_TITLE_CHARS = 80;
1490
+ function isStubSummary(s) {
1491
+ return !s.title && !s.endedAt;
1492
+ }
1493
+ function containedJsonlPath(sessionsDir, id) {
1494
+ const root = path8.resolve(sessionsDir);
1495
+ const file = path8.resolve(root, `${id}.jsonl`);
1496
+ if (file !== root && !file.startsWith(root + path8.sep)) return void 0;
1497
+ return file;
1498
+ }
1499
+ function stripControlChars(text) {
1500
+ return text.replaceAll(/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07]*(?:\x07|\x1b\\)|[\u0000-\u001f\u007f-\u009f]/g, "");
1501
+ }
1502
+ function truncate(text) {
1503
+ const oneLine = stripControlChars(text).replaceAll(/\s+/g, " ").trim();
1504
+ return oneLine.length > MAX_TITLE_CHARS ? `${oneLine.slice(0, MAX_TITLE_CHARS - 1)}\u2026` : oneLine;
1505
+ }
1506
+ function contentToText(content) {
1507
+ if (typeof content === "string") return content;
1508
+ if (Array.isArray(content)) {
1509
+ return content.map(
1510
+ (block) => block && typeof block === "object" && "text" in block && typeof block.text === "string" ? block.text : ""
1511
+ ).filter(Boolean).join(" ");
1512
+ }
1513
+ return "";
1514
+ }
1515
+ function scanUserInputs(chunk) {
1516
+ let first;
1517
+ let last;
1518
+ for (const line of chunk.split("\n")) {
1519
+ const trimmed = line.trim();
1520
+ if (!trimmed.includes('"user_input"')) continue;
1521
+ try {
1522
+ const event = JSON.parse(trimmed);
1523
+ if (event.type !== "user_input" || typeof event.ts !== "string") continue;
1524
+ const text = contentToText(event.content).trim();
1525
+ if (!text) continue;
1526
+ const hit = { ts: event.ts, text };
1527
+ if (!first) first = hit;
1528
+ last = hit;
1529
+ } catch {
1530
+ }
1531
+ }
1532
+ return { first, last };
1533
+ }
1534
+ async function firstUserInput(file) {
1535
+ let handle;
1536
+ try {
1537
+ handle = await fs3.open(file, "r");
1538
+ const { size } = await handle.stat();
1539
+ const length = Math.min(SLICE_BYTES, size);
1540
+ const buffer = Buffer.alloc(length);
1541
+ await handle.read(buffer, 0, length, 0);
1542
+ const text = buffer.toString("utf8");
1543
+ const cutoff = text.lastIndexOf("\n");
1544
+ return scanUserInputs(cutoff > 0 ? text.slice(0, cutoff) : text).first;
1545
+ } catch {
1546
+ return void 0;
1547
+ } finally {
1548
+ await handle?.close().catch(() => void 0);
1549
+ }
1550
+ }
1551
+ async function lastUserInput(file) {
1552
+ let handle;
1553
+ try {
1554
+ handle = await fs3.open(file, "r");
1555
+ const { size } = await handle.stat();
1556
+ const start = Math.max(0, size - SLICE_BYTES);
1557
+ const length = size - start;
1558
+ const buffer = Buffer.alloc(length);
1559
+ await handle.read(buffer, 0, length, start);
1560
+ const text = buffer.toString("utf8");
1561
+ const from = text.indexOf("\n");
1562
+ return scanUserInputs(from >= 0 ? text.slice(from + 1) : text).last;
1563
+ } catch {
1564
+ return void 0;
1565
+ } finally {
1566
+ await handle?.close().catch(() => void 0);
1567
+ }
1568
+ }
1569
+ function effectiveLastActivity(s) {
1570
+ return s.lastActivityAt ?? s.endedAt ?? s.startedAt ?? "";
1571
+ }
1572
+ async function selectPickerSessions(storeList, sessionsDir, limit) {
1573
+ const poolSize = Math.min(200, Math.max(limit, limit * 3));
1574
+ const enriched = await enrichStubSummaries(await storeList(poolSize), sessionsDir);
1575
+ return enriched.sort((a, b) => effectiveLastActivity(b).localeCompare(effectiveLastActivity(a))).slice(0, limit);
1576
+ }
1577
+ async function enrichStubSummaries(summaries, sessionsDir) {
1578
+ return Promise.all(
1579
+ summaries.map(async (s) => {
1580
+ if (!isStubSummary(s)) return s;
1581
+ const file = containedJsonlPath(sessionsDir, s.id);
1582
+ if (!file) return s;
1583
+ try {
1584
+ const stat3 = await fs3.stat(file);
1585
+ const [first, last] = await Promise.all([firstUserInput(file), lastUserInput(file)]);
1586
+ const title = truncate(first?.text ?? "");
1587
+ return {
1588
+ ...s,
1589
+ ...title ? { title } : {},
1590
+ ...last ? { lastUserMessage: truncate(last.text) } : {},
1591
+ lastActivityAt: stat3.mtime.toISOString()
1592
+ };
1593
+ } catch {
1594
+ return s;
1595
+ }
1596
+ })
1597
+ );
1598
+ }
1599
+
1600
+ // src/boot/tui-settings-adapter.ts
1601
+ import * as fs4 from "node:fs/promises";
1602
+ import * as path9 from "node:path";
1488
1603
  import { decryptConfigSecrets, encryptConfigSecrets, noOpVault } from "@wrongstack/core/security";
1489
1604
  import { normalizeTokenSavingTier, resolveFleetChatVerbosity } from "@wrongstack/core/types";
1490
1605
  import { atomicWrite, deepMerge } from "@wrongstack/core/utils";
@@ -1622,7 +1737,7 @@ function createSettingsAdapter(ctx) {
1622
1737
  const targetPath = resolvePersistPath(persistDeps);
1623
1738
  let raw;
1624
1739
  try {
1625
- raw = await fs3.readFile(targetPath, "utf8");
1740
+ raw = await fs4.readFile(targetPath, "utf8");
1626
1741
  } catch (err) {
1627
1742
  if (err.code !== "ENOENT") {
1628
1743
  throw new Error(
@@ -1759,7 +1874,7 @@ function createSettingsAdapter(ctx) {
1759
1874
  let mergedToWrite = decrypted;
1760
1875
  if (actualTarget !== targetPath) {
1761
1876
  try {
1762
- const destRaw = await fs3.readFile(actualTarget, "utf8");
1877
+ const destRaw = await fs4.readFile(actualTarget, "utf8");
1763
1878
  const destParsed = JSON.parse(destRaw);
1764
1879
  const destDecrypted = decryptConfigSecrets(destParsed, noOpVault);
1765
1880
  mergedToWrite = deepMerge(destDecrypted, decrypted);
@@ -1775,7 +1890,7 @@ function createSettingsAdapter(ctx) {
1775
1890
  const isProjectTarget = actualTarget === wpaths.inProjectConfig;
1776
1891
  const toWrite = isProjectTarget ? filterSafeForProject(mergedToWrite) : mergedToWrite;
1777
1892
  const encrypted = encryptConfigSecrets(toWrite, noOpVault);
1778
- await fs3.mkdir(path8.dirname(actualTarget), { recursive: true });
1893
+ await fs4.mkdir(path9.dirname(actualTarget), { recursive: true });
1779
1894
  await atomicWrite(actualTarget, JSON.stringify(encrypted, null, 2), { mode: 384 });
1780
1895
  const currentConfig = configStore.get();
1781
1896
  const nextModelRuntime = {
@@ -1881,8 +1996,8 @@ function createSettingsAdapter(ctx) {
1881
1996
  }
1882
1997
 
1883
1998
  // src/boot/tui-theme-adapter.ts
1884
- import * as fs4 from "node:fs/promises";
1885
- import * as path9 from "node:path";
1999
+ import * as fs5 from "node:fs/promises";
2000
+ import * as path10 from "node:path";
1886
2001
  import { THEME_PRESET_IDS } from "@wrongstack/core/types";
1887
2002
  import { atomicWrite as atomicWrite2 } from "@wrongstack/core/utils";
1888
2003
  var VALID_PRESETS = new Set(THEME_PRESET_IDS);
@@ -1901,7 +2016,7 @@ function createThemeAdapter({ configStore, wpaths }) {
1901
2016
  const configPath = activeProfileConfigPath(wpaths, configStore.get());
1902
2017
  let parsed = {};
1903
2018
  try {
1904
- const raw = await fs4.readFile(configPath, "utf8");
2019
+ const raw = await fs5.readFile(configPath, "utf8");
1905
2020
  parsed = JSON.parse(raw);
1906
2021
  } catch (err) {
1907
2022
  const e = err;
@@ -1910,7 +2025,7 @@ function createThemeAdapter({ configStore, wpaths }) {
1910
2025
  }
1911
2026
  }
1912
2027
  parsed.themePreset = preset;
1913
- await fs4.mkdir(path9.dirname(configPath), { recursive: true });
2028
+ await fs5.mkdir(path10.dirname(configPath), { recursive: true });
1914
2029
  await atomicWrite2(configPath, JSON.stringify(parsed, null, 2), { mode: 384 });
1915
2030
  }
1916
2031
  };
@@ -2797,7 +2912,7 @@ function createChimeraWorkRegistry() {
2797
2912
 
2798
2913
  // src/execution-chimera-cascade.ts
2799
2914
  import * as fsp from "node:fs/promises";
2800
- import * as path10 from "node:path";
2915
+ import * as path11 from "node:path";
2801
2916
  import { emitReviewIfChanged } from "@wrongstack/core/plugin";
2802
2917
 
2803
2918
  // src/chimera-cascade-evidence.ts
@@ -2891,7 +3006,7 @@ var runCascadeVerificationCommand = (command, cwd, timeoutMs) => {
2891
3006
  const tokens = command.trim().split(/\s+/);
2892
3007
  const executable = tokens[0];
2893
3008
  const args = tokens.slice(1);
2894
- return new Promise((resolve3) => {
3009
+ return new Promise((resolve4) => {
2895
3010
  let child;
2896
3011
  try {
2897
3012
  child = spawn2(executable, args, {
@@ -2901,11 +3016,11 @@ var runCascadeVerificationCommand = (command, cwd, timeoutMs) => {
2901
3016
  signal: AbortSignal.timeout(timeoutMs)
2902
3017
  });
2903
3018
  } catch {
2904
- resolve3({ exitCode: CASCADE_EVIDENCE_RUN_ERROR_EXIT });
3019
+ resolve4({ exitCode: CASCADE_EVIDENCE_RUN_ERROR_EXIT });
2905
3020
  return;
2906
3021
  }
2907
- child.on("error", () => resolve3({ exitCode: CASCADE_EVIDENCE_RUN_ERROR_EXIT }));
2908
- child.on("close", (code) => resolve3({ exitCode: code ?? CASCADE_EVIDENCE_RUN_ERROR_EXIT }));
3022
+ child.on("error", () => resolve4({ exitCode: CASCADE_EVIDENCE_RUN_ERROR_EXIT }));
3023
+ child.on("close", (code) => resolve4({ exitCode: code ?? CASCADE_EVIDENCE_RUN_ERROR_EXIT }));
2909
3024
  });
2910
3025
  };
2911
3026
  async function verifyCascadeEvidence(evidence, cwd, runCommand = runCascadeVerificationCommand, timeoutMs = CASCADE_EVIDENCE_COMMAND_TIMEOUT_MS) {
@@ -3405,7 +3520,7 @@ async function maybeReReviewCascade({
3405
3520
  const reReadFiles = [];
3406
3521
  for (const f of evidenceBundle.files) {
3407
3522
  try {
3408
- const absPath = path10.join(evidenceBundle.cwd, f.path);
3523
+ const absPath = path11.join(evidenceBundle.cwd, f.path);
3409
3524
  const content = await fsp.readFile(absPath, "utf8");
3410
3525
  reReadFiles.push({ path: f.path, status: "modified", content });
3411
3526
  } catch {
@@ -3482,7 +3597,7 @@ function errorText2(error) {
3482
3597
 
3483
3598
  // src/execution-chimera-review.ts
3484
3599
  import { randomUUID as randomUUID3 } from "node:crypto";
3485
- import path11 from "node:path";
3600
+ import path12 from "node:path";
3486
3601
  import { effectiveFallbackChain, fallbackProfileChain as fallbackProfileChain2 } from "@wrongstack/core/agent";
3487
3602
  import {
3488
3603
  CHIMERA_REVIEW_PROMPT,
@@ -3497,7 +3612,7 @@ import {
3497
3612
  function normalizeFileKeyForCitation(raw, cwd) {
3498
3613
  const forward = raw.replace(/\\/g, "/").replace(/^\.\//, "");
3499
3614
  const isAbsolute = forward.startsWith("/") || /^[a-zA-Z]:\//.test(forward);
3500
- const pathMod = process.platform === "win32" ? path11.win32 : path11;
3615
+ const pathMod = process.platform === "win32" ? path12.win32 : path12;
3501
3616
  const relative = isAbsolute ? pathMod.relative(cwd, forward).replace(/\\/g, "/").replace(/^\.\//, "") : forward;
3502
3617
  return process.platform === "win32" ? relative.toLowerCase() : relative;
3503
3618
  }
@@ -3717,7 +3832,7 @@ function installChimeraReviewHandler({
3717
3832
  const changedBasenameIndex = /* @__PURE__ */ new Map();
3718
3833
  for (const file of p.files) {
3719
3834
  const normalized = normalizeFileKeyForCitation(file.path, p.cwd);
3720
- const basename7 = path11.basename(file.path).toLowerCase();
3835
+ const basename7 = path12.basename(file.path).toLowerCase();
3721
3836
  const bucket = changedBasenameIndex.get(basename7);
3722
3837
  if (bucket) bucket.push(normalized);
3723
3838
  else changedBasenameIndex.set(basename7, [normalized]);
@@ -3729,7 +3844,7 @@ function installChimeraReviewHandler({
3729
3844
  (cp) => cp.endsWith(`/${citedKey}`) || cp === citedKey
3730
3845
  );
3731
3846
  if (suffixMatches.length === 1) return true;
3732
- const basename7 = path11.basename(finding.location.file).toLowerCase();
3847
+ const basename7 = path12.basename(finding.location.file).toLowerCase();
3733
3848
  const bucket = changedBasenameIndex.get(basename7);
3734
3849
  return !!(bucket && bucket.length === 1);
3735
3850
  });
@@ -4159,12 +4274,12 @@ ${color6.cyan("\u23F3 Auto")} ${color6.dim("(Ctrl+C to cancel)")}
4159
4274
  let interval;
4160
4275
  let lastTickedSecond = sec + 1;
4161
4276
  let onAbort;
4162
- return new Promise((resolve3) => {
4163
- onAbort = () => resolve3(false);
4277
+ return new Promise((resolve4) => {
4278
+ onAbort = () => resolve4(false);
4164
4279
  signal.addEventListener("abort", onAbort, { once: true });
4165
4280
  interval = setInterval(() => {
4166
4281
  if (signal.aborted) {
4167
- resolve3(false);
4282
+ resolve4(false);
4168
4283
  return;
4169
4284
  }
4170
4285
  const elapsed = Date.now() - start;
@@ -4172,7 +4287,7 @@ ${color6.cyan("\u23F3 Auto")} ${color6.dim("(Ctrl+C to cancel)")}
4172
4287
  if (remaining <= 0) {
4173
4288
  opts.renderer.write(color6.dim(` \u21B3 ${truncated}
4174
4289
  `));
4175
- resolve3(true);
4290
+ resolve4(true);
4176
4291
  return;
4177
4292
  }
4178
4293
  if (opts.onCountdownTick && remaining !== lastTickedSecond) {
@@ -4183,7 +4298,7 @@ ${color6.cyan("\u23F3 Auto")} ${color6.dim("(Ctrl+C to cancel)")}
4183
4298
  opts.renderer.write(
4184
4299
  color6.yellow(" \u21B3 Countdown cancelled \u2014 switching to manual mode\n")
4185
4300
  );
4186
- resolve3(false);
4301
+ resolve4(false);
4187
4302
  return;
4188
4303
  }
4189
4304
  } catch {
@@ -4215,7 +4330,7 @@ async function runContextCompaction(opts, _signal) {
4215
4330
 
4216
4331
  // src/repl-client-registration.ts
4217
4332
  import * as crypto from "node:crypto";
4218
- import * as path12 from "node:path";
4333
+ import * as path13 from "node:path";
4219
4334
  import { getSharedProjectMailbox, resolveProjectDir } from "@wrongstack/core/coordination";
4220
4335
  import { wstackGlobalRoot } from "@wrongstack/core/utils";
4221
4336
  function registerReplClient(opts) {
@@ -4225,7 +4340,7 @@ function registerReplClient(opts) {
4225
4340
  const hqConnection = startCliHqConnection({
4226
4341
  clientKind: "repl",
4227
4342
  projectRoot: replProjectRoot,
4228
- projectName: path12.basename(replProjectRoot),
4343
+ projectName: path13.basename(replProjectRoot),
4229
4344
  appConfig: opts.appConfig,
4230
4345
  capabilities: ["telemetry.publish", "mailbox.summary"]
4231
4346
  });
@@ -4239,7 +4354,7 @@ function registerReplClient(opts) {
4239
4354
  clientMailbox.registerClient({
4240
4355
  clientId,
4241
4356
  sessionId: opts.getSessionId?.() ?? replProjectRoot,
4242
- name: `REPL [${path12.basename(replProjectRoot)}]`,
4357
+ name: `REPL [${path13.basename(replProjectRoot)}]`,
4243
4358
  source: "repl",
4244
4359
  pid: process.pid
4245
4360
  }).then(() => {
@@ -4379,7 +4494,7 @@ async function runReplEternalLoop(opts, onInterruptsReset) {
4379
4494
  } catch (err) {
4380
4495
  opts.renderer.writeError(`[eternal] ${toErrorMessage2(err)}`);
4381
4496
  }
4382
- await new Promise((resolve3) => setTimeout(resolve3, 250));
4497
+ await new Promise((resolve4) => setTimeout(resolve4, 250));
4383
4498
  return true;
4384
4499
  }
4385
4500
  if (autonomy === "eternal-parallel") {
@@ -4454,7 +4569,7 @@ async function runReplEternalLoop(opts, onInterruptsReset) {
4454
4569
  } catch (err) {
4455
4570
  opts.renderer.writeError(`[parallel] ${toErrorMessage2(err)}`);
4456
4571
  }
4457
- await new Promise((resolve3) => setTimeout(resolve3, 250));
4572
+ await new Promise((resolve4) => setTimeout(resolve4, 250));
4458
4573
  return true;
4459
4574
  }
4460
4575
  return false;
@@ -5236,8 +5351,8 @@ async function profileMenu(store, paths) {
5236
5351
  }
5237
5352
  const items = await Promise.all(
5238
5353
  names.map(async (name) => {
5239
- const path14 = paths.profileConfig(name);
5240
- const data = await readJsonObjectFile(path14);
5354
+ const path15 = paths.profileConfig(name);
5355
+ const data = await readJsonObjectFile(path15);
5241
5356
  const provider = typeof data["provider"] === "string" ? data["provider"] : "unset";
5242
5357
  const model = typeof data["model"] === "string" ? data["model"] : "unset";
5243
5358
  const fallbackCount = Array.isArray(data["fallbackModels"]) ? data["fallbackModels"].length : 0;
@@ -5258,7 +5373,7 @@ async function profileMenu(store, paths) {
5258
5373
  },
5259
5374
  { label: "fallbacks", value: String(fallbackCount) },
5260
5375
  { label: "fallback profiles", value: String(profileCount) },
5261
- { label: "config", value: path14 }
5376
+ { label: "config", value: path15 }
5262
5377
  ],
5263
5378
  body: isActive ? "This profile owns the current session configuration." : "Switching profiles closes this session so every service restarts with the selected configuration.",
5264
5379
  actions: isActive ? [] : [{ key: "s", label: "switch", command: `/profile switch ${name}`, confirm: true }]
@@ -5333,7 +5448,7 @@ async function memoryMenu(store) {
5333
5448
  emptyText: "No memories found.",
5334
5449
  items: entries.map((entry, index) => ({
5335
5450
  id: `${entry.ts}:${index}`,
5336
- label: truncate(entry.text.replace(/\s+/g, " "), 52),
5451
+ label: truncate2(entry.text.replace(/\s+/g, " "), 52),
5337
5452
  status: entry.priority === "critical" || entry.priority === "high" ? "warn" : "muted",
5338
5453
  summary: `${entry.scope} \xB7 ${entry.type ?? "fact"}`,
5339
5454
  details: [
@@ -5388,19 +5503,19 @@ async function gitMenu(projectRoot) {
5388
5503
  },
5389
5504
  ...lines.map((line, index) => {
5390
5505
  const code = line.slice(0, 2);
5391
- const path14 = line.slice(3);
5506
+ const path15 = line.slice(3);
5392
5507
  const staged = code[0] !== " " && code[0] !== "?";
5393
5508
  const unstaged = code[1] !== " " || code === "??";
5394
5509
  return {
5395
- id: `change:${index}:${path14}`,
5396
- label: path14,
5510
+ id: `change:${index}:${path15}`,
5511
+ label: path15,
5397
5512
  status: staged ? "good" : "warn",
5398
5513
  summary: `${code} \xB7 ${staged ? "staged" : "not staged"}${unstaged ? " \xB7 working tree" : ""}`,
5399
5514
  details: [
5400
5515
  { label: "status", value: code },
5401
5516
  { label: "staged", value: staged ? "yes" : "no" },
5402
5517
  { label: "unstaged", value: unstaged ? "yes" : "no" },
5403
- { label: "path", value: path14 }
5518
+ { label: "path", value: path15 }
5404
5519
  ],
5405
5520
  actions: [
5406
5521
  { key: "d", label: "diff summary", command: staged ? "/git diff --staged" : "/git diff" }
@@ -5429,20 +5544,20 @@ async function worktreeMenu(projectRoot) {
5429
5544
  return split < 0 ? [line, "yes"] : [line.slice(0, split), line.slice(split + 1)];
5430
5545
  })
5431
5546
  );
5432
- const path14 = fields["worktree"] ?? "(unknown path)";
5547
+ const path15 = fields["worktree"] ?? "(unknown path)";
5433
5548
  const branchRef = fields["branch"];
5434
5549
  const branch = branchRef?.replace(/^refs\/heads\//, "") ?? (fields["detached"] ? "(detached)" : "(bare)");
5435
- const status = path14 === "(unknown path)" || fields["prunable"] ? null : await runGit(["status", "--porcelain=v1"], path14);
5550
+ const status = path15 === "(unknown path)" || fields["prunable"] ? null : await runGit(["status", "--porcelain=v1"], path15);
5436
5551
  const changes = status?.code === 0 ? status.stdout.split(/\r?\n/).filter(Boolean) : [];
5437
5552
  const dirty = changes.length > 0;
5438
5553
  const isMain = index === 0;
5439
5554
  return {
5440
- id: path14,
5555
+ id: path15,
5441
5556
  label: branch,
5442
5557
  status: fields["prunable"] ? "bad" : dirty ? "warn" : "good",
5443
5558
  summary: `${isMain ? "main" : "linked"} \xB7 ${dirty ? `${changes.length} changes` : "clean"}`,
5444
5559
  details: [
5445
- { label: "path", value: path14 },
5560
+ { label: "path", value: path15 },
5446
5561
  { label: "branch", value: branch },
5447
5562
  { label: "HEAD", value: fields["HEAD"]?.slice(0, 12) ?? "unknown" },
5448
5563
  { label: "working tree", value: dirty ? `${changes.length} changed paths` : "clean" },
@@ -5480,7 +5595,7 @@ async function worktreeMenu(projectRoot) {
5480
5595
  function isRecord(value) {
5481
5596
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5482
5597
  }
5483
- function truncate(value, max) {
5598
+ function truncate2(value, max) {
5484
5599
  return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
5485
5600
  }
5486
5601
 
@@ -5915,7 +6030,11 @@ async function execute(deps) {
5915
6030
  restoredEvents,
5916
6031
  listSessions: async (limit = 20) => {
5917
6032
  if (!activeSessionStore) return [];
5918
- const summaries = await activeSessionStore.list(limit);
6033
+ const summaries = await selectPickerSessions(
6034
+ (poolLimit) => activeSessionStore.list(poolLimit),
6035
+ wpaths.projectSessions,
6036
+ limit
6037
+ );
5919
6038
  const currentId = agent.ctx.session?.id ?? session.id;
5920
6039
  return summaries.map((s) => ({
5921
6040
  id: s.id,
@@ -6035,7 +6154,7 @@ async function execute(deps) {
6035
6154
  attachments,
6036
6155
  effectiveMaxContext,
6037
6156
  getEffectiveMaxContext,
6038
- projectName: path13.basename(projectRoot) || void 0,
6157
+ projectName: path14.basename(projectRoot) || void 0,
6039
6158
  projectRoot,
6040
6159
  appConfig: config,
6041
6160
  getSessionId: () => agent.ctx.session?.id ?? session.id,
@@ -6094,4 +6213,4 @@ export {
6094
6213
  execute,
6095
6214
  resolveReviewerFallbackModels
6096
6215
  };
6097
- //# sourceMappingURL=execution-TYUXABWI.js.map
6216
+ //# sourceMappingURL=execution-WA2UCXNM.js.map
@@ -64,4 +64,4 @@ var exportCmd = async (args, deps) => {
64
64
  export {
65
65
  exportCmd
66
66
  };
67
- //# sourceMappingURL=export-CCUXRJOU.js.map
67
+ //# sourceMappingURL=export-ROG3DKTZ.js.map
@@ -51,7 +51,7 @@ var hqCmd = async (args, deps) => {
51
51
  return 1;
52
52
  };
53
53
  async function startServer(deps) {
54
- const { startHqServer } = await import("./hq-server-PBRU275L.js");
54
+ const { startHqServer } = await import("./hq-server-GZGM4BHA.js");
55
55
  const dataDir = resolveDataDir(deps);
56
56
  const flags = deps.flags ?? {};
57
57
  const host = typeof flags["host"] === "string" ? flags["host"] : HQ_CLI_DEFAULT_HOST;
@@ -632,16 +632,22 @@ function printTokenHelp(deps) {
632
632
  ` wstack hq token create --client [label] [--ttl <dur>] Mint a client token (/ws/client).
633
633
  `
634
634
  );
635
- deps.renderer.write(` wstack hq token list List issued browser tokens (alias: ls).
636
- `);
637
- deps.renderer.write(` wstack hq token list --client List issued client tokens.
638
- `);
635
+ deps.renderer.write(
636
+ ` wstack hq token list List issued browser tokens (alias: ls).
637
+ `
638
+ );
639
+ deps.renderer.write(
640
+ ` wstack hq token list --client List issued client tokens.
641
+ `
642
+ );
639
643
  deps.renderer.write(
640
644
  ` wstack hq token revoke <id> Revoke a browser token (id prefix match).
641
645
  `
642
646
  );
643
- deps.renderer.write(` wstack hq token revoke --client <id> Revoke a client token.
644
- `);
647
+ deps.renderer.write(
648
+ ` wstack hq token revoke --client <id> Revoke a client token.
649
+ `
650
+ );
645
651
  deps.renderer.write("\n");
646
652
  deps.renderer.write(`The token secret is printed once at create time and cannot be recovered
647
653
  `);
@@ -656,8 +662,10 @@ function printTokenHelp(deps) {
656
662
  ` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
657
663
  `
658
664
  );
659
- deps.renderer.write(` --client, -c Operate on client tokens instead of browser tokens.
660
- `);
665
+ deps.renderer.write(
666
+ ` --client, -c Operate on client tokens instead of browser tokens.
667
+ `
668
+ );
661
669
  deps.renderer.write(
662
670
  ` --capabilities <csv> Comma-separated capability grants (browser: control.enqueue; client: telemetry.publish,control.execute).
663
671
  `
@@ -701,4 +709,4 @@ export {
701
709
  hqCmd,
702
710
  resolveAuditActor
703
711
  };
704
- //# sourceMappingURL=hq-PA6RH2UW.js.map
712
+ //# sourceMappingURL=hq-AG4VW4XO.js.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Type-only leaf for the public HQ server handle.
3
+ *
4
+ * Lives separately from `hq-server.ts` so callers (notably
5
+ * `subcommands/handlers/hq.ts`) can depend on the public types without
6
+ * pulling in the HQ server implementation. Breaks a long-standing type-only
7
+ * import edge `handlers/hq.ts → hq-server.ts` that participated in the
8
+ * 33-member CLI SCC (see docs/reports/modularity-assessment-2026-08-22.md).
9
+ *
10
+ * This module MUST contain no runtime imports.
11
+ */
12
+ export interface HqStartupConnectionInfo {
13
+ dataDir: string;
14
+ browserUrl: string;
15
+ clientUrl: string;
16
+ clientEnv: {
17
+ WRONGSTACK_HQ_URL: string;
18
+ WRONGSTACK_HQ_TOKEN?: string;
19
+ };
20
+ createdAuth: boolean;
21
+ browserTokenMode: boolean;
22
+ passwordMode: boolean;
23
+ }
24
+ export type HqFirstRunSetup = HqStartupConnectionInfo;
25
+ export interface HqServerHandle {
26
+ host: string;
27
+ port: number;
28
+ firstRunSetup?: HqFirstRunSetup;
29
+ trustPublicOrigin(origin: string): void;
30
+ close(): Promise<void>;
31
+ }
32
+ //# sourceMappingURL=handle-types.d.ts.map