frizz-server 0.15.4 → 0.15.5

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 (98) hide show
  1. package/dist/dev-child.js +259 -93
  2. package/package.json +1 -1
  3. package/runtime/cc-worker/bin/frizz-mcp.mjs +21 -2
  4. package/web-dist/assets/{abnfDiagram-VRR7QNED-BxfU2ky7.js → abnfDiagram-VRR7QNED-CbqOYv6J.js} +1 -1
  5. package/web-dist/assets/{arc-CgErjH1d.js → arc-C7pirKdF.js} +1 -1
  6. package/web-dist/assets/architecture-TIHT7OUA-Bd5iF22L.js +1 -0
  7. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-DFARVJoN.js → architectureDiagram-ZJ3FMSHR-GSvfiia8.js} +1 -1
  8. package/web-dist/assets/{blockDiagram-677ZJIJ3-BS3Cwm7J.js → blockDiagram-677ZJIJ3-CEoI_nEr.js} +1 -1
  9. package/web-dist/assets/{c4Diagram-LMCZKHZV-Ib3IHrEi.js → c4Diagram-LMCZKHZV-Db0N8ZKZ.js} +1 -1
  10. package/web-dist/assets/channel-Bagqh84I.js +1 -0
  11. package/web-dist/assets/{chunk-32BRIVSS-ByRx6NUK.js → chunk-32BRIVSS-DT3immeA.js} +1 -1
  12. package/web-dist/assets/{chunk-52WLFC77-hjwNAryc.js → chunk-52WLFC77-D3HCw3CA.js} +1 -1
  13. package/web-dist/assets/{chunk-C7G6YPKG-C6Ad4Bd0.js → chunk-C7G6YPKG-DW27d4eB.js} +1 -1
  14. package/web-dist/assets/{chunk-EX3LRPZG-CQVUaGoV.js → chunk-EX3LRPZG-OPZph9SR.js} +1 -1
  15. package/web-dist/assets/{chunk-FWX5IMBZ-CZTMmNQk.js → chunk-FWX5IMBZ-Bm9FHMa7.js} +2 -2
  16. package/web-dist/assets/{chunk-HOUHSVGY-C6BUv_ws.js → chunk-HOUHSVGY-BTOEnIzu.js} +1 -1
  17. package/web-dist/assets/{chunk-ICXQ74PX-oh3XyLFV.js → chunk-ICXQ74PX-zs-5RXZE.js} +1 -1
  18. package/web-dist/assets/{chunk-MOJQB5TN-Bp7LUwam.js → chunk-MOJQB5TN-DOsCoW_N.js} +1 -1
  19. package/web-dist/assets/{chunk-OGEWGWER-sAmFDKFT.js → chunk-OGEWGWER-BZIl0Yj7.js} +1 -1
  20. package/web-dist/assets/{chunk-PUDLZKDR-DlN32NhF.js → chunk-PUDLZKDR-5eWMPQZ0.js} +1 -1
  21. package/web-dist/assets/{chunk-Q4XR5HBZ-DEjynXCt.js → chunk-Q4XR5HBZ-BtHztk0F.js} +1 -1
  22. package/web-dist/assets/{chunk-RYQCIY6F-CZehtcWj.js → chunk-RYQCIY6F-DlTYPhZ8.js} +1 -1
  23. package/web-dist/assets/{chunk-V7JOEXUC-DMBTmrLA.js → chunk-V7JOEXUC-YalOqDL7.js} +1 -1
  24. package/web-dist/assets/{chunk-VAUOI2AC-pLTcMAXA.js → chunk-VAUOI2AC-M_2D8Gwk.js} +1 -1
  25. package/web-dist/assets/{chunk-VR4S4FIN-B31zgsto.js → chunk-VR4S4FIN-HZPLNG7A.js} +1 -1
  26. package/web-dist/assets/{chunk-WYO6CB5R-BYr0TKte.js → chunk-WYO6CB5R-gtQVqXEb.js} +1 -1
  27. package/web-dist/assets/{chunk-XXDRQBXY-DezATMt-.js → chunk-XXDRQBXY-CsAuYtU4.js} +1 -1
  28. package/web-dist/assets/{chunk-ZGVPDNZ5-BZRpC7D4.js → chunk-ZGVPDNZ5-DtcuYy6F.js} +1 -1
  29. package/web-dist/assets/classDiagram-OUVF2IWQ-DXPARKeI.js +1 -0
  30. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DXPARKeI.js +1 -0
  31. package/web-dist/assets/{cose-bilkent-JH36ORCC-DCj8LJT7.js → cose-bilkent-JH36ORCC-DN8G4z--.js} +1 -1
  32. package/web-dist/assets/{cynefin-VYW2F7L2-BdtJMX-t.js → cynefin-VYW2F7L2-DmE5ulRO.js} +1 -1
  33. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-CmCMm_Wq.js → cynefinDiagram-TSTJHNR4-D_EVG7EI.js} +1 -1
  34. package/web-dist/assets/{dagre-VKFMJZFB-DjAmUhWm.js → dagre-VKFMJZFB-B7qpCNzR.js} +1 -1
  35. package/web-dist/assets/{diagram-FQU43EPY-0jj1-eWC.js → diagram-FQU43EPY-XJ39UoQP.js} +1 -1
  36. package/web-dist/assets/{diagram-G47NLZAW-CwnRmOlr.js → diagram-G47NLZAW-CU3wW01X.js} +1 -1
  37. package/web-dist/assets/{diagram-NH7WQ7WH-CeATVwIZ.js → diagram-NH7WQ7WH-Cb2jmTDE.js} +1 -1
  38. package/web-dist/assets/{diagram-OA4YK3LP-yi-rZaxR.js → diagram-OA4YK3LP-Du53ln1W.js} +1 -1
  39. package/web-dist/assets/{diagram-WEI45ONY-DGA41j7G.js → diagram-WEI45ONY-EYSYIJXB.js} +1 -1
  40. package/web-dist/assets/{dist-ClPP980o.js → dist-Coq6Bx6Y.js} +1 -1
  41. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-BQ0eK7BV.js → ebnfDiagram-CCIWWBDH-Bq4LpJn6.js} +1 -1
  42. package/web-dist/assets/{erDiagram-Q63AITRT-BNjpwgDH.js → erDiagram-Q63AITRT-Beo30eeI.js} +1 -1
  43. package/web-dist/assets/eventmodeling-45OFAUF4-DmLge5-D.js +1 -0
  44. package/web-dist/assets/flowDiagram-23GEKE2U-rndT3Z05.js +1 -0
  45. package/web-dist/assets/{ganttDiagram-NO4QXBWP-C4na1dCg.js → ganttDiagram-NO4QXBWP-BBC4eUEO.js} +1 -1
  46. package/web-dist/assets/{gitGraph-TEB2WS4Q-r5HbDgDu.js → gitGraph-TEB2WS4Q-DEGavvzP.js} +1 -1
  47. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-Ezyr9l2F.js → gitGraphDiagram-IHSO6WYX-CULHtc5i.js} +1 -1
  48. package/web-dist/assets/index-BtlZUVLY.css +2 -0
  49. package/web-dist/assets/{index-AuO_Psrz.js → index-Cxroyxuc.js} +57 -54
  50. package/web-dist/assets/{info-DKCQHKI2-DW4lo23y.js → info-DKCQHKI2-B2Njf2Cf.js} +1 -1
  51. package/web-dist/assets/{infoDiagram-FWYZ7A6U-CXiyOu2-.js → infoDiagram-FWYZ7A6U-Ca0ZciuC.js} +1 -1
  52. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-CpMuWt_7.js → ishikawaDiagram-FXEZZL3T-CPsNqnqs.js} +1 -1
  53. package/web-dist/assets/{journeyDiagram-5HDEW3XC-BkPeIp41.js → journeyDiagram-5HDEW3XC-C0DA07RV.js} +1 -1
  54. package/web-dist/assets/{kanban-definition-HUTT4EX6-BV_9FKSZ.js → kanban-definition-HUTT4EX6-CXXam7zc.js} +1 -1
  55. package/web-dist/assets/{line-oIX8MMfl.js → line-B6ofc5bQ.js} +1 -1
  56. package/web-dist/assets/{linear-DNK_UIsk.js → linear-CLBVhrVv.js} +1 -1
  57. package/web-dist/assets/{mermaid-parser.core-KXhY4GxP.js → mermaid-parser.core-CcEAp6DX.js} +3 -3
  58. package/web-dist/assets/{mermaid.core-h9KNJFJJ.js → mermaid.core-CC-fPRQ3.js} +3 -3
  59. package/web-dist/assets/{mindmap-definition-LN4V7U3C-DVEffHYP.js → mindmap-definition-LN4V7U3C-DxmJXxM1.js} +1 -1
  60. package/web-dist/assets/{packet-7NZHBO7P-DXFLYz0v.js → packet-7NZHBO7P-CvlFg_io.js} +1 -1
  61. package/web-dist/assets/{pegDiagram-2B236MQR-Bpf2-lwS.js → pegDiagram-2B236MQR-Bgwx28BQ.js} +1 -1
  62. package/web-dist/assets/{pie-RZYD4A2V-CRzNTyT_.js → pie-RZYD4A2V-DAMTNQcW.js} +1 -1
  63. package/web-dist/assets/{pieDiagram-ENE6RG2P-5OxjOvPl.js → pieDiagram-ENE6RG2P-DfTw_3mN.js} +1 -1
  64. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DmYfnHMg.js → quadrantDiagram-ABIIQ3AL-COTsv2Kc.js} +1 -1
  65. package/web-dist/assets/{radar-I7S5WNFK-WOiYkQ_h.js → radar-I7S5WNFK-DQRMGMPS.js} +1 -1
  66. package/web-dist/assets/{railroad-3IZDKUUU-DQqlel4-.js → railroad-3IZDKUUU-z3gzfpLJ.js} +1 -1
  67. package/web-dist/assets/railroad-abnf-AHOZXSZD-CPdyVixb.js +1 -0
  68. package/web-dist/assets/railroad-ebnf-EBAXGLYW-CW9g40ih.js +1 -0
  69. package/web-dist/assets/railroad-peg-LSFZ7HO6-BisCRXMy.js +1 -0
  70. package/web-dist/assets/{railroadDiagram-RFXS5EU6-Dy-QXMYm.js → railroadDiagram-RFXS5EU6-cyqSv0hl.js} +1 -1
  71. package/web-dist/assets/{requirementDiagram-TGXJPOKE-DqiaxdLf.js → requirementDiagram-TGXJPOKE-BECiaDhq.js} +1 -1
  72. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-CALQykld.js → sankeyDiagram-HTMAVEWB-BQvf8K8I.js} +1 -1
  73. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-CkcHqhEB.js → sequenceDiagram-DBY2YBRQ-BLQoSIOd.js} +1 -1
  74. package/web-dist/assets/{src-mutgQtwo.js → src-ClqzeqlV.js} +1 -1
  75. package/web-dist/assets/{stateDiagram-2N3HPSRC-BiNElNmG.js → stateDiagram-2N3HPSRC-DWOZvXE6.js} +1 -1
  76. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BlGBJ8Sv.js +1 -0
  77. package/web-dist/assets/{swimlanes-5IMT3BWC-CJe_K-xH.js → swimlanes-5IMT3BWC-D_OgCclp.js} +1 -1
  78. package/web-dist/assets/swimlanesDiagram-G3AALYLV-CJ5vUUEc.js +8 -0
  79. package/web-dist/assets/{timeline-definition-FHXFAJF6-_n-XbLIo.js → timeline-definition-FHXFAJF6-CzFA213Q.js} +1 -1
  80. package/web-dist/assets/{treeView-QDETBFTQ-G53LKf3k.js → treeView-QDETBFTQ-VAA4e9vM.js} +1 -1
  81. package/web-dist/assets/{treemap-6X3UGDF4-GinzV1R9.js → treemap-6X3UGDF4-BoLIw2ix.js} +1 -1
  82. package/web-dist/assets/{vennDiagram-L72KCM5P-BpbLkzpA.js → vennDiagram-L72KCM5P-C5flYkCp.js} +1 -1
  83. package/web-dist/assets/{wardley-OPB4EBWU-7cfRg4gk.js → wardley-OPB4EBWU-DqRI-fT7.js} +1 -1
  84. package/web-dist/assets/{wardleyDiagram-EHGQE667-BtkHWBJy.js → wardleyDiagram-EHGQE667-Pp4ADVTI.js} +1 -1
  85. package/web-dist/assets/{xychartDiagram-FW5EYKEG-DqHJvx14.js → xychartDiagram-FW5EYKEG-BAGoibt3.js} +1 -1
  86. package/web-dist/index.html +2 -2
  87. package/web-dist/assets/architecture-TIHT7OUA-Tn4efhzP.js +0 -1
  88. package/web-dist/assets/channel-4H014B-1.js +0 -1
  89. package/web-dist/assets/classDiagram-OUVF2IWQ-8JajOrhY.js +0 -1
  90. package/web-dist/assets/classDiagram-v2-EOCWNBFH-8JajOrhY.js +0 -1
  91. package/web-dist/assets/eventmodeling-45OFAUF4-BGxDGBm7.js +0 -1
  92. package/web-dist/assets/flowDiagram-23GEKE2U-BOD8PP2C.js +0 -1
  93. package/web-dist/assets/index-BSl6rM3u.css +0 -2
  94. package/web-dist/assets/railroad-abnf-AHOZXSZD-EtMjMxgl.js +0 -1
  95. package/web-dist/assets/railroad-ebnf-EBAXGLYW-f-9Oguw0.js +0 -1
  96. package/web-dist/assets/railroad-peg-LSFZ7HO6-DyJccj3F.js +0 -1
  97. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-4cGI50SD.js +0 -1
  98. package/web-dist/assets/swimlanesDiagram-G3AALYLV-B9sjhf80.js +0 -8
