@wrongstack/cli 0.301.0 → 0.302.2

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 (113) hide show
  1. package/data/providers.json +41 -155
  2. package/dist/{acp-DATHHPNT.js → acp-XCE4JJF3.js} +4 -4
  3. package/dist/{audit-QRCLEHHW.js → audit-BBR22QH3.js} +2 -2
  4. package/dist/{auth-JASC4K3F.js → auth-K7CYVVKH.js} +121 -78
  5. package/dist/auth-menu/index.d.ts +5 -5
  6. package/dist/auth-menu/local.d.ts +4 -5
  7. package/dist/auth-menu/openai-codex-oauth.d.ts +1 -1
  8. package/dist/{auto-discover-providers-DRW4OZHG.js → auto-discover-providers-MHFLDSD3.js} +2 -2
  9. package/dist/{bench-7ZDWSNEF.js → bench-XNDUJOSZ.js} +10 -11
  10. package/dist/boot/auto-discover-providers.d.ts +1 -1
  11. package/dist/boot/container-wiring.d.ts +3 -3
  12. package/dist/boot/dispatch-webui.d.ts +3 -16
  13. package/dist/boot/system-prompt.d.ts +1 -2
  14. package/dist/boot/tool-registry.d.ts +1 -1
  15. package/dist/boot/tui-coordinator-setup.d.ts +1 -1
  16. package/dist/boot/tui-project-picker-callback.d.ts +1 -1
  17. package/dist/boot/webui-session-child.d.ts +91 -0
  18. package/dist/boot-config.d.ts +2 -2
  19. package/dist/boot.d.ts +1 -1
  20. package/dist/{chunk-ETOEGL3V.js → chunk-3IC4IEZC.js} +7 -2
  21. package/dist/chunk-3JPTNADJ.js +128 -0
  22. package/dist/{chunk-4GVH7V3S.js → chunk-52C7PD2H.js} +1 -1
  23. package/dist/{chunk-OP47B3IX.js → chunk-7YLN7YUA.js} +7 -2
  24. package/dist/{chunk-263G3FMB.js → chunk-B4JLSXZB.js} +11 -14
  25. package/dist/{chunk-I5MEUFDI.js → chunk-BXQG3H2Y.js} +8 -3
  26. package/dist/{chunk-MHF2IJDE.js → chunk-C5NXM2SI.js} +21 -6
  27. package/dist/{chunk-XTIXVJXP.js → chunk-DGXNL7OT.js} +1 -1
  28. package/dist/{chunk-O7XNGCRT.js → chunk-FJVCVZIV.js} +974 -935
  29. package/dist/{chunk-MRLYDHQ7.js → chunk-JQURRYU4.js} +4 -6
  30. package/dist/{chunk-ZECLGUTF.js → chunk-KV6DNQT6.js} +2 -2
  31. package/dist/{chunk-F4PEGAJZ.js → chunk-NUIHRGPY.js} +1 -1
  32. package/dist/{chunk-GUHQQG63.js → chunk-RK7E3IXT.js} +2 -4
  33. package/dist/{chunk-PYTFS4MC.js → chunk-SSSJQVUY.js} +27 -16
  34. package/dist/{chunk-PJHET45A.js → chunk-SZ42FYPT.js} +3 -3
  35. package/dist/{chunk-2KDOFTTM.js → chunk-WOXUE2CN.js} +1067 -900
  36. package/dist/{chunk-A6Q5KGLV.js → chunk-YKBRFSGL.js} +5 -5
  37. package/dist/cli-context.d.ts +3 -1
  38. package/dist/cli-eternal-flag.d.ts +1 -2
  39. package/dist/{cli-main-XWC57MGE.js → cli-main-PJMDZHDK.js} +2683 -2134
  40. package/dist/context-limit.d.ts +11 -5
  41. package/dist/{diag-doctor-OQ3AA63O.js → diag-doctor-ZF5BF2MK.js} +2 -3
  42. package/dist/execute-deps.d.ts +3 -0
  43. package/dist/{execution-LHMSMDHB.js → execution-LZRYRGDD.js} +343 -177
  44. package/dist/{export-DOBGPY23.js → export-CCUXRJOU.js} +3 -11
  45. package/dist/fleet/host-supervisor.d.ts +1 -1
  46. package/dist/fleet/host.d.ts +1 -1
  47. package/dist/fleet/routing.d.ts +1 -2
  48. package/dist/goal-host.d.ts +2 -2
  49. package/dist/hooks-wiring.d.ts +1 -1
  50. package/dist/{hq-LN5CJHCM.js → hq-AHPAE7EN.js} +104 -55
  51. package/dist/hq-command-controller.d.ts +1 -1
  52. package/dist/hq-server/routes/system-handlers.d.ts +1 -2
  53. package/dist/hq-server/routes.d.ts +7 -7
  54. package/dist/{hq-server-S7HZG3PA.js → hq-server-KU2Z54QU.js} +2 -2
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.js +2712 -2642
  57. package/dist/mailbox-bridge-bootstrap.d.ts +2 -2
  58. package/dist/{mcp-OHPJH73U.js → mcp-E5EBGOHF.js} +6 -6
  59. package/dist/mcp-serve.d.ts +1 -1
  60. package/dist/{modeldiag-3DOK4BWW.js → modeldiag-SIVUOX2Y.js} +18 -13
  61. package/dist/{permissions-FNYLZIL4.js → permissions-2PWBL4YU.js} +5 -3
  62. package/dist/picker.d.ts +1 -1
  63. package/dist/plugin-management.d.ts +1 -1
  64. package/dist/{plugin-usage-YEVLOR33.js → plugin-usage-PTEETL3J.js} +2 -2
  65. package/dist/{plugins-K3BAUP4D.js → plugins-XRGWC3NJ.js} +3 -3
  66. package/dist/pre-launch.d.ts +2 -2
  67. package/dist/{providers-models-WEZ4EGLL.js → providers-models-VV74TRQ2.js} +86 -37
  68. package/dist/repl.d.ts +1 -1
  69. package/dist/{replay-FCBNHW3K.js → replay-WBRMEWQ5.js} +2 -2
  70. package/dist/{rewind-AOD3JIYX.js → rewind-7RE6ONIC.js} +17 -17
  71. package/dist/{sdd-runtime-AIJCJGWC.js → sdd-runtime-GFZ3NJKS.js} +2 -2
  72. package/dist/{sessions-config-XXN7267N.js → sessions-config-YX2ZPAFM.js} +36 -32
  73. package/dist/{simpleui-dist-JIFGUJO7.js → simpleui-dist-33VO3QHF.js} +9 -2
  74. package/dist/slash-commands/agents.d.ts +14 -0
  75. package/dist/slash-commands/command-context.d.ts +2 -3
  76. package/dist/slash-commands/helpers.d.ts +1 -1
  77. package/dist/slash-commands/index.d.ts +1 -1
  78. package/dist/slash-commands/intake.d.ts +10 -0
  79. package/dist/slash-commands/memory-triage.d.ts +1 -1
  80. package/dist/slash-commands/provider-status.d.ts +1 -1
  81. package/dist/subcommands/handlers/hq.d.ts +20 -0
  82. package/dist/subcommands/handlers/per-subcommand-help-data.d.ts +1 -1
  83. package/dist/{update-MV6TUACD.js → update-LTDJGAFU.js} +3 -3
  84. package/dist/{update-check-UMYTOH7Z.js → update-check-WARHSVZA.js} +2 -2
  85. package/dist/webui-server/connection-handler.d.ts +1 -1
  86. package/dist/webui-server/context-breakdown.d.ts +1 -1
  87. package/dist/webui-server/cost-helpers.d.ts +1 -1
  88. package/dist/webui-server/lifecycle.d.ts +1 -1
  89. package/dist/webui-server/prefs-seeding.d.ts +1 -1
  90. package/dist/webui-server/setup-events.d.ts +1 -1
  91. package/dist/webui-server/static-serve.d.ts +1 -1
  92. package/dist/{webui-server-DD35QFNO.js → webui-server-E3OPEKU5.js} +66 -25
  93. package/dist/webui-server-options.d.ts +7 -0
  94. package/dist/wiring/command-host-state.d.ts +2 -2
  95. package/dist/wiring/controllers.d.ts +1 -2
  96. package/dist/wiring/dep-watcher.d.ts +1 -1
  97. package/dist/wiring/director-setup.d.ts +3 -3
  98. package/dist/wiring/eternal-command-handlers.d.ts +2 -2
  99. package/dist/wiring/management-tools.d.ts +2 -2
  100. package/dist/wiring/provider-runtime.d.ts +1 -1
  101. package/dist/wiring/provider-status.d.ts +1 -1
  102. package/dist/wiring/provider-utility-tools.d.ts +3 -3
  103. package/dist/wiring/provider.d.ts +1 -1
  104. package/dist/wiring/replay.d.ts +1 -1
  105. package/dist/wiring/runtime-controller-deps.d.ts +1 -1
  106. package/dist/wiring/runtime-dispatch-state.d.ts +1 -2
  107. package/dist/wiring/runtime-lifecycle-deps.d.ts +2 -2
  108. package/dist/wiring/runtime-picker-deps.d.ts +1 -2
  109. package/dist/wiring/sage.d.ts +1 -1
  110. package/dist/wiring/session-command-handlers.d.ts +1 -2
  111. package/dist/wiring/session.d.ts +6 -1
  112. package/dist/wiring/slash-commands.d.ts +2 -3
  113. package/package.json +23 -23
