@wrongstack/cli 0.313.1 → 0.316.1

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 (233) hide show
  1. package/dist/{acp-LQMSMV32.js → acp-CEQINXWB.js} +2 -2
  2. package/dist/acp-registry-cache.d.ts +0 -2
  3. package/dist/acp-server-agent.d.ts +2 -1
  4. package/dist/arg-parser.d.ts +2 -1
  5. package/dist/{auth-VQMSZGKE.js → auth-GZ5A5OF5.js} +3 -3
  6. package/dist/auth-menu/local.d.ts +3 -2
  7. package/dist/boot/boot-auto-thin.d.ts +44 -0
  8. package/dist/boot/brain-decision-log.d.ts +2 -1
  9. package/dist/boot/config-backup-recovery.d.ts +2 -6
  10. package/dist/boot/dispatch-singleshot.d.ts +2 -1
  11. package/dist/boot/dispatch-webui.d.ts +5 -1
  12. package/dist/boot/event-wiring.d.ts +1 -1
  13. package/dist/boot/execution-mode.d.ts +2 -1
  14. package/dist/boot/governance-shadow-bridge.d.ts +4 -3
  15. package/dist/boot/governance-trace-context.d.ts +4 -4
  16. package/dist/boot/launch-menu.d.ts +2 -2
  17. package/dist/boot/system-prompt-builder.d.ts +1 -1
  18. package/dist/boot/system-prompt-menu.d.ts +10 -58
  19. package/dist/boot/system-prompt.d.ts +3 -3
  20. package/dist/boot/tool-registry.d.ts +3 -1
  21. package/dist/boot/tui-coordinator-callbacks.d.ts +2 -1
  22. package/dist/boot/tui-coordinator-setup.d.ts +3 -2
  23. package/dist/boot/tui-goal-wiring.d.ts +2 -1
  24. package/dist/boot/tui-live-sessions.d.ts +3 -1
  25. package/dist/boot/tui-session-resume.d.ts +82 -10
  26. package/dist/boot/tui-session-stub-enrich.d.ts +7 -1
  27. package/dist/boot/tui-settings-adapter.d.ts +3 -2
  28. package/dist/boot/tui-theme-adapter.d.ts +3 -2
  29. package/dist/boot/webui-session-child.d.ts +2 -12
  30. package/dist/boot-auto-thin-BZ675EVT.js +102 -0
  31. package/dist/boot-config.d.ts +1 -1
  32. package/dist/brain-menu/panel-service.d.ts +2 -1
  33. package/dist/chimera-cascade-evidence.d.ts +4 -21
  34. package/dist/chimera-review-task.d.ts +0 -7
  35. package/dist/chimera-subagent-ladder.d.ts +2 -2
  36. package/dist/{chunk-USYOJIV2.js → chunk-32MTOI2I.js} +2 -2
  37. package/dist/{chunk-CNQZ4HG4.js → chunk-37SPPLUD.js} +57 -8
  38. package/dist/chunk-ALE5KHCA.js +1 -0
  39. package/dist/{chunk-GWVLRUVH.js → chunk-G3IMKQRH.js} +25 -6
  40. package/dist/{chunk-BZJ4MP32.js → chunk-GKHUHAIK.js} +8 -3
  41. package/dist/{chunk-3JPTNADJ.js → chunk-GPPRNAKW.js} +1 -1
  42. package/dist/{chunk-KE7E7DPX.js → chunk-HXJYHAR4.js} +1 -1
  43. package/dist/{chunk-X3N5TS2S.js → chunk-JACOMTIH.js} +2 -76
  44. package/dist/{chunk-DGXNL7OT.js → chunk-JHUJUIOH.js} +1 -18
  45. package/dist/{chunk-WOTGMHAH.js → chunk-KG4X5F7Z.js} +1 -1
  46. package/dist/{chunk-NUIHRGPY.js → chunk-NV3JDK4F.js} +1 -1
  47. package/dist/{chunk-E3X4KM7T.js → chunk-NZZOYLQ7.js} +5 -10
  48. package/dist/{chunk-H6C7SO5H.js → chunk-QC5I4VWZ.js} +1 -1
  49. package/dist/chunk-SXJTVNWF.js +78 -0
  50. package/dist/{chunk-AOAIPYFB.js → chunk-SYIBTG3X.js} +2 -2
  51. package/dist/{chunk-PKHGLWUJ.js → chunk-T642Q732.js} +5 -4
  52. package/dist/{chunk-BGFM3PD7.js → chunk-UZ2TMHNH.js} +1 -1
  53. package/dist/{chunk-4S52MIIM.js → chunk-VXCCBI2W.js} +2 -2
  54. package/dist/{chunk-FKWHSFX4.js → chunk-XYKYXFEE.js} +1 -1
  55. package/dist/cli-entry-point.d.ts +9 -0
  56. package/dist/cli-eternal-flag.d.ts +1 -1
  57. package/dist/{cli-main-UOQ2ICUO.js → cli-main-IEAM6SK7.js} +3578 -1626
  58. package/dist/cli-main-helpers.d.ts +3 -3
  59. package/dist/config-doctor.d.ts +34 -3
  60. package/dist/context-limit.d.ts +4 -3
  61. package/dist/{diag-doctor-OPTB2NWY.js → diag-doctor-LFCCBPMD.js} +3 -3
  62. package/dist/execute-deps.d.ts +36 -7
  63. package/dist/{execution-L4CXQEND.js → execution-TZUGCKFU.js} +459 -77
  64. package/dist/execution-chimera-cascade.d.ts +1 -1
  65. package/dist/execution-chimera-review.d.ts +1 -1
  66. package/dist/execution-cleanup.d.ts +2 -1
  67. package/dist/execution-kanban-dispatch.d.ts +2 -1
  68. package/dist/execution-repl-fleet-callbacks.d.ts +3 -2
  69. package/dist/fleet/budget-source.d.ts +2 -1
  70. package/dist/fleet/host-context.d.ts +8 -1
  71. package/dist/fleet/host-director-event-bridges.d.ts +28 -3
  72. package/dist/fleet/host-event-bridge.d.ts +6 -1
  73. package/dist/fleet/host-explore-companion-registry.d.ts +60 -0
  74. package/dist/fleet/host-explore-companion.d.ts +7 -3
  75. package/dist/fleet/host-provider.d.ts +2 -1
  76. package/dist/fleet/host-session-writer.d.ts +9 -1
  77. package/dist/fleet/host-shadow-manager.d.ts +82 -20
  78. package/dist/fleet/host-shadow-pass.d.ts +9 -1
  79. package/dist/fleet/host-spawn-types.d.ts +9 -0
  80. package/dist/fleet/host-status.d.ts +2 -1
  81. package/dist/fleet/host-subagent-factory.d.ts +2 -1
  82. package/dist/fleet/host-subagent-session-audit.d.ts +56 -0
  83. package/dist/fleet/host-supervisor.d.ts +11 -1
  84. package/dist/fleet/host-task-result-report.d.ts +2 -1
  85. package/dist/fleet/host.d.ts +38 -6
  86. package/dist/fleet/status-broadcast.d.ts +2 -1
  87. package/dist/fleet-statusline.d.ts +2 -1
  88. package/dist/goal-host.d.ts +3 -2
  89. package/dist/{governance-V2Z42RBE.js → governance-JSGHHA2R.js} +1 -1
  90. package/dist/governance-hq-telemetry.d.ts +2 -2
  91. package/dist/{hq-2XIXGAER.js → hq-NDTJRRX3.js} +3 -3
  92. package/dist/hq-publisher.d.ts +1 -1
  93. package/dist/hq-recovery-html.d.ts +1 -6
  94. package/dist/hq-server/auth-state.d.ts +2 -1
  95. package/dist/hq-server/auth.d.ts +3 -2
  96. package/dist/hq-server/login-attempt-store.d.ts +2 -1
  97. package/dist/hq-server/mailbox-gateway-manager.d.ts +2 -1
  98. package/dist/hq-server/preflight.d.ts +3 -2
  99. package/dist/hq-server/server-lifecycle.d.ts +2 -1
  100. package/dist/hq-server/snapshot.d.ts +0 -9
  101. package/dist/hq-server/startup.d.ts +2 -3
  102. package/dist/hq-server/types.d.ts +2 -2
  103. package/dist/hq-server/upgrade-handler.d.ts +2 -1
  104. package/dist/hq-server/ws-leader.d.ts +0 -6
  105. package/dist/{hq-server-DBT3OOYD.js → hq-server-OH3SPSE2.js} +3 -13
  106. package/dist/hq-server.d.ts +1 -6
  107. package/dist/hq-static-serve.d.ts +2 -1
  108. package/dist/{hq-ttl-U2FAYFAT.js → hq-ttl-KUO3AU7X.js} +2 -2
  109. package/dist/{hq-tunnel-RFKGC4HI.js → hq-tunnel-LO55RCZE.js} +1 -1
  110. package/dist/hq-tunnel.d.ts +2 -1
  111. package/dist/index.js +113 -109
  112. package/dist/input-reader.d.ts +2 -1
  113. package/dist/kanban-dispatch-route.d.ts +27 -2
  114. package/dist/kanban-hq-sync.d.ts +2 -1
  115. package/dist/launch-hints.d.ts +2 -1
  116. package/dist/mailbox-bridge-bootstrap.d.ts +2 -3
  117. package/dist/{mailbox-serve-5S3PHG5D.js → mailbox-serve-VKQIRCCB.js} +47 -28
  118. package/dist/{mcp-RRPKNRSN.js → mcp-AQKSASHD.js} +1 -1
  119. package/dist/mcp-serve.d.ts +2 -1
  120. package/dist/{modeldiag-H6DKWJ2N.js → modeldiag-4NYBRSFP.js} +1 -1
  121. package/dist/next-task-predictor.d.ts +3 -2
  122. package/dist/permission-prompt.d.ts +2 -1
  123. package/dist/picker.d.ts +0 -18
  124. package/dist/plugin-management.d.ts +3 -14
  125. package/dist/{plugin-usage-GCTYOZPH.js → plugin-usage-AP7SJCDA.js} +2 -2
  126. package/dist/{plugins-EEKHCMBE.js → plugins-HQ5FU2AM.js} +3 -5
  127. package/dist/preflight.d.ts +2 -1
  128. package/dist/{proxy-wiring-G26YGP7S.js → proxy-wiring-EQB5X5YH.js} +3 -3
  129. package/dist/renderer.d.ts +18 -1
  130. package/dist/repl-client-registration.d.ts +2 -1
  131. package/dist/repl.d.ts +1 -1
  132. package/dist/{replay-XU6ZD7GM.js → replay-FJ2JBXUA.js} +1 -1
  133. package/dist/{sdd-runtime-GFZ3NJKS.js → sdd-runtime-FLKCSTYV.js} +3 -5
  134. package/dist/services/commit-message.d.ts +2 -1
  135. package/dist/services/sdd/state.d.ts +0 -2
  136. package/dist/services/sdd-runtime.d.ts +1 -1
  137. package/dist/services/statusline-config.d.ts +27 -4
  138. package/dist/session-event-wiring.d.ts +3 -5
  139. package/dist/{sessions-config-7Q7QJBKJ.js → sessions-config-P2LK2L32.js} +5 -1
  140. package/dist/sessions-doctor-EXHAZSSE.js +146 -0
  141. package/dist/settings-menu.d.ts +2 -1
  142. package/dist/shutdown-cleanup.d.ts +3 -2
  143. package/dist/{simpleui-dist-33VO3QHF.js → simpleui-dist-JKNRCRRK.js} +1 -1
  144. package/dist/simpleui-dist.d.ts +3 -2
  145. package/dist/slash-commands/brain-council.d.ts +0 -4
  146. package/dist/slash-commands/brain-status.d.ts +0 -1
  147. package/dist/slash-commands/command-context.d.ts +16 -2
  148. package/dist/slash-commands/fix-classifier.d.ts +2 -1
  149. package/dist/slash-commands/kanban-agent-helpers.d.ts +2 -1
  150. package/dist/slash-commands/kanban-board-handlers.d.ts +2 -1
  151. package/dist/slash-commands/kanban-lifecycle-diagnostics.d.ts +2 -1
  152. package/dist/slash-commands/kanban-task-subcommands.d.ts +0 -1
  153. package/dist/slash-commands/memory-audience.d.ts +1 -10
  154. package/dist/slash-commands/memory-flags.d.ts +2 -1
  155. package/dist/slash-commands/sdd-command-helpers.d.ts +3 -2
  156. package/dist/slash-commands/sdd.d.ts +2 -2
  157. package/dist/slash-commands/settings-mutations.d.ts +0 -1
  158. package/dist/slash-commands/statusline.d.ts +4 -4
  159. package/dist/slash-commands/telegram-pairing.d.ts +2 -2
  160. package/dist/slash-commands/telegram-setup.d.ts +2 -1
  161. package/dist/slash-commands/tier.d.ts +13 -0
  162. package/dist/subcommands/handlers/acp-connection-gate.d.ts +4 -3
  163. package/dist/subcommands/handlers/bench-run-help.d.ts +3 -8
  164. package/dist/subcommands/handlers/daemon-inventory.d.ts +3 -2
  165. package/dist/subcommands/handlers/governance.d.ts +2 -1
  166. package/dist/subcommands/handlers/model-smoke-test.d.ts +3 -2
  167. package/dist/subcommands/handlers/modeldiag-eval.d.ts +0 -4
  168. package/dist/subcommands/handlers/modeldiag-profiles.d.ts +1 -1
  169. package/dist/subcommands/handlers/models-add-help.d.ts +3 -8
  170. package/dist/subcommands/handlers/sessions-doctor.d.ts +3 -0
  171. package/dist/subcommands/handlers/update.d.ts +1 -1
  172. package/dist/terminal-format.d.ts +3 -2
  173. package/dist/tui-resource-menus.d.ts +2 -1
  174. package/dist/tuneup.d.ts +5 -5
  175. package/dist/{update-ZXNC6I6G.js → update-XKARO3CY.js} +3 -3
  176. package/dist/{update-check-WARHSVZA.js → update-check-LICQNYFK.js} +2 -2
  177. package/dist/update-check.d.ts +1 -1
  178. package/dist/utils/hq-ttl.d.ts +2 -1
  179. package/dist/webui-server/connection-handler.d.ts +34 -2
  180. package/dist/webui-server/prefs-seeding.d.ts +11 -1
  181. package/dist/webui-server/route-contexts.d.ts +45 -5
  182. package/dist/webui-server/session-start-payload.d.ts +13 -0
  183. package/dist/webui-server/setup-events.d.ts +14 -1
  184. package/dist/{webui-server-I53IYBW4.js → webui-server-LZOEH7O6.js} +374 -169
  185. package/dist/webui-server-options.d.ts +30 -4
  186. package/dist/wiring/brain-and-orchestration.d.ts +3 -3
  187. package/dist/wiring/cli-execute-builder.d.ts +3 -0
  188. package/dist/wiring/cli-heap-watchdog.d.ts +2 -1
  189. package/dist/wiring/cli-prompt-and-tools-setup.d.ts +10 -8
  190. package/dist/wiring/codebase-index.d.ts +2 -1
  191. package/dist/wiring/command-host-state.d.ts +61 -5
  192. package/dist/wiring/controllers.d.ts +3 -4
  193. package/dist/wiring/dep-watcher-bridge.d.ts +3 -2
  194. package/dist/wiring/dep-watcher.d.ts +2 -1
  195. package/dist/wiring/design-studio.d.ts +2 -1
  196. package/dist/wiring/director-setup.d.ts +3 -2
  197. package/dist/wiring/domain-terms-mirror.d.ts +2 -1
  198. package/dist/wiring/external-plugins.d.ts +3 -2
  199. package/dist/wiring/fleet-command-handlers.d.ts +2 -2
  200. package/dist/wiring/heap-watchdog-setup.d.ts +2 -1
  201. package/dist/wiring/hq-telemetry.d.ts +3 -2
  202. package/dist/wiring/lifecycle-plugins.d.ts +2 -2
  203. package/dist/wiring/management-tools.d.ts +30 -2
  204. package/dist/wiring/metrics.d.ts +2 -2
  205. package/dist/wiring/plugins.d.ts +0 -1
  206. package/dist/wiring/prompt-journal-recorder.d.ts +1 -1
  207. package/dist/wiring/provider-runtime-setup.d.ts +9 -2
  208. package/dist/wiring/provider-runtime.d.ts +23 -3
  209. package/dist/wiring/provider-status.d.ts +2 -1
  210. package/dist/wiring/provider-utility-tools.d.ts +2 -1
  211. package/dist/wiring/provider.d.ts +2 -1
  212. package/dist/wiring/replay-governance-setup.d.ts +2 -1
  213. package/dist/wiring/replay.d.ts +2 -1
  214. package/dist/wiring/resume-candidate.d.ts +27 -0
  215. package/dist/wiring/runtime-controller-deps.d.ts +8 -1
  216. package/dist/wiring/runtime-dispatch-state.d.ts +2 -1
  217. package/dist/wiring/runtime-lifecycle-deps.d.ts +2 -1
  218. package/dist/wiring/runtime-picker-deps.d.ts +2 -1
  219. package/dist/wiring/session-command-handlers.d.ts +2 -2
  220. package/dist/wiring/session-establishment.d.ts +2 -1
  221. package/dist/wiring/session-registry.d.ts +3 -2
  222. package/dist/wiring/session-runtime.d.ts +1 -1
  223. package/dist/wiring/slash-commands.d.ts +5 -4
  224. package/dist/wiring/teardown-registrar.d.ts +3 -2
  225. package/dist/wiring/vector-memory-setup.d.ts +3 -2
  226. package/dist/wiring/wrongtrace-hooks.d.ts +1 -1
  227. package/dist/wiring/wrongtrace-telemetry.d.ts +2 -1
  228. package/dist/{wrongtrace-telemetry-6M2CCBX5.js → wrongtrace-telemetry-FNLANZ5I.js} +1 -1
  229. package/package.json +30 -30
  230. package/dist/auth-menu.d.ts +0 -7
  231. package/dist/chunk-WHOIR577.js +0 -1
  232. package/dist/webui-server/terminal-log-view.d.ts +0 -47
  233. package/dist/wiring/tools.d.ts +0 -29