package/dist/dev-child.js CHANGED
@@ -14782,6 +14782,11 @@ ${ANSWER_CONTINUATION_INDENT}`);
14782
14782
  * same card and the swap is invisible. Absent whenever there is nothing in flight, which is almost
14783
14783
  * always — it exists for the seconds between the human sending and the worker being handed it. */
14784
14784
  answersInFlight: external_exports.string().optional(),
14785
+ /** The human's message — a follow-up or a registered answer — is on its way to the worker and the turn
14786
+ * has not started yet (board.deriveDeliveryInFlight). The queue has already let the thread go; this
14787
+ * tells the rail to draw it as working in every tab, not only the one that sent it (web
14788
+ * lib/steering.ts). Absent otherwise. */
14789
+ deliveryInFlight: external_exports.boolean().optional(),
14785
14790
  // ISO8601 of the newest REAL user interaction (answer/steer/dispatch) — the chronological listing
14786
14791
  // sort key. Optional; the listing falls back to spawnedAt when absent (a dispatch IS an interaction).
14787
14792
  lastUserAt: external_exports.string().optional(),
@@ -23755,6 +23760,7 @@ var init_tail_cache = __esm({
23755
23760
  // packages/server/src/tailer.ts
23756
23761
  import { statSync as statSync8, openSync as openSync10, readSync as readSync4, closeSync as closeSync9, readdirSync as readdirSync5, realpathSync as realpathSync5, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as readFileSync12, existsSync as existsSync5 } from "node:fs";
23757
23762
  import { execFile as execFile2 } from "node:child_process";
23763
+ import { createHash as createHash7 } from "node:crypto";
23758
23764
  import { promisify as promisify2 } from "node:util";
23759
23765
  import { basename as basename4, join as join18, win32 } from "node:path";
23760
23766
  import { homedir as homedir7 } from "node:os";
@@ -23991,7 +23997,7 @@ function trackDispatches(state, rec) {
23991
23997
  state.subAgents.set(id, { kind: "agent", toolUseId: id, label: desc ?? "sub-agent", startedAt, subagentType, outputFile });
23992
23998
  } else if (b.name === "Bash" && input.run_in_background === true || b.name === "Monitor") {
23993
23999
  const command = typeof input.command === "string" ? input.command : previous?.command;
23994
- state.subAgents.set(id, { kind: "shell", toolUseId: id, label: desc ?? shellSummary(input.command), startedAt, command, outputFile, taskId: previous?.taskId });
24000
+ state.subAgents.set(id, { kind: "shell", toolUseId: id, label: desc ?? shellSummary(input.command), startedAt, command, outputFile, taskId: previous?.taskId, ...b.name === "Monitor" ? { monitor: true } : {} });
23995
24001
  } else if (b.name === "Bash") {
23996
24002
  const pending = state.pendingShells ??= /* @__PURE__ */ new Map();
23997
24003
  pending.set(id, { label: desc ?? shellSummary(input.command), command: typeof input.command === "string" ? input.command : void 0, startedAt });
@@ -24062,6 +24068,22 @@ function findLiveByTaskId(state, taskId) {
24062
24068
  for (const e14 of state.subAgents.values()) if (e14.taskId === taskId) return e14;
24063
24069
  return void 0;
24064
24070
  }
24071
+ function knowsDirectOp(state, taskId) {
24072
+ if (findLiveByTaskId(state, taskId)) return true;
24073
+ for (const r of state.retiredSubAgents.values()) if (r.taskId === taskId) return true;
24074
+ for (const r of state.retiredShells.values()) if (r.taskId === taskId) return true;
24075
+ return false;
24076
+ }
24077
+ function rememberFoldedTerminal(state, taskId, fingerprint) {
24078
+ const seen = state.foldedTerminals ??= /* @__PURE__ */ new Map();
24079
+ seen.delete(taskId);
24080
+ seen.set(taskId, fingerprint);
24081
+ while (seen.size > FOLDED_TERMINALS_MAX) {
24082
+ const oldest = seen.keys().next().value;
24083
+ if (oldest === void 0) break;
24084
+ seen.delete(oldest);
24085
+ }
24086
+ }
24065
24087
  function launchOutputFile(state, text2) {
24066
24088
  const m = text2.match(/output_file:\s*(\S+)/) ?? text2.match(/Output is being written to:\s*(\S+)/);
24067
24089
  if (m) return m[1].replace(/\.$/, "");
@@ -24227,14 +24249,21 @@ function trackCompletions(state, rec) {
24227
24249
  const monitorTimedOut = block.includes("<event>[Monitor timed out");
24228
24250
  const terminal = status === "completed" || status === "failed" || status === "killed" ? status : status === "stopped" || monitorTimedOut ? "killed" : void 0;
24229
24251
  if (!terminal) continue;
24252
+ const fingerprint = createHash7("sha1").update(block).digest("hex").slice(0, 16);
24253
+ const repeatOf = /* @__PURE__ */ new Set();
24254
+ for (const id of blockTaskIds(block)) {
24255
+ if (state.foldedTerminals?.get(id) === fingerprint) repeatOf.add(id);
24256
+ else if (knowsDirectOp(state, id)) rememberFoldedTerminal(state, id, fingerprint);
24257
+ }
24230
24258
  const doomed = /* @__PURE__ */ new Set();
24231
24259
  for (const m of block.matchAll(/<tool-use-id>([^<]*)<\/tool-use-id>/g)) {
24232
24260
  const entry = state.subAgents.get(m[1]);
24233
- if (entry) doomed.add(entry);
24261
+ if (entry && !(entry.taskId && repeatOf.has(entry.taskId))) doomed.add(entry);
24234
24262
  }
24235
24263
  const stampedAt = typeof rec.timestamp === "string" ? Date.parse(rec.timestamp) : Number.NaN;
24236
24264
  for (const m of block.matchAll(/<task-id>([^<]*)<\/task-id>/g)) {
24237
24265
  if (m[1].startsWith("__orphan_summary__")) continue;
24266
+ if (repeatOf.has(m[1])) continue;
24238
24267
  const entry = findLiveByTaskId(state, m[1]);
24239
24268
  if (entry) doomed.add(entry);
24240
24269
  else if (Number.isFinite(stampedAt)) recordDescendantTerminal(state, m[1], stampedAt);
@@ -24814,7 +24843,7 @@ function createTailer(deps) {
24814
24843
  if (e14.kind !== "shell") continue;
24815
24844
  const lastActivityAt = entryLastActivity(state, e14);
24816
24845
  const shellState = shellIsGone(e14) ? "stale" : "running";
24817
- out.push({ label: e14.label, startedAt: e14.startedAt, state: shellState, id: e14.toolUseId, ...e14.taskId ? { stoppable: true, taskId: e14.taskId } : {}, ...lastActivityAt ? { lastActivityAt } : {} });
24846
+ out.push({ label: e14.label, startedAt: e14.startedAt, state: shellState, id: e14.toolUseId, ...e14.taskId ? { stoppable: true, taskId: e14.taskId } : {}, ...lastActivityAt ? { lastActivityAt } : {}, ...e14.monitor ? { outputUnavailable: true } : {} });
24818
24847
  }
24819
24848
  return out;
24820
24849
  }
@@ -25998,7 +26027,7 @@ function landsAfterRead(eventAt, lastReadAt) {
25998
26027
  if (!Number.isFinite(e14) || !Number.isFinite(r)) return true;
25999
26028
  return e14 > r;
26000
26029
  }
26001
- var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS2, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
26030
+ var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS2, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, FOLDED_TERMINALS_MAX, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
26002
26031
  var init_tailer = __esm({
26003
26032
  "packages/server/src/tailer.ts"() {
26004
26033
  "use strict";
@@ -26052,6 +26081,7 @@ var init_tailer = __esm({
26052
26081
  LOCAL_COMMAND_RECEIPT = /^<local-command-(stdout|stderr)>[\s\S]*<\/local-command-\1>$/;
26053
26082
  LAUNCH_ACK_RE = /^\s*(Async agent launched successfully|Spawned successfully|Command running in background|Monitor started|Command did not complete within its)/;
26054
26083
  AUTO_BACKGROUND_ACK_RE = /^\s*Command did not complete within its .{0,40}?and was moved to the background/;
26084
+ FOLDED_TERMINALS_MAX = 64;
26055
26085
  DESCENDANT_SIDECAR_MAX = 512;
26056
26086
  DESCENDANT_NOTIFY_GRACE_MS = 5e3;
26057
26087
  MAX_OWNED_TOOL_USE_IDS = 25e3;
@@ -29148,7 +29178,7 @@ var require_websocket = __commonJS({
29148
29178
  var http = __require("http");
29149
29179
  var net2 = __require("net");
29150
29180
  var tls = __require("tls");
29151
- var { randomBytes, createHash: createHash17 } = __require("crypto");
29181
+ var { randomBytes, createHash: createHash18 } = __require("crypto");
29152
29182
  var { Duplex, Readable: Readable2 } = __require("stream");
29153
29183
  var { URL: URL2 } = __require("url");
29154
29184
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -29816,7 +29846,7 @@ var require_websocket = __commonJS({
29816
29846
  abortHandshake(websocket, socket, "Invalid Upgrade header");
29817
29847
  return;
29818
29848
  }
29819
- const digest = createHash17("sha1").update(key + GUID).digest("base64");
29849
+ const digest = createHash18("sha1").update(key + GUID).digest("base64");
29820
29850
  if (res.headers["sec-websocket-accept"] !== digest) {
29821
29851
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
29822
29852
  return;
@@ -30185,7 +30215,7 @@ var require_websocket_server = __commonJS({
30185
30215
  var EventEmitter = __require("events");
30186
30216
  var http = __require("http");
30187
30217
  var { Duplex } = __require("stream");
30188
- var { createHash: createHash17 } = __require("crypto");
30218
+ var { createHash: createHash18 } = __require("crypto");
30189
30219
  var extension2 = require_extension();
30190
30220
  var PerMessageDeflate2 = require_permessage_deflate();
30191
30221
  var subprotocol2 = require_subprotocol();
@@ -30492,7 +30522,7 @@ var require_websocket_server = __commonJS({
30492
30522
  );
30493
30523
  }
30494
30524
  if (this._state > RUNNING) return abortHandshake(socket, 503);
30495
- const digest = createHash17("sha1").update(key + GUID).digest("base64");
30525
+ const digest = createHash18("sha1").update(key + GUID).digest("base64");
30496
30526
  const headers = [
30497
30527
  "HTTP/1.1 101 Switching Protocols",
30498
30528
  "Upgrade: websocket",
@@ -30723,7 +30753,7 @@ var init_codex_mcp = __esm({
30723
30753
  import { spawn as spawn2 } from "node:child_process";
30724
30754
  import { connect } from "node:net";
30725
30755
  import { Agent as HttpAgent } from "node:http";
30726
- import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
30756
+ import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
30727
30757
  import { existsSync as existsSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync15, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
30728
30758
  import { join as join20 } from "node:path";
30729
30759
  import { PassThrough, Writable } from "node:stream";
@@ -30735,7 +30765,7 @@ function nativeRecordPath(stateDir, projectId) {
30735
30765
  return join20(nativeDir(stateDir), `${projectId}.json`);
30736
30766
  }
30737
30767
  function nativeListenSocketPath(stateDir, projectId) {
30738
- const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
30768
+ const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
30739
30769
  return frizzIpcPath(`frizz-codex-native-${key}`);
30740
30770
  }
30741
30771
  function pidAlive2(pid) {
@@ -31003,7 +31033,7 @@ var init_codex_app_server_native = __esm({
31003
31033
  // packages/server/src/backend/codex-app-server-host.ts
31004
31034
  import { spawn as spawn3 } from "node:child_process";
31005
31035
  import { createConnection } from "node:net";
31006
- import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
31036
+ import { createHash as createHash9, randomUUID as randomUUID10 } from "node:crypto";
31007
31037
  import { existsSync as existsSync7, mkdirSync as mkdirSync12, readFileSync as readFileSync16, unlinkSync as unlinkSync3 } from "node:fs";
31008
31038
  import { join as join21 } from "node:path";
31009
31039
  import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
@@ -31015,7 +31045,7 @@ function recordPath(stateDir, projectId) {
31015
31045
  return join21(daemonDir(stateDir), `${projectId}.json`);
31016
31046
  }
31017
31047
  function codexAppServerSocketPath(stateDir, projectId) {
31018
- const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
31048
+ const key = createHash9("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
31019
31049
  return frizzIpcPath(`frizz-codex-${key}`);
31020
31050
  }
31021
31051
  function pidAlive3(pid) {
@@ -31312,7 +31342,7 @@ var init_codex_app_server_host = __esm({
31312
31342
  // packages/server/src/backend/claude-quota.ts
31313
31343
  import { join as join22 } from "node:path";
31314
31344
  import { homedir as homedir9, platform } from "node:os";
31315
- import { createHash as createHash9 } from "node:crypto";
31345
+ import { createHash as createHash10 } from "node:crypto";
31316
31346
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
31317
31347
  import { execFile as execFile3 } from "node:child_process";
31318
31348
  import { promisify as promisify3 } from "node:util";
@@ -31419,7 +31449,7 @@ function retryAtFrom(res, now) {
31419
31449
  return now + Math.min(backoff, RATE_LIMIT_MAX_BACKOFF_MS);
31420
31450
  }
31421
31451
  function cachePaths(cacheDir, configDir) {
31422
- const profile = createHash9("sha256").update(configDir).digest("hex").slice(0, 12);
31452
+ const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
31423
31453
  return {
31424
31454
  data: join22(cacheDir, `claude-${profile}.json`),
31425
31455
  lock: join22(cacheDir, `claude-${profile}.lock`)
@@ -31599,15 +31629,15 @@ async function tryAcquireLock2(path3) {
31599
31629
  }
31600
31630
  return void 0;
31601
31631
  }
31602
- function rateLimited(shared, now) {
31603
- return shared?.retryAt !== void 0 && now < shared.retryAt;
31632
+ function rateLimited(shared2, now) {
31633
+ return shared2?.retryAt !== void 0 && now < shared2.retryAt;
31604
31634
  }
31605
- function serveRateLimited(shared, now) {
31606
- if (shared.quota.status !== "ok" || now - shared.at >= STALE_MAX_AGE_MS) return UNAVAILABLE;
31635
+ function serveRateLimited(shared2, now) {
31636
+ if (shared2.quota.status !== "ok" || now - shared2.at >= STALE_MAX_AGE_MS) return UNAVAILABLE;
31607
31637
  const minutes = (ms, round) => Math.max(1, round(ms / 6e4));
31608
31638
  return {
31609
- ...shared.quota,
31610
- detail: `Next refresh in ${minutes(shared.retryAt - now, Math.ceil)}m \xB7 last updated ${minutes(now - shared.at, Math.round)}m ago`
31639
+ ...shared2.quota,
31640
+ detail: `Next refresh in ${minutes(shared2.retryAt - now, Math.ceil)}m \xB7 last updated ${minutes(now - shared2.at, Math.round)}m ago`
31611
31641
  };
31612
31642
  }
31613
31643
  function refreshSharedInBackground(paths, claudeBin, deps, now) {
@@ -32028,7 +32058,7 @@ var init_codex_execution_health = __esm({
32028
32058
  });
32029
32059
 
32030
32060
  // packages/server/src/backend/codex-app-server.ts
32031
- import { createHash as createHash10, randomUUID as randomUUID11 } from "node:crypto";
32061
+ import { createHash as createHash11, randomUUID as randomUUID11 } from "node:crypto";
32032
32062
  import { existsSync as existsSync8 } from "node:fs";
32033
32063
  import { StringDecoder as StringDecoder3 } from "node:string_decoder";
32034
32064
  function selectCodexHostKind(flagValue, platform3, hasSpawn) {
@@ -32376,7 +32406,7 @@ function canonicalJson2(value) {
32376
32406
  return JSON.stringify(normalize2(value));
32377
32407
  }
32378
32408
  function logicalRequestId(method, parts) {
32379
- const digest = createHash10("sha256").update(JSON.stringify([method, ...parts])).digest("hex");
32409
+ const digest = createHash11("sha256").update(JSON.stringify([method, ...parts])).digest("hex");
32380
32410
  return `codex-${digest}`;
32381
32411
  }
32382
32412
  function requestFingerprint(value) {
@@ -32386,7 +32416,7 @@ function requestFingerprint(value) {
32386
32416
  delete record.startedAtMs;
32387
32417
  delete record.autoResolutionMs;
32388
32418
  }
32389
- return createHash10("sha256").update(canonicalJson2(normalized)).digest("hex");
32419
+ return createHash11("sha256").update(canonicalJson2(normalized)).digest("hex");
32390
32420
  }
32391
32421
  function decision(id, semantic, label) {
32392
32422
  return { id, semantic, label };
@@ -32674,7 +32704,7 @@ function createCodexAppServerBridge(options) {
32674
32704
  function codexAppServerBridgeEnabled() {
32675
32705
  return true;
32676
32706
  }
32677
- var CODEX_APP_SERVER_PROVIDER, CODEX_NATIVE_LISTEN_FLAG, CODEX_APP_SERVER_SUPPORTED_VERSION, CODEX_APP_SERVER_PROTOCOL_REVISION, aheadVersionWarned, PROTOCOL_FINGERPRINT, CLIENT_INFO, CLIENT_CAPABILITIES, CODEX_SANDBOX_MODES, CODEX_APPROVAL_POLICY, CODEX_DEFAULT_SANDBOX, SANDBOX_CONFIRM_TIMEOUT_MS, SANDBOX_NOOP_GRACE_MS, MAX_JSONL_BYTES, MAX_INBOUND_JSONL_BYTES, MAX_INBOUND_RECORDS, MAX_INBOUND_QUEUED_BYTES, MAX_OUTBOUND_REQUESTS, MAX_STDERR_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, AUTH_REPLACEMENT_WAIT_MS, MAX_AUTH_REPLACEMENT_ATTEMPTS, BRIDGE_DB_SCHEMA_VERSION, RpcIdSchema, Opaque, SafeTimestampMs, NullableString, CommandAction, NetworkApprovalContext, FileSystemSpecialPath, FileSystemPath, FileSystemSandboxEntry, NetworkPermissions, FileSystemPermissions, RequestedPermissions, NetworkPolicyAmendment, CommandApprovalParams, FileApprovalParams, PatchChangeKind, FileUpdateChange, FileChangeItem, CommandExecutionItem, ItemStartedNotification, ItemCompletedNotification, FileChangePatchUpdatedNotification, PermissionsApprovalParams, UserInputQuestion, UserInputParams, McpBase, McpElicitationParams, ResolvedNotification, RpcProtocolError, JsonlRpcConnection, BindingRowSchema, BridgeMetaRowSchema, DISPLAY_REDACTION, UNSAFE_DISPLAY_TEXT, SECRET_NAME, commandDecisionMap, InitializeResponse, ThreadResponse, TurnResponse, TurnSteerResponse, SkillsListResponse, ThreadResumeSandbox, ThreadResumeStatus, ThreadSettingsUpdated, TurnStarted, TurnCompleted, MAX_CORRELATED_FILE_ITEMS, CODEX_APP_SERVER_TABLES, CodexAppServerBridge;
32707
+ var CODEX_APP_SERVER_PROVIDER, CODEX_NATIVE_LISTEN_FLAG, CODEX_APP_SERVER_SUPPORTED_VERSION, CODEX_APP_SERVER_PROTOCOL_REVISION, aheadVersionWarned, PROTOCOL_FINGERPRINT, CLIENT_INFO, CLIENT_CAPABILITIES, CODEX_SANDBOX_MODES, CODEX_APPROVAL_POLICY, CODEX_DEFAULT_SANDBOX, SANDBOX_CONFIRM_TIMEOUT_MS, SANDBOX_NOOP_GRACE_MS, MAX_JSONL_BYTES, MAX_INBOUND_JSONL_BYTES, MAX_INBOUND_RECORDS, MAX_INBOUND_QUEUED_BYTES, MAX_OUTBOUND_REQUESTS, MAX_STDERR_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, AUTH_REPLACEMENT_WAIT_MS, MAX_AUTH_REPLACEMENT_ATTEMPTS, BRIDGE_DB_SCHEMA_VERSION, RpcIdSchema, Opaque, SafeTimestampMs, NullableString, CommandAction, NetworkApprovalContext, FileSystemSpecialPath, FileSystemPath, FileSystemSandboxEntry, NetworkPermissions, FileSystemPermissions, RequestedPermissions, NetworkPolicyAmendment, CommandApprovalParams, FileApprovalParams, PatchChangeKind, FileUpdateChange, FileChangeItem, CommandExecutionItem, BackgroundTerminalsListResponse, ItemStartedNotification, ItemCompletedNotification, FileChangePatchUpdatedNotification, PermissionsApprovalParams, UserInputQuestion, UserInputParams, McpBase, McpElicitationParams, ResolvedNotification, RpcProtocolError, JsonlRpcConnection, BindingRowSchema, BridgeMetaRowSchema, DISPLAY_REDACTION, UNSAFE_DISPLAY_TEXT, SECRET_NAME, commandDecisionMap, InitializeResponse, ThreadResponse, TurnResponse, TurnSteerResponse, SkillsListResponse, ThreadResumeSandbox, ThreadResumeStatus, ThreadSettingsUpdated, TurnStarted, TurnCompleted, MAX_CORRELATED_FILE_ITEMS, CODEX_APP_SERVER_TABLES, CodexAppServerBridge;
32678
32708
  var init_codex_app_server = __esm({
32679
32709
  "packages/server/src/backend/codex-app-server.ts"() {
32680
32710
  "use strict";
@@ -32845,6 +32875,13 @@ var init_codex_app_server = __esm({
32845
32875
  status: external_exports.string().max(64).optional(),
32846
32876
  exitCode: external_exports.number().nullish()
32847
32877
  });
32878
+ BackgroundTerminalsListResponse = external_exports.object({
32879
+ data: external_exports.array(external_exports.object({
32880
+ processId: external_exports.union([external_exports.string().max(128), external_exports.number()]),
32881
+ command: external_exports.string().max(8192).optional()
32882
+ })).max(256),
32883
+ nextCursor: external_exports.string().max(1024).nullish()
32884
+ });
32848
32885
  ItemStartedNotification = external_exports.object({
32849
32886
  item: external_exports.unknown(),
32850
32887
  threadId: Opaque,
@@ -33296,8 +33333,9 @@ var init_codex_app_server = __esm({
33296
33333
  // ops-strip row it projects has no handle to address a kill with. This map is what gives a codex
33297
33334
  // shell row an id, and the id it gives is exactly what `backgroundTerminals/terminate` accepts.
33298
33335
  //
33299
- // A LEVEL, not an edge log: `item/started` adds, any terminal `item/*` removes, and the whole
33300
- // per-thread entry is dropped when the session is released or the process goes away. Nothing here is
33336
+ // A LEVEL, not an edge log: `item/started` adds, any terminal `item/*` removes, a rejoin of the same
33337
+ // process re-seeds it from `backgroundTerminals/list` (seedLiveExecs), and the whole per-thread entry
33338
+ // is dropped when the session is released or the process goes away. Nothing here is
33301
33339
  // durable, and it must not be — a processId belongs to one app-server process, so a stale one
33302
33340
  // surviving a restart would offer an × that addresses a PTY that no longer exists.
33303
33341
  liveExecs = /* @__PURE__ */ new Map();