@@ -24,13 +24,24 @@ import {
24
24
  trySaveImplementationPlan,
25
25
  trySaveSpecFromAIOutput,
26
26
  trySaveTasksFromAIOutput
27
- } from "./chunk-XTIXVJXP.js";
27
+ } from "./chunk-DGXNL7OT.js";
28
+ import {
29
+ WEBUI_SESSION_CHILD_CAPABILITIES,
30
+ writeWebuiSessionChildError,
31
+ writeWebuiSessionChildReady
32
+ } from "./chunk-3JPTNADJ.js";
28
33
  import {
29
34
  theme
30
35
  } from "./chunk-QD544J2B.js";
31
36
  import {
32
37
  fmtTok
33
38
  } from "./chunk-TYO2OVAD.js";
39
+ import {
40
+ resolveActiveApiKey
41
+ } from "./chunk-SZ42FYPT.js";
42
+ import {
43
+ activeProfileConfigPath
44
+ } from "./chunk-YMXXOOFN.js";
34
45
  import {
35
46
  terminalLink,
36
47
  terminalText
@@ -38,16 +49,10 @@ import {
38
49
  import {
39
50
  CLI_VERSION
40
51
  } from "./chunk-XJXDOF63.js";
41
- import {
42
- resolveActiveApiKey
43
- } from "./chunk-PJHET45A.js";
44
- import {
45
- activeProfileConfigPath
46
- } from "./chunk-YMXXOOFN.js";
47
52
  import "./chunk-7OCVIDC7.js";
48
53
 
49
54
  // src/execution.ts
50
- import * as path11 from "node:path";
55
+ import * as path12 from "node:path";
51
56
  import { effectiveFallbackChain as effectiveFallbackChain2, setQueuedMessagesSnapshot as setQueuedMessagesSnapshot2 } from "@wrongstack/core/agent";
52
57
  import { attachTodosCheckpoint as attachTodosCheckpoint2 } from "@wrongstack/core/storage";
53
58
  import { normalizeTokenSavingTier as normalizeTokenSavingTier2 } from "@wrongstack/core/types";
@@ -155,6 +160,7 @@ async function runTuiDispatch(options) {
155
160
  }
156
161
 
157
162
  // src/boot/dispatch-webui.ts
163
+ import * as path from "node:path";
158
164
  import { color as color2 } from "@wrongstack/core/utils";
159
165
  async function runWebUIDispatch(ctx) {
160
166
  const {
@@ -190,12 +196,14 @@ async function runWebUIDispatch(ctx) {
190
196
  agentTranscripts,
191
197
  sddSubagentFactory,
192
198
  onKanbanDispatch,
193
- getFleetBudget
199
+ getFleetBudget,
200
+ webuiSessionChild
194
201
  } = ctx;
195
- const isSimpleUi = flags["simpleui"] === true;
202
+ const isSessionChild = Boolean(webuiSessionChild);
203
+ const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
196
204
  agent.disableInteractiveConfirmation();
197
205
  renderer.setSilent(true);
198
- const { runWebUI } = await import("./webui-server-DD35QFNO.js");
206
+ const { runWebUI } = await import("./webui-server-E3OPEKU5.js");
199
207
  const flagValue = (names) => {
200
208
  for (const name of names) {
201
209
  if (!Object.hasOwn(flags, name)) continue;
@@ -238,22 +246,32 @@ async function runWebUIDispatch(ctx) {
238
246
  let webuiRequireToken;
239
247
  let frontendDistDir;
240
248
  try {
241
- webuiHost = flagValue(["webui-host", "host"]) ?? process.env["WEBUI_HOST"] ?? process.env["WS_HOST"] ?? "127.0.0.1";
249
+ webuiHost = webuiSessionChild?.host ?? flagValue(["webui-host", "host"]) ?? process.env["WEBUI_HOST"] ?? process.env["WS_HOST"] ?? "127.0.0.1";
242
250
  const defaultPort = isSimpleUi ? 3466 : 3456;
243
- webuiPort = parsePort(
251
+ webuiPort = webuiSessionChild?.port ?? parsePort(
244
252
  flagValue(["webui-port", "http-port", "port", "ws-port"]) ?? process.env["WEBUI_PORT"] ?? process.env["PORT"] ?? process.env["WS_PORT"],
245
253
  defaultPort,
246
254
  "--port"
247
255
  );
248
- webuiAccessToken = flagValue(["webui-token"]) ?? process.env["WEBUI_TOKEN"] ?? process.env["WEBUI_AUTH_TOKEN"];
249
- webuiPublicUrl = flagValue(["webui-public-url", "public-url"]) ?? process.env["WEBUI_PUBLIC_URL"];
250
- webuiPublicWsUrl = flagValue(["webui-public-ws-url", "public-ws-url"]) ?? process.env["WEBUI_PUBLIC_WS_URL"];
251
- webuiRequireToken = flagBoolean(["webui-require-token", "require-token"]) ?? envFlag("WEBUI_REQUIRE_TOKEN");
256
+ webuiAccessToken = webuiSessionChild?.token ?? flagValue(["webui-token"]) ?? process.env["WEBUI_TOKEN"] ?? process.env["WEBUI_AUTH_TOKEN"];
257
+ webuiPublicUrl = webuiSessionChild?.publicUrl ?? flagValue(["webui-public-url", "public-url"]) ?? process.env["WEBUI_PUBLIC_URL"];
258
+ webuiPublicWsUrl = webuiSessionChild?.publicWsUrl ?? flagValue(["webui-public-ws-url", "public-ws-url"]) ?? process.env["WEBUI_PUBLIC_WS_URL"];
259
+ webuiRequireToken = webuiSessionChild?.requireToken ?? flagBoolean(["webui-require-token", "require-token"]) ?? envFlag("WEBUI_REQUIRE_TOKEN");
252
260
  if (isSimpleUi) {
253
- const { ensureSimpleUiDistDir } = await import("./simpleui-dist-JIFGUJO7.js");
261
+ const { ensureSimpleUiDistDir } = await import("./simpleui-dist-33VO3QHF.js");
254
262
  frontendDistDir = await ensureSimpleUiDistDir();
255
263
  }
256
264
  } catch (err) {
265
+ if (webuiSessionChild) {
266
+ await writeWebuiSessionChildError(webuiSessionChild.readyFile, {
267
+ protocolVersion: webuiSessionChild.protocolVersion,
268
+ runtimeId: webuiSessionChild.runtimeId,
269
+ parentShellId: webuiSessionChild.parentShellId,
270
+ phase: "validate_args",
271
+ recoverable: false,
272
+ error: err
273
+ }).catch(() => void 0);
274
+ }
257
275
  renderer.setSilent(false);
258
276
  renderer.writeInfo(color2.red(` ${err instanceof Error ? err.message : String(err)}`));
259
277
  return 1;
@@ -271,9 +289,11 @@ async function runWebUIDispatch(ctx) {
271
289
  publicUrl: webuiPublicUrl,
272
290
  publicWsUrl: webuiPublicWsUrl,
273
291
  requireToken: webuiRequireToken,
292
+ strictPort: webuiSessionChild?.strictPort,
274
293
  projectRoot,
275
294
  appConfig: config,
276
- open: !!flags.open,
295
+ open: webuiSessionChild ? false : !!flags.open,
296
+ webuiSessionChild,
277
297
  agentTranscripts,
278
298
  hqAllowExec: flagBoolean(["hq-allow-exec"]) ?? false,
279
299
  modelsRegistry,
@@ -316,7 +336,50 @@ async function runWebUIDispatch(ctx) {
316
336
  // listening, using the RESOLVED port. Requested ports auto-advance past
317
337
  // busy ports inside runWebUI, so a banner printed up-front lies whenever
318
338
  // the default when it is taken (a second instance, leftover socket).
319
- onListening: ({ url }) => {
339
+ onListening: ({ httpPort, host, url, authToken }) => {
340
+ if (webuiSessionChild) {
341
+ void writeWebuiSessionChildReady(webuiSessionChild.readyFile, {
342
+ type: "webui.session_child.ready",
343
+ protocolVersion: webuiSessionChild.protocolVersion,
344
+ runtime: {
345
+ role: "session-child",
346
+ runtimeId: webuiSessionChild.runtimeId,
347
+ pid: process.pid,
348
+ parentPid: webuiSessionChild.parentPid,
349
+ parentShellId: webuiSessionChild.parentShellId,
350
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
351
+ },
352
+ project: {
353
+ projectRoot,
354
+ workingDir: webuiSessionChild.workingDir,
355
+ projectSlug: path.basename(projectRoot) || projectRoot,
356
+ projectName: path.basename(projectRoot) || projectRoot
357
+ },
358
+ session: {
359
+ sessionId: session.id,
360
+ created: !webuiSessionChild.resume,
361
+ resumed: webuiSessionChild.resume,
362
+ provider: config.provider,
363
+ model: config.model
364
+ },
365
+ endpoint: {
366
+ surface: "webui",
367
+ host,
368
+ httpPort,
369
+ url,
370
+ ...webuiPublicUrl ? { publicUrl: webuiPublicUrl } : {},
371
+ ...webuiPublicWsUrl ? { publicWsUrl: webuiPublicWsUrl } : {},
372
+ requireToken: webuiRequireToken,
373
+ auth: authToken ? { scheme: "registry-token", tokenPresent: true, token: authToken } : { scheme: "none", tokenPresent: false }
374
+ },
375
+ registry: {
376
+ webuiInstanceRegistered: true,
377
+ sessionRegistered: true
378
+ },
379
+ capabilities: [...WEBUI_SESSION_CHILD_CAPABILITIES]
380
+ }).catch(() => void 0);
381
+ return;
382
+ }
320
383
  const surface = isSimpleUi ? "SimpleUI" : "WebUI";
321
384
  renderer.writeInfo(
322
385
  ` \u2726 ${terminalText(surface, "success", { bold: true })} ${terminalText("running \u2192", "muted")} ${terminalLink(url)}`
@@ -346,6 +409,16 @@ async function runWebUIDispatch(ctx) {
346
409
  );
347
410
  resolve3(0);
348
411
  }).catch((err) => {
412
+ if (webuiSessionChild) {
413
+ void writeWebuiSessionChildError(webuiSessionChild.readyFile, {
414
+ protocolVersion: webuiSessionChild.protocolVersion,
415
+ runtimeId: webuiSessionChild.runtimeId,
416
+ parentShellId: webuiSessionChild.parentShellId,
417
+ phase: "start_server",
418
+ recoverable: false,
419
+ error: err
420
+ }).catch(() => void 0);
421
+ }
349
422
  renderer.setSilent(false);
350
423
  renderer.writeInfo(
351
424
  color2.red(
@@ -362,8 +435,9 @@ async function runWebUIDispatch(ctx) {
362
435
  function resolveExecutionMode(positional, flags) {
363
436
  const prompt = typeof flags["prompt"] === "string" ? flags["prompt"] : "";
364
437
  if (positional.length > 0 || prompt.length > 0) return "single-shot";
365
- if (flags.tui && flags["no-tui"] !== true && !flags.webui) return "tui";
366
- if (flags.webui) return "webui";
438
+ if (flags.tui && flags["no-tui"] !== true && !flags.webui && !flags["webui-session-child"])
439
+ return "tui";
440
+ if (flags.webui || flags["webui-session-child"]) return "webui";
367
441
  return "repl";
368
442
  }
369
443
 
@@ -503,16 +577,26 @@ function createTuiCoordinatorCallbacks({
503
577
  }
504
578
 
505
579
  // src/boot/tui-coordinator-setup.ts
506
- import * as path from "node:path";
580
+ import * as path2 from "node:path";
507
581
  import { AutonomousCoordinator } from "@wrongstack/core/coordination";
508
582
  function setupAutonomousCoordinator(ctx) {
509
- const { state, events, context, wpaths, mailbox, director, getDirector, coordinatorController, onCoordinatorStopSetter } = ctx;
583
+ const {
584
+ state,
585
+ events,
586
+ context,
587
+ wpaths,
588
+ mailbox,
589
+ director,
590
+ getDirector,
591
+ coordinatorController,
592
+ onCoordinatorStopSetter
593
+ } = ctx;
510
594
  const ensure = () => {
511
595
  if (state.autonomousCoordinator) return state.autonomousCoordinator;
512
596
  const currentDirector = getDirector?.() ?? director;
513
597
  if (!currentDirector) return null;
514
598
  const transcript = context.session.transcriptPath;
515
- const sessionDir = transcript ? path.dirname(transcript) : wpaths.projectDir;
599
+ const sessionDir = transcript ? path2.dirname(transcript) : wpaths.projectDir;
516
600
  const llmProvider = {
517
601
  decide: async (prompt) => {
518
602
  const sysPrompt = [
@@ -528,7 +612,9 @@ function setupAutonomousCoordinator(ctx) {
528
612
  Context: ${JSON.stringify(prompt.context)}
529
613
 
530
614
  Options:
531
- ${prompt.options.map((o, i) => ` ${i + 1}. [${o.id}] ${o.label}${o.consequence ? ` \u2014 ${o.consequence}` : ""}`).join("\n")}
615
+ ${prompt.options.map(
616
+ (o, i) => ` ${i + 1}. [${o.id}] ${o.label}${o.consequence ? ` \u2014 ${o.consequence}` : ""}`
617
+ ).join("\n")}
532
618
 
533
619
  Risk: ${prompt.risk}
534
620
 
@@ -549,7 +635,9 @@ Reply with ONLY the JSON object.`
549
635
  },
550
636
  { signal: context.signal }
551
637
  );
552
- const text = resp.content.filter((b) => b.type === "text").map((b) => b.text).join("\n").trim();
638
+ const text = resp.content.filter(
639
+ (b) => b.type === "text"
640
+ ).map((b) => b.text).join("\n").trim();
553
641
  const cleaned = text.replace(/^```(?:json)?\s*/i, "").replace(/```$/, "").trim();
554
642
  try {
555
643
  const parsed = JSON.parse(cleaned);
@@ -593,14 +681,20 @@ Reply with ONLY the JSON object.`
593
681
  coordinatorController["onCoordinatorTasks"] = async () => {
594
682
  if (!state.autonomousCoordinator) return null;
595
683
  await state.autonomousCoordinator.graph.load();
596
- return state.autonomousCoordinator.auction.getPendingTasks().map((task) => ({ id: task.id, title: task.title, priority: task.priority, tags: task.tags }));
684
+ return state.autonomousCoordinator.auction.getPendingTasks().map((task) => ({
685
+ id: task.id,
686
+ title: task.title,
687
+ priority: task.priority,
688
+ tags: task.tags
689
+ }));
597
690
  };
598
691
  coordinatorController["onCoordinatorClaim"] = async (taskId) => {
599
692
  if (!state.autonomousCoordinator) return "No coordinator is active.";
600
693
  await state.autonomousCoordinator.graph.load();
601
694
  const goal = state.autonomousCoordinator.graph.get(taskId);
602
695
  if (goal?.type !== "goal") return `Task ${taskId.slice(0, 8)} not found.`;
603
- if (goal.status !== "pending") return `Task ${taskId.slice(0, 8)} is ${goal.status}, not claimable.`;
696
+ if (goal.status !== "pending")
697
+ return `Task ${taskId.slice(0, 8)} is ${goal.status}, not claimable.`;
604
698
  const ok = await state.autonomousCoordinator.auction.claim(
605
699
  taskId,
606
700
  `terminal@${context.session.id ?? "unknown"}`,
@@ -614,8 +708,12 @@ Reply with ONLY the JSON object.`
614
708
  await state.autonomousCoordinator.graph.load();
615
709
  const goal = state.autonomousCoordinator.graph.get(taskId);
616
710
  if (goal?.type !== "goal") return `Task ${taskId.slice(0, 8)} not found.`;
617
- if (goal.status !== "in_progress") return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot complete.`;
618
- await state.autonomousCoordinator.reportTaskCompletion(taskId, result ?? "Terminal worker completed the task");
711
+ if (goal.status !== "in_progress")
712
+ return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot complete.`;
713
+ await state.autonomousCoordinator.reportTaskCompletion(
714
+ taskId,
715
+ result ?? "Terminal worker completed the task"
716
+ );
619
717
  return null;
620
718
  };
621
719
  coordinatorController["onCoordinatorFail"] = async (taskId, error) => {
@@ -623,7 +721,8 @@ Reply with ONLY the JSON object.`
623
721
  await state.autonomousCoordinator.graph.load();
624
722
  const goal = state.autonomousCoordinator.graph.get(taskId);
625
723
  if (goal?.type !== "goal") return `Task ${taskId.slice(0, 8)} not found.`;
626
- if (goal.status !== "in_progress") return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot fail.`;
724
+ if (goal.status !== "in_progress")
725
+ return `Task ${taskId.slice(0, 8)} is ${goal.status}, cannot fail.`;
627
726
  await state.autonomousCoordinator.reportTaskFailure(taskId, error);
628
727
  return null;
629
728
  };
@@ -632,8 +731,18 @@ Reply with ONLY the JSON object.`
632
731
  await state.autonomousCoordinator.syncFromGraph();
633
732
  const stats = state.autonomousCoordinator.getStats();
634
733
  return {
635
- goals: { total: stats.goals.total, done: stats.goals.done, pending: stats.goals.pending, failed: stats.goals.failed },
636
- dag: { running: stats.dag.running, ready: stats.dag.ready, done: stats.dag.done, failed: stats.dag.failed },
734
+ goals: {
735
+ total: stats.goals.total,
736
+ done: stats.goals.done,
737
+ pending: stats.goals.pending,
738
+ failed: stats.goals.failed
739
+ },
740
+ dag: {
741
+ running: stats.dag.running,
742
+ ready: stats.dag.ready,
743
+ done: stats.dag.done,
744
+ failed: stats.dag.failed
745
+ },
637
746
  auction: { pending: stats.auction.pending, inProgress: stats.auction.in_progress }
638
747
  };
639
748
  };
@@ -723,11 +832,11 @@ function wireGoal(events) {
723
832
  }
724
833
 
725
834
  // src/boot/tui-live-sessions.ts
726
- import * as path2 from "node:path";
835
+ import * as path3 from "node:path";
727
836
  async function getLiveSessions(ctx) {
728
- const { SessionRegistry } = await import("@wrongstack/core/storage");
729
- const globalRoot = path2.dirname(ctx.state.wpaths.globalConfig);
730
- const registry = new SessionRegistry(globalRoot);
837
+ const { getSessionRegistry } = await import("@wrongstack/core/storage");
838
+ const globalRoot = path3.dirname(ctx.state.wpaths.globalConfig);
839
+ const registry = getSessionRegistry(globalRoot);
731
840
  const sessions = await registry.list();
732
841
  return sessions.filter((s) => s.status !== "stale").map((s) => ({
733
842
  sessionId: s.sessionId,
@@ -756,7 +865,7 @@ function onSwitchToSession(ctx, _sessionId, targetRoot, projectName) {
756
865
  }
757
866
 
758
867
  // src/boot/tui-project-picker-callback.ts
759
- import * as path3 from "node:path";
868
+ import * as path4 from "node:path";
760
869
  import { color as color3 } from "@wrongstack/core/utils";
761
870
  async function getProjectPickerItems(ctx) {
762
871
  const { buildPickerItems } = await import("./project-picker-BOCWHBXP.js");
@@ -770,7 +879,7 @@ async function onProjectSelect(ctx, slug, kind) {
770
879
  try {
771
880
  if (kind === "action") {
772
881
  if (slug === "new-session") {
773
- const name = path3.basename(state.projectRoot) || state.projectRoot;
882
+ const name = path4.basename(state.projectRoot) || state.projectRoot;
774
883
  const err2 = await switchProjectInPlace2(state.projectRoot, name);
775
884
  if (err2) renderer.write(color3.red(`Project switch failed: ${err2}
776
885
  `));
@@ -781,8 +890,8 @@ async function onProjectSelect(ctx, slug, kind) {
781
890
  const manifest = await loadManifest(state.wpaths.globalConfig);
782
891
  const project = manifest.projects.find((p) => p.slug === slug);
783
892
  if (!project) return;
784
- const targetRoot = path3.resolve(project.root);
785
- if (path3.resolve(state.projectRoot) === targetRoot) return;
893
+ const targetRoot = path4.resolve(project.root);
894
+ if (path4.resolve(state.projectRoot) === targetRoot) return;
786
895
  const fleetStatus = director?.status();
787
896
  const fleetRunning = fleetStatus?.subagents.filter((a) => a.status === "running").length ?? 0;
788
897
  const eternalActive = getEternalEngine?.()?.currentState === "running";
@@ -790,9 +899,12 @@ async function onProjectSelect(ctx, slug, kind) {
790
899
  const hasActiveAgents = fleetRunning > 0 || eternalActive || parallelActive;
791
900
  if (hasActiveAgents) {
792
901
  const parts = [
793
- color3.yellow("\u26A0 Switching project in place; active background work is still tied to the previous project:")
902
+ color3.yellow(
903
+ "\u26A0 Switching project in place; active background work is still tied to the previous project:"
904
+ )
794
905
  ];
795
- if (fleetRunning > 0) parts.push(color3.dim(` \u2022 ${fleetRunning} subagent(s) currently running`));
906
+ if (fleetRunning > 0)
907
+ parts.push(color3.dim(` \u2022 ${fleetRunning} subagent(s) currently running`));
796
908
  if (eternalActive) parts.push(color3.dim(" \u2022 Eternal engine is active"));
797
909
  if (parallelActive) parts.push(color3.dim(" \u2022 Parallel engine is active"));
798
910
  parts.push("");
@@ -808,19 +920,17 @@ ${parts.join("\n")}
808
920
  `));
809
921
  } catch (err) {
810
922
  renderer.write(
811
- color3.red(
812
- `Project switch failed: ${err instanceof Error ? err.message : String(err)}
813
- `
814
- )
923
+ color3.red(`Project switch failed: ${err instanceof Error ? err.message : String(err)}
924
+ `)
815
925
  );
816
926
  }
817
927
  }
818
928
 
819
929
  // src/boot/tui-project-spawn.ts
820
930
  import { spawn } from "node:child_process";
821
- import { createRequire } from "node:module";
822
931
  import * as fs from "node:fs/promises";
823
- import * as path4 from "node:path";
932
+ import { createRequire } from "node:module";
933
+ import * as path5 from "node:path";
824
934
  import { color as color4 } from "@wrongstack/core/utils";
825
935
  async function handleProjectSwitchSpawn(opts) {
826
936
  const PROJECT_SWITCH_EXIT_CODE = 42;
@@ -833,8 +943,8 @@ async function handleProjectSwitchSpawn(opts) {
833
943
  try {
834
944
  const req = createRequire(import.meta.url);
835
945
  const pkgPath = req.resolve("@wrongstack/cli/package.json");
836
- const pkgDir = path4.dirname(pkgPath);
837
- cliPath = path4.join(pkgDir, "dist", "index.js");
946
+ const pkgDir = path5.dirname(pkgPath);
947
+ cliPath = path5.join(pkgDir, "dist", "index.js");
838
948
  await fs.access(cliPath);
839
949
  } catch {
840
950
  cliPath = process.argv[1] ?? "";
@@ -870,7 +980,7 @@ async function handleProjectSwitchSpawn(opts) {
870
980
 
871
981
  // src/boot/tui-project-switch.ts
872
982
  import * as fs2 from "node:fs/promises";
873
- import * as path5 from "node:path";
983
+ import * as path6 from "node:path";
874
984
  import {
875
985
  DefaultSystemPromptBuilder,
876
986
  setQueuedMessagesSnapshot
@@ -891,10 +1001,11 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
891
1001
  skillLoader,
892
1002
  attachTodosCheckpoint: attachTodosCheckpoint3
893
1003
  } = ctx;
894
- const resolved = path5.resolve(targetRoot);
1004
+ const resolved = path6.resolve(targetRoot);
895
1005
  const stat2 = await fs2.stat(resolved).catch(() => null);
896
1006
  if (!stat2?.isDirectory()) return `Cannot switch: not a directory: ${resolved}`;
897
1007
  const oldWriter = context.session;
1008
+ const oldSessionStore = state.activeSessionStore;
898
1009
  const oldUsage = tokenCounter.total();
899
1010
  const oldProjectRoot = state.projectRoot;
900
1011
  const nextWpaths = resolveWstackPaths({
@@ -919,23 +1030,53 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
919
1030
  } catch (err) {
920
1031
  await nextWriter.close().catch(() => void 0);
921
1032
  await nextSessionStore.delete(nextWriter.id).catch(() => void 0);
1033
+ await nextSessionStore.dispose?.();
922
1034
  return `Cannot switch: ${err instanceof Error ? err.message : String(err)}`;
923
1035
  }
924
1036
  if (!state.activateSessionIdentity) {
925
1037
  await nextWriter.close().catch(() => void 0);
926
1038
  await nextSessionStore.delete(nextWriter.id).catch(() => void 0);
1039
+ await nextSessionStore.dispose?.();
927
1040
  return "Cannot switch: session ownership registry is unavailable.";
928
1041
  }
1042
+ let targetClaim;
1043
+ let targetActivated = false;
929
1044
  try {
930
- await state.activateSessionIdentity(nextWriter.id, {
1045
+ const { getSessionRegistry } = await import("@wrongstack/core/storage");
1046
+ const registry = getSessionRegistry(state.wpaths.globalRoot);
1047
+ targetClaim = await registry.reserveResume({
1048
+ sessionId: nextWriter.id,
1049
+ projectSlug: nextWpaths.projectSlug,
1050
+ projectRoot: resolved
1051
+ });
1052
+ const target = {
931
1053
  projectSlug: nextWpaths.projectSlug,
932
1054
  projectRoot: resolved,
933
- projectName: displayName || path5.basename(resolved),
1055
+ projectName: displayName || path6.basename(resolved),
934
1056
  workingDir: resolved
1057
+ };
1058
+ await targetClaim.activate({
1059
+ sessionId: nextWriter.id,
1060
+ ...target,
1061
+ clientType: "tui",
1062
+ pid: process.pid,
1063
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
935
1064
  });
1065
+ targetActivated = true;
1066
+ await state.activateSessionIdentity(nextWriter.id, target);
936
1067
  } catch (err) {
1068
+ if (!targetActivated) await targetClaim?.cancel().catch(() => void 0);
1069
+ else if (oldWriter) {
1070
+ await state.activateSessionIdentity(oldWriter.id, {
1071
+ projectSlug: state.wpaths.projectSlug,
1072
+ projectRoot: oldProjectRoot,
1073
+ projectName: path6.basename(oldProjectRoot),
1074
+ workingDir: context.workingDir
1075
+ }).catch(() => void 0);
1076
+ }
937
1077
  await nextWriter.close().catch(() => void 0);
938
1078
  await nextSessionStore.delete(nextWriter.id).catch(() => void 0);
1079
+ await nextSessionStore.dispose?.();
939
1080
  return `Cannot switch: ${err instanceof Error ? err.message : String(err)}`;
940
1081
  }
941
1082
  await Promise.resolve(state.detachActiveTodosCheckpoint?.()).catch(() => void 0);
@@ -1020,6 +1161,7 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1020
1161
  })
1021
1162
  );
1022
1163
  }
1164
+ await oldSessionStore?.dispose?.().catch(() => void 0);
1023
1165
  const emitUntyped = events.emit;
1024
1166
  emitUntyped("project.switched", { from: oldProjectRoot, to: resolved, name: displayName });
1025
1167
  return null;
@@ -1027,7 +1169,7 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1027
1169
 
1028
1170
  // src/boot/tui-sdd-callback.ts
1029
1171
  async function getSDDContext() {
1030
- const { getActiveSDDContext: getActiveSDDContext2 } = await import("./sdd-runtime-AIJCJGWC.js");
1172
+ const { getActiveSDDContext: getActiveSDDContext2 } = await import("./sdd-runtime-GFZ3NJKS.js");
1031
1173
  return getActiveSDDContext2();
1032
1174
  }
1033
1175
  async function onSDDOutput(output) {
@@ -1038,11 +1180,10 @@ async function onSDDOutput(output) {
1038
1180
  autoDetectTaskCompletion: autoDetectTaskCompletion2,
1039
1181
  getTaskProgress: getTaskProgress2,
1040
1182
  getActiveSDDPhase: getActiveSDDPhase2
1041
- } = await import("./sdd-runtime-AIJCJGWC.js");
1183
+ } = await import("./sdd-runtime-GFZ3NJKS.js");
1042
1184
  const messages = [];
1043
1185
  const specSaved = await trySaveSpecFromAIOutput2(output);
1044
- if (specSaved)
1045
- messages.push("\u2713 Spec detected and saved! Use /sdd approve to continue.");
1186
+ if (specSaved) messages.push("\u2713 Spec detected and saved! Use /sdd approve to continue.");
1046
1187
  const planSaved = trySaveImplementationPlan2(output);
1047
1188
  if (planSaved) messages.push("\u2713 Implementation plan saved!");
1048
1189
  const tasksSaved = await trySaveTasksFromAIOutput2(output);
@@ -1067,7 +1208,7 @@ async function onSDDOutput(output) {
1067
1208
  }
1068
1209
 
1069
1210
  // src/boot/tui-session-resume.ts
1070
- import * as path6 from "node:path";
1211
+ import * as path7 from "node:path";
1071
1212
  import { attachTodosCheckpoint, loadTodosCheckpoint } from "@wrongstack/core/storage";
1072
1213
  import { sessionScopedPath as sessionScopedPath2 } from "@wrongstack/core/utils";
1073
1214
  async function resumeSession(ctx, sessionId) {
@@ -1091,22 +1232,9 @@ async function resumeSession(ctx, sessionId) {
1091
1232
  );
1092
1233
  return null;
1093
1234
  }
1094
- try {
1095
- const { SessionRegistry } = await import("@wrongstack/core/storage");
1096
- const registry = new SessionRegistry(path6.dirname(state.wpaths.globalConfig));
1097
- const live = (await registry.list()).find(
1098
- (s) => s.sessionId === canonicalSessionId && s.status !== "stale" && s.pid !== process.pid
1099
- );
1100
- if (live) {
1101
- throw new Error(
1102
- `Session is open in another running wstack (pid ${live.pid}) \u2014 it cannot be resumed here while live.`
1103
- );
1104
- }
1105
- } catch (err) {
1106
- if (err instanceof Error && err.message.startsWith("Session is open")) throw err;
1107
- }
1108
1235
  const previousSessionId = agent.ctx.session?.id;
1109
1236
  let identityClaimed = false;
1237
+ let resumeClaim;
1110
1238
  let writerSwapped = false;
1111
1239
  let openedWriter;
1112
1240
  let oldWriter;
@@ -1116,12 +1244,34 @@ async function resumeSession(ctx, sessionId) {
1116
1244
  let oldPlanPath;
1117
1245
  let oldTaskPath;
1118
1246
  try {
1119
- if (state.activateSessionIdentity) {
1247
+ if (state.wpaths.projectSlug && state.wpaths.globalRoot) {
1248
+ const { getSessionRegistry } = await import("@wrongstack/core/storage");
1249
+ const registry = getSessionRegistry(state.wpaths.globalRoot);
1250
+ resumeClaim = await registry.reserveResume({
1251
+ sessionId: canonicalSessionId,
1252
+ projectSlug: state.wpaths.projectSlug,
1253
+ projectRoot: state.projectRoot
1254
+ });
1255
+ } else if (state.activateSessionIdentity) {
1120
1256
  await state.activateSessionIdentity(canonicalSessionId);
1121
1257
  identityClaimed = true;
1122
1258
  }
1123
1259
  const resumed = await state.activeSessionStore.resume(canonicalSessionId);
1124
1260
  openedWriter = resumed.writer;
1261
+ if (resumeClaim) {
1262
+ await resumeClaim.activate({
1263
+ sessionId: canonicalSessionId,
1264
+ projectSlug: state.wpaths.projectSlug,
1265
+ projectRoot: state.projectRoot,
1266
+ projectName: path7.basename(state.projectRoot),
1267
+ workingDir: agent.ctx.workingDir,
1268
+ clientType: "tui",
1269
+ pid: process.pid,
1270
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
1271
+ });
1272
+ identityClaimed = true;
1273
+ await state.activateSessionIdentity?.(canonicalSessionId);
1274
+ }
1125
1275
  const meta = resumed.data.metadata;
1126
1276
  const entries = replaySessionMessages(
1127
1277
  resumed.data.messages,
@@ -1256,6 +1406,7 @@ async function resumeSession(ctx, sessionId) {
1256
1406
  void oldWriterFinalize;
1257
1407
  return result;
1258
1408
  } catch (err) {
1409
+ if (!identityClaimed) await resumeClaim?.cancel().catch(() => void 0);
1259
1410
  if (identityClaimed && previousSessionId) {
1260
1411
  await state.activateSessionIdentity?.(previousSessionId).catch((rollbackErr) => {
1261
1412
  console.error(
@@ -1304,7 +1455,7 @@ async function resumeSession(ctx, sessionId) {
1304
1455
 
1305
1456
  // src/boot/tui-settings-adapter.ts
1306
1457
  import * as fs3 from "node:fs/promises";
1307
- import * as path7 from "node:path";
1458
+ import * as path8 from "node:path";
1308
1459
  import { decryptConfigSecrets, encryptConfigSecrets, noOpVault } from "@wrongstack/core/security";
1309
1460
  import { normalizeTokenSavingTier, resolveFleetChatVerbosity } from "@wrongstack/core/types";
1310
1461
  import { atomicWrite, deepMerge } from "@wrongstack/core/utils";
@@ -1595,7 +1746,7 @@ function createSettingsAdapter(ctx) {
1595
1746
  const isProjectTarget = actualTarget === wpaths.inProjectConfig;
1596
1747
  const toWrite = isProjectTarget ? filterSafeForProject(mergedToWrite) : mergedToWrite;
1597
1748
  const encrypted = encryptConfigSecrets(toWrite, noOpVault);
1598
- await fs3.mkdir(path7.dirname(actualTarget), { recursive: true });
1749
+ await fs3.mkdir(path8.dirname(actualTarget), { recursive: true });
1599
1750
  await atomicWrite(actualTarget, JSON.stringify(encrypted, null, 2), { mode: 384 });
1600
1751
  const currentConfig = configStore.get();
1601
1752
  const nextModelRuntime = {
@@ -2054,19 +2205,16 @@ async function finalizeExecutionCleanup(input) {
2054
2205
  );
2055
2206
  });
2056
2207
  const sessionEndProducers = /* @__PURE__ */ new Set();
2057
- events.emit(
2058
- "session.ended",
2059
- {
2060
- id: activeSession.id,
2061
- sessionId: activeSession.id,
2062
- usage: tokenCounter.total(),
2063
- waitUntil: (work) => {
2064
- const tracked = Promise.resolve(work).finally(() => sessionEndProducers.delete(tracked));
2065
- void tracked.catch(() => void 0);
2066
- sessionEndProducers.add(tracked);
2067
- }
2208
+ events.emit("session.ended", {
2209
+ id: activeSession.id,
2210
+ sessionId: activeSession.id,
2211
+ usage: tokenCounter.total(),
2212
+ waitUntil: (work) => {
2213
+ const tracked = Promise.resolve(work).finally(() => sessionEndProducers.delete(tracked));
2214
+ void tracked.catch(() => void 0);
2215
+ sessionEndProducers.add(tracked);
2068
2216
  }
2069
- );
2217
+ });
2070
2218
  try {
2071
2219
  while (sessionEndProducers.size > 0) {
2072
2220
  await Promise.allSettled([...sessionEndProducers]);
@@ -2123,10 +2271,7 @@ import { randomUUID } from "node:crypto";
2123
2271
  import { WIDE_SUBAGENT_CAPABILITIES } from "@wrongstack/core/security";
2124
2272
 
2125
2273
  // src/kanban-dispatch-route.ts
2126
- import {
2127
- fallbackProfileChain,
2128
- parseModelRef as parseModelRef2
2129
- } from "@wrongstack/core/agent";
2274
+ import { fallbackProfileChain, parseModelRef as parseModelRef2 } from "@wrongstack/core/agent";
2130
2275
  function resolveKanbanDispatchRoute(config, spawnOpts) {
2131
2276
  let provider = spawnOpts?.provider;
2132
2277
  let model = spawnOpts?.model;
@@ -2257,8 +2402,7 @@ function createReplFleetCallbacks({
2257
2402
  }
2258
2403
 
2259
2404
  // src/fleet-statusline.ts
2260
- import { color as color5 } from "@wrongstack/core/utils";
2261
- import { onResize } from "@wrongstack/core/utils";
2405
+ import { color as color5, onResize } from "@wrongstack/core/utils";
2262
2406
  function fmtElapsed(ms) {
2263
2407
  const s = Math.floor(ms / 1e3);
2264
2408
  if (s < 60) return `${s}s`;
@@ -2520,7 +2664,7 @@ function createChimeraWorkRegistry() {
2520
2664
 
2521
2665
  // src/execution-chimera-cascade.ts
2522
2666
  import * as fsp from "node:fs/promises";
2523
- import * as path8 from "node:path";
2667
+ import * as path9 from "node:path";
2524
2668
  import { emitReviewIfChanged } from "@wrongstack/core/plugin";
2525
2669
 
2526
2670
  // src/chimera-review-task.ts
@@ -2883,7 +3027,7 @@ async function maybeReReviewCascade({
2883
3027
  const reReadFiles = [];
2884
3028
  for (const f of bundle.files) {
2885
3029
  try {
2886
- const absPath = path8.join(bundle.cwd, f.path);
3030
+ const absPath = path9.join(bundle.cwd, f.path);
2887
3031
  const content = await fsp.readFile(absPath, "utf8");
2888
3032
  reReadFiles.push({ path: f.path, status: "modified", content });
2889
3033
  } catch {
@@ -2952,7 +3096,7 @@ async function maybeReReviewCascade({
2952
3096
 
2953
3097
  // src/execution-chimera-review.ts
2954
3098
  import { randomUUID as randomUUID3 } from "node:crypto";
2955
- import path9 from "node:path";
3099
+ import path10 from "node:path";
2956
3100
  import { effectiveFallbackChain } from "@wrongstack/core/agent";
2957
3101
  import {
2958
3102
  CHIMERA_REVIEW_PROMPT,
@@ -2965,7 +3109,7 @@ import {
2965
3109
  function normalizeFileKeyForCitation(raw, cwd) {
2966
3110
  const forward = raw.replace(/\\/g, "/").replace(/^\.\//, "");
2967
3111
  const isAbsolute = forward.startsWith("/") || /^[a-zA-Z]:\//.test(forward);
2968
- const pathMod = process.platform === "win32" ? path9.win32 : path9;
3112
+ const pathMod = process.platform === "win32" ? path10.win32 : path10;
2969
3113
  const relative = isAbsolute ? pathMod.relative(cwd, forward).replace(/\\/g, "/").replace(/^\.\//, "") : forward;
2970
3114
  return process.platform === "win32" ? relative.toLowerCase() : relative;
2971
3115
  }
@@ -3163,16 +3307,16 @@ function installChimeraReviewHandler({
3163
3307
  const changedBasenameIndex = /* @__PURE__ */ new Map();
3164
3308
  for (const file of p.files) {
3165
3309
  const normalized = normalizeFileKeyForCitation(file.path, p.cwd);
3166
- const basename5 = path9.basename(file.path).toLowerCase();
3167
- const bucket = changedBasenameIndex.get(basename5);
3310
+ const basename7 = path10.basename(file.path).toLowerCase();
3311
+ const bucket = changedBasenameIndex.get(basename7);
3168
3312
  if (bucket) bucket.push(normalized);
3169
- else changedBasenameIndex.set(basename5, [normalized]);
3313
+ else changedBasenameIndex.set(basename7, [normalized]);
3170
3314
  }
3171
3315
  const droppedCitations = citedFindings.filter((finding) => {
3172
3316
  const citedKey = normalizeFileKeyForCitation(finding.location.file, p.cwd);
3173
3317
  if (citedPaths.has(citedKey)) return false;
3174
- const basename5 = path9.basename(finding.location.file).toLowerCase();
3175
- const bucket = changedBasenameIndex.get(basename5);
3318
+ const basename7 = path10.basename(finding.location.file).toLowerCase();
3319
+ const bucket = changedBasenameIndex.get(basename7);
3176
3320
  return !(bucket && bucket.length === 1);
3177
3321
  });
3178
3322
  const effectiveHasFindings = reviewHasFindings && (parsedReview.findings.length === 0 || parsedReview.findings.length > droppedCitations.length);
@@ -3461,11 +3605,23 @@ async function predictNextTasks(input, opts) {
3461
3605
  }
3462
3606
 
3463
3607
  // src/repl.ts
3464
- import { toErrorMessage } from "@wrongstack/core/utils";
3465
- import { color as color9, estimateRequestTokensCalibrated as estimateRequestTokensCalibrated2, expectDefined, hasOpenTodos as hasOpenTodos2 } from "@wrongstack/core/utils";
3466
3608
  import { detectContinueIntent, InputBuilder, resolveContinuation } from "@wrongstack/core/agent";
3467
3609
  import { goalFilePath, loadGoal, summarizeUsage } from "@wrongstack/core/goal";
3610
+ import {
3611
+ color as color9,
3612
+ estimateRequestTokensCalibrated as estimateRequestTokensCalibrated2,
3613
+ expectDefined,
3614
+ hasOpenTodos as hasOpenTodos2,
3615
+ toErrorMessage
3616
+ } from "@wrongstack/core/utils";
3468
3617
  import { readClipboardImage, routeImagesForModel } from "@wrongstack/runtime";
3618
+ import { createAutoProceedLoopGuard } from "@wrongstack/tools/auto-proceed-loop-guard";
3619
+
3620
+ // src/repl-auto-proceed.ts
3621
+ import { color as color6, estimateRequestTokensCalibrated } from "@wrongstack/core/utils";
3622
+ import {
3623
+ GROUNDED_NO_PROGRESS_STEER
3624
+ } from "@wrongstack/tools/auto-proceed-loop-guard";
3469
3625
 
3470
3626
  // src/repl-suggestions.ts
3471
3627
  import { hasOpenTodos } from "@wrongstack/core/utils";
@@ -3483,8 +3639,6 @@ function parseSuggestionsFromOutput(finalText, todos) {
3483
3639
  }
3484
3640
 
3485
3641
  // src/repl-auto-proceed.ts
3486
- import { color as color6, estimateRequestTokensCalibrated } from "@wrongstack/core/utils";
3487
- import { GROUNDED_NO_PROGRESS_STEER } from "@wrongstack/tools/auto-proceed-loop-guard";
3488
3642
  async function runAutoProceed(opts, suggestion, delayMs, ctrl, loopGuard, grounded = false) {
3489
3643
  const truncated = suggestion.length > 80 ? `${suggestion.slice(0, 77)}\u2026` : suggestion;
3490
3644
  console.log(
@@ -3635,6 +3789,54 @@ async function runContextCompaction(opts, _signal) {
3635
3789
  }
3636
3790
  }
3637
3791
 
3792
+ // src/repl-client-registration.ts
3793
+ import * as crypto from "node:crypto";
3794
+ import * as path11 from "node:path";
3795
+ import { getSharedProjectMailbox, resolveProjectDir } from "@wrongstack/core/coordination";
3796
+ import { wstackGlobalRoot } from "@wrongstack/core/utils";
3797
+ function registerReplClient(opts) {
3798
+ const replProjectRoot = opts.projectRoot ?? process.cwd();
3799
+ const projectDir = resolveProjectDir(replProjectRoot, wstackGlobalRoot());
3800
+ const clientId = `repl@${crypto.randomUUID().slice(0, 8)}`;
3801
+ const hqConnection = startCliHqConnection({
3802
+ clientKind: "repl",
3803
+ projectRoot: replProjectRoot,
3804
+ projectName: path11.basename(replProjectRoot),
3805
+ appConfig: opts.appConfig,
3806
+ capabilities: ["telemetry.publish", "mailbox.summary"]
3807
+ });
3808
+ const clientMailbox = getSharedProjectMailbox(
3809
+ projectDir,
3810
+ void 0,
3811
+ () => hqConnection.getPublisher()
3812
+ );
3813
+ let closed = false;
3814
+ let clientHeartbeat;
3815
+ clientMailbox.registerClient({
3816
+ clientId,
3817
+ sessionId: opts.getSessionId?.() ?? replProjectRoot,
3818
+ name: `REPL [${path11.basename(replProjectRoot)}]`,
3819
+ source: "repl",
3820
+ pid: process.pid
3821
+ }).then(() => {
3822
+ if (closed) return;
3823
+ clientHeartbeat = setInterval(() => {
3824
+ clientMailbox.clientHeartbeat({ clientId, sessionId: opts.getSessionId?.() ?? replProjectRoot }).catch(() => {
3825
+ });
3826
+ }, 15e3);
3827
+ }).catch(() => {
3828
+ });
3829
+ return {
3830
+ clientId,
3831
+ close() {
3832
+ closed = true;
3833
+ if (clientHeartbeat) clearInterval(clientHeartbeat);
3834
+ clientMailbox.deregisterClient(clientId).catch(() => void 0);
3835
+ hqConnection.stop();
3836
+ }
3837
+ };
3838
+ }
3839
+
3638
3840
  // src/repl-input.ts
3639
3841
  import { color as color7 } from "@wrongstack/core/utils";
3640
3842
  async function readPossiblyMultiline(opts) {
@@ -3692,59 +3894,7 @@ function printBanner(renderer, projectName) {
3692
3894
  `);
3693
3895
  }
3694
3896
 
3695
- // src/repl-client-registration.ts
3696
- import * as crypto from "node:crypto";
3697
- import * as path10 from "node:path";
3698
- import {
3699
- getSharedProjectMailbox,
3700
- resolveProjectDir
3701
- } from "@wrongstack/core/coordination";
3702
- import { wstackGlobalRoot } from "@wrongstack/core/utils";
3703
- function registerReplClient(opts) {
3704
- const replProjectRoot = opts.projectRoot ?? process.cwd();
3705
- const projectDir = resolveProjectDir(replProjectRoot, wstackGlobalRoot());
3706
- const clientId = `repl@${crypto.randomUUID().slice(0, 8)}`;
3707
- const hqConnection = startCliHqConnection({
3708
- clientKind: "repl",
3709
- projectRoot: replProjectRoot,
3710
- projectName: path10.basename(replProjectRoot),
3711
- appConfig: opts.appConfig,
3712
- capabilities: ["telemetry.publish", "mailbox.summary"]
3713
- });
3714
- const clientMailbox = getSharedProjectMailbox(
3715
- projectDir,
3716
- void 0,
3717
- () => hqConnection.getPublisher()
3718
- );
3719
- let closed = false;
3720
- let clientHeartbeat;
3721
- clientMailbox.registerClient({
3722
- clientId,
3723
- sessionId: opts.getSessionId?.() ?? replProjectRoot,
3724
- name: `REPL [${path10.basename(replProjectRoot)}]`,
3725
- source: "repl",
3726
- pid: process.pid
3727
- }).then(() => {
3728
- if (closed) return;
3729
- clientHeartbeat = setInterval(() => {
3730
- clientMailbox.clientHeartbeat({ clientId, sessionId: opts.getSessionId?.() ?? replProjectRoot }).catch(() => {
3731
- });
3732
- }, 15e3);
3733
- }).catch(() => {
3734
- });
3735
- return {
3736
- clientId,
3737
- close() {
3738
- closed = true;
3739
- if (clientHeartbeat) clearInterval(clientHeartbeat);
3740
- clientMailbox.deregisterClient(clientId).catch(() => void 0);
3741
- hqConnection.stop();
3742
- }
3743
- };
3744
- }
3745
-
3746
3897
  // src/repl.ts
3747
- import { createAutoProceedLoopGuard } from "@wrongstack/tools/auto-proceed-loop-guard";
3748
3898
  var DEFAULT_MAX_CONSECUTIVE_AUTO_PROCEED = 50;
3749
3899
  async function runRepl(opts) {
3750
3900
  if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
@@ -3858,9 +4008,7 @@ async function runRepl(opts) {
3858
4008
  continue;
3859
4009
  }
3860
4010
  } catch (err) {
3861
- opts.renderer.writeError(
3862
- `[eternal] ${toErrorMessage(err)}`
3863
- );
4011
+ opts.renderer.writeError(`[eternal] ${toErrorMessage(err)}`);
3864
4012
  }
3865
4013
  await new Promise((resolve3) => setTimeout(resolve3, 250));
3866
4014
  continue;
@@ -3934,9 +4082,7 @@ async function runRepl(opts) {
3934
4082
  continue;
3935
4083
  }
3936
4084
  } catch (err) {
3937
- opts.renderer.writeError(
3938
- `[parallel] ${toErrorMessage(err)}`
3939
- );
4085
+ opts.renderer.writeError(`[parallel] ${toErrorMessage(err)}`);
3940
4086
  }
3941
4087
  await new Promise((resolve3) => setTimeout(resolve3, 250));
3942
4088
  continue;
@@ -3968,6 +4114,16 @@ ${lines.join("\n")}
3968
4114
  const resolved = resolveContinuation({ todos, suggestions: [] });
3969
4115
  top = resolved.source === "todo" ? resolved.text : "";
3970
4116
  groundedTodo = top !== "";
4117
+ if (resolved.source === "todo" && resolved.todoId) {
4118
+ const selected = todos.find((todo) => todo.id === resolved.todoId);
4119
+ if (selected?.status === "pending") {
4120
+ opts.agent.ctx.state.replaceTodos(
4121
+ todos.map(
4122
+ (todo) => todo.id === resolved.todoId ? { ...todo, status: "in_progress" } : todo.status === "in_progress" ? { ...todo, status: "pending" } : todo
4123
+ )
4124
+ );
4125
+ }
4126
+ }
3971
4127
  }
3972
4128
  if (!top) {
3973
4129
  } else {
@@ -4134,10 +4290,22 @@ ${color9.dim(taskList2)}
4134
4290
  todos: opts.agent.ctx.todos,
4135
4291
  suggestions: getSuggestions()
4136
4292
  });
4293
+ if (resolved.source === "todo" && resolved.todoId) {
4294
+ const selected = opts.agent.ctx.todos.find((todo) => todo.id === resolved.todoId);
4295
+ if (selected?.status === "pending") {
4296
+ opts.agent.ctx.state.replaceTodos(
4297
+ opts.agent.ctx.todos.map(
4298
+ (todo) => todo.id === resolved.todoId ? { ...todo, status: "in_progress" } : todo.status === "in_progress" ? { ...todo, status: "pending" } : todo
4299
+ )
4300
+ );
4301
+ }
4302
+ }
4137
4303
  if (resolved.source === "open") {
4138
4304
  opts.renderer.write(
4139
4305
  ` ${color9.amber("\u26A0")} ${color9.bold("'continue' has no anchor")} ${color9.dim("\u2014 no pending todo or suggestion.")}
4140
- ` + color9.dim(" If you proceed, I'll choose the next step from context; that can drift.\n")
4306
+ ` + color9.dim(
4307
+ " If you proceed, I'll choose the next step from context; that can drift.\n"
4308
+ )
4141
4309
  );
4142
4310
  const ans = (await opts.reader.readLine(color9.dim(" Proceed anyway? [Y/n \xB7 e = type your own] "))).trim().toLowerCase();
4143
4311
  if (ans === "n" || ans === "no") {
@@ -4414,9 +4582,7 @@ async function pasteClipboardImage(builder, opts) {
4414
4582
  opts.renderer.write(color9.dim(` \u21B3 ${placeholder} (PNG ${kb}KB)
4415
4583
  `));
4416
4584
  } catch (err) {
4417
- opts.renderer.writeError(
4418
- `Clipboard image error: ${toErrorMessage(err)}`
4419
- );
4585
+ opts.renderer.writeError(`Clipboard image error: ${toErrorMessage(err)}`);
4420
4586
  }
4421
4587
  }
4422
4588
  async function loadGoalSafe(opts) {
@@ -4452,9 +4618,7 @@ async function renderGoalBanner(opts) {
4452
4618
  try {
4453
4619
  await opts.slashRegistry.dispatch("/autonomy eternal", opts.agent.ctx);
4454
4620
  } catch (err) {
4455
- opts.renderer.writeError(
4456
- `Auto-resume failed: ${toErrorMessage(err)}`
4457
- );
4621
+ opts.renderer.writeError(`Auto-resume failed: ${toErrorMessage(err)}`);
4458
4622
  }
4459
4623
  } else {
4460
4624
  opts.renderer.write(
@@ -4515,7 +4679,8 @@ async function execute(deps) {
4515
4679
  slashRegistry,
4516
4680
  tokenCounter,
4517
4681
  activateSessionIdentity,
4518
- updateInfo: initialUpdateInfo
4682
+ updateInfo: initialUpdateInfo,
4683
+ webuiSessionChild
4519
4684
  },
4520
4685
  session: {
4521
4686
  session,
@@ -4983,6 +5148,7 @@ async function execute(deps) {
4983
5148
  sddSubagentFactory,
4984
5149
  statusTracker,
4985
5150
  updateInfo: bootUpdateInfo,
5151
+ webuiSessionChild,
4986
5152
  getFleetBudget: () => {
4987
5153
  const d = getDirector?.() ?? null;
4988
5154
  if (!d) return null;
@@ -5025,7 +5191,7 @@ async function execute(deps) {
5025
5191
  attachments,
5026
5192
  effectiveMaxContext,
5027
5193
  getEffectiveMaxContext,
5028
- projectName: path11.basename(projectRoot) || void 0,
5194
+ projectName: path12.basename(projectRoot) || void 0,
5029
5195
  projectRoot,
5030
5196
  appConfig: config,
5031
5197
  getSessionId: () => agent.ctx.session?.id ?? session.id,
@@ -5084,4 +5250,4 @@ export {
5084
5250
  execute,
5085
5251
  resolveReviewerFallbackModels
5086
5252
  };
5087
- //# sourceMappingURL=execution-LHMSMDHB.js.map
5253
+ //# sourceMappingURL=execution-LZRYRGDD.js.map