@@ -1,15 +1,17 @@
1
1
  import {
2
- deriveFsAccessPair,
3
- filterSafeForProject,
4
2
  getSuggestions,
5
3
  normalizeTuiThinkingWord,
6
- resolveActualTarget,
7
- resolvePersistPath,
8
4
  runGit,
9
5
  setAutoSuggestions,
10
6
  setSuggestions
11
- } from "./chunk-X3N5TS2S.js";
12
- import "./chunk-WHOIR577.js";
7
+ } from "./chunk-SXJTVNWF.js";
8
+ import {
9
+ deriveFsAccessPair,
10
+ filterSafeForProject,
11
+ resolveActualTarget,
12
+ resolvePersistPath
13
+ } from "./chunk-JACOMTIH.js";
14
+ import "./chunk-ALE5KHCA.js";
13
15
  import {
14
16
  advanceToNextTask,
15
17
  autoDetectTaskCompletion,
@@ -22,10 +24,10 @@ import {
22
24
  trySaveImplementationPlan,
23
25
  trySaveSpecFromAIOutput,
24
26
  trySaveTasksFromAIOutput
25
- } from "./chunk-DGXNL7OT.js";
27
+ } from "./chunk-JHUJUIOH.js";
26
28
  import {
27
29
  startCliHqConnection
28
- } from "./chunk-FKWHSFX4.js";
30
+ } from "./chunk-XYKYXFEE.js";
29
31
  import {
30
32
  theme
31
33
  } from "./chunk-QD544J2B.js";