@@ -34186,8 +34224,11 @@ var init_codex_app_server = __esm({
34186
34224
  deathAt: matched?.at || void 0
34187
34225
  });
34188
34226
  }
34189
- await this.reconcileOwnedSessions(connection, negotiated.sameProcess);
34227
+ const sameGeneration = attachment.reattached && negotiated.previousGeneration === attachment.generation;
34228
+ const execThreads = sameGeneration ? [...(await this.listLiveExecs(connection, this.boundCodexThreadIds())).keys()] : [];
34229
+ await this.reconcileOwnedSessions(connection, negotiated.sameProcess, execThreads);
34190
34230
  if (this.connection !== connection) throw new Error("Codex app-server disconnected during session reconciliation");
34231
+ if (execThreads.length > 0) this.seedLiveExecs(connection, await this.listLiveExecs(connection, execThreads));
34191
34232
  return connection;
34192
34233
  } catch (error) {
34193
34234
  connection.close();
@@ -34229,16 +34270,27 @@ var init_codex_app_server = __esm({
34229
34270
  * mid-turn detached rows too; idle detached rows stay lazily rebound on next use, which keeps this
34230
34271
  * bounded on a board with a long history.
34231
34272
  *
34273
+ * The one exception is `execThreads`: idle threads that still own a running background exec. Over
34274
+ * the native listener subscriptions are per-connection, so an idle thread left detached never
34275
+ * hears its exec END — the `item/completed` goes nowhere and the re-seeded row outlives the command
34276
+ * (measured live, backend/_live_codex_bgterm_reseed.mts). Rebinding them here, exactly as the next
34277
+ * follow-up would, is what re-subscribes this connection to them.
34278
+ *
34232
34279
  * `sameProcess` says we rejoined the very app-server that owned these turns (it outlived our
34233
34280
  * restart inside the daemon). Then the turns are STILL RUNNING and the only correct action is to
34234
34281
  * re-mark the binding active and keep `current_turn_id`: issuing `thread/resume` against a live
34235
34282
  * turn would disturb it, and clearing the id would orphan the `turn/completed` still to come.
34236
34283
  */
34237
- async reconcileOwnedSessions(connection, sameProcess) {
34284
+ async reconcileOwnedSessions(connection, sameProcess, execThreads = []) {
34238
34285
  const rows = this.scope.prepare(`
34239
34286
  SELECT * FROM codex_app_server_session
34240
34287
  WHERE project_id = @project_id AND (state = 'active' OR (state = 'detached' AND current_turn_id IS NOT NULL))
34241
34288
  `).all().map(checkedBindingRow);
34289
+ for (const threadId of execThreads) {
34290
+ if (rows.some((row2) => row2.codex_thread_id === threadId)) continue;
34291
+ const row = this.bindingForCodexThread(threadId);
34292
+ if (row) rows.push(row);
34293
+ }
34242
34294
  const detach = (row) => {
34243
34295
  this.scope.prepare("UPDATE codex_app_server_session SET state = 'detached', updated_at = ? WHERE project_id = @project_id AND frizz_session_id = ?").run(this.now().toISOString(), row.frizz_session_id);
34244
34296
  };
@@ -34688,8 +34740,9 @@ var init_codex_app_server = __esm({
34688
34740
  // The live background-exec level rides the same lifecycle as the correlated file items — a released
34689
34741
  // session and a lost process both invalidate it — but for a different reason. A `processId` names a
34690
34742
  // PTY inside ONE app-server process, so a surviving entry after that process goes away would put an ×
34691
- // on the board that addresses a handle nothing can honour. The next connection's item stream
34692
- // repopulates it, exactly as the SDK's `background_tasks_changed` level does on the Claude side.
34743
+ // on the board that addresses a handle nothing can honour. The next connection's item stream only
34744
+ // repopulates it with execs that START after it attached; one already running when we rejoin the same
34745
+ // process is re-learned by seedLiveExecs, because its `item/started` is never sent again.
34693
34746
  forgetCorrelatedFileItems(threadId, turnId) {
34694
34747
  if (threadId === void 0) {
34695
34748
  this.correlatedFileItems.clear();
@@ -34995,6 +35048,71 @@ var init_codex_app_server = __esm({
34995
35048
  startedAtMs: existing?.startedAtMs ?? startedAtMs ?? this.now().getTime()
34996
35049
  });
34997
35050
  }
35051
+ // Re-learn the live background execs after rejoining an app-server we had already been talking to.
35052
+ //
35053
+ // The level above is folded off `item/started`, and that notification went to the client connection
35054
+ // we just lost: the daemon queues only while NO client is attached, and the native listener queues
35055
+ // nothing, so neither ever replays it. The exec, meanwhile, is still running in that process's PTY —
35056
+ // so without this its row vanished from the board after every Frizz restart or dropped socket and
35057
+ // never came back until the exec ended, taking its × with it. `thread/backgroundTerminals/list` is
35058
+ // the app-server's own answer to "what is still running".
35059
+ //
35060
+ // connect() asks TWICE. The first pass goes to every bound thread, because a yielded exec outlives
35061
+ // its turn and the thread most likely to own one is an IDLE one whose binding sat detached; it only
35062
+ // decides which threads reconcile must rebind. The second pass, after that rebind re-subscribed this
35063
+ // connection, is the one that seeds — so an exec that ended in between is not seeded as a row no
35064
+ // `item/completed` will ever clear. A thread the process never loaded answers "thread not found"
35065
+ // (measured on 0.158.0, and the list does not load it), and any failure — that, an older codex
35066
+ // without the method — leaves the thread out, which is exactly the level it had before this existed.
35067
+ // Nothing here throws: a board row is not worth a failed connect.
35068
+ async listLiveExecs(connection, threadIds) {
35069
+ const found = /* @__PURE__ */ new Map();
35070
+ const seenAtMs = this.now().getTime();
35071
+ await Promise.all(threadIds.map(async (threadId) => {
35072
+ const execs = [];
35073
+ let cursor;
35074
+ for (let page = 0; page < 8; page++) {
35075
+ let parsed;
35076
+ try {
35077
+ parsed = BackgroundTerminalsListResponse.parse(await connection.request(
35078
+ "thread/backgroundTerminals/list",
35079
+ cursor === void 0 ? { threadId } : { threadId, cursor }
35080
+ ));
35081
+ } catch {
35082
+ return;
35083
+ }
35084
+ for (const terminal of parsed.data) {
35085
+ execs.push({ processId: String(terminal.processId), command: terminal.command, startedAtMs: seenAtMs });
35086
+ }
35087
+ if (!parsed.nextCursor) break;
35088
+ cursor = parsed.nextCursor;
35089
+ }
35090
+ if (execs.length > 0) found.set(threadId, execs);
35091
+ }));
35092
+ return found;
35093
+ }
35094
+ seedLiveExecs(connection, found) {
35095
+ if (this.connection !== connection) return;
35096
+ for (const [threadId, execs] of found) {
35097
+ let byProcess = this.liveExecs.get(threadId);
35098
+ if (!byProcess) {
35099
+ byProcess = /* @__PURE__ */ new Map();
35100
+ this.liveExecs.set(threadId, byProcess);
35101
+ }
35102
+ for (const exec of execs) {
35103
+ if (!byProcess.has(exec.processId)) byProcess.set(exec.processId, exec);
35104
+ }
35105
+ }
35106
+ }
35107
+ boundCodexThreadIds() {
35108
+ try {
35109
+ return this.scope.prepare(
35110
+ "SELECT codex_thread_id FROM codex_app_server_session WHERE project_id = @project_id"
35111
+ ).all().map((row) => row.codex_thread_id);
35112
+ } catch {
35113
+ return [];
35114
+ }
35115
+ }
34998
35116
  async handleNotification(connection, method, rawParams) {
34999
35117
  if (method === "error") {
35000
35118
  const parsed = external_exports.object({ threadId: Opaque, turnId: Opaque, error: external_exports.unknown(), willRetry: external_exports.boolean() }).passthrough().safeParse(rawParams);
@@ -38166,7 +38284,7 @@ var init_claude_agent_broker_bridge = __esm({
38166
38284
  // packages/server/src/dispatch.ts
38167
38285
  import { closeSync as closeSync12, constants as constants2, existsSync as existsSync11, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync20, realpathSync as realpathSync8, statSync as statSync14, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync9 } from "node:fs";
38168
38286
  import { basename as basename6, join as join30, dirname as dirname12 } from "node:path";
38169
- import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
38287
+ import { createHash as createHash12, randomUUID as randomUUID13 } from "node:crypto";
38170
38288
  function fallbackTitle(prompt) {
38171
38289
  const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
38172
38290
  let allWords = firstLine2.split(/\s+/).filter(Boolean);
@@ -38235,7 +38353,7 @@ function resolveLegacyThreadFile(projectDir, value) {
38235
38353
  size: after.size,
38236
38354
  mtimeMs: after.mtimeMs,
38237
38355
  ctimeMs: after.ctimeMs,
38238
- digest: createHash11("sha256").update(contents).digest("hex")
38356
+ digest: createHash12("sha256").update(contents).digest("hex")
38239
38357
  };
38240
38358
  } catch {
38241
38359
  return null;
@@ -39029,6 +39147,10 @@ function hasLiveBackgroundWork(tele) {
39029
39147
  function hasUnretiredOwnAgents(tele) {
39030
39148
  return Boolean(tele?.subAgents?.some((agent) => isDirectSubAgent(agent) && (agent.state === "running" || agent.state === "stale")));
39031
39149
  }
39150
+ function orphanedAgents(agents, ownerGone) {
39151
+ if (!ownerGone) return agents;
39152
+ return agents.map((agent) => agent.state === "running" ? { ...agent, state: "stale" } : agent);
39153
+ }
39032
39154
  function stampStoppable(agents, row) {
39033
39155
  if (!isBrokerClaudeRow(row)) return agents;
39034
39156
  return agents.map((agent) => agent.state === "running" ? { ...agent, stoppable: true } : agent);
@@ -39233,6 +39355,14 @@ function hasFreshDelivery(row, processGone) {
39233
39355
  if (processGone) return false;
39234
39356
  return parseDeliveryLedger(row.delivery_ledger).some((d) => d.state === "pending" || d.state === "enqueued" || d.state === "delivered");
39235
39357
  }
39358
+ function deriveDeliveryInFlight(row, runtime, needsYou, deliveryProcessGone, answerInFlight, nowMs = Date.now()) {
39359
+ if (needsYou || runtime !== "turn-idle" && runtime !== "exited") return false;
39360
+ if (answerInFlight) return true;
39361
+ if (deliveryProcessGone) return false;
39362
+ return parseDeliveryLedger(row.delivery_ledger).some(
39363
+ (d) => (d.state === "pending" || d.state === "enqueued" || d.state === "delivered") && nowMs - Date.parse(d.at) < DELIVERY_IN_FLIGHT_SPIN_MS
39364
+ );
39365
+ }
39236
39366
  function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, nowMs = Date.now(), limitPause = void 0, excuseLiveOwnWork = true, deliveryProcessGone = false, github = {}, registeredPrWatches = /* @__PURE__ */ new Set(), armedTimerIds = /* @__PURE__ */ new Set(), armedWatches = [], openQuestions = 0, answerInFlight = false) {
39237
39367
  if (futureSnooze(row, nowMs)) return false;
39238
39368
  if (hasActionableInteraction) return true;
@@ -39432,7 +39562,9 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
39432
39562
  const state = effectiveSessionState(row, registeredLegacyTerminal);
39433
39563
  const archived = state === "archived";
39434
39564
  const limitPause = resolveLimitPause(row, tele, nowMs);
39435
- const needsYou = archived ? false : deriveNeedsYou(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, true, deliveryProcessGone, github, registeredPrWatches, armedTimerIds, armedWatches, questions.length, answerAwaitingDelivery(questionRows, rawTele?.lastUserAt, nowMs));
39565
+ const answerInFlight = answerAwaitingDelivery(questionRows, rawTele?.lastUserAt, nowMs);
39566
+ const needsYou = archived ? false : deriveNeedsYou(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, true, deliveryProcessGone, github, registeredPrWatches, armedTimerIds, armedWatches, questions.length, answerInFlight);
39567
+ const deliveryInFlight = !archived && deriveDeliveryInFlight(row, runtime, needsYou, deliveryProcessGone, answerInFlight, nowMs);
39436
39568
  const awaitingBackground = archived ? false : deriveAwaitingBackground(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, deliveryProcessGone, github, registeredPrWatches, armedTimerIds, armedWatches, questions.length);
39437
39569
  const crashed = runtime === "exited" && (tele?.turn === "in-flight" || hasLiveBackgroundWork(tele) || headlessLostWork);
39438
39570
  const snoozedUntil = futureSnooze(row, nowMs);
@@ -39465,7 +39597,7 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
39465
39597
  spawnedAt: row.spawned_at,
39466
39598
  lastActivityAt: tele?.lastActivityAt,
39467
39599
  lastAssistantAt: tele?.lastAssistantAt,
39468
- subAgents: stampStoppable(tele?.subAgents ?? [], row),
39600
+ subAgents: stampStoppable(orphanedAgents(tele?.subAgents ?? [], deliveryProcessGone), row),
39469
39601
  bgShells: stampStoppableShells(tele?.bgShells ?? [], row),
39470
39602
  links: (registries.links.get(row.slug) ?? []).map(threadLinkView),
39471
39603
  // ONE SOURCE: the FENCE. Both kinds are derived from what the worker wrote — `prs:` entries
@@ -39477,6 +39609,7 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
39477
39609
  pendingQuestion: tele?.pendingQuestion ?? false,
39478
39610
  questions,
39479
39611
  answersInFlight: inFlightAnswers,
39612
+ deliveryInFlight: deliveryInFlight || void 0,
39480
39613
  lastUserAt: tele?.lastUserAt,
39481
39614
  // Runtime provider-auth rejection (claude-auth plan): only the typed category travels — the raw
39482
39615
  // error/provider text never leaves the server. Drives the trusted sign-in recovery card in ChatView.
@@ -39915,7 +40048,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
39915
40048
  }
39916
40049
  };
39917
40050
  }
39918
- var DEBOUNCE_MS, RECONCILE_MS, STALL_GRACE_MS, LINE_CAP, FRIZZ_WATCH_IGNORED_DIRS, DECLARED_PARK_MAX_MS, ANSWER_IN_FLIGHT_EXCUSAL_MS;
40051
+ var DEBOUNCE_MS, RECONCILE_MS, STALL_GRACE_MS, LINE_CAP, FRIZZ_WATCH_IGNORED_DIRS, DECLARED_PARK_MAX_MS, ANSWER_IN_FLIGHT_EXCUSAL_MS, DELIVERY_IN_FLIGHT_SPIN_MS;
39919
40052
  var init_board = __esm({
39920
40053
  "packages/server/src/board.ts"() {
39921
40054
  "use strict";
@@ -39940,6 +40073,7 @@ var init_board = __esm({
39940
40073
  FRIZZ_WATCH_IGNORED_DIRS = ["threads", ".session-state"];
39941
40074
  DECLARED_PARK_MAX_MS = 24 * 60 * 60 * 1e3;
39942
40075
  ANSWER_IN_FLIGHT_EXCUSAL_MS = 6e4;
40076
+ DELIVERY_IN_FLIGHT_SPIN_MS = 6e4;
39943
40077
  }
39944
40078
  });
39945
40079
 
@@ -40726,7 +40860,7 @@ var init_pr_watch_noise = __esm({
40726
40860
  // packages/server/src/scheduler.ts
40727
40861
  import { execFile as execFile8 } from "node:child_process";
40728
40862
  import { promisify as promisify7 } from "node:util";
40729
- import { createHash as createHash12, randomUUID as randomUUID14 } from "node:crypto";
40863
+ import { createHash as createHash13, randomUUID as randomUUID14 } from "node:crypto";
40730
40864
  function failureSignature(rollup) {
40731
40865
  const ids = [];
40732
40866
  for (const c of Array.isArray(rollup) ? rollup : []) {
@@ -40736,7 +40870,7 @@ function failureSignature(rollup) {
40736
40870
  ids.push(`${label}@${c.detailsUrl ?? c.targetUrl ?? c.completedAt ?? ""}`);
40737
40871
  }
40738
40872
  if (ids.length === 0) return "";
40739
- return createHash12("sha1").update(ids.sort().join("\n")).digest("hex").slice(0, 12);
40873
+ return createHash13("sha1").update(ids.sort().join("\n")).digest("hex").slice(0, 12);
40740
40874
  }
40741
40875
  function ghPrViewArgs(ref) {
40742
40876
  return ["pr", "view", String(ref.number), "--repo", `${ref.owner}/${ref.repo}`, "--json", "state,mergedAt,statusCheckRollup,headRefOid,mergeable,reviewDecision"];
@@ -40824,7 +40958,7 @@ function githubWatchStatus(pr2, polledAt) {
40824
40958
  };
40825
40959
  }
40826
40960
  function wakeDeliveryId(slug, sessionId, fenceId) {
40827
- return createHash12("sha256").update(slug).update("\0").update(sessionId).update("\0").update(fenceId).digest("hex");
40961
+ return createHash13("sha256").update(slug).update("\0").update(sessionId).update("\0").update(fenceId).digest("hex");
40828
40962
  }
40829
40963
  function limitFenceId(fault) {
40830
40964
  return `${LIMIT_FENCE_PREFIX}${fault.at}`;
@@ -40839,7 +40973,7 @@ function isReportFenceId(fenceId) {
40839
40973
  return fenceId.startsWith(`${REPORT_FENCE_PREFIX}:`);
40840
40974
  }
40841
40975
  function snoozeFenceId(until, prompt) {
40842
- const digest = createHash12("sha256").update(prompt).digest("hex").slice(0, 16);
40976
+ const digest = createHash13("sha256").update(prompt).digest("hex").slice(0, 16);
40843
40977
  return `${SNOOZE_FENCE_PREFIX}:${until}:${digest}`;
40844
40978
  }
40845
40979
  function isSnoozeFenceId(fenceId) {
@@ -40983,7 +41117,7 @@ function isOwnWatchExpiredFenceId(fenceId) {
40983
41117
  return fenceId.startsWith(`${OWN_WATCH_EXPIRED_FENCE_PREFIX}:`);
40984
41118
  }
40985
41119
  function questionAnswerFenceId(ids) {
40986
- return `${QUESTION_ANSWER_FENCE_PREFIX}:${createHash12("sha256").update([...ids].sort().join(",")).digest("hex").slice(0, 16)}`;
41120
+ return `${QUESTION_ANSWER_FENCE_PREFIX}:${createHash13("sha256").update([...ids].sort().join(",")).digest("hex").slice(0, 16)}`;
40987
41121
  }
40988
41122
  function isQuestionAnswerFenceId(fenceId) {
40989
41123
  return fenceId.startsWith(`${QUESTION_ANSWER_FENCE_PREFIX}:`);
@@ -43470,7 +43604,7 @@ var init_acp_rpc = __esm({
43470
43604
  // packages/server/src/backend/acp-host.ts
43471
43605
  import { spawn as spawn7 } from "node:child_process";
43472
43606
  import { createConnection as createConnection2 } from "node:net";
43473
- import { createHash as createHash13, randomUUID as randomUUID15 } from "node:crypto";
43607
+ import { createHash as createHash14, randomUUID as randomUUID15 } from "node:crypto";
43474
43608
  import { existsSync as existsSync14, mkdirSync as mkdirSync15, readFileSync as readFileSync22, readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
43475
43609
  import { join as join34 } from "node:path";
43476
43610
  import { PassThrough as PassThrough3, Writable as Writable3 } from "node:stream";
@@ -43482,7 +43616,7 @@ function acpDaemonRecordPath(stateDir, sessionId) {
43482
43616
  return join34(daemonDir2(stateDir), `${sessionId}.json`);
43483
43617
  }
43484
43618
  function acpDaemonSocketPath(stateDir, sessionId) {
43485
- const key = createHash13("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
43619
+ const key = createHash14("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
43486
43620
  return frizzIpcPath(`frizz-acp-${key}`);
43487
43621
  }
43488
43622
  function pidAlive4(pid) {
@@ -69792,9 +69926,10 @@ var init_stale_socket_sweep = __esm({
69792
69926
  });
69793
69927
 
69794
69928
  // packages/server/src/orphan-reaper.ts
69795
- import { execFileSync as execFileSync4 } from "node:child_process";
69929
+ import { execFile as execFile10 } from "node:child_process";
69796
69930
  import { readFileSync as readFileSync24 } from "node:fs";
69797
69931
  import { dirname as dirname16 } from "node:path";
69932
+ import { promisify as promisify8 } from "node:util";
69798
69933
  function firstTokenBasename(command) {
69799
69934
  const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
69800
69935
  const slash = first.lastIndexOf("/");
@@ -69893,8 +70028,8 @@ function parseEtimeMs(etime) {
69893
70028
  else return 0;
69894
70029
  return (((days * 24 + h2) * 60 + m) * 60 + s) * 1e3;
69895
70030
  }
69896
- function enumerateProcs(exec = defaultExec, opts = {}) {
69897
- const base = exec("ps", ["-Aww", "-o", "pid=,ppid=,etime=,command="]);
70031
+ async function enumerateProcs(exec = defaultExec, opts = {}) {
70032
+ const base = await exec("ps", ["-Aww", "-o", "pid=,ppid=,etime=,command="]);
69898
70033
  const rows = [];
69899
70034
  const byPid = /* @__PURE__ */ new Map();
69900
70035
  const pids = [];
@@ -69927,7 +70062,7 @@ function enumerateProcs(exec = defaultExec, opts = {}) {
69927
70062
  }
69928
70063
  let text2;
69929
70064
  try {
69930
- text2 = exec("ps", ["-Eww", "-o", "pid=,command=", "-p", pids.join(",")]);
70065
+ text2 = await exec("ps", ["-Eww", "-o", "pid=,command=", "-p", pids.join(",")]);
69931
70066
  } catch {
69932
70067
  return rows;
69933
70068
  }
@@ -69962,12 +70097,12 @@ function parseCpuTimeMs(value) {
69962
70097
  const ms = ((Number(d ?? 0) * 24 + Number(h2 ?? 0)) * 3600 + Number(min) * 60 + Number(s)) * 1e3;
69963
70098
  return Number.isFinite(ms) ? ms : 0;
69964
70099
  }
69965
- function detectRunawayAux(rows, liveSlugs, exec = defaultExec, options = {}) {
70100
+ async function detectRunawayAux(rows, liveSlugs, exec = defaultExec, options = {}) {
69966
70101
  const minCores = options.minCores ?? 0.5;
69967
70102
  const minAgeMs = options.minAgeMs ?? 30 * 6e4;
69968
70103
  let text2;
69969
70104
  try {
69970
- text2 = exec("ps", ["-Ao", "pid=,cputime="]);
70105
+ text2 = await exec("ps", ["-Ao", "pid=,cputime="]);
69971
70106
  } catch {
69972
70107
  return [];
69973
70108
  }
@@ -69994,13 +70129,13 @@ function summarizeRunaways(runaways) {
69994
70129
  return `orphan-reaper: thread "${slug}" is holding ~${cores.toFixed(1)} core(s) across ${list.length} background process(es), oldest ${hours}h \u2014 frizz dispatched these but does not reap a LIVE thread's work`;
69995
70130
  });
69996
70131
  }
69997
- function sweepOrphansOnce(deps = {}) {
70132
+ async function sweepOrphansOnce(deps = {}) {
69998
70133
  const exec = deps.exec ?? defaultExec;
69999
70134
  const selfPid = deps.selfPid ?? process.pid;
70000
70135
  const minAgeMs = deps.minAgeMs ?? ORPHAN_MIN_AGE_MS;
70001
70136
  let rows;
70002
70137
  try {
70003
- rows = enumerateProcs(exec, { platform: deps.platform, readEnv: deps.readEnv });
70138
+ rows = await enumerateProcs(exec, { platform: deps.platform, readEnv: deps.readEnv });
70004
70139
  } catch (error) {
70005
70140
  const code = error?.code;
70006
70141
  return { reaped: 0, deadSlugs: [], liveSlugs: [], ...code === "ENOENT" ? { unavailable: "`ps` is not on PATH" } : {} };
@@ -70008,7 +70143,7 @@ function sweepOrphansOnce(deps = {}) {
70008
70143
  const protectedPids = selfAndAncestors(rows, selfPid);
70009
70144
  const { reap, liveSlugs } = decideOrphans(rows, { minAgeMs, protectedPids });
70010
70145
  if (deps.log && deps.runawayReport !== false) {
70011
- for (const line of summarizeRunaways(detectRunawayAux(rows, new Set(liveSlugs), exec, deps.runaway))) deps.log(line);
70146
+ for (const line of summarizeRunaways(await detectRunawayAux(rows, new Set(liveSlugs), exec, deps.runaway))) deps.log(line);
70012
70147
  }
70013
70148
  if (!reap.length) return { reaped: 0, deadSlugs: [], liveSlugs };
70014
70149
  const bySlug = new Map(rows.map((r) => [r.pid, r.slug]));
@@ -70033,34 +70168,60 @@ function startOrphanReaper(deps = {}) {
70033
70168
  };
70034
70169
  }
70035
70170
  const intervalMs = deps.intervalMs ?? ORPHAN_REAP_INTERVAL_MS;
70036
- const unavailable = (result) => {
70037
- if (!result.unavailable) return false;
70038
- deps.log?.(`orphan-reaper: unavailable on this machine \u2014 ${result.unavailable}; background processes a stopped thread leaves behind are not collected here`);
70039
- return true;
70171
+ let stopped = false;
70172
+ let timer = null;
70173
+ let sweeping = false;
70174
+ const stopSweeps = () => {
70175
+ if (timer) clearInterval(timer);
70176
+ timer = null;
70040
70177
  };
70041
- try {
70042
- if (unavailable(sweepOrphansOnce(deps))) return () => {
70043
- };
70044
- } catch {
70045
- }
70046
- const timer = setInterval(() => {
70178
+ const sweep = async () => {
70179
+ if (sweeping || stopped) return;
70180
+ sweeping = true;
70047
70181
  try {
70048
- if (unavailable(sweepOrphansOnce(deps))) clearInterval(timer);
70182
+ const result = await sweepOrphansOnce(deps);
70183
+ if (result.unavailable && !stopped) {
70184
+ stopped = true;
70185
+ stopSweeps();
70186
+ deps.log?.(`orphan-reaper: unavailable on this machine \u2014 ${result.unavailable}; background processes a stopped thread leaves behind are not collected here`);
70187
+ }
70049
70188
  } catch {
70189
+ } finally {
70190
+ sweeping = false;
70050
70191
  }
70051
- }, intervalMs);
70052
- timer.unref?.();
70192
+ };
70193
+ void sweep().then(() => {
70194
+ if (stopped) return;
70195
+ timer = setInterval(() => void sweep(), intervalMs);
70196
+ timer.unref?.();
70197
+ });
70053
70198
  const socketDelay = setTimeout(sweepStaleBrokerSockets, STALE_SOCKET_SWEEP_DELAY_MS);
70054
70199
  socketDelay.unref?.();
70055
70200
  const socketTimer = setInterval(sweepStaleBrokerSockets, STALE_SOCKET_SWEEP_INTERVAL_MS);
70056
70201
  socketTimer.unref?.();
70057
70202
  return () => {
70058
- clearInterval(timer);
70203
+ stopped = true;
70204
+ stopSweeps();
70059
70205
  clearTimeout(socketDelay);
70060
70206
  clearInterval(socketTimer);
70061
70207
  };
70062
70208
  }
70063
- var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, defaultExec, defaultReadEnv, defaultKill2, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX, UNAVAILABLE_ON_WINDOWS;
70209
+ function acquireSharedOrphanReaper(deps = {}) {
70210
+ if (!shared) shared = { refs: 0, stop: startOrphanReaper(deps) };
70211
+ const handle = shared;
70212
+ handle.refs++;
70213
+ let released = false;
70214
+ return () => {
70215
+ if (released) return;
70216
+ released = true;
70217
+ handle.refs--;
70218
+ if (handle.refs === 0 && shared === handle) {
70219
+ shared = null;
70220
+ handle.stop();
70221
+ }
70222
+ };
70223
+ }
70224
+ var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, execFileAsync6, defaultExec, defaultReadEnv, defaultKill2, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX, UNAVAILABLE_ON_WINDOWS, shared;
70064
70225
  var init_orphan_reaper = __esm({
70065
70226
  "packages/server/src/orphan-reaper.ts"() {
70066
70227
  "use strict";
@@ -70069,7 +70230,8 @@ var init_orphan_reaper = __esm({
70069
70230
  ORPHAN_REAP_INTERVAL_MS = 6e4;
70070
70231
  ORPHAN_MIN_AGE_MS = 12e4;
70071
70232
  SLUG_RE = /FRIZZ_THREAD=([A-Za-z0-9._-]+)/;
70072
- defaultExec = (file, args) => execFileSync4(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 });
70233
+ execFileAsync6 = promisify8(execFile10);
70234
+ defaultExec = async (file, args) => (await execFileAsync6(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout;
70073
70235
  defaultReadEnv = (pid) => {
70074
70236
  try {
70075
70237
  return readFileSync24(`/proc/${pid}/environ`, "utf8");
@@ -70087,6 +70249,7 @@ var init_orphan_reaper = __esm({
70087
70249
  STALE_SOCKET_SWEEP_DELAY_MS = 3e4;
70088
70250
  CLAUDE_BROKER_SOCKET_PREFIX = "frizz-claude-";
70089
70251
  UNAVAILABLE_ON_WINDOWS = "orphan-reaper: unavailable on Windows \u2014 a worker's FRIZZ_THREAD is read from its process environment, which Windows does not expose; background processes a stopped thread leaves behind are not collected here, and a live thread's runaway work is not reported";
70252
+ shared = null;
70090
70253
  }
70091
70254
  });
70092
70255
 
@@ -70305,7 +70468,7 @@ function createContextUnchecked(opts, resources) {
70305
70468
  contextUnsubscribers.push(() => clearInterval(quotaRefreshTimer));
70306
70469
  }
70307
70470
  if (!process.env.FRIZZ_ORPHAN_REAPER_OFF) {
70308
- contextUnsubscribers.push(startOrphanReaper({ log: (m) => log.info("reaper", m) }));
70471
+ contextUnsubscribers.push(acquireSharedOrphanReaper({ log: (m) => log.info("reaper", m) }));
70309
70472
  }
70310
70473
  opts.startup?.afterPhase?.("orphan reaper");
70311
70474
  reconcileSessions(storage);
@@ -73519,10 +73682,10 @@ var init_edited_files = __esm({
73519
73682
  });
73520
73683
 
73521
73684
  // packages/server/src/repo-files.ts
73522
- import { execFileSync as execFileSync5 } from "node:child_process";
73685
+ import { execFileSync as execFileSync4 } from "node:child_process";
73523
73686
  import path2 from "node:path";
73524
73687
  function git(args, cwd) {
73525
- return execFileSync5("git", args, {
73688
+ return execFileSync4("git", args, {
73526
73689
  cwd,
73527
73690
  encoding: "utf8",
73528
73691
  env: { ...process.env, LC_ALL: "C" },
@@ -73563,7 +73726,7 @@ function probeIgnored(projectDir, inside) {
73563
73726
  return /* @__PURE__ */ new Set();
73564
73727
  }
73565
73728
  try {
73566
- const out = execFileSync5("git", ["check-ignore", "-z", "--stdin"], {
73729
+ const out = execFileSync4("git", ["check-ignore", "-z", "--stdin"], {
73567
73730
  cwd: projectDir,
73568
73731
  encoding: "utf8",
73569
73732
  env: { ...process.env, LC_ALL: "C" },
@@ -73755,7 +73918,7 @@ var init_bash_background = __esm({
73755
73918
 
73756
73919
  // packages/server/src/transcript.ts
73757
73920
  import { closeSync as closeSync14, existsSync as existsSync17, fstatSync as fstatSync3, mkdirSync as mkdirSync18, openSync as openSync15, readdirSync as readdirSync11, readFileSync as readFileSync27, readSync as readSync8, renameSync as renameSync10, statSync as statSync17, unlinkSync as unlinkSync7, writeFileSync as writeFileSync12 } from "node:fs";
73758
- import { createHash as createHash14 } from "node:crypto";
73921
+ import { createHash as createHash15 } from "node:crypto";
73759
73922
  import { StringDecoder as StringDecoder6 } from "node:string_decoder";
73760
73923
  import { join as join39 } from "node:path";
73761
73924
  import { homedir as homedir16 } from "node:os";
@@ -74394,7 +74557,7 @@ function persistDataUrlImage(dataUrl, idKey) {
74394
74557
  function persistBase64Image(mediaType, data, idKey) {
74395
74558
  const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
74396
74559
  if (!ext || !data) return void 0;
74397
- const name = createHash14("sha256").update(idKey).digest("hex").slice(0, 32);
74560
+ const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
74398
74561
  const path3 = join39(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
74399
74562
  try {
74400
74563
  if (existsSync17(path3)) return path3;
@@ -74416,7 +74579,7 @@ function persistSentFile(srcPath, idKey) {
74416
74579
  if (!ATTACHMENT_IMAGE_EXTENSIONS.includes(ext)) return void 0;
74417
74580
  const outExt = ext === "jpeg" ? "jpg" : ext;
74418
74581
  try {
74419
- const name = createHash14("sha256").update(idKey).digest("hex").slice(0, 32);
74582
+ const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
74420
74583
  const dest = join39(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
74421
74584
  if (existsSync17(dest)) return dest;
74422
74585
  const size = statSync17(srcPath).size;
@@ -75230,7 +75393,7 @@ function latestTranscriptWindow(messages) {
75230
75393
  );
75231
75394
  if (tools.length === 0) continue;
75232
75395
  pinned.push({
75233
- sourceId: `pinned-bg:${createHash14("sha256").update(message.sourceId).digest("base64url").slice(0, 24)}`,
75396
+ sourceId: `pinned-bg:${createHash15("sha256").update(message.sourceId).digest("base64url").slice(0, 24)}`,
75234
75397
  pinnedFromSourceId: message.sourceId,
75235
75398
  role: "assistant",
75236
75399
  text: "",
@@ -76026,7 +76189,7 @@ function fixedSnapshot(source) {
76026
76189
  };
76027
76190
  let allBytes;
76028
76191
  const fileKey = `${before.dev}:${before.ino}:${Math.trunc(before.birthtimeMs)}`;
76029
- const transcriptKey = createHash14("sha256").update(`${source.slug}\0${source.sessionId}\0${source.nativeId}\0${source.backend}\0${source.runtimeGeneration}\0${fileKey}`).digest("base64url").slice(0, 32);
76192
+ const transcriptKey = createHash15("sha256").update(`${source.slug}\0${source.sessionId}\0${source.nativeId}\0${source.backend}\0${source.runtimeGeneration}\0${fileKey}`).digest("base64url").slice(0, 32);
76030
76193
  let rawText;
76031
76194
  return {
76032
76195
  ...source,
@@ -76059,7 +76222,7 @@ function projectSnapshot(snapshot) {
76059
76222
  return retireStaleQueuedBubbles([...entry.fold.allMessages()]);
76060
76223
  }
76061
76224
  function digestPrefix(bytes, length = bytes.length) {
76062
- return createHash14("sha256").update(bytes.subarray(0, length)).digest("base64url");
76225
+ return createHash15("sha256").update(bytes.subarray(0, length)).digest("base64url");
76063
76226
  }
76064
76227
  function fullDigest(snapshot) {
76065
76228
  const key = `${snapshot.fileKey}\0${snapshot.size}`;
@@ -76069,7 +76232,7 @@ function fullDigest(snapshot) {
76069
76232
  fullDigestCache.set(key, hit);
76070
76233
  return hit;
76071
76234
  }
76072
- const hash = createHash14("sha256");
76235
+ const hash = createHash15("sha256");
76073
76236
  for (let at2 = 0; at2 < snapshot.size; ) {
76074
76237
  const buf = snapshot.readRange(at2, Math.min(TRANSCRIPT_DECODE_WINDOW, snapshot.size - at2));
76075
76238
  if (buf.length === 0) break;
@@ -76152,7 +76315,7 @@ function emptyTranscriptPage(source) {
76152
76315
  beforeCursor: null,
76153
76316
  hasEarlier: false,
76154
76317
  reachedTurnBoundary: true,
76155
- transcriptKey: createHash14("sha256").update(keySeed).digest("base64url").slice(0, 32),
76318
+ transcriptKey: createHash15("sha256").update(keySeed).digest("base64url").slice(0, 32),
76156
76319
  editedFiles: []
76157
76320
  };
76158
76321
  }
@@ -76293,7 +76456,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
76293
76456
  }
76294
76457
  function readTranscriptFile(absPath) {
76295
76458
  try {
76296
- const pathKey = createHash14("sha256").update(absPath).digest("base64url").slice(0, 16);
76459
+ const pathKey = createHash15("sha256").update(absPath).digest("base64url").slice(0, 16);
76297
76460
  return parseTranscript(readFileSync27(absPath, "utf8"), `claude-file:${pathKey}`);
76298
76461
  } catch {
76299
76462
  return [];
@@ -76694,8 +76857,8 @@ var init_github_hovercard = __esm({
76694
76857
  });
76695
76858
 
76696
76859
  // packages/server/src/backend/account-actions.ts
76697
- import { execFile as execFile10 } from "node:child_process";
76698
- import { promisify as promisify8 } from "node:util";
76860
+ import { execFile as execFile11 } from "node:child_process";
76861
+ import { promisify as promisify9 } from "node:util";
76699
76862
  function liveThreadsForBackend(threads, backend) {
76700
76863
  let count = 0;
76701
76864
  for (const thread of threads) {
@@ -76715,7 +76878,7 @@ async function runProviderLogout(opts) {
76715
76878
  const args = opts.backend === "codex" ? ["logout"] : ["auth", "logout"];
76716
76879
  let failure;
76717
76880
  try {
76718
- await execFileAsync6(bin, args, { encoding: "utf8", timeout: opts.timeoutMs ?? 15e3 });
76881
+ await execFileAsync7(bin, args, { encoding: "utf8", timeout: opts.timeoutMs ?? 15e3 });
76719
76882
  } catch (err) {
76720
76883
  const e14 = err;
76721
76884
  const stderr = typeof e14.stderr === "string" ? e14.stderr.trim() : "";
@@ -76725,12 +76888,12 @@ async function runProviderLogout(opts) {
76725
76888
  if (failure && auth !== "signed-out") return { status: "failed", detail: failure, auth };
76726
76889
  return { status: "done", auth };
76727
76890
  }
76728
- var execFileAsync6, LIVE_RUNTIMES;
76891
+ var execFileAsync7, LIVE_RUNTIMES;
76729
76892
  var init_account_actions = __esm({
76730
76893
  "packages/server/src/backend/account-actions.ts"() {
76731
76894
  "use strict";
76732
76895
  init_auth_status();
76733
- execFileAsync6 = promisify8(execFile10);
76896
+ execFileAsync7 = promisify9(execFile11);
76734
76897
  LIVE_RUNTIMES = /* @__PURE__ */ new Set(["spawning", "running", "perm-prompt"]);
76735
76898
  }
76736
76899
  });
@@ -77005,8 +77168,8 @@ var init_image_header = __esm({
77005
77168
  });
77006
77169
 
77007
77170
  // packages/server/src/directory-picker.ts
77008
- import { execFile as execFile11 } from "node:child_process";
77009
- import { promisify as promisify9 } from "node:util";
77171
+ import { execFile as execFile12 } from "node:child_process";
77172
+ import { promisify as promisify10 } from "node:util";
77010
77173
  async function pickImageFile(startIn, prompt = "Choose an image for this project", platform3 = process.platform) {
77011
77174
  if (platform3 === "darwin") {
77012
77175
  const location = startIn ? ` default location POSIX file ${JSON.stringify(startIn)}` : "";
@@ -77116,7 +77279,7 @@ var run2, PICKER_TIMEOUT_MS, timedOut, unanswered, OSASCRIPT, WINDOWS_PICKER_EDI
77116
77279
  var init_directory_picker = __esm({
77117
77280
  "packages/server/src/directory-picker.ts"() {
77118
77281
  "use strict";
77119
- run2 = promisify9(execFile11);
77282
+ run2 = promisify10(execFile12);
77120
77283
  PICKER_TIMEOUT_MS = 5 * 6e4;
77121
77284
  timedOut = (error) => error.killed === true;
77122
77285
  unanswered = (what) => ({
@@ -78680,6 +78843,7 @@ ${gapNote}` : input.message;
78680
78843
  fireAtMs: Date.parse(input.fireAt),
78681
78844
  createdAtMs: Date.now()
78682
78845
  });
78846
+ ctx.board.refresh();
78683
78847
  return { id, fireAt: input.fireAt, timers: armedTimerViews(input.slug) };
78684
78848
  }
78685
78849
  }),
@@ -78688,6 +78852,7 @@ ${gapNote}` : input.message;
78688
78852
  output: CancelOwnThreadTimerResult,
78689
78853
  handler: async ({ input }) => {
78690
78854
  const cancelled = ctx.storage.cancelThreadTimer(input.slug, input.id, Date.now());
78855
+ if (cancelled) ctx.board.refresh();
78691
78856
  return { cancelled, timers: armedTimerViews(input.slug) };
78692
78857
  }
78693
78858
  }),
@@ -78811,7 +78976,8 @@ ${gapNote}` : input.message;
78811
78976
  throw new Error(`\`${input.target}\` is not ${kind === "issue" ? "an issue" : "a pull request"} I can watch \u2014 give owner/repo#123 or ${kind === "issue" ? "an issue" : "a PR"} URL`);
78812
78977
  }
78813
78978
  const armed = ctx.storage.listPrWatches(input.slug, { armedOnly: true });
78814
- const existing = armed.find((w) => w.kind === kind && w.owner === ref.owner && w.repo === ref.repo && w.number === ref.number);
78979
+ const sameName = (a, b) => a.toLowerCase() === b.toLowerCase();
78980
+ const existing = armed.find((w) => w.kind === kind && sameName(w.owner, ref.owner) && sameName(w.repo, ref.repo) && w.number === ref.number);
78815
78981
  const target = `${ref.owner}/${ref.repo}#${ref.number}`;
78816
78982
  if (existing) {
78817
78983
  const expiresAt = new Date(existing.expires_at ?? Date.now()).toISOString();
@@ -80645,7 +80811,7 @@ var init_app = __esm({
80645
80811
  });
80646
80812
 
80647
80813
  // packages/server/src/app-socket.ts
80648
- import { createHash as createHash15 } from "node:crypto";
80814
+ import { createHash as createHash16 } from "node:crypto";
80649
80815
  function isWsPath(url) {
80650
80816
  return (url ?? "").split("?")[0] === WS_PATH;
80651
80817
  }
@@ -80849,7 +81015,7 @@ function createAppSocketServer(deps) {
80849
81015
  sendEncoded(ws, frame, false);
80850
81016
  }
80851
81017
  function frameSignature(frame) {
80852
- return createHash15("sha256").update(frame.text).digest("base64url");
81018
+ return createHash16("sha256").update(frame.text).digest("base64url");
80853
81019
  }
80854
81020
  const globalReadTimes = [];
80855
81021
  const originReadTimes = /* @__PURE__ */ new Map();
@@ -81697,7 +81863,7 @@ var init_runtime_lease = __esm({
81697
81863
  });
81698
81864
 
81699
81865
  // packages/server/src/runtimes.ts
81700
- import { createHash as createHash16 } from "node:crypto";
81866
+ import { createHash as createHash17 } from "node:crypto";
81701
81867
  import {
81702
81868
  chmodSync,
81703
81869
  closeSync as closeSync17,
@@ -81811,7 +81977,7 @@ async function provisionRuntime(backend, options) {
81811
81977
  const response = await fetchImpl(tarball);
81812
81978
  if (!response.ok || !response.body) throw new Error(`tarball download answered ${response.status}`);
81813
81979
  const total = Number(response.headers.get("content-length") ?? 0);
81814
- const hash = createHash16("sha512");
81980
+ const hash = createHash17("sha512");
81815
81981
  let seen = 0;
81816
81982
  let lastReport = 0;
81817
81983
  const hasher = new Transform({