@@ -36,11 +38,11 @@ import {
36
38
  WEBUI_SESSION_CHILD_CAPABILITIES,
37
39
  writeWebuiSessionChildError,
38
40
  writeWebuiSessionChildReady
39
- } from "./chunk-3JPTNADJ.js";
41
+ } from "./chunk-GPPRNAKW.js";
40
42
  import {
41
43
  terminalLink,
42
44
  terminalText
43
- } from "./chunk-KE7E7DPX.js";
45
+ } from "./chunk-HXJYHAR4.js";
44
46
  import {
45
47
  CLI_VERSION
46
48
  } from "./chunk-XJXDOF63.js";
@@ -58,9 +60,10 @@ import { effectiveFallbackChain as effectiveFallbackChain2, setQueuedMessagesSna
58
60
  import { updateReviewReportEvidence } from "@wrongstack/core/plugin";
59
61
  import { attachTodosCheckpoint as attachTodosCheckpoint2 } from "@wrongstack/core/storage";
60
62
  import { normalizeTokenSavingTier as normalizeTokenSavingTier2 } from "@wrongstack/core/types";
61
- import { mergeCustomModelDefs } from "@wrongstack/core/utils";
63
+ import { hasOpenTodos as hasOpenTodos3, mergeCustomModelDefs } from "@wrongstack/core/utils";
62
64
  import { capabilitiesFor } from "@wrongstack/providers";
63
65
  import { createToolVisionAdapters } from "@wrongstack/runtime/vision";
66
+ import { parseNextSteps as parseNextSteps2 } from "@wrongstack/tools/next-steps";
64
67
 
65
68
  // src/boot/dispatch-singleshot.ts
66
69
  import { color, writeOut } from "@wrongstack/core/utils";
@@ -201,13 +204,15 @@ async function runWebUIDispatch(ctx) {
201
204
  sddSubagentFactory,
202
205
  onKanbanDispatch,
203
206
  getFleetBudget,
207
+ stopSessionFleet,
208
+ onSessionRetired,
204
209
  webuiSessionChild
205
210
  } = ctx;
206
211
  const isSessionChild = Boolean(webuiSessionChild);
207
212
  const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
208
213
  agent.disableInteractiveConfirmation();
209
214
  renderer.setSilent(true);
210
- const { runWebUI } = await import("./webui-server-I53IYBW4.js");
215
+ const { runWebUI } = await import("./webui-server-LZOEH7O6.js");
211
216
  const flagValue = (names) => {
212
217
  for (const name of names) {
213
218
  if (!Object.hasOwn(flags, name)) continue;
@@ -262,7 +267,7 @@ async function runWebUIDispatch(ctx) {
262
267
  webuiPublicWsUrl = webuiSessionChild?.publicWsUrl ?? flagValue(["webui-public-ws-url", "public-ws-url"]) ?? process.env["WEBUI_PUBLIC_WS_URL"];
263
268
  webuiRequireToken = webuiSessionChild?.requireToken ?? flagBoolean(["webui-require-token", "require-token"]) ?? envFlag("WEBUI_REQUIRE_TOKEN");
264
269
  if (isSimpleUi) {
265
- const { ensureSimpleUiDistDir } = await import("./simpleui-dist-33VO3QHF.js");
270
+ const { ensureSimpleUiDistDir } = await import("./simpleui-dist-JKNRCRRK.js");
266
271
  frontendDistDir = await ensureSimpleUiDistDir();
267
272
  }
268
273
  } catch (err) {
@@ -307,6 +312,8 @@ async function runWebUIDispatch(ctx) {
307
312
  subscribeEternalIteration,
308
313
  sessionStore,
309
314
  ...getFleetBudget ? { getFleetBudget } : {},
315
+ ...stopSessionFleet ? { stopSessionFleet } : {},
316
+ ...onSessionRetired ? { onSessionRetired } : {},
310
317
  sessionsDir: projectSessionsDir,
311
318
  claimSession: activateSessionIdentity ? async (sessionId) => {
312
319
  const previousSessionId = agent.ctx.session?.id ?? session.id;
@@ -397,16 +404,18 @@ async function runWebUIDispatch(ctx) {
397
404
  },
398
405
  // Make autonomy.switch from the browser flip the CLI's real
399
406
  // autonomy mode — context.meta alone never reaches the run loop.
400
- onAutonomySwitch: (mode) => {
407
+ onAutonomySwitch: (mode, sessionId) => {
408
+ if (sessionId !== void 0 && sessionId !== agent.ctx.session?.id) return;
401
409
  if (mode === "off" || mode === "suggest" || mode === "auto" || mode === "eternal" || mode === "eternal-parallel") {
402
410
  onAutonomy?.(mode);
403
411
  }
404
412
  },
405
- onYoloSwitch: (enabled) => {
413
+ onYoloSwitch: (enabled, sessionId) => {
414
+ if (sessionId !== void 0 && sessionId !== agent.ctx.session?.id) return;
406
415
  applyLiveSettings?.({ yolo: enabled });
407
416
  },
408
417
  onWrongProxyPrefsChange: (payload) => {
409
- void import("./proxy-wiring-G26YGP7S.js").then(
418
+ void import("./proxy-wiring-EQB5X5YH.js").then(
410
419
  ({ applyWrongProxyPrefs }) => applyWrongProxyPrefs(payload)
411
420
  );
412
421
  }
@@ -858,6 +867,11 @@ async function getLiveSessions(ctx) {
858
867
  gitBranch: s.gitBranch,
859
868
  status: s.status,
860
869
  pid: s.pid,
870
+ // Which surface owns it — 'tui' | 'webui' | 'cli' | 'repl'. The /resume
871
+ // picker names it when it refuses a live session, because "open
872
+ // somewhere else" is not actionable and "open in the WebUI (pid 1234)"
873
+ // is. Optional on the registry entry for back-compat with older rows.
874
+ clientType: s.clientType,
861
875
  startedAt: s.startedAt,
862
876
  agentCount: s.agentCount,
863
877
  agents: s.agents.map((a) => ({
@@ -1198,7 +1212,7 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1198
1212
 
1199
1213
  // src/boot/tui-sdd-callback.ts
1200
1214
  async function getSDDContext() {
1201
- const { getActiveSDDContext: getActiveSDDContext2 } = await import("./sdd-runtime-GFZ3NJKS.js");
1215
+ const { getActiveSDDContext: getActiveSDDContext2 } = await import("./sdd-runtime-FLKCSTYV.js");
1202
1216
  return getActiveSDDContext2();
1203
1217
  }
1204
1218
  async function onSDDOutput(output) {
@@ -1209,7 +1223,7 @@ async function onSDDOutput(output) {
1209
1223
  autoDetectTaskCompletion: autoDetectTaskCompletion2,
1210
1224
  getTaskProgress: getTaskProgress2,
1211
1225
  getActiveSDDPhase: getActiveSDDPhase2
1212
- } = await import("./sdd-runtime-GFZ3NJKS.js");
1226
+ } = await import("./sdd-runtime-FLKCSTYV.js");
1213
1227
  const messages = [];
1214
1228
  const specSaved = await trySaveSpecFromAIOutput2(output);
1215
1229
  if (specSaved) messages.push("\u2713 Spec detected and saved! Use /sdd approve to continue.");
@@ -1239,11 +1253,61 @@ async function onSDDOutput(output) {
1239
1253
  // src/boot/tui-session-resume.ts
1240
1254
  import * as path7 from "node:path";
1241
1255
  import { attachTodosCheckpoint, loadTodosCheckpoint } from "@wrongstack/core/storage";
1256
+ import { projectLastRequestTokens } from "@wrongstack/core/types/session-timeline";
1242
1257
  import { sessionScopedPath as sessionScopedPath2 } from "@wrongstack/core/utils";
1258
+ var RESERVATION_WINDOW_MS = 6e4;
1259
+ var RESERVATION_RENEW_MS = 2e4;
1260
+ function messageText(content) {
1261
+ if (typeof content === "string") return content;
1262
+ if (!Array.isArray(content)) return "";
1263
+ return content.map(
1264
+ (block) => block && typeof block === "object" && "text" in block && typeof block.text === "string" ? block.text : ""
1265
+ ).filter(Boolean).join("\n");
1266
+ }
1267
+ function lastAssistantTextOf(messages) {
1268
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
1269
+ const message = messages[index];
1270
+ if (message?.role !== "assistant") continue;
1271
+ const text = messageText(message.content).trim();
1272
+ if (text) return text;
1273
+ }
1274
+ return void 0;
1275
+ }
1243
1276
  async function resumeSession(ctx, sessionId) {
1244
- const { state, agent, tokenCounter, switchProviderAndModel, events } = ctx;
1245
- if (!state.activeSessionStore) return null;
1246
- const { replaySessionMessages } = await import("@wrongstack/tui");
1277
+ const { state, agent, tokenCounter, switchProviderAndModel, events, onLoadProgress } = ctx;
1278
+ const fail = (stage2, message) => {
1279
+ try {
1280
+ ctx.onFailure?.({ stage: stage2, message: message || "unknown error" });
1281
+ } catch {
1282
+ }
1283
+ return null;
1284
+ };
1285
+ const warnings = [];
1286
+ const warn = (label, err) => {
1287
+ warnings.push(`${label}: ${err instanceof Error ? err.message : String(err)}`);
1288
+ };
1289
+ let stage = "start";
1290
+ const setStage = (next) => {
1291
+ stage = next;
1292
+ try {
1293
+ ctx.onStage?.(next);
1294
+ } catch {
1295
+ }
1296
+ };
1297
+ if (!state.activeSessionStore) {
1298
+ return fail("no_session_store", "No session store is bound to this project.");
1299
+ }
1300
+ setStage("load_replay_module");
1301
+ let replaySessionMessages;
1302
+ try {
1303
+ ({ replaySessionMessages } = await import("@wrongstack/tui"));
1304
+ if (typeof replaySessionMessages !== "function") {
1305
+ throw new TypeError("@wrongstack/tui does not export replaySessionMessages");
1306
+ }
1307
+ } catch (err) {
1308
+ return fail(stage, err instanceof Error ? err.message : String(err));
1309
+ }
1310
+ setStage("resolve_id");
1247
1311
  let canonicalSessionId = sessionId;
1248
1312
  try {
1249
1313
  if (state.activeSessionStore.resolveId) {
@@ -1259,34 +1323,66 @@ async function resumeSession(ctx, sessionId) {
1259
1323
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1260
1324
  })
1261
1325
  );
1262
- return null;
1326
+ return fail(stage, err instanceof Error ? err.message : String(err));
1263
1327
  }
1264
1328
  const previousSessionId = agent.ctx.session?.id;
1329
+ let hydrated;
1265
1330
  let identityClaimed = false;
1266
1331
  let resumeClaim;
1267
1332
  let writerSwapped = false;
1268
1333
  let openedWriter;
1269
1334
  let oldWriter;
1270
1335
  let oldMessages;
1336
+ let oldSessionRefCurrent;
1271
1337
  let previousDetachFn;
1272
1338
  let oldTodos = [];
1273
1339
  let oldPlanPath;
1274
1340
  let oldTaskPath;
1275
1341
  try {
1342
+ setStage("reserve_ownership");
1276
1343
  if (state.wpaths.projectSlug && state.wpaths.globalRoot) {
1277
1344
  const { getSessionRegistry } = await import("@wrongstack/core/storage");
1278
1345
  const registry = getSessionRegistry(state.wpaths.globalRoot);
1279
1346
  resumeClaim = await registry.reserveResume({
1280
1347
  sessionId: canonicalSessionId,
1281
1348
  projectSlug: state.wpaths.projectSlug,
1282
- projectRoot: state.projectRoot
1349
+ projectRoot: state.projectRoot,
1350
+ reservationMs: RESERVATION_WINDOW_MS
1283
1351
  });
1284
1352
  } else if (state.activateSessionIdentity) {
1285
1353
  await state.activateSessionIdentity(canonicalSessionId);
1286
1354
  identityClaimed = true;
1287
1355
  }
1288
- const resumed = await state.activeSessionStore.resume(canonicalSessionId);
1356
+ setStage("open_journal");
1357
+ const claimToRenew = resumeClaim;
1358
+ let renewFailures = 0;
1359
+ const renew = () => {
1360
+ if (!claimToRenew) return;
1361
+ void claimToRenew.renew(RESERVATION_WINDOW_MS).catch((err) => {
1362
+ if (renewFailures++ > 0) return;
1363
+ console.error(
1364
+ JSON.stringify({
1365
+ level: "warn",
1366
+ event: "execution.resume_reservation_renew_failed",
1367
+ sessionId: canonicalSessionId,
1368
+ message: err instanceof Error ? err.message : String(err),
1369
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1370
+ })
1371
+ );
1372
+ });
1373
+ };
1374
+ const renewTimer = setInterval(renew, RESERVATION_RENEW_MS);
1375
+ renewTimer.unref?.();
1376
+ let resumed;
1377
+ try {
1378
+ resumed = await state.activeSessionStore.resume(canonicalSessionId, onLoadProgress);
1379
+ } finally {
1380
+ clearInterval(renewTimer);
1381
+ }
1289
1382
  openedWriter = resumed.writer;
1383
+ hydrated = resumed.data;
1384
+ setStage("activate_ownership");
1385
+ await Promise.resolve(resumeClaim?.renew(RESERVATION_WINDOW_MS)).catch(() => void 0);
1290
1386
  if (resumeClaim) {
1291
1387
  await resumeClaim.activate({
1292
1388
  sessionId: canonicalSessionId,
@@ -1301,6 +1397,7 @@ async function resumeSession(ctx, sessionId) {
1301
1397
  identityClaimed = true;
1302
1398
  await state.activateSessionIdentity?.(canonicalSessionId);
1303
1399
  }
1400
+ setStage("replay_history");
1304
1401
  const meta = resumed.data.metadata;
1305
1402
  const entries = replaySessionMessages(
1306
1403
  resumed.data.messages,
@@ -1308,6 +1405,7 @@ async function resumeSession(ctx, sessionId) {
1308
1405
  /* startId */
1309
1406
  1
1310
1407
  );
1408
+ setStage("read_sidecars");
1311
1409
  const sessionsDir = state.wpaths.projectSessions;
1312
1410
  const resumedTodosPath = sessionScopedPath2(sessionsDir, resumed.writer.id, ".todos.json");
1313
1411
  const restoredTodos = await loadTodosCheckpoint(
@@ -1316,6 +1414,7 @@ async function resumeSession(ctx, sessionId) {
1316
1414
  agent.ctx.traceId,
1317
1415
  resumed.writer.id
1318
1416
  ).catch(() => null);
1417
+ setStage("swap_writer");
1319
1418
  oldWriter = agent.ctx.session;
1320
1419
  oldMessages = [...agent.ctx.messages];
1321
1420
  agent.ctx.session = resumed.writer;
@@ -1327,7 +1426,11 @@ async function resumeSession(ctx, sessionId) {
1327
1426
  throw err;
1328
1427
  }
1329
1428
  writerSwapped = true;
1330
- if (state.sessionRef) state.sessionRef.current = resumed.writer;
1429
+ if (state.sessionRef) {
1430
+ oldSessionRefCurrent = state.sessionRef.current;
1431
+ state.sessionRef.current = resumed.writer;
1432
+ }
1433
+ setStage("flush_journal");
1331
1434
  await agent.ctx.flushConversationJournal().catch((err) => {
1332
1435
  console.error(
1333
1436
  JSON.stringify({
@@ -1337,32 +1440,46 @@ async function resumeSession(ctx, sessionId) {
1337
1440
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1338
1441
  })
1339
1442
  );
1443
+ warn("conversation journal did not flush", err);
1340
1444
  });
1445
+ setStage("repoint_sidecars");
1341
1446
  previousDetachFn = state.detachActiveTodosCheckpoint;
1342
1447
  oldTodos = agent.ctx.state.todos ? [...agent.ctx.state.todos] : [];
1343
1448
  oldPlanPath = agent.ctx.state.meta?.["plan.path"];
1344
1449
  oldTaskPath = agent.ctx.state.meta?.["task.path"];
1345
- await Promise.resolve(previousDetachFn?.()).catch(() => void 0);
1346
- agent.ctx.state.setMeta(
1347
- "plan.path",
1348
- sessionScopedPath2(sessionsDir, resumed.writer.id, ".plan.json")
1349
- );
1350
- agent.ctx.state.setMeta(
1351
- "task.path",
1352
- sessionScopedPath2(sessionsDir, resumed.writer.id, ".tasks.json")
1353
- );
1354
- agent.ctx.state.replaceTodos(restoredTodos ?? []);
1355
1450
  try {
1356
- state.detachActiveTodosCheckpoint = attachTodosCheckpoint(
1357
- agent.ctx.state,
1358
- resumedTodosPath,
1359
- resumed.writer.id,
1360
- events,
1361
- agent.ctx.traceId
1451
+ await Promise.resolve(previousDetachFn?.()).catch(() => void 0);
1452
+ agent.ctx.state.setMeta(
1453
+ "plan.path",
1454
+ sessionScopedPath2(sessionsDir, resumed.writer.id, ".plan.json")
1362
1455
  );
1363
- } catch {
1364
- state.detachActiveTodosCheckpoint = void 0;
1456
+ agent.ctx.state.setMeta(
1457
+ "task.path",
1458
+ sessionScopedPath2(sessionsDir, resumed.writer.id, ".tasks.json")
1459
+ );
1460
+ agent.ctx.state.replaceTodos(restoredTodos ?? []);
1461
+ try {
1462
+ state.detachActiveTodosCheckpoint = attachTodosCheckpoint(
1463
+ agent.ctx.state,
1464
+ resumedTodosPath,
1465
+ resumed.writer.id,
1466
+ events,
1467
+ agent.ctx.traceId
1468
+ );
1469
+ } catch {
1470
+ state.detachActiveTodosCheckpoint = void 0;
1471
+ }
1472
+ } catch (err) {
1473
+ warn("todo/plan sidecars were not re-pointed", err);
1474
+ try {
1475
+ state.detachActiveTodosCheckpoint = previousDetachFn;
1476
+ agent.ctx.state.replaceTodos([...oldTodos]);
1477
+ if (oldPlanPath !== void 0) agent.ctx.state.setMeta("plan.path", oldPlanPath);
1478
+ if (oldTaskPath !== void 0) agent.ctx.state.setMeta("task.path", oldTaskPath);
1479
+ } catch {
1480
+ }
1365
1481
  }
1482
+ setStage("restore_model");
1366
1483
  const currentProviderId = agent.ctx.provider.id;
1367
1484
  const targetProviderId = typeof meta.provider === "string" && meta.provider.length > 0 ? meta.provider : currentProviderId;
1368
1485
  const targetModel = typeof meta.model === "string" && meta.model.length > 0 ? meta.model : agent.ctx.model;
@@ -1380,10 +1497,12 @@ async function resumeSession(ctx, sessionId) {
1380
1497
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1381
1498
  })
1382
1499
  );
1500
+ warn(`could not restore ${targetProviderId}/${targetModel}`, err);
1383
1501
  }
1384
1502
  } else if (targetModel !== agent.ctx.model) {
1385
1503
  agent.ctx.model = targetModel;
1386
1504
  }
1505
+ setStage("finalize_previous_session");
1387
1506
  let finalizeOldWriter;
1388
1507
  if (oldWriter && oldWriter !== resumed.writer) {
1389
1508
  const staleWriter = oldWriter;
@@ -1423,19 +1542,27 @@ async function resumeSession(ctx, sessionId) {
1423
1542
  }
1424
1543
  };
1425
1544
  }
1426
- tokenCounter.reset();
1427
- tokenCounter.account(resumed.data.usage, targetModel, targetProviderId);
1428
- if (typeof resumed.data.usage?.input === "number" && resumed.data.usage.input > 0) {
1429
- agent.ctx.lastRequestTokens = resumed.data.usage.input;
1545
+ setStage("token_accounting");
1546
+ try {
1547
+ tokenCounter.reset();
1548
+ tokenCounter.account(resumed.data.usage, targetModel, targetProviderId);
1549
+ } catch (err) {
1550
+ warn("token accounting for the resumed session failed", err);
1430
1551
  }
1431
- const reqTokens = tokenCounter.currentRequestTokens?.();
1432
- const tokens = (typeof reqTokens === "number" ? reqTokens : 0) + (typeof reqTokens?.input === "number" ? reqTokens.input : 0) + (typeof reqTokens?.cacheRead === "number" ? reqTokens.cacheRead : 0) + (typeof reqTokens?.cacheWrite === "number" ? reqTokens.cacheWrite : 0);
1552
+ const resumedRequestTokens = projectLastRequestTokens(resumed.data.events);
1553
+ agent.ctx.lastRequestTokens = resumedRequestTokens;
1554
+ tokenCounter.setCurrentRequestTokens?.(resumedRequestTokens ?? 0);
1555
+ const tokens = resumedRequestTokens ?? 0;
1433
1556
  const maxContext = agent.ctx.provider?.capabilities?.maxContext ?? 0;
1557
+ const finalText = lastAssistantTextOf(resumed.data.messages);
1434
1558
  const result = {
1435
1559
  entries,
1436
1560
  nextId: entries.length + 1,
1437
1561
  sessionId: resumed.writer.id,
1438
- contextSnapshot: { tokens, maxContext }
1562
+ contextSnapshot: { tokens, maxContext },
1563
+ attached: true,
1564
+ warnings,
1565
+ ...finalText !== void 0 ? { lastAssistantText: finalText } : {}
1439
1566
  };
1440
1567
  if (finalizeOldWriter) void finalizeOldWriter();
1441
1568
  return result;
@@ -1459,6 +1586,7 @@ async function resumeSession(ctx, sessionId) {
1459
1586
  } else {
1460
1587
  try {
1461
1588
  if (oldWriter !== void 0) agent.ctx.session = oldWriter;
1589
+ if (state.sessionRef) state.sessionRef.current = oldSessionRefCurrent;
1462
1590
  if (oldMessages !== void 0) agent.ctx.state.replaceMessages(oldMessages);
1463
1591
  if (previousDetachFn !== void 0) state.detachActiveTodosCheckpoint = previousDetachFn;
1464
1592
  agent.ctx.state.replaceTodos([...oldTodos]);
@@ -1474,16 +1602,76 @@ async function resumeSession(ctx, sessionId) {
1474
1602
  })
1475
1603
  );
1476
1604
  }
1605
+ if (openedWriter && openedWriter !== oldWriter) {
1606
+ await openedWriter.close().catch((closeErr) => {
1607
+ console.error(
1608
+ JSON.stringify({
1609
+ level: "error",
1610
+ event: "execution.resume_opened_writer_close_failed",
1611
+ message: closeErr instanceof Error ? closeErr.message : String(closeErr),
1612
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1613
+ })
1614
+ );
1615
+ });
1616
+ }
1477
1617
  }
1618
+ const reason = err instanceof Error ? err.stack ?? err.message : String(err);
1478
1619
  console.error(
1479
1620
  JSON.stringify({
1480
1621
  level: "error",
1481
1622
  event: "execution.resume_session_failed",
1482
- message: err instanceof Error ? err.message : String(err),
1623
+ sessionId: canonicalSessionId,
1624
+ stage,
1625
+ message: reason,
1483
1626
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1484
1627
  })
1485
1628
  );
1486
- return null;
1629
+ const message = err instanceof Error ? err.message : String(err);
1630
+ if (err instanceof Error && err.name === "SessionOwnershipConflictError") {
1631
+ return fail(stage, message);
1632
+ }
1633
+ let data = hydrated;
1634
+ if (!data) {
1635
+ try {
1636
+ data = await state.activeSessionStore.load(canonicalSessionId, onLoadProgress);
1637
+ } catch {
1638
+ data = void 0;
1639
+ }
1640
+ }
1641
+ if (data) {
1642
+ try {
1643
+ const entries = replaySessionMessages(
1644
+ data.messages,
1645
+ data.events,
1646
+ /* startId */
1647
+ 1
1648
+ );
1649
+ const finalText = lastAssistantTextOf(data.messages);
1650
+ fail(stage, message);
1651
+ return {
1652
+ entries,
1653
+ nextId: entries.length + 1,
1654
+ sessionId: canonicalSessionId,
1655
+ // Deliberately no contextSnapshot: the chip reports the LIVE
1656
+ // window, and the live session is still the one we rolled back to.
1657
+ // Painting the viewed session's fill over it would be a lie.
1658
+ attached: false,
1659
+ warnings: [...warnings, `not attached (at ${stage}): ${message}`],
1660
+ ...finalText !== void 0 ? { lastAssistantText: finalText } : {}
1661
+ };
1662
+ } catch (renderErr) {
1663
+ console.error(
1664
+ JSON.stringify({
1665
+ level: "error",
1666
+ event: "execution.resume_readonly_render_failed",
1667
+ sessionId: canonicalSessionId,
1668
+ message: renderErr instanceof Error ? renderErr.message : String(renderErr),
1669
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1670
+ })
1671
+ );
1672
+ }
1673
+ }
1674
+ return fail(stage, message);
1487
1675
  }
1488
1676
  }
1489
1677
 
@@ -1492,6 +1680,8 @@ import * as fs3 from "node:fs/promises";
1492
1680
  import * as path8 from "node:path";
1493
1681
  var SLICE_BYTES = 256 * 1024;
1494
1682
  var MAX_TITLE_CHARS = 80;
1683
+ var PICKER_POOL_CEILING = 1500;
1684
+ var ENRICH_CONCURRENCY = 16;
1495
1685
  function isStubSummary(s) {
1496
1686
  return !s.title && !s.endedAt;
1497
1687
  }
@@ -1502,7 +1692,10 @@ function containedJsonlPath(sessionsDir, id) {
1502
1692
  return file;
1503
1693
  }
1504
1694
  function stripControlChars(text) {
1505
- return text.replaceAll(/\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07]*(?:\x07|\x1b\\)|[\u0000-\u001f\u007f-\u009f]/g, "");
1695
+ return text.replaceAll(
1696
+ /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07]*(?:\x07|\x1b\\)|[\u0000-\u001f\u007f-\u009f]/g,
1697
+ ""
1698
+ );
1506
1699
  }
1507
1700
  function truncate(text) {
1508
1701
  const oneLine = stripControlChars(text).replaceAll(/\s+/g, " ").trim();
@@ -1574,32 +1767,48 @@ async function lastUserInput(file) {
1574
1767
  function effectiveLastActivity(s) {
1575
1768
  return s.lastActivityAt ?? s.endedAt ?? s.startedAt ?? "";
1576
1769
  }
1770
+ function hasActivity(s) {
1771
+ return (s.messageCount ?? 0) > 0 || (s.iterationCount ?? 0) > 0 || (s.toolCallCount ?? 0) > 0 || (s.tokenTotal ?? 0) > 0 || Boolean(s.title?.trim()) || Boolean(s.lastUserMessage?.trim());
1772
+ }
1577
1773
  async function selectPickerSessions(storeList, sessionsDir, limit) {
1578
- const poolSize = Math.min(200, Math.max(limit, limit * 3));
1774
+ const poolSize = Math.max(limit, Math.min(PICKER_POOL_CEILING, limit * 3));
1579
1775
  const enriched = await enrichStubSummaries(await storeList(poolSize), sessionsDir);
1580
- return enriched.sort((a, b) => effectiveLastActivity(b).localeCompare(effectiveLastActivity(a))).slice(0, limit);
1776
+ return enriched.filter(hasActivity).sort((a, b) => effectiveLastActivity(b).localeCompare(effectiveLastActivity(a))).slice(0, limit);
1581
1777
  }
1582
1778
  async function enrichStubSummaries(summaries, sessionsDir) {
1583
- return Promise.all(
1584
- summaries.map(async (s) => {
1585
- if (!isStubSummary(s)) return s;
1586
- const file = containedJsonlPath(sessionsDir, s.id);
1587
- if (!file) return s;
1779
+ const out = [...summaries];
1780
+ const pending = summaries.reduce((indexes, summary, index) => {
1781
+ if (isStubSummary(summary)) indexes.push(index);
1782
+ return indexes;
1783
+ }, []);
1784
+ if (pending.length === 0) return out;
1785
+ let cursor = 0;
1786
+ const worker = async () => {
1787
+ for (; ; ) {
1788
+ const slot = cursor++;
1789
+ if (slot >= pending.length) return;
1790
+ const index = pending[slot];
1791
+ const summary = out[index];
1792
+ const file = containedJsonlPath(sessionsDir, summary.id);
1793
+ if (!file) continue;
1588
1794
  try {
1589
1795
  const stat3 = await fs3.stat(file);
1590
1796
  const [first, last] = await Promise.all([firstUserInput(file), lastUserInput(file)]);
1591
1797
  const title = truncate(first?.text ?? "");
1592
- return {
1593
- ...s,
1798
+ out[index] = {
1799
+ ...summary,
1594
1800
  ...title ? { title } : {},
1595
1801
  ...last ? { lastUserMessage: truncate(last.text) } : {},
1596
1802
  lastActivityAt: stat3.mtime.toISOString()
1597
1803
  };
1598
1804
  } catch {
1599
- return s;
1600
1805
  }
1601
- })
1806
+ }
1807
+ };
1808
+ await Promise.all(
1809
+ Array.from({ length: Math.min(ENRICH_CONCURRENCY, pending.length) }, () => worker())
1602
1810
  );
1811
+ return out;
1603
1812
  }
1604
1813
 
1605
1814
  // src/boot/tui-settings-adapter.ts
@@ -1695,6 +1904,7 @@ function createSettingsAdapter(ctx) {
1695
1904
  thinkingWord: normalizeTuiThinkingWord(autonomy?.thinkingWord),
1696
1905
  animationStyle: normalizeAnimationStyle(autonomy?.animationStyle),
1697
1906
  configScope: cfg.configScope ?? "global",
1907
+ systemPromptVariant: cfg.systemPrompt?.variant === "lite" || cfg.systemPrompt?.variant === "pro" ? cfg.systemPrompt.variant : "default",
1698
1908
  enhanceDelayMs: cfg.autonomy?.enhanceDelayMs ?? 6e4,
1699
1909
  enhanceEnabled: cfg.autonomy?.enhance ?? true,
1700
1910
  enhanceLanguage: cfg.autonomy?.enhanceLanguage === "english" ? "english" : "original",
@@ -2451,7 +2661,7 @@ async function finalizeExecutionCleanup(input) {
2451
2661
  })
2452
2662
  );
2453
2663
  } else {
2454
- const { reportWrongTraceSessionTelemetry } = await import("./wrongtrace-telemetry-6M2CCBX5.js");
2664
+ const { reportWrongTraceSessionTelemetry } = await import("./wrongtrace-telemetry-FNLANZ5I.js");
2455
2665
  const usage = tokenCounter.total();
2456
2666
  const report = reportWrongTraceSessionTelemetry({
2457
2667
  sessionId: activeSession.id,
@@ -2577,10 +2787,12 @@ import { stripFrontmatter } from "@wrongstack/core/skills";
2577
2787
 
2578
2788
  // src/kanban-dispatch-route.ts
2579
2789
  import { fallbackProfileChain, parseModelRef as parseModelRef2 } from "@wrongstack/core/agent";
2790
+ import { resolveTier } from "@wrongstack/core/coordination";
2580
2791
  function resolveKanbanDispatchRoute(config, spawnOpts) {
2581
2792
  let provider = spawnOpts?.provider;
2582
2793
  let model = spawnOpts?.model;
2583
2794
  let fallbackModels = spawnOpts?.fallbackModels;
2795
+ let tier;
2584
2796
  if (spawnOpts?.fallbackProfile) {
2585
2797
  const chain = fallbackProfileChain(config, spawnOpts.fallbackProfile);
2586
2798
  const primary = chain[0] ? parseModelRef2(chain[0]) : void 0;
@@ -2589,8 +2801,19 @@ function resolveKanbanDispatchRoute(config, spawnOpts) {
2589
2801
  model = primary.model;
2590
2802
  fallbackModels = spawnOpts.fallbackModels ?? chain.slice(1);
2591
2803
  }
2804
+ } else if (spawnOpts?.tier || spawnOpts?.role) {
2805
+ const resolved = resolveTier(config, {
2806
+ ...spawnOpts.tier ? { tier: spawnOpts.tier } : {},
2807
+ ...spawnOpts.role ? { role: spawnOpts.role } : {}
2808
+ });
2809
+ if (resolved?.model) {
2810
+ tier = resolved.tier;
2811
+ provider = provider ?? resolved.provider ?? config.provider;
2812
+ model = model ?? resolved.model;
2813
+ fallbackModels = fallbackModels ?? (resolved.fallbackModels?.slice() ?? void 0);
2814
+ }
2592
2815
  }
2593
- return { provider, model, fallbackModels };
2816
+ return { provider, model, fallbackModels, ...tier ? { tier } : {} };
2594
2817
  }
2595
2818
 
2596
2819
  // src/execution-kanban-dispatch.ts
@@ -3156,7 +3379,14 @@ function buildChimeraReviewTaskDescription(p) {
3156
3379
  lines.push("```");
3157
3380
  } else if (f.status === "added") {
3158
3381
  lines.push("");
3159
- lines.push("(New file \u2014 full content provided)");
3382
+ if (f.content && f.content.length <= 25e3) {
3383
+ lines.push("(New file content:)");
3384
+ lines.push("```");
3385
+ lines.push(f.content);
3386
+ lines.push("```");
3387
+ } else {
3388
+ lines.push("(New file \u2014 large content, use read tool only if needed)");
3389
+ }
3160
3390
  }
3161
3391
  lines.push("");
3162
3392
  }
@@ -3218,10 +3448,11 @@ function buildChimeraReviewTaskDescription(p) {
3218
3448
  }
3219
3449
  lines.push("---");
3220
3450
  lines.push("");
3221
- lines.push("Read each file using the read tool. For modified files, focus on the");
3222
- lines.push("diff above \u2014 do not re-review unchanged pre-existing code.");
3223
- lines.push("Check for bugs, type issues, security problems, and produce a");
3224
- lines.push("structured review report.");
3451
+ lines.push("**Review Instructions:**");
3452
+ lines.push("- Review the diffs and new file contents carefully for real bugs, broken logic, null dereferences, and security gaps.");
3453
+ lines.push("- Stay strictly within the scoped diffs. DO NOT audit unchanged files, pre-existing debt, or stylistic preferences.");
3454
+ lines.push("- Use tools only when you need surrounding lines to verify a concrete issue.");
3455
+ lines.push("- Once the diff is validated, output your report (findings or all-clear) promptly.");
3225
3456
  return lines.join("\n");
3226
3457
  }
3227
3458
  var CASCADE_EVIDENCE_INSTRUCTIONS = [
@@ -5317,12 +5548,15 @@ function createTuiNextStepCallbacks(input) {
5317
5548
 
5318
5549
  // src/tui-resource-menus.ts
5319
5550
  import { readdir } from "node:fs/promises";
5551
+ import { leaderTierPolicy, resolveTier as resolveTier2 } from "@wrongstack/core/coordination";
5320
5552
  import { readJsonObjectFile } from "@wrongstack/core/utils";
5321
5553
  function createTuiResourceMenuGetter(ctx) {
5322
5554
  return async (id) => {
5323
5555
  switch (id) {
5324
5556
  case "fallback":
5325
5557
  return fallbackMenu(ctx.configStore);
5558
+ case "tier":
5559
+ return tierMenu(ctx.configStore);
5326
5560
  case "profile":
5327
5561
  return profileMenu(ctx.configStore, ctx.paths);
5328
5562
  case "provider-status":
@@ -5425,6 +5659,95 @@ function fallbackMenu(store) {
5425
5659
  items
5426
5660
  };
5427
5661
  }
5662
+ function tierMenu(store) {
5663
+ const config = store.get();
5664
+ const tiers = config.modelTiers;
5665
+ const enabled = tiers?.enabled === true;
5666
+ const levels = tiers?.levels ?? {};
5667
+ const routing = tiers?.routing ?? {};
5668
+ const policy = leaderTierPolicy(config);
5669
+ const levelIds = Object.keys(levels);
5670
+ const items = [
5671
+ {
5672
+ id: "enabled",
5673
+ label: "Model tiers",
5674
+ status: enabled ? "good" : "muted",
5675
+ summary: enabled ? "enabled" : "disabled",
5676
+ details: [
5677
+ { label: "levels", value: String(levelIds.length) },
5678
+ { label: "routing rules", value: String(Object.keys(routing).length) },
5679
+ { label: "default", value: tiers?.default ?? "standard" }
5680
+ ],
5681
+ body: "A tier binds a fallback profile, a spend budget and a runtime setting under one name, then routes work to it by role or phase. While disabled, spawns resolve exactly as they did before tiers existed.",
5682
+ actions: [
5683
+ { key: "t", label: enabled ? "turn off" : "turn on", command: `/tier ${enabled ? "off" : "on"}` }
5684
+ ]
5685
+ },
5686
+ {
5687
+ id: "leader",
5688
+ label: "Leader self-switching",
5689
+ status: policy.mode === "auto" ? "warn" : policy.mode === "propose" ? "good" : "muted",
5690
+ summary: policy.mode,
5691
+ details: [
5692
+ { label: "mode", value: policy.mode },
5693
+ { label: "dwell", value: `${policy.dwellTurns} turn(s)` },
5694
+ { label: "min saving", value: `$${policy.minSavingsUsd}` },
5695
+ { label: "context cap", value: `${Math.round(policy.maxContextFillForSwitch * 100)}%` },
5696
+ { label: "ceiling", value: policy.maxTier ?? "none" }
5697
+ ],
5698
+ body: "propose (default): the leader asks before changing its own model. auto: it applies the switch itself, still bounded by dwell, context window, ceiling and a break-even test against the prompt-cache re-warm the switch costs. off: it never self-switches.",
5699
+ actions: [
5700
+ { key: "p", label: "propose", command: "/tier leader propose" },
5701
+ { key: "a", label: "auto", command: "/tier leader auto", confirm: true },
5702
+ { key: "o", label: "off", command: "/tier leader off" }
5703
+ ]
5704
+ },
5705
+ ...levelIds.map((id, index) => {
5706
+ const level = levels[id];
5707
+ const resolved = enabled ? resolveTier2(config, { tier: id }) : void 0;
5708
+ const routedBy = Object.entries(routing).filter(([, value]) => value === id).map(([key]) => key);
5709
+ return {
5710
+ id: `level:${id}`,
5711
+ label: `${index + 1}. ${id}`,
5712
+ status: level?.fallbackProfile ? "good" : "muted",
5713
+ summary: resolved?.model ? `${resolved.provider ?? config.provider}/${resolved.model}` : level?.fallbackProfile ?? "(no profile)",
5714
+ details: [
5715
+ { label: "rung", value: `${index + 1} of ${levelIds.length}` },
5716
+ { label: "profile", value: level?.fallbackProfile ?? "(none)" },
5717
+ { label: "max cost", value: level?.maxCostUsd !== void 0 ? `$${level.maxCostUsd}` : "(role default)" },
5718
+ { label: "max iterations", value: level?.maxIterations !== void 0 ? String(level.maxIterations) : "(role default)" },
5719
+ { label: "routed by", value: routedBy.join(", ") || "(nothing)" }
5720
+ ],
5721
+ body: [
5722
+ resolved?.fallbackModels?.length ? `Failover: ${resolved.fallbackModels.join(" \u2192 ")}` : "No failover chain \u2014 the profile has a single entry.",
5723
+ "Declaration order is the ladder: rung 1 is the cheapest."
5724
+ ].join("\n"),
5725
+ actions: [
5726
+ { key: "x", label: "delete", command: `/tier remove ${id}`, confirm: true },
5727
+ { key: "d", label: "make default", command: `/tier default ${id}` }
5728
+ ]
5729
+ };
5730
+ }),
5731
+ ...Object.entries(routing).sort(([a], [b]) => a.localeCompare(b)).map(([key, tier]) => ({
5732
+ id: `route:${key}`,
5733
+ label: `${key} \u2192 ${tier}`,
5734
+ status: levels[tier] ? "good" : "warn",
5735
+ summary: levels[tier] ? "routing rule" : "points at a missing level",
5736
+ details: [
5737
+ { label: "key", value: key },
5738
+ { label: "tier", value: tier },
5739
+ { label: "kind", value: key === "*" ? "default" : "role or phase" }
5740
+ ],
5741
+ actions: [{ key: "x", label: "remove", command: `/tier unroute ${key}`, confirm: true }]
5742
+ }))
5743
+ ];
5744
+ return {
5745
+ id: "tier",
5746
+ title: "Model cost tiers",
5747
+ subtitle: enabled ? `${levelIds.length} level(s) \xB7 ${Object.keys(routing).length} rule(s) \xB7 leader: ${policy.mode}` : "disabled",
5748
+ items
5749
+ };
5750
+ }
5428
5751
  async function profileMenu(store, paths) {
5429
5752
  const active = store.get().activeProfile ?? paths.profileName ?? "default";
5430
5753
  let names = [];
@@ -5744,6 +6067,7 @@ async function execute(deps) {
5744
6067
  fleet: {
5745
6068
  director,
5746
6069
  getDirector,
6070
+ releaseSessionHelpers,
5747
6071
  coordinatorController,
5748
6072
  fleetRoster,
5749
6073
  fleetStreamController,
@@ -5756,12 +6080,16 @@ async function execute(deps) {
5756
6080
  interruptController,
5757
6081
  enhanceController,
5758
6082
  getEnhancerReasoning,
6083
+ getActiveModelReasoningEffortLevels,
5759
6084
  buildEnhancerProvider,
5760
6085
  getEnhanceFallbackRef,
5761
6086
  getConfiguredRefinerRef,
5762
6087
  statuslineHiddenItems,
5763
6088
  setStatuslineHiddenItems,
5764
6089
  saveStatuslineHiddenItems,
6090
+ statuslineLines,
6091
+ setStatuslineLines,
6092
+ saveStatuslineLines,
5765
6093
  getYolo,
5766
6094
  onYolo,
5767
6095
  getAutonomy,
@@ -6054,12 +6382,16 @@ async function execute(deps) {
6054
6382
  interruptController,
6055
6383
  enhanceController,
6056
6384
  getEnhancerReasoning,
6385
+ getActiveModelReasoningEffortLevels,
6057
6386
  buildEnhancerProvider,
6058
6387
  getEnhanceFallbackRef,
6059
6388
  getConfiguredRefinerRef,
6060
6389
  statuslineHiddenItems,
6061
6390
  setStatuslineHiddenItems,
6062
6391
  saveStatuslineHiddenItems,
6392
+ statuslineLines,
6393
+ setStatuslineLines,
6394
+ saveStatuslineLines,
6063
6395
  getPluginItems,
6064
6396
  onPluginToggle,
6065
6397
  getMcpServers,
@@ -6121,6 +6453,17 @@ async function execute(deps) {
6121
6453
  wpaths.projectSessions,
6122
6454
  limit
6123
6455
  );
6456
+ const liveBySession = /* @__PURE__ */ new Map();
6457
+ try {
6458
+ for (const entry of await getLiveSessions({ state })) {
6459
+ if (entry.pid == null) continue;
6460
+ liveBySession.set(entry.sessionId, {
6461
+ pid: entry.pid,
6462
+ ...entry.clientType ? { clientType: entry.clientType } : {}
6463
+ });
6464
+ }
6465
+ } catch {
6466
+ }
6124
6467
  const currentId = agent.ctx.session?.id ?? session.id;
6125
6468
  return summaries.map((s) => ({
6126
6469
  id: s.id,
@@ -6136,13 +6479,39 @@ async function execute(deps) {
6136
6479
  toolCallCount: s.toolCallCount ?? 0,
6137
6480
  toolErrorCount: s.toolErrorCount ?? 0,
6138
6481
  outcome: s.outcome,
6139
- isCurrent: s.id === currentId
6482
+ isCurrent: s.id === currentId,
6483
+ // The session this process owns is `isCurrent`, not "live
6484
+ // elsewhere" — it holds its own lease and would otherwise be
6485
+ // labelled as owned by another surface.
6486
+ ...s.id !== currentId && liveBySession.has(s.id) ? { live: liveBySession.get(s.id) } : {}
6140
6487
  }));
6141
6488
  },
6142
- onResumeSession: (sessionId) => resumeSession(
6143
- { state, agent, tokenCounter, switchProviderAndModel, events },
6144
- sessionId
6145
- ),
6489
+ onResumeSession: async (sessionId, onLoadProgress, onStage) => {
6490
+ let failure;
6491
+ const result = await resumeSession(
6492
+ {
6493
+ state,
6494
+ agent,
6495
+ tokenCounter,
6496
+ switchProviderAndModel,
6497
+ events,
6498
+ onLoadProgress,
6499
+ onStage,
6500
+ onFailure: (info) => {
6501
+ failure = info;
6502
+ }
6503
+ },
6504
+ sessionId
6505
+ );
6506
+ if (!result) {
6507
+ throw new Error(
6508
+ failure ? `${failure.message} (at ${failure.stage})` : `Session "${sessionId}" could not be resumed.`
6509
+ );
6510
+ }
6511
+ setAutoSuggestions([]);
6512
+ const resumedNextSteps = result.attached && !hasOpenTodos3(agent.ctx.todos) && result.lastAssistantText ? parseNextSteps2(result.lastAssistantText).texts : [];
6513
+ return { ...result, nextSteps: resumedNextSteps };
6514
+ },
6146
6515
  getProjectPickerItems: () => getProjectPickerItems(pickerCtx),
6147
6516
  onProjectSelect: (slug, kind) => onProjectSelect(pickerCtx, slug, kind),
6148
6517
  initialAgentsMonitorOpen: !!flags.quick,
@@ -6198,6 +6567,19 @@ async function execute(deps) {
6198
6567
  statusTracker,
6199
6568
  updateInfo: bootUpdateInfo,
6200
6569
  webuiSessionChild,
6570
+ // Stopping a tab's run stops the work that tab started — its
6571
+ // subagents included. Aborting the leader's controller only unwinds
6572
+ // workers it is BLOCKED on; anything started with `spawn_subagent` +
6573
+ // `assign_task` keeps going unless asked to stop. Scoped to the
6574
+ // session so one tab's Stop never reaches another tab's fleet.
6575
+ stopSessionFleet: async (sessionId) => {
6576
+ await getDirector?.()?.terminateSession(sessionId);
6577
+ },
6578
+ // Closing a tab is not stopping it. The run keeps going and keeps its
6579
+ // fleet; what goes is the background help pinned to that conversation
6580
+ // — the explore companion's poll timer and the shadow reviewer's
6581
+ // bookkeeping — which nobody is watching any more.
6582
+ ...releaseSessionHelpers ? { onSessionRetired: releaseSessionHelpers } : {},
6201
6583
  getFleetBudget: () => {
6202
6584
  const d = getDirector?.() ?? null;
6203
6585
  if (!d) return null;
@@ -6305,4 +6687,4 @@ export {
6305
6687
  execute,
6306
6688
  resolveReviewerFallbackModels
6307
6689
  };
6308
- //# sourceMappingURL=execution-L4CXQEND.js.map
6690
+ //# sourceMappingURL=execution-TZUGCKFU.js.map