frizz 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +1 -1
  2. package/dist/claude-agent-broker.js +9 -3
  3. package/dist/codex-app-server-daemon.js +12 -3
  4. package/dist/dev-child.js +387 -209
  5. package/dist/frizz.js +36 -4
  6. package/package.json +2 -2
  7. package/web-dist/assets/{TerminalPane-DW91LtY6.js → TerminalPane-K-DhxpCR.js} +1 -1
  8. package/web-dist/assets/{abnfDiagram-VRR7QNED-Cz9pKsnx.js → abnfDiagram-VRR7QNED-D1qyMYic.js} +1 -1
  9. package/web-dist/assets/architecture-TIHT7OUA-DhCDPuB9.js +1 -0
  10. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-Cx1Inab9.js → architectureDiagram-ZJ3FMSHR-B7OHBGs-.js} +1 -1
  11. package/web-dist/assets/{blockDiagram-677ZJIJ3-Dkow3KWq.js → blockDiagram-677ZJIJ3-BOkbWfnO.js} +1 -1
  12. package/web-dist/assets/{c4Diagram-LMCZKHZV-D54f0v8B.js → c4Diagram-LMCZKHZV-DcfWo37Z.js} +1 -1
  13. package/web-dist/assets/channel-C0ssx150.js +1 -0
  14. package/web-dist/assets/{chunk-32BRIVSS-5HfLNqOq.js → chunk-32BRIVSS-DG_MDBh7.js} +1 -1
  15. package/web-dist/assets/{chunk-52WLFC77-CoVH-jjk.js → chunk-52WLFC77-HgYoNFkS.js} +1 -1
  16. package/web-dist/assets/{chunk-C7G6YPKG-w41h00On.js → chunk-C7G6YPKG-Dfpg508V.js} +1 -1
  17. package/web-dist/assets/{chunk-EX3LRPZG-BC_Frphy.js → chunk-EX3LRPZG-zaEux9Wm.js} +1 -1
  18. package/web-dist/assets/{chunk-FWX5IMBZ-DLZVUhWr.js → chunk-FWX5IMBZ-CpSICFGT.js} +2 -2
  19. package/web-dist/assets/{chunk-HOUHSVGY-DCl7dozs.js → chunk-HOUHSVGY-CSwYs-ck.js} +1 -1
  20. package/web-dist/assets/{chunk-ICXQ74PX-I8bc3hpu.js → chunk-ICXQ74PX-CkRfiAJk.js} +1 -1
  21. package/web-dist/assets/{chunk-MOJQB5TN-D1tbS5-A.js → chunk-MOJQB5TN-DFtJBynx.js} +1 -1
  22. package/web-dist/assets/{chunk-OGEWGWER-CLa17J5_.js → chunk-OGEWGWER-B1ST2fth.js} +1 -1
  23. package/web-dist/assets/{chunk-PUDLZKDR-DcYIQuxf.js → chunk-PUDLZKDR-B7ABSn_A.js} +1 -1
  24. package/web-dist/assets/{chunk-Q4XR5HBZ-DGHqsWli.js → chunk-Q4XR5HBZ-CivO3j1P.js} +1 -1
  25. package/web-dist/assets/{chunk-V7JOEXUC-DdVYI4tg.js → chunk-V7JOEXUC-BaM6_dmG.js} +1 -1
  26. package/web-dist/assets/{chunk-VAUOI2AC-Dn_uoDoN.js → chunk-VAUOI2AC-BY3O_FOQ.js} +1 -1
  27. package/web-dist/assets/{chunk-VR4S4FIN-AM_J_EWt.js → chunk-VR4S4FIN-BIV_iEar.js} +1 -1
  28. package/web-dist/assets/{chunk-WYO6CB5R-BldKUlC0.js → chunk-WYO6CB5R-CUi65Li4.js} +1 -1
  29. package/web-dist/assets/{chunk-ZGVPDNZ5-Oh85mcuX.js → chunk-ZGVPDNZ5-Dg0vMfMN.js} +1 -1
  30. package/web-dist/assets/classDiagram-OUVF2IWQ-DGsI7bj0.js +1 -0
  31. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DGsI7bj0.js +1 -0
  32. package/web-dist/assets/{cynefin-VYW2F7L2-5lF8kTLT.js → cynefin-VYW2F7L2-DWJeaT_t.js} +1 -1
  33. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-_otwu953.js → cynefinDiagram-TSTJHNR4-ClaGZDTr.js} +1 -1
  34. package/web-dist/assets/{dagre-VKFMJZFB-DxX5d4Jp.js → dagre-VKFMJZFB-C0pp3Xyc.js} +1 -1
  35. package/web-dist/assets/{diagram-FQU43EPY-JkCl7NEC.js → diagram-FQU43EPY-SSBAJs6v.js} +1 -1
  36. package/web-dist/assets/{diagram-G47NLZAW-ETwnVi8G.js → diagram-G47NLZAW-3GFBBF81.js} +1 -1
  37. package/web-dist/assets/{diagram-NH7WQ7WH-DZXKHMOv.js → diagram-NH7WQ7WH-DqYwuzE7.js} +1 -1
  38. package/web-dist/assets/{diagram-OA4YK3LP--Yt9Hbcy.js → diagram-OA4YK3LP-K6M4KioM.js} +1 -1
  39. package/web-dist/assets/{diagram-WEI45ONY-BXUskT8t.js → diagram-WEI45ONY-ByTNMmJD.js} +1 -1
  40. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-C7E1X1Dl.js → ebnfDiagram-CCIWWBDH-Bl6rAFTA.js} +1 -1
  41. package/web-dist/assets/{erDiagram-Q63AITRT-DOfGp1t7.js → erDiagram-Q63AITRT-BGWlKkvA.js} +1 -1
  42. package/web-dist/assets/eventmodeling-45OFAUF4-CwE_bxam.js +1 -0
  43. package/web-dist/assets/flowDiagram-23GEKE2U-BY0J247Q.js +1 -0
  44. package/web-dist/assets/{ganttDiagram-NO4QXBWP-P5HZV3uF.js → ganttDiagram-NO4QXBWP-C5eEoPLo.js} +1 -1
  45. package/web-dist/assets/{gitGraph-TEB2WS4Q-CsJYjOme.js → gitGraph-TEB2WS4Q-BNmphrH5.js} +1 -1
  46. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-BNyrduBc.js → gitGraphDiagram-IHSO6WYX-zHU_D41b.js} +1 -1
  47. package/web-dist/assets/index-C-3lsl4q.css +1 -0
  48. package/web-dist/assets/{index-CYVVF_ZU.js → index-Kzg-vTmI.js} +114 -114
  49. package/web-dist/assets/{info-DKCQHKI2-WzpT_dbU.js → info-DKCQHKI2-BfD-7Xcw.js} +1 -1
  50. package/web-dist/assets/{infoDiagram-FWYZ7A6U-CA_SxvAY.js → infoDiagram-FWYZ7A6U-CR3bcaik.js} +1 -1
  51. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DXMy0GH9.js → ishikawaDiagram-FXEZZL3T-VtEgUbJP.js} +1 -1
  52. package/web-dist/assets/{journeyDiagram-5HDEW3XC-Bwmn4bNv.js → journeyDiagram-5HDEW3XC-DZ3fGB6L.js} +1 -1
  53. package/web-dist/assets/{kanban-definition-HUTT4EX6-D265Z0Fg.js → kanban-definition-HUTT4EX6-ChfTvN7D.js} +1 -1
  54. package/web-dist/assets/{line-DNn_Towe.js → line-B6kig2Co.js} +1 -1
  55. package/web-dist/assets/{mermaid-parser.core-3CrMhKoT.js → mermaid-parser.core-jyk1DbDV.js} +3 -3
  56. package/web-dist/assets/{mermaid.core-DfCFu8_x.js → mermaid.core-C5yyeZnx.js} +3 -3
  57. package/web-dist/assets/{mindmap-definition-LN4V7U3C-CQ5g8Qrh.js → mindmap-definition-LN4V7U3C-BcXFy-N9.js} +1 -1
  58. package/web-dist/assets/{packet-7NZHBO7P-CRDQ5t5W.js → packet-7NZHBO7P-BXfwnw74.js} +1 -1
  59. package/web-dist/assets/{pegDiagram-2B236MQR-B0XFyb7d.js → pegDiagram-2B236MQR-BCD3YN2p.js} +1 -1
  60. package/web-dist/assets/{pie-RZYD4A2V-DqjiBFGO.js → pie-RZYD4A2V-AinCQhe4.js} +1 -1
  61. package/web-dist/assets/{pieDiagram-ENE6RG2P-C41GJ3-U.js → pieDiagram-ENE6RG2P-D91RCAtQ.js} +1 -1
  62. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-9cF0WJaM.js → quadrantDiagram-ABIIQ3AL-CiOs81pa.js} +1 -1
  63. package/web-dist/assets/{radar-I7S5WNFK-S1F7Z4Kj.js → radar-I7S5WNFK-PjwSEfhJ.js} +1 -1
  64. package/web-dist/assets/{railroad-3IZDKUUU-da9Pjcp1.js → railroad-3IZDKUUU-De7aPcv6.js} +1 -1
  65. package/web-dist/assets/railroad-abnf-AHOZXSZD-BdaR6aMg.js +1 -0
  66. package/web-dist/assets/railroad-ebnf-EBAXGLYW-BQ1i-m_V.js +1 -0
  67. package/web-dist/assets/railroad-peg-LSFZ7HO6-Bz7gY9Z5.js +1 -0
  68. package/web-dist/assets/{railroadDiagram-RFXS5EU6-CkXBDByE.js → railroadDiagram-RFXS5EU6-Ba5vfAy2.js} +1 -1
  69. package/web-dist/assets/{requirementDiagram-TGXJPOKE-CL9Famg0.js → requirementDiagram-TGXJPOKE-cl6D_V6r.js} +1 -1
  70. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-LyB-A0pD.js → sankeyDiagram-HTMAVEWB-BiL7lO9N.js} +1 -1
  71. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DXfA9UDM.js → sequenceDiagram-DBY2YBRQ-DWwMnGgF.js} +1 -1
  72. package/web-dist/assets/{stateDiagram-2N3HPSRC-DgxMkPRv.js → stateDiagram-2N3HPSRC-DyDSg9bX.js} +1 -1
  73. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DdKoRulX.js +1 -0
  74. package/web-dist/assets/{swimlanes-5IMT3BWC-TvRb3Iib.js → swimlanes-5IMT3BWC-DXcDUTKt.js} +1 -1
  75. package/web-dist/assets/swimlanesDiagram-G3AALYLV-e28nOYgP.js +8 -0
  76. package/web-dist/assets/{timeline-definition-FHXFAJF6-BBvC3bzZ.js → timeline-definition-FHXFAJF6-BmhB--di.js} +1 -1
  77. package/web-dist/assets/{treeView-QDETBFTQ-CvCYIkJk.js → treeView-QDETBFTQ-uZOu6XJp.js} +1 -1
  78. package/web-dist/assets/{treemap-6X3UGDF4-Bj60PrS0.js → treemap-6X3UGDF4-vvG-U9_8.js} +1 -1
  79. package/web-dist/assets/{vennDiagram-L72KCM5P-CLuLJiNi.js → vennDiagram-L72KCM5P-1w9D4erz.js} +1 -1
  80. package/web-dist/assets/{wardley-OPB4EBWU-C4tNB2Mi.js → wardley-OPB4EBWU-BJKEDRlS.js} +1 -1
  81. package/web-dist/assets/{wardleyDiagram-EHGQE667-D_bno6Pc.js → wardleyDiagram-EHGQE667-BZuQjgMm.js} +1 -1
  82. package/web-dist/assets/{xychartDiagram-FW5EYKEG-CklFVNTA.js → xychartDiagram-FW5EYKEG-BuCgSm0a.js} +1 -1
  83. package/web-dist/index.html +2 -2
  84. package/web-dist/assets/architecture-TIHT7OUA-pEHgxrgQ.js +0 -1
  85. package/web-dist/assets/channel-DmtoXjBB.js +0 -1
  86. package/web-dist/assets/classDiagram-OUVF2IWQ-CUGsPtaX.js +0 -1
  87. package/web-dist/assets/classDiagram-v2-EOCWNBFH-CUGsPtaX.js +0 -1
  88. package/web-dist/assets/eventmodeling-45OFAUF4-D47al60X.js +0 -1
  89. package/web-dist/assets/flowDiagram-23GEKE2U-Cfew-ywI.js +0 -1
  90. package/web-dist/assets/index-CjEngYN7.css +0 -1
  91. package/web-dist/assets/railroad-abnf-AHOZXSZD-cPb8e4yf.js +0 -1
  92. package/web-dist/assets/railroad-ebnf-EBAXGLYW-BdArTI_P.js +0 -1
  93. package/web-dist/assets/railroad-peg-LSFZ7HO6-cRtFMlRA.js +0 -1
  94. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BVl1T6pD.js +0 -1
  95. package/web-dist/assets/swimlanesDiagram-G3AALYLV-CaBRomjp.js +0 -8
package/dist/dev-child.js CHANGED
@@ -50,8 +50,14 @@ function xdg(env, name) {
50
50
  const value = env[name];
51
51
  return value && (value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value)) ? value : void 0;
52
52
  }
53
+ function insideHome(child, home) {
54
+ const norm = (value) => value.replace(/[\\/]+$/u, "").replaceAll("\\", "/").toLowerCase();
55
+ const parent = norm(home);
56
+ const inner = norm(child);
57
+ return inner === parent || inner.startsWith(`${parent}/`);
58
+ }
53
59
  function windowsRoots(env, home) {
54
- const local = env.LOCALAPPDATA || join(env.USERPROFILE || home, "AppData", "Local");
60
+ const local = env.LOCALAPPDATA && insideHome(env.LOCALAPPDATA, home) ? env.LOCALAPPDATA : join(home, "AppData", "Local");
55
61
  const base = join(local, "Frizz");
56
62
  return {
57
63
  data: join(base, "Data"),
@@ -475,7 +481,7 @@ function readGitWorktreeProjectId(worktree) {
475
481
  );
476
482
  }
477
483
  function syncGitConfigPath(path) {
478
- const fd = openSync(path, "r");
484
+ const fd = openSync(path, process.platform === "win32" ? "r+" : "r");
479
485
  try {
480
486
  fsyncSync(fd);
481
487
  } finally {
@@ -12702,6 +12708,16 @@ var init_interactions = __esm({
12702
12708
  }
12703
12709
  });
12704
12710
 
12711
+ // packages/shared/src/claim.ts
12712
+ var CLAIM_MAX_AGE_MS, CLAIM_LEASE_MS;
12713
+ var init_claim = __esm({
12714
+ "packages/shared/src/claim.ts"() {
12715
+ "use strict";
12716
+ CLAIM_MAX_AGE_MS = 5 * 6e4;
12717
+ CLAIM_LEASE_MS = 30 * 24 * 60 * 6e4;
12718
+ }
12719
+ });
12720
+
12705
12721
  // packages/shared/src/code-fences.ts
12706
12722
  function fencedInteriors(text) {
12707
12723
  const out = [];
@@ -13062,6 +13078,9 @@ function prWatchExpiredWakeMessage(ref) {
13062
13078
 
13063
13079
  If you still care about it, register it again with \`mcp__frizz__watch_pr\` and a fresh \`for:\`. If you do not, and it was the only thing you were waiting on, end in a proper terminal state instead of parking on it again.`;
13064
13080
  }
13081
+ function queuedThread(t) {
13082
+ return t.kind === "session" && t.foreign !== true && t.needsYou === true && t.state !== "archived";
13083
+ }
13065
13084
  function formatElapsed(ms) {
13066
13085
  if (!Number.isFinite(ms) || ms < 0) return "an unknown time";
13067
13086
  const s = Math.floor(ms / 1e3);
@@ -13208,6 +13227,7 @@ var init_src = __esm({
13208
13227
  init_zod();
13209
13228
  init_interactions();
13210
13229
  init_thread_slug();
13230
+ init_claim();
13211
13231
  init_code_fences();
13212
13232
  init_delta();
13213
13233
  init_drainable_worker();
@@ -14026,8 +14046,8 @@ var init_src = __esm({
14026
14046
  PermissionMode = external_exports.enum(["auto", "default", "acceptEdits", "plan", "bypassPermissions"]);
14027
14047
  LocalFileOpener = external_exports.enum(["system", "cursor", "vscode", "finder", "copy"]);
14028
14048
  Settings = external_exports.object({
14029
- // The mode NEW Claude workers launch in. Settings surfaces exactly two of them — `auto` (the shipped
14030
- // default) and `bypassPermissions` (--dangerously-skip-permissions) — because those are the only two
14049
+ // The mode NEW Claude workers launch in. Settings surfaces exactly two of them — `bypassPermissions`
14050
+ // (--dangerously-skip-permissions, the shipped default since 0.7.2) and `auto` — because those are the only two
14031
14051
  // an unattended worker can actually run in; the server's workerDispatchPermission enforces that same
14032
14052
  // floor, so a restrictive value left here by an older build cannot reach a spawn.
14033
14053
  permissionMode: PermissionMode,
@@ -19531,11 +19551,13 @@ var init_settings = __esm({
19531
19551
  SETTINGS_KEY = "settings";
19532
19552
  MACHINE_KEYS = ["font", "notifications", "localFileOpener", "projectRail"];
19533
19553
  defaultSettings = () => ({
19534
- // `auto` = the CLI's classifier mode: safe actions auto-approve, risky ones still surface an approval
19535
- // card. Fewer invisible permission stalls than acceptEdits/default. The Settings "Claude permissions"
19536
- // control can raise this to `bypassPermissions` (--dangerously-skip-permissions) — the only other
19537
- // value a headless worker can run in, and the only deviation workerDispatchPermission honors.
19538
- permissionMode: "auto",
19554
+ // `bypassPermissions` = claude's --dangerously-skip-permissions: a headless worker never stops on an
19555
+ // approval card. Shipped default since 0.7.2 (maintainer 2026-08-24); the Settings "Permissions"
19556
+ // (under Claude) control can lower it to `auto` — the CLI's classifier mode, where risky actions
19557
+ // still surface an approval card in the thread. Those are the only two values a headless worker can
19558
+ // run in: the dispatch floor (WORKER_DISPATCH_PERMISSION) stays `auto`, and workerDispatchPermission
19559
+ // honors exactly one deviation from it, which is this one.
19560
+ permissionMode: "bypassPermissions",
19539
19561
  model: void 0,
19540
19562
  effort: void 0,
19541
19563
  notifications: true,
@@ -20591,11 +20613,23 @@ var init_detached_daemons = __esm({
20591
20613
  }
20592
20614
  });
20593
20615
 
20616
+ // packages/server/src/backend/ipc-path.ts
20617
+ import { join as join13 } from "node:path";
20618
+ function frizzIpcPath(name) {
20619
+ if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
20620
+ return join13(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
20621
+ }
20622
+ var init_ipc_path = __esm({
20623
+ "packages/server/src/backend/ipc-path.ts"() {
20624
+ "use strict";
20625
+ }
20626
+ });
20627
+
20594
20628
  // packages/server/src/backend/claude-broker-host.ts
20595
20629
  import { spawn } from "node:child_process";
20596
20630
  import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
20597
20631
  import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
20598
- import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as join13 } from "node:path";
20632
+ import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as join14 } from "node:path";
20599
20633
  function windowsShimTarget(shimPath) {
20600
20634
  let body;
20601
20635
  try {
@@ -20605,7 +20639,7 @@ function windowsShimTarget(shimPath) {
20605
20639
  }
20606
20640
  const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
20607
20641
  if (!target) return void 0;
20608
- const full = join13(dirname8(shimPath), target);
20642
+ const full = join14(dirname8(shimPath), target);
20609
20643
  try {
20610
20644
  accessSync(full, fsConstants.F_OK);
20611
20645
  return full;
@@ -20620,17 +20654,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
20620
20654
  for (const dir of (env.PATH ?? "").split(delimiter)) {
20621
20655
  if (!dir) continue;
20622
20656
  if (windows) {
20623
- const exe = join13(dir, `${candidate}.exe`);
20657
+ const exe = join14(dir, `${candidate}.exe`);
20624
20658
  try {
20625
20659
  accessSync(exe, fsConstants.F_OK);
20626
20660
  return exe;
20627
20661
  } catch {
20628
20662
  }
20629
- const viaShim = windowsShimTarget(join13(dir, `${candidate}.cmd`));
20663
+ const viaShim = windowsShimTarget(join14(dir, `${candidate}.cmd`));
20630
20664
  if (viaShim) return viaShim;
20631
20665
  continue;
20632
20666
  }
20633
- const full = join13(dir, candidate);
20667
+ const full = join14(dir, candidate);
20634
20668
  try {
20635
20669
  accessSync(full, fsConstants.X_OK);
20636
20670
  return full;
@@ -20641,16 +20675,15 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
20641
20675
  }
20642
20676
  function claudeBrokerSocketPath(stateDir, sessionId) {
20643
20677
  const key = createHash5("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
20644
- if (process.platform === "win32") return `\\\\.\\pipe\\frizz-claude-${key}`;
20645
- return join13(process.env.TMPDIR ?? "/tmp", `frizz-claude-${key}.sock`);
20678
+ return frizzIpcPath(`frizz-claude-${key}`);
20646
20679
  }
20647
20680
  function claudeBrokerRecordPath(stateDir, sessionId) {
20648
20681
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
20649
- return join13(stateDir, "claude-broker", `${key}.json`);
20682
+ return join14(stateDir, "claude-broker", `${key}.json`);
20650
20683
  }
20651
20684
  function claudeBrokerRetirementPath(stateDir, sessionId) {
20652
20685
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
20653
- return join13(stateDir, "claude-broker", `${key}.retired`);
20686
+ return join14(stateDir, "claude-broker", `${key}.retired`);
20654
20687
  }
20655
20688
  function markBrokerRetired(stateDir, sessionId, reason, generation) {
20656
20689
  const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
@@ -20717,7 +20750,7 @@ function liveBrokerRecord(recordPath2) {
20717
20750
  return null;
20718
20751
  }
20719
20752
  function liveBrokerRecords(stateDir) {
20720
- const dir = join13(stateDir, "claude-broker");
20753
+ const dir = join14(stateDir, "claude-broker");
20721
20754
  let names;
20722
20755
  try {
20723
20756
  names = readdirSync4(dir);
@@ -20727,7 +20760,7 @@ function liveBrokerRecords(stateDir) {
20727
20760
  const out = [];
20728
20761
  for (const name of names) {
20729
20762
  if (!name.endsWith(".json")) continue;
20730
- const record = liveBrokerRecord(join13(dir, name));
20763
+ const record = liveBrokerRecord(join14(dir, name));
20731
20764
  if (record) out.push(record);
20732
20765
  }
20733
20766
  return out;
@@ -20807,6 +20840,7 @@ var init_claude_broker_host = __esm({
20807
20840
  "use strict";
20808
20841
  init_detached_daemons();
20809
20842
  init_claude_broker_diagnostics();
20843
+ init_ipc_path();
20810
20844
  WINDOWS_SHIM_TARGET = /^\s*"%dp0%\\(.+?)"/mu;
20811
20845
  }
20812
20846
  });
@@ -20916,6 +20950,21 @@ function retireOutstandingDeliveries(storage, slug) {
20916
20950
  storage.setDeliveryLedger(slug, serializeDeliveryLedger(next));
20917
20951
  return items.length - next.length;
20918
20952
  }
20953
+ function deliverOutstandingDeliveries(storage, slug) {
20954
+ const row = storage.getSession(slug);
20955
+ if (!row) return 0;
20956
+ const items = parseDeliveryLedger(row.delivery_ledger);
20957
+ const at = (/* @__PURE__ */ new Date()).toISOString();
20958
+ let moved = 0;
20959
+ const next = items.map((item) => {
20960
+ if (item.state !== "pending" && item.state !== "enqueued") return item;
20961
+ moved++;
20962
+ return { ...item, state: "delivered", updatedAt: at };
20963
+ });
20964
+ if (!moved) return 0;
20965
+ storage.setDeliveryLedger(slug, serializeDeliveryLedger(next));
20966
+ return moved;
20967
+ }
20919
20968
  function deliveryItem(storage, slug, id) {
20920
20969
  const row = storage.getSession(slug);
20921
20970
  if (!row) return null;
@@ -21520,14 +21569,14 @@ var init_completion_relay = __esm({
21520
21569
  // packages/server/src/tail-cache.ts
21521
21570
  import { createHash as createHash6 } from "node:crypto";
21522
21571
  import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync10, readSync as readSync3, statSync as statSync7 } from "node:fs";
21523
- import { join as join14 } from "node:path";
21572
+ import { join as join15 } from "node:path";
21524
21573
  function foldSchemaDigest(dir = import.meta.dirname) {
21525
21574
  if (foldSchemaMemo) return foldSchemaMemo;
21526
21575
  const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
21527
21576
  let read = 0;
21528
21577
  for (const name of FOLD_SOURCES) {
21529
21578
  try {
21530
- hash.update(name).update("\0").update(readFileSync10(join14(dir, name)));
21579
+ hash.update(name).update("\0").update(readFileSync10(join15(dir, name)));
21531
21580
  read++;
21532
21581
  } catch {
21533
21582
  hash.update(name).update("\0missing\0");
@@ -21725,7 +21774,7 @@ var init_tail_cache = __esm({
21725
21774
  // packages/server/src/tailer.ts
21726
21775
  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 readFileSync11, existsSync as existsSync5 } from "node:fs";
21727
21776
  import { execFileSync as execFileSync4 } from "node:child_process";
21728
- import { basename as basename4, join as join15 } from "node:path";
21777
+ import { basename as basename4, join as join16 } from "node:path";
21729
21778
  import { homedir as homedir7 } from "node:os";
21730
21779
  function probeShellAlive(outputFile) {
21731
21780
  if (!existsSync5(outputFile)) return void 0;
@@ -21987,7 +22036,7 @@ function launchTaskId(text) {
21987
22036
  function readDescendantSidecars(sessionDir, mtimeMs) {
21988
22037
  let names;
21989
22038
  try {
21990
- names = readdirSync5(join15(sessionDir, "subagents"));
22039
+ names = readdirSync5(join16(sessionDir, "subagents"));
21991
22040
  } catch {
21992
22041
  return [];
21993
22042
  }
@@ -21998,7 +22047,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
21998
22047
  if (!agentId) continue;
21999
22048
  let parsed;
22000
22049
  try {
22001
- parsed = JSON.parse(readFileSync11(join15(sessionDir, "subagents", name), "utf8"));
22050
+ parsed = JSON.parse(readFileSync11(join16(sessionDir, "subagents", name), "utf8"));
22002
22051
  } catch {
22003
22052
  continue;
22004
22053
  }
@@ -22012,7 +22061,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
22012
22061
  agentType: text(meta.agentType),
22013
22062
  parentAgentId: text(meta.parentAgentId),
22014
22063
  spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
22015
- spawnedAtMs: mtimeMs(join15(sessionDir, "subagents", name))
22064
+ spawnedAtMs: mtimeMs(join16(sessionDir, "subagents", name))
22016
22065
  });
22017
22066
  }
22018
22067
  return out;
@@ -22492,7 +22541,7 @@ function defaultMtimeMs(path) {
22492
22541
  }
22493
22542
  }
22494
22543
  function defaultLogDir(project) {
22495
- return join15(homedir7(), ".claude", "projects", project.cwdSlug);
22544
+ return join16(homedir7(), ".claude", "projects", project.cwdSlug);
22496
22545
  }
22497
22546
  function defaultReadPermMarker(project) {
22498
22547
  if (!project.stateDir) return () => void 0;
@@ -22623,7 +22672,7 @@ function createTailer(deps) {
22623
22672
  return paneDead(row.slug);
22624
22673
  }
22625
22674
  const defaultBackend = {
22626
- transcriptPath: (sessionId) => join15(logDir, `${sessionId}.jsonl`),
22675
+ transcriptPath: (sessionId) => join16(logDir, `${sessionId}.jsonl`),
22627
22676
  foldLine: (state, line) => {
22628
22677
  const rec = parseLine(line);
22629
22678
  if (rec) applyRecord(state, rec);
@@ -22748,7 +22797,7 @@ ${ask}`;
22748
22797
  return state.path.replace(/\.jsonl$/, "");
22749
22798
  }
22750
22799
  function descendantSidecars(state) {
22751
- const at = mtimeMs(join15(sessionDirOf(state), "subagents"));
22800
+ const at = mtimeMs(join16(sessionDirOf(state), "subagents"));
22752
22801
  const cached2 = descendantIndex.get(state.slug);
22753
22802
  if (cached2 && cached2.at === at) return cached2.all;
22754
22803
  const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
@@ -22762,7 +22811,7 @@ ${ask}`;
22762
22811
  return descendantIndex.get(state.slug)?.byToolUse.get(id);
22763
22812
  }
22764
22813
  function descendantTranscript(state, meta) {
22765
- return join15(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
22814
+ return join16(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
22766
22815
  }
22767
22816
  function subAgentDescendantTasks(slug, id) {
22768
22817
  const state = states.get(slug);
@@ -23076,7 +23125,7 @@ ${ask}`;
23076
23125
  if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
23077
23126
  const id = name.slice(0, -".jsonl".length);
23078
23127
  if (!id || registered.has(id)) continue;
23079
- const path = join15(logDir, name);
23128
+ const path = join16(logDir, name);
23080
23129
  let mtime;
23081
23130
  try {
23082
23131
  mtime = statSync8(path).mtimeMs;
@@ -23348,7 +23397,7 @@ ${ask}`;
23348
23397
  );
23349
23398
  try {
23350
23399
  mkdirSync10(stallLogDir, { recursive: true });
23351
- writeFileSync8(join15(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
23400
+ writeFileSync8(join16(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
23352
23401
  captured_at: ${new Date(now()).toISOString()}
23353
23402
 
23354
23403
  ${detail}
@@ -23376,7 +23425,7 @@ ${detail}
23376
23425
  state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
23377
23426
  const strandedDir = discoverTranscriptDir(logDir, row.session_id);
23378
23427
  if (strandedDir) {
23379
- state.path = join15(strandedDir, `${row.session_id}.jsonl`);
23428
+ state.path = join16(strandedDir, `${row.session_id}.jsonl`);
23380
23429
  state.offset = 0;
23381
23430
  state.partial = "";
23382
23431
  state.primed = false;
@@ -23399,7 +23448,7 @@ ${detail}
23399
23448
  committed = false;
23400
23449
  }
23401
23450
  if (!committed) return false;
23402
- state.path = join15(logDir, `${found}.jsonl`);
23451
+ state.path = join16(logDir, `${found}.jsonl`);
23403
23452
  state.offset = 0;
23404
23453
  state.partial = "";
23405
23454
  state.primed = false;
@@ -23445,7 +23494,7 @@ ${detail}
23445
23494
  let state = states.get(row.slug);
23446
23495
  const runtimeGeneration = row.runtime_generation ?? 0;
23447
23496
  if (!state || state.sessionId !== row.session_id || state.nativeSessionId !== nativeId || state.runtimeGeneration !== runtimeGeneration) {
23448
- const path = backend.transcriptPath(nativeId) ?? join15(logDir, `${nativeId}.jsonl`);
23497
+ const path = backend.transcriptPath(nativeId) ?? join16(logDir, `${nativeId}.jsonl`);
23449
23498
  state = newTailState(row.slug, row.session_id, path, false, nativeId, runtimeGeneration);
23450
23499
  state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
23451
23500
  hydrateFromCache(state, row, nativeId);
@@ -23894,14 +23943,14 @@ var init_tailer = __esm({
23894
23943
  });
23895
23944
 
23896
23945
  // packages/server/src/backend/codex.ts
23897
- import { join as join16 } from "node:path";
23946
+ import { join as join17 } from "node:path";
23898
23947
  import { homedir as homedir8 } from "node:os";
23899
23948
  import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync12, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
23900
23949
  function defaultCodexHome() {
23901
- return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join16(homedir8(), ".codex");
23950
+ return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join17(homedir8(), ".codex");
23902
23951
  }
23903
23952
  function sessionsDir(codexHome) {
23904
- return join16(codexHome, "sessions");
23953
+ return join17(codexHome, "sessions");
23905
23954
  }
23906
23955
  function codexSandbox(mode) {
23907
23956
  switch (mode) {
@@ -24282,17 +24331,17 @@ function collectRollouts(dir, out, budget) {
24282
24331
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).sort(descByName);
24283
24332
  for (const d of dirs) {
24284
24333
  if (budget.n <= 0) return;
24285
- collectRollouts(join16(dir, d.name), out, budget);
24334
+ collectRollouts(join17(dir, d.name), out, budget);
24286
24335
  }
24287
24336
  for (const f of files) {
24288
24337
  if (budget.n <= 0) return;
24289
24338
  let mtimeMs;
24290
24339
  try {
24291
- mtimeMs = statSync9(join16(dir, f.name)).mtimeMs;
24340
+ mtimeMs = statSync9(join17(dir, f.name)).mtimeMs;
24292
24341
  } catch {
24293
24342
  continue;
24294
24343
  }
24295
- out.push({ path: join16(dir, f.name), mtimeMs });
24344
+ out.push({ path: join17(dir, f.name), mtimeMs });
24296
24345
  budget.n--;
24297
24346
  }
24298
24347
  }
@@ -24336,7 +24385,7 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
24336
24385
  const out = /* @__PURE__ */ new Map();
24337
24386
  let raw2;
24338
24387
  try {
24339
- const path = join16(codexHome, "session_index.jsonl");
24388
+ const path = join17(codexHome, "session_index.jsonl");
24340
24389
  if (statSync9(path).size > SESSION_INDEX_MAX_BYTES) return out;
24341
24390
  raw2 = readFileSync12(path, "utf8");
24342
24391
  } catch {
@@ -28374,16 +28423,16 @@ var init_wrapper = __esm({
28374
28423
 
28375
28424
  // packages/server/src/worker-plugin-dir.ts
28376
28425
  import { existsSync as existsSync6 } from "node:fs";
28377
- import { dirname as dirname9, join as join17 } from "node:path";
28426
+ import { dirname as dirname9, join as join18 } from "node:path";
28378
28427
  import { fileURLToPath as fileURLToPath2 } from "node:url";
28379
28428
  function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
28380
28429
  const override = env.FRIZZ_WORKER_PLUGIN_DIR;
28381
- if (override && existsSync6(join17(override, ".claude-plugin", "plugin.json")))
28430
+ if (override && existsSync6(join18(override, ".claude-plugin", "plugin.json")))
28382
28431
  return override;
28383
28432
  let current = dirname9(fileURLToPath2(moduleUrl));
28384
28433
  for (; ; ) {
28385
- const candidate = join17(current, "cc-worker");
28386
- if (existsSync6(join17(candidate, ".claude-plugin", "plugin.json"))) return candidate;
28434
+ const candidate = join18(current, "cc-worker");
28435
+ if (existsSync6(join18(candidate, ".claude-plugin", "plugin.json"))) return candidate;
28387
28436
  const parent = dirname9(current);
28388
28437
  if (parent === current) return void 0;
28389
28438
  current = parent;
@@ -28397,7 +28446,7 @@ var init_worker_plugin_dir = __esm({
28397
28446
 
28398
28447
  // packages/server/src/backend/types.ts
28399
28448
  import { existsSync as existsSync7 } from "node:fs";
28400
- import { join as join18 } from "node:path";
28449
+ import { join as join19 } from "node:path";
28401
28450
  function frizzMcpEnv(mcp) {
28402
28451
  return {
28403
28452
  FRIZZ_STATE_DIR: mcp.stateDir,
@@ -28421,7 +28470,7 @@ function chromeDevtoolsMcpMount() {
28421
28470
  function resolveBrowserMcpScript(moduleUrl = import.meta.url, env = process.env) {
28422
28471
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
28423
28472
  if (!pluginDir) return void 0;
28424
- const scriptPath = join18(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28473
+ const scriptPath = join19(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28425
28474
  return existsSync7(scriptPath) ? scriptPath : void 0;
28426
28475
  }
28427
28476
  function workerCap(name, lifted, env) {
@@ -28517,21 +28566,21 @@ var init_codex_mcp = __esm({
28517
28566
  // packages/server/src/backend/codex-app-server-native.ts
28518
28567
  import { spawn as spawn2 } from "node:child_process";
28519
28568
  import { connect } from "node:net";
28569
+ import { Agent as HttpAgent } from "node:http";
28520
28570
  import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
28521
28571
  import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync13, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
28522
- import { join as join19 } from "node:path";
28572
+ import { join as join20 } from "node:path";
28523
28573
  import { PassThrough, Writable } from "node:stream";
28524
28574
  import { StringDecoder } from "node:string_decoder";
28525
28575
  function nativeDir(stateDir) {
28526
- return join19(stateDir, "codex-app-server-native");
28576
+ return join20(stateDir, "codex-app-server-native");
28527
28577
  }
28528
28578
  function nativeRecordPath(stateDir, projectId) {
28529
- return join19(nativeDir(stateDir), `${projectId}.json`);
28579
+ return join20(nativeDir(stateDir), `${projectId}.json`);
28530
28580
  }
28531
28581
  function nativeListenSocketPath(stateDir, projectId) {
28532
28582
  const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
28533
- if (process.platform === "win32") return `\\\\.\\pipe\\frizz-codex-native-${key}`;
28534
- return join19(process.env.TMPDIR ?? "/tmp", `frizz-codex-native-${key}.sock`);
28583
+ return frizzIpcPath(`frizz-codex-native-${key}`);
28535
28584
  }
28536
28585
  function pidAlive2(pid) {
28537
28586
  try {
@@ -28608,9 +28657,18 @@ function socketAccepting(socketPath) {
28608
28657
  setTimeout(() => done(false), 2e3).unref?.();
28609
28658
  });
28610
28659
  }
28660
+ function ipcWebSocket(endpoint) {
28661
+ if (process.platform !== "win32") return new import_websocket.default(`ws+unix://${endpoint}:/`, { perMessageDeflate: false });
28662
+ class PipeAgent extends HttpAgent {
28663
+ createConnection() {
28664
+ return connect(endpoint);
28665
+ }
28666
+ }
28667
+ return new import_websocket.default("ws://localhost/", { agent: new PipeAgent(), perMessageDeflate: false });
28668
+ }
28611
28669
  function attach(record, timeoutMs) {
28612
28670
  return new Promise((resolve10, reject) => {
28613
- const socket = new import_websocket.default(`ws+unix://${record.socketPath}:/`, { perMessageDeflate: false });
28671
+ const socket = ipcWebSocket(record.socketPath);
28614
28672
  const stdout = new PassThrough();
28615
28673
  const stderr = new PassThrough();
28616
28674
  const listeners = { exit: [], error: [] };
@@ -28727,6 +28785,7 @@ var init_codex_app_server_native = __esm({
28727
28785
  "packages/server/src/backend/codex-app-server-native.ts"() {
28728
28786
  "use strict";
28729
28787
  init_wrapper();
28788
+ init_ipc_path();
28730
28789
  init_codex_mcp();
28731
28790
  init_logging();
28732
28791
  PRESUMED_LOSSY_REJOIN = 1;
@@ -28778,23 +28837,22 @@ var init_codex_app_server_native = __esm({
28778
28837
  });
28779
28838
 
28780
28839
  // packages/server/src/backend/codex-app-server-host.ts
28781
- import { spawn as spawn3 } from "node:child_process";
28840
+ import { spawn as spawn3, spawnSync } from "node:child_process";
28782
28841
  import { createConnection } from "node:net";
28783
28842
  import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
28784
28843
  import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "node:fs";
28785
- import { join as join20 } from "node:path";
28844
+ import { join as join21 } from "node:path";
28786
28845
  import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
28787
28846
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
28788
28847
  function daemonDir(stateDir) {
28789
- return join20(stateDir, "codex-app-server");
28848
+ return join21(stateDir, "codex-app-server");
28790
28849
  }
28791
28850
  function recordPath(stateDir, projectId) {
28792
- return join20(daemonDir(stateDir), `${projectId}.json`);
28851
+ return join21(daemonDir(stateDir), `${projectId}.json`);
28793
28852
  }
28794
28853
  function codexAppServerSocketPath(stateDir, projectId) {
28795
28854
  const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
28796
- if (process.platform === "win32") return `\\\\.\\pipe\\frizz-codex-${key}`;
28797
- return join20(process.env.TMPDIR ?? "/tmp", `frizz-codex-${key}.sock`);
28855
+ return frizzIpcPath(`frizz-codex-${key}`);
28798
28856
  }
28799
28857
  function pidAlive3(pid) {
28800
28858
  try {
@@ -28845,13 +28903,26 @@ function liveDaemonRecord(stateDir, projectId) {
28845
28903
  }
28846
28904
  return null;
28847
28905
  }
28906
+ function endDaemonTree(pid, signal) {
28907
+ if (process.platform !== "win32") {
28908
+ try {
28909
+ process.kill(pid, signal);
28910
+ } catch {
28911
+ }
28912
+ return;
28913
+ }
28914
+ const killed = spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
28915
+ if (killed.error || killed.status !== 0) {
28916
+ try {
28917
+ process.kill(pid, signal);
28918
+ } catch {
28919
+ }
28920
+ }
28921
+ }
28848
28922
  function killCodexAppServerDaemon(stateDir, projectId) {
28849
28923
  const record = liveDaemonRecord(stateDir, projectId);
28850
28924
  if (!record) return;
28851
- try {
28852
- process.kill(record.daemonPid, "SIGTERM");
28853
- } catch {
28854
- }
28925
+ endDaemonTree(record.daemonPid, "SIGTERM");
28855
28926
  try {
28856
28927
  unlinkSync3(recordPath(stateDir, projectId));
28857
28928
  } catch {
@@ -28867,10 +28938,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
28867
28938
  await new Promise((resolve10) => setTimeout(resolve10, 25));
28868
28939
  }
28869
28940
  if (pidAlive3(record.daemonPid)) {
28870
- try {
28871
- process.kill(record.daemonPid, "SIGKILL");
28872
- } catch {
28873
- }
28941
+ endDaemonTree(record.daemonPid, "SIGKILL");
28874
28942
  while (pidAlive3(record.daemonPid) && Date.now() < deadline + 2e3) {
28875
28943
  await new Promise((resolve10) => setTimeout(resolve10, 25));
28876
28944
  }
@@ -29017,6 +29085,14 @@ function inProcessCodexAppServer(options) {
29017
29085
  env: options.env,
29018
29086
  stdio: ["pipe", "pipe", "pipe"]
29019
29087
  });
29088
+ const kill = child.kill.bind(child);
29089
+ child.kill = ((signal) => {
29090
+ try {
29091
+ return kill(signal);
29092
+ } catch {
29093
+ return false;
29094
+ }
29095
+ });
29020
29096
  return { process: child, generation: randomUUID10(), reattached: false, daemonPid: process.pid, droppedWhileDetached: 0 };
29021
29097
  }
29022
29098
  function directChildHost(spawnChild, generationId = randomUUID10) {
@@ -29034,6 +29110,7 @@ var init_codex_app_server_host = __esm({
29034
29110
  "use strict";
29035
29111
  init_detached_daemons();
29036
29112
  init_codex_app_server_native();
29113
+ init_ipc_path();
29037
29114
  init_codex_mcp();
29038
29115
  init_logging();
29039
29116
  daemonEntry = () => resolveDetachedDaemonEntry(import.meta.url, "codex-app-server-daemon");
@@ -31999,11 +32076,11 @@ var init_codex_app_server = __esm({
31999
32076
  });
32000
32077
 
32001
32078
  // packages/server/src/backend/codex-quota.ts
32002
- import { join as join21 } from "node:path";
32079
+ import { join as join22 } from "node:path";
32003
32080
  import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
32004
32081
  import { spawn as spawn4 } from "node:child_process";
32005
32082
  function sessionsDir2(codexHome) {
32006
- return join21(codexHome, "sessions");
32083
+ return join22(codexHome, "sessions");
32007
32084
  }
32008
32085
  function newestRollouts(dir, out, budget) {
32009
32086
  if (budget.n <= 0) return;
@@ -32017,11 +32094,11 @@ function newestRollouts(dir, out, budget) {
32017
32094
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
32018
32095
  for (const d of dirs) {
32019
32096
  if (budget.n <= 0) return;
32020
- newestRollouts(join21(dir, d), out, budget);
32097
+ newestRollouts(join22(dir, d), out, budget);
32021
32098
  }
32022
32099
  for (const f of files) {
32023
32100
  if (budget.n <= 0) return;
32024
- out.push(join21(dir, f));
32101
+ out.push(join22(dir, f));
32025
32102
  budget.n--;
32026
32103
  }
32027
32104
  }
@@ -32221,7 +32298,7 @@ var init_codex_quota = __esm({
32221
32298
  });
32222
32299
 
32223
32300
  // packages/server/src/backend/claude-quota.ts
32224
- import { join as join22 } from "node:path";
32301
+ import { join as join23 } from "node:path";
32225
32302
  import { homedir as homedir9, platform } from "node:os";
32226
32303
  import { createHash as createHash10 } from "node:crypto";
32227
32304
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -32229,7 +32306,7 @@ import { execFile as execFile2 } from "node:child_process";
32229
32306
  import { promisify as promisify2 } from "node:util";
32230
32307
  function claudeConfigDir() {
32231
32308
  const override = process.env.CLAUDE_CONFIG_DIR;
32232
- return override && override.trim() ? override : join22(homedir9(), ".claude");
32309
+ return override && override.trim() ? override : join23(homedir9(), ".claude");
32233
32310
  }
32234
32311
  function tokenFromCredentialsJson(raw2) {
32235
32312
  let doc;
@@ -32258,7 +32335,7 @@ async function readKeychainToken() {
32258
32335
  }
32259
32336
  async function readAccessToken(configDir) {
32260
32337
  try {
32261
- const fromFile = tokenFromCredentialsJson(await readFile(join22(configDir, ".credentials.json"), "utf8"));
32338
+ const fromFile = tokenFromCredentialsJson(await readFile(join23(configDir, ".credentials.json"), "utf8"));
32262
32339
  if (fromFile) return fromFile;
32263
32340
  } catch {
32264
32341
  }
@@ -32327,8 +32404,8 @@ function parseClaudeUsage(body, planType) {
32327
32404
  function cachePaths(cacheDir, configDir) {
32328
32405
  const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
32329
32406
  return {
32330
- data: join22(cacheDir, `claude-${profile}.json`),
32331
- lock: join22(cacheDir, `claude-${profile}.lock`)
32407
+ data: join23(cacheDir, `claude-${profile}.json`),
32408
+ lock: join23(cacheDir, `claude-${profile}.lock`)
32332
32409
  };
32333
32410
  }
32334
32411
  async function readShared(path) {
@@ -32520,7 +32597,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
32520
32597
  async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32521
32598
  const now = (deps.now ?? Date.now)();
32522
32599
  const configDir = claudeConfigDir();
32523
- const cacheDir = deps.cacheDir ?? join22(frizzRoots().cache, "quota-cache");
32600
+ const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32524
32601
  try {
32525
32602
  await mkdir(cacheDir, { recursive: true, mode: 448 });
32526
32603
  } catch {
@@ -32531,7 +32608,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32531
32608
  async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
32532
32609
  const now = (deps.now ?? Date.now)();
32533
32610
  const configDir = claudeConfigDir();
32534
- const cacheDir = deps.cacheDir ?? join22(frizzRoots().cache, "quota-cache");
32611
+ const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32535
32612
  const paths = cachePaths(cacheDir, configDir);
32536
32613
  try {
32537
32614
  await mkdir(cacheDir, { recursive: true, mode: 448 });
@@ -32690,7 +32767,7 @@ var init_quota = __esm({
32690
32767
  // packages/server/src/frizz.ts
32691
32768
  import { execFile as execFile3 } from "node:child_process";
32692
32769
  import { lstatSync as lstatSync2, realpathSync as realpathSync6 } from "node:fs";
32693
- import { basename as basename5, dirname as dirname10, join as join23, resolve as resolve4 } from "node:path";
32770
+ import { basename as basename5, dirname as dirname10, join as join24, resolve as resolve4 } from "node:path";
32694
32771
  import { promisify as promisify3 } from "node:util";
32695
32772
  function frizzScriptsDir() {
32696
32773
  if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
@@ -32699,7 +32776,7 @@ function frizzScriptsDir() {
32699
32776
  function directFrizzRoot(projectDir) {
32700
32777
  try {
32701
32778
  const projectRoot = realpathSync6(projectDir);
32702
- const path = join23(projectRoot, ".frizz");
32779
+ const path = join24(projectRoot, ".frizz");
32703
32780
  const stat2 = lstatSync2(path);
32704
32781
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
32705
32782
  const real = realpathSync6(path);
@@ -32713,7 +32790,7 @@ function frizzDirExists(projectDir) {
32713
32790
  }
32714
32791
  async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32715
32792
  if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
32716
- const { stdout } = await execFileP("node", [join23(scriptsDir, "index.mjs"), "--json"], {
32793
+ const { stdout } = await execFileP("node", [join24(scriptsDir, "index.mjs"), "--json"], {
32717
32794
  cwd: projectDir,
32718
32795
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
32719
32796
  maxBuffer: 32 * 1024 * 1024
@@ -32738,7 +32815,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32738
32815
  };
32739
32816
  }
32740
32817
  async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
32741
- await execFileP("node", [join23(scriptsDir, "thread-update.mjs"), slug, ...args], {
32818
+ await execFileP("node", [join24(scriptsDir, "thread-update.mjs"), slug, ...args], {
32742
32819
  cwd: projectDir,
32743
32820
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
32744
32821
  });
@@ -34623,19 +34700,19 @@ var init_claude_agent_broker_bridge = __esm({
34623
34700
  });
34624
34701
 
34625
34702
  // packages/server/src/backend/auth-status.ts
34626
- import { join as join24 } from "node:path";
34703
+ import { join as join25 } from "node:path";
34627
34704
  import { homedir as homedir11, platform as platform2 } from "node:os";
34628
34705
  import { readFileSync as readFileSync15, statSync as statSync11 } from "node:fs";
34629
34706
  import { execFile as execFile4 } from "node:child_process";
34630
34707
  import { promisify as promisify4 } from "node:util";
34631
34708
  function claudeConfigDir2() {
34632
34709
  const override = process.env.CLAUDE_CONFIG_DIR;
34633
- return override && override.trim() ? override : join24(homedir11(), ".claude");
34710
+ return override && override.trim() ? override : join25(homedir11(), ".claude");
34634
34711
  }
34635
34712
  function claudeFileState(configDir) {
34636
34713
  let raw2;
34637
34714
  try {
34638
- raw2 = readFileSync15(join24(configDir, ".credentials.json"), "utf8");
34715
+ raw2 = readFileSync15(join25(configDir, ".credentials.json"), "utf8");
34639
34716
  } catch (err) {
34640
34717
  return err.code === "ENOENT" ? "absent" : "error";
34641
34718
  }
@@ -34668,7 +34745,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
34668
34745
  if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
34669
34746
  let raw2;
34670
34747
  try {
34671
- raw2 = readFileSync15(join24(codexHome, "auth.json"), "utf8");
34748
+ raw2 = readFileSync15(join25(codexHome, "auth.json"), "utf8");
34672
34749
  } catch (err) {
34673
34750
  return err.code === "ENOENT" ? "signed-out" : "unknown";
34674
34751
  }
@@ -34733,7 +34810,7 @@ function asEmail(value) {
34733
34810
  }
34734
34811
  function claudeAccountFile() {
34735
34812
  const override = process.env.CLAUDE_CONFIG_DIR;
34736
- return override && override.trim() ? join24(override, ".claude.json") : join24(homedir11(), ".claude.json");
34813
+ return override && override.trim() ? join25(override, ".claude.json") : join25(homedir11(), ".claude.json");
34737
34814
  }
34738
34815
  function readClaudeAccountEmail(path = claudeAccountFile()) {
34739
34816
  let stat2;
@@ -34757,7 +34834,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
34757
34834
  function readCodexAccountEmail(codexHome = defaultCodexHome()) {
34758
34835
  let doc;
34759
34836
  try {
34760
- doc = JSON.parse(readFileSync15(join24(codexHome, "auth.json"), "utf8"));
34837
+ doc = JSON.parse(readFileSync15(join25(codexHome, "auth.json"), "utf8"));
34761
34838
  } catch {
34762
34839
  return void 0;
34763
34840
  }
@@ -34825,7 +34902,7 @@ var init_auth_status = __esm({
34825
34902
 
34826
34903
  // packages/server/src/dispatch.ts
34827
34904
  import { closeSync as closeSync12, constants, existsSync as existsSync10, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync16, realpathSync as realpathSync7, statSync as statSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync8 } from "node:fs";
34828
- import { basename as basename6, join as join25, dirname as dirname11 } from "node:path";
34905
+ import { basename as basename6, join as join26, dirname as dirname11 } from "node:path";
34829
34906
  import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
34830
34907
  function fallbackTitle(prompt) {
34831
34908
  const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
@@ -34844,7 +34921,7 @@ function fallbackTitle(prompt) {
34844
34921
  }
34845
34922
  function resolveSlug(frizzDir, base, taken) {
34846
34923
  base = ThreadSlug.parse(base);
34847
- const isTaken = (slug) => existsSync10(join25(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
34924
+ const isTaken = (slug) => existsSync10(join26(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
34848
34925
  if (!isTaken(base)) return base;
34849
34926
  for (let n = 2; ; n++) {
34850
34927
  const suffix = `-${n}`;
@@ -34861,12 +34938,12 @@ function resolveLegacyThreadFile(projectDir, value) {
34861
34938
  if (!parsed.success) return null;
34862
34939
  try {
34863
34940
  const projectRoot = realpathSync7(projectDir);
34864
- const frizzPath = join25(projectRoot, ".frizz");
34941
+ const frizzPath = join26(projectRoot, ".frizz");
34865
34942
  const frizzStat = lstatSync3(frizzPath);
34866
34943
  if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
34867
34944
  const realFrizz = realpathSync7(frizzPath);
34868
34945
  if (dirname11(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
34869
- const path = join25(realFrizz, `${parsed.data}.md`);
34946
+ const path = join26(realFrizz, `${parsed.data}.md`);
34870
34947
  const before = lstatSync3(path);
34871
34948
  if (!before.isFile() || before.isSymbolicLink()) return null;
34872
34949
  const realPath = realpathSync7(path);
@@ -34910,7 +34987,7 @@ function boardAuthorizesAdoption(board, slug) {
34910
34987
  return !board.errorItems.some((item) => item.file === `${slug}.md`);
34911
34988
  }
34912
34989
  function ensureSafeDirectDirectory(parent, name) {
34913
- const path = join25(parent, name);
34990
+ const path = join26(parent, name);
34914
34991
  try {
34915
34992
  mkdirSync13(path);
34916
34993
  } catch (error) {
@@ -34940,8 +35017,8 @@ function loadWorkerPrompt(kind = "claude") {
34940
35017
  function monitorScriptsDir() {
34941
35018
  const plugin = workerPluginDir();
34942
35019
  if (!plugin) return void 0;
34943
- const dir = join25(plugin, "skills", "gh", "scripts");
34944
- return existsSync10(join25(dir, "ci-watch.mjs")) ? dir : void 0;
35020
+ const dir = join26(plugin, "skills", "gh", "scripts");
35021
+ return existsSync10(join26(dir, "ci-watch.mjs")) ? dir : void 0;
34945
35022
  }
34946
35023
  function codexScratchpadHookConfig(hookScript, sessionId) {
34947
35024
  if (!hookScript || !sessionId) return {};
@@ -34953,7 +35030,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
34953
35030
  }
34954
35031
  ]
34955
35032
  });
34956
- const bashBackgroundHook = join25(dirname11(hookScript), "bash-background.mjs");
35033
+ const bashBackgroundHook = join26(dirname11(hookScript), "bash-background.mjs");
34957
35034
  return {
34958
35035
  bypass_hook_trust: true,
34959
35036
  hooks: {
@@ -34979,7 +35056,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
34979
35056
  }
34980
35057
  function scratchpadHookScript() {
34981
35058
  const plugin = workerPluginDir();
34982
- return plugin ? join25(plugin, "hooks", "scratchpad.mjs") : void 0;
35059
+ return plugin ? join26(plugin, "hooks", "scratchpad.mjs") : void 0;
34983
35060
  }
34984
35061
  function composePrompt(sessionId, prompt, kind = "claude") {
34985
35062
  const children2 = kind === "codex" ? "Native sub-agents share it \u2014 have each write its OWN file rather than all editing one." : "Name it in a sub-agent's prompt when you want its notes to land somewhere you can read; give each child its OWN file rather than having them all edit one.";
@@ -34995,7 +35072,7 @@ function scratchpadOrientation(sessionId, kind = "claude") {
34995
35072
  return `SCRATCH DIRECTORY: .frizz/threads/${sessionId}/ \u2014 yours, free-form, as many files as you like, and nothing is expected in it. A single direct task usually needs none; writing notes is never a substitute for doing the work. On a long effort write the doc you would want if you lost your context (${children2}), then arm mcp__frizz__recurring_prompt with post_compaction: true and a prompt LINKING that file \u2014 frizz hands the link back when your context is compacted. Nothing in this directory is read automatically.`;
34996
35073
  }
34997
35074
  function frizzConfigBlock(projectDir) {
34998
- const path = join25(projectDir, "FRIZZ.md");
35075
+ const path = join26(projectDir, "FRIZZ.md");
34999
35076
  let body;
35000
35077
  try {
35001
35078
  const st = statSync12(path);
@@ -35035,7 +35112,7 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
35035
35112
  const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
35036
35113
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
35037
35114
  if (!pluginDir) return void 0;
35038
- const scriptPath = join25(pluginDir, "bin", FRIZZ_MCP.script);
35115
+ const scriptPath = join26(pluginDir, "bin", FRIZZ_MCP.script);
35039
35116
  if (!existsSync10(scriptPath)) return void 0;
35040
35117
  return {
35041
35118
  scriptPath,
@@ -35118,7 +35195,7 @@ function buildClaudeResumeCommand(opts) {
35118
35195
  }
35119
35196
  function createDispatcher(deps) {
35120
35197
  const readBoardSource = deps.readBoard ?? readBoard;
35121
- const frizzDir = join25(deps.project.dir, ".frizz");
35198
+ const frizzDir = join26(deps.project.dir, ".frizz");
35122
35199
  const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
35123
35200
  function cleanupPrewrites(built) {
35124
35201
  for (const path of new Set(built.prewrite.map((file) => file.path))) {
@@ -35131,7 +35208,7 @@ function createDispatcher(deps) {
35131
35208
  function cleanupDispatchFiles(scratchRel, built, sessionId) {
35132
35209
  cleanupPrewrites(built);
35133
35210
  try {
35134
- rmSync8(join25(deps.project.dir, scratchRel), { force: true, recursive: true });
35211
+ rmSync8(join26(deps.project.dir, scratchRel), { force: true, recursive: true });
35135
35212
  } catch {
35136
35213
  }
35137
35214
  cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
@@ -35564,7 +35641,7 @@ import {
35564
35641
  watch as fsWatch
35565
35642
  } from "node:fs";
35566
35643
  import { homedir as homedir12 } from "node:os";
35567
- import { join as join26 } from "node:path";
35644
+ import { join as join27 } from "node:path";
35568
35645
  import watcher from "@parcel/watcher";
35569
35646
  function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
35570
35647
  if (!liveness) return false;
@@ -36249,7 +36326,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
36249
36326
  if (parcelSub || stopped) return Promise.resolve();
36250
36327
  if (watchSetup) return watchSetup;
36251
36328
  const setup = (async () => {
36252
- const next = await subscribe(join26(project.dir, ".frizz"), () => scheduleRebuild());
36329
+ const next = await subscribe(join27(project.dir, ".frizz"), () => scheduleRebuild());
36253
36330
  if (stopped) {
36254
36331
  await next.unsubscribe();
36255
36332
  return;
@@ -38183,7 +38260,7 @@ var init_resume = __esm({
38183
38260
  });
38184
38261
 
38185
38262
  // packages/server/src/backend/claude.ts
38186
- import { join as join27 } from "node:path";
38263
+ import { join as join28 } from "node:path";
38187
38264
  function toolResultText2(content) {
38188
38265
  if (typeof content === "string") return content;
38189
38266
  if (!Array.isArray(content)) return "";
@@ -38272,7 +38349,7 @@ function createClaudeBackend(opts) {
38272
38349
  return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
38273
38350
  },
38274
38351
  transcriptPath(sessionId) {
38275
- return join27(opts.logDir, `${sessionId}.jsonl`);
38352
+ return join28(opts.logDir, `${sessionId}.jsonl`);
38276
38353
  },
38277
38354
  parseLine(line) {
38278
38355
  return parseClaudeLine(line);
@@ -38442,12 +38519,12 @@ var init_login_utility = __esm({
38442
38519
 
38443
38520
  // packages/server/src/backend/codex-app-server-diagnostics.ts
38444
38521
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync14, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
38445
- import { join as join28 } from "node:path";
38522
+ import { join as join29 } from "node:path";
38446
38523
  function codexDiagnosticLogPath(stateDir, projectId) {
38447
- return join28(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38524
+ return join29(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38448
38525
  }
38449
38526
  function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
38450
- const dir = join28(stateDir, "codex-app-server");
38527
+ const dir = join29(stateDir, "codex-app-server");
38451
38528
  const path = codexDiagnosticLogPath(stateDir, projectId);
38452
38529
  let ensured = false;
38453
38530
  return (event) => {
@@ -38479,13 +38556,24 @@ var init_codex_app_server_diagnostics = __esm({
38479
38556
  import { execFile as execFile7 } from "node:child_process";
38480
38557
  import { readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
38481
38558
  import { connect as connectSocket } from "node:net";
38482
- import { join as join29 } from "node:path";
38559
+ import { join as join30 } from "node:path";
38560
+ function parseLsofSocketNames(stdout) {
38561
+ const referenced = /* @__PURE__ */ new Set();
38562
+ for (const line of stdout.split("\n")) {
38563
+ if (!line.startsWith("n/")) continue;
38564
+ const raw2 = line.slice(1);
38565
+ referenced.add(raw2);
38566
+ const meta = raw2.indexOf(" type=");
38567
+ if (meta > 0) referenced.add(raw2.slice(0, meta));
38568
+ }
38569
+ return referenced;
38570
+ }
38483
38571
  function sweepStaleSockets(options, deps = {}) {
38484
38572
  if (process.platform === "win32") return;
38485
38573
  const keep = new Set(options.keep ?? []);
38486
38574
  let candidates;
38487
38575
  try {
38488
- candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join29(options.dir, name)).filter((path) => !keep.has(path));
38576
+ candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join30(options.dir, name)).filter((path) => !keep.has(path));
38489
38577
  } catch {
38490
38578
  return;
38491
38579
  }
@@ -38515,9 +38603,7 @@ var init_stale_socket_sweep = __esm({
38515
38603
  execFile7("lsof", ["-U", "-F", "n"], { timeout: 3e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
38516
38604
  if (!stdout) return done(null);
38517
38605
  if (error && !stdout.includes(prefix)) return done(null);
38518
- const referenced = /* @__PURE__ */ new Set();
38519
- for (const line of stdout.split("\n")) if (line.startsWith("n/")) referenced.add(line.slice(1));
38520
- done(referenced);
38606
+ done(parseLsofSocketNames(stdout));
38521
38607
  }).unref?.();
38522
38608
  };
38523
38609
  defaultProbe = (path, verdict) => {
@@ -38537,6 +38623,7 @@ var init_stale_socket_sweep = __esm({
38537
38623
 
38538
38624
  // packages/server/src/orphan-reaper.ts
38539
38625
  import { execFileSync as execFileSync5 } from "node:child_process";
38626
+ import { readFileSync as readFileSync17 } from "node:fs";
38540
38627
  import { dirname as dirname12 } from "node:path";
38541
38628
  function firstTokenBasename(command) {
38542
38629
  const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
@@ -38636,8 +38723,8 @@ function parseEtimeMs(etime) {
38636
38723
  else return 0;
38637
38724
  return (((days * 24 + h) * 60 + m) * 60 + s) * 1e3;
38638
38725
  }
38639
- function enumerateProcs(exec = defaultExec) {
38640
- const base = exec("ps", ["-axww", "-o", "pid=,ppid=,etime=,command="]);
38726
+ function enumerateProcs(exec = defaultExec, opts = {}) {
38727
+ const base = exec("ps", ["-Aww", "-o", "pid=,ppid=,etime=,command="]);
38641
38728
  const rows = [];
38642
38729
  const byPid = /* @__PURE__ */ new Map();
38643
38730
  const pids = [];
@@ -38653,6 +38740,21 @@ function enumerateProcs(exec = defaultExec) {
38653
38740
  pids.push(pid);
38654
38741
  }
38655
38742
  if (!pids.length) return rows;
38743
+ if ((opts.platform ?? process.platform) === "linux") {
38744
+ const readEnv = opts.readEnv ?? defaultReadEnv;
38745
+ for (const row of rows) {
38746
+ const environ = readEnv(row.pid);
38747
+ if (environ === null) continue;
38748
+ for (const entry of environ.split("\0")) {
38749
+ const m = entry.match(/^FRIZZ_THREAD=([A-Za-z0-9._-]+)$/);
38750
+ if (m) {
38751
+ row.slug = m[1];
38752
+ break;
38753
+ }
38754
+ }
38755
+ }
38756
+ return rows;
38757
+ }
38656
38758
  let text;
38657
38759
  try {
38658
38760
  text = exec("ps", ["-Eww", "-o", "pid=,command=", "-p", pids.join(",")]);
@@ -38728,7 +38830,7 @@ function sweepOrphansOnce(deps = {}) {
38728
38830
  const minAgeMs = deps.minAgeMs ?? ORPHAN_MIN_AGE_MS;
38729
38831
  let rows;
38730
38832
  try {
38731
- rows = enumerateProcs(exec);
38833
+ rows = enumerateProcs(exec, { platform: deps.platform, readEnv: deps.readEnv });
38732
38834
  } catch {
38733
38835
  return { reaped: 0, deadSlugs: [], liveSlugs: [] };
38734
38836
  }
@@ -38776,7 +38878,7 @@ function startOrphanReaper(deps = {}) {
38776
38878
  clearInterval(socketTimer);
38777
38879
  };
38778
38880
  }
38779
- var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, defaultExec, defaultKill, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX;
38881
+ var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, defaultExec, defaultReadEnv, defaultKill, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX;
38780
38882
  var init_orphan_reaper = __esm({
38781
38883
  "packages/server/src/orphan-reaper.ts"() {
38782
38884
  "use strict";
@@ -38786,6 +38888,13 @@ var init_orphan_reaper = __esm({
38786
38888
  ORPHAN_MIN_AGE_MS = 12e4;
38787
38889
  SLUG_RE = /FRIZZ_THREAD=([A-Za-z0-9._-]+)/;
38788
38890
  defaultExec = (file, args) => execFileSync5(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 });
38891
+ defaultReadEnv = (pid) => {
38892
+ try {
38893
+ return readFileSync17(`/proc/${pid}/environ`, "utf8");
38894
+ } catch {
38895
+ return null;
38896
+ }
38897
+ };
38789
38898
  defaultKill = (pid) => {
38790
38899
  try {
38791
38900
  process.kill(pid, "SIGKILL");
@@ -38928,7 +39037,7 @@ var init_thread_hibernation = __esm({
38928
39037
  });
38929
39038
 
38930
39039
  // packages/server/src/context.ts
38931
- import { join as join30 } from "node:path";
39040
+ import { join as join31 } from "node:path";
38932
39041
  import { randomUUID as randomUUID15 } from "node:crypto";
38933
39042
  import { homedir as homedir13 } from "node:os";
38934
39043
  function reconcileSessions(storage) {
@@ -39086,7 +39195,7 @@ async function createContext(opts = {}) {
39086
39195
  function createContextUnchecked(opts, resources) {
39087
39196
  const home = opts.home ?? homedir13();
39088
39197
  const project = opts.project ?? resolveProject();
39089
- const dbPath = join30(project.stateDir, "ui.db");
39198
+ const dbPath = join31(project.stateDir, "ui.db");
39090
39199
  const storage = createStorage(dbPath);
39091
39200
  resources.storage = storage;
39092
39201
  const bus = new Bus();
@@ -39414,6 +39523,7 @@ ${wakeDeliveryToken(deliveryId)}`;
39414
39523
  getSettings: () => getSettings(storage, home),
39415
39524
  setSettings: (s) => setSettings(storage, s, home),
39416
39525
  resetSettings: () => resetSettings(storage, home),
39526
+ activeTenants: opts.activeTenants,
39417
39527
  claudeBin: opts.claudeBin,
39418
39528
  codexBin: opts.codexBin,
39419
39529
  loginUtility: createLoginUtility({ claudeBin: opts.claudeBin, codexBin: opts.codexBin, cwd: project.dir })
@@ -42113,7 +42223,7 @@ var init_server = __esm({
42113
42223
  });
42114
42224
 
42115
42225
  // packages/server/src/repair.ts
42116
- import { existsSync as existsSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "node:fs";
42226
+ import { existsSync as existsSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "node:fs";
42117
42227
  import { basename as basename7, dirname as dirname13, resolve as resolve6 } from "node:path";
42118
42228
  function quoteValue(v) {
42119
42229
  if (/^[\w./#:+-]+$/.test(v)) return v;
@@ -42129,7 +42239,7 @@ function repairThreadFile(frizzDir, file) {
42129
42239
  if (dirname13(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
42130
42240
  if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
42131
42241
  if (!existsSync12(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
42132
- const content = readFileSync17(abs, "utf8");
42242
+ const content = readFileSync18(abs, "utf8");
42133
42243
  const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
42134
42244
  if (firstLine2?.trim() === "---") {
42135
42245
  throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
@@ -42162,7 +42272,7 @@ var init_repair = __esm({
42162
42272
  });
42163
42273
 
42164
42274
  // cc-worker/hooks/bash-background.mjs
42165
- import { readFileSync as readFileSync18 } from "node:fs";
42275
+ import { readFileSync as readFileSync19 } from "node:fs";
42166
42276
  import { basename as basename8 } from "node:path";
42167
42277
  import { pathToFileURL } from "node:url";
42168
42278
  function emit(obj) {
@@ -42311,7 +42421,7 @@ var init_bash_background = __esm({
42311
42421
  if (isDirectHookExecution(process.argv[1], import.meta.url)) {
42312
42422
  try {
42313
42423
  const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
42314
- emit(evaluateBashBackgroundHook(JSON.parse(readFileSync18(0, "utf8")), env));
42424
+ emit(evaluateBashBackgroundHook(JSON.parse(readFileSync19(0, "utf8")), env));
42315
42425
  } catch {
42316
42426
  emit({});
42317
42427
  }
@@ -42320,10 +42430,10 @@ var init_bash_background = __esm({
42320
42430
  });
42321
42431
 
42322
42432
  // packages/server/src/transcript.ts
42323
- import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync19, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
42433
+ import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync20, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
42324
42434
  import { createHash as createHash13 } from "node:crypto";
42325
42435
  import { StringDecoder as StringDecoder4 } from "node:string_decoder";
42326
- import { join as join31 } from "node:path";
42436
+ import { join as join32 } from "node:path";
42327
42437
  import { homedir as homedir14 } from "node:os";
42328
42438
  function formatTokens(n) {
42329
42439
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
@@ -42428,17 +42538,28 @@ function pushToolPart(m, call) {
42428
42538
  else m.parts.push({ kind: "tools", tools: [call] });
42429
42539
  }
42430
42540
  function coalescedQueuedKeys(deliveredText, pendingKeys) {
42431
- const consumed = [];
42432
- let cursor = 0;
42433
- for (const key of pendingKeys) {
42434
- if (!deliveredText.startsWith(key, cursor)) break;
42435
- cursor += key.length;
42436
- consumed.push(key);
42437
- if (cursor === deliveredText.length) return consumed;
42438
- if (!deliveredText.startsWith("\n", cursor)) break;
42439
- cursor += 1;
42440
- }
42441
- return cursor === deliveredText.length && consumed.length > 0 ? consumed : [];
42541
+ if (!deliveredText) return [];
42542
+ const keys = [...pendingKeys];
42543
+ const dead = /* @__PURE__ */ new Set();
42544
+ const walk = (cursor, index) => {
42545
+ if (index >= keys.length) return null;
42546
+ const state = cursor * (keys.length + 1) + index;
42547
+ if (dead.has(state)) return null;
42548
+ const key = keys[index];
42549
+ if (key && deliveredText.startsWith(key, cursor)) {
42550
+ const next = cursor + key.length;
42551
+ if (next === deliveredText.length) return [key];
42552
+ if (deliveredText.startsWith("\n", next)) {
42553
+ const rest = walk(next + 1, index + 1);
42554
+ if (rest) return [key, ...rest];
42555
+ }
42556
+ }
42557
+ const skipped = walk(cursor, index + 1);
42558
+ if (skipped) return skipped;
42559
+ dead.add(state);
42560
+ return null;
42561
+ };
42562
+ return walk(0, 0) ?? [];
42442
42563
  }
42443
42564
  function commandEnvelopeQueuedKey(deliveredText) {
42444
42565
  const name = COMMAND_NAME_RE.exec(deliveredText)?.[1]?.trim();
@@ -42862,14 +42983,14 @@ function pruneScreenshotCache() {
42862
42983
  if (entries.length <= SCREENSHOT_CACHE_MAX) return;
42863
42984
  const byMtime = entries.map((n) => {
42864
42985
  try {
42865
- return { n, m: statSync14(join31(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
42986
+ return { n, m: statSync14(join32(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
42866
42987
  } catch {
42867
42988
  return { n, m: 0 };
42868
42989
  }
42869
42990
  }).sort((a, b) => b.m - a.m);
42870
42991
  for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
42871
42992
  try {
42872
- unlinkSync5(join31(SCREENSHOT_CACHE_DIR, n));
42993
+ unlinkSync5(join32(SCREENSHOT_CACHE_DIR, n));
42873
42994
  } catch {
42874
42995
  }
42875
42996
  }
@@ -42899,14 +43020,14 @@ function persistBase64Image(mediaType, data, idKey) {
42899
43020
  const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
42900
43021
  if (!ext || !data) return void 0;
42901
43022
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
42902
- const path = join31(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
43023
+ const path = join32(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
42903
43024
  try {
42904
43025
  if (existsSync13(path)) return path;
42905
43026
  if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
42906
43027
  const buf = Buffer.from(data, "base64");
42907
43028
  if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
42908
43029
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
42909
- const tmp = join31(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43030
+ const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
42910
43031
  writeFileSync12(tmp, buf);
42911
43032
  renameSync9(tmp, path);
42912
43033
  pruneScreenshotCache();
@@ -42921,14 +43042,14 @@ function persistSentFile(srcPath, idKey) {
42921
43042
  const outExt = ext === "jpeg" ? "jpg" : ext;
42922
43043
  try {
42923
43044
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
42924
- const dest = join31(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
43045
+ const dest = join32(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
42925
43046
  if (existsSync13(dest)) return dest;
42926
43047
  const size = statSync14(srcPath).size;
42927
43048
  if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
42928
- const buf = readFileSync19(srcPath);
43049
+ const buf = readFileSync20(srcPath);
42929
43050
  if (!looksLikeImage(buf, outExt)) return void 0;
42930
43051
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
42931
- const tmp = join31(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43052
+ const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
42932
43053
  writeFileSync12(tmp, buf);
42933
43054
  renameSync9(tmp, dest);
42934
43055
  pruneScreenshotCache();
@@ -43345,7 +43466,7 @@ function readTranscript(project, sessionId) {
43345
43466
  }
43346
43467
  function verifyIncrementalParse(path, identityPrefix, incremental) {
43347
43468
  try {
43348
- const fresh = parseTranscript(readFileSync19(path, "utf8"), identityPrefix);
43469
+ const fresh = parseTranscript(readFileSync20(path, "utf8"), identityPrefix);
43349
43470
  const a = JSON.stringify(incremental);
43350
43471
  const b = JSON.stringify(fresh);
43351
43472
  if (a !== b) {
@@ -43365,16 +43486,16 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
43365
43486
  }
43366
43487
  }
43367
43488
  function logDirOf(project) {
43368
- return join31(homedir14(), ".claude", "projects", project.cwdSlug);
43489
+ return join32(homedir14(), ".claude", "projects", project.cwdSlug);
43369
43490
  }
43370
43491
  function resolveTranscriptPath(project, sessionId) {
43371
- const path = join31(logDirOf(project), `${sessionId}.jsonl`);
43492
+ const path = join32(logDirOf(project), `${sessionId}.jsonl`);
43372
43493
  try {
43373
43494
  if (statSync14(path).size > 0) return path;
43374
43495
  } catch {
43375
43496
  }
43376
43497
  const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
43377
- return stranded ? join31(stranded, `${sessionId}.jsonl`) : path;
43498
+ return stranded ? join32(stranded, `${sessionId}.jsonl`) : path;
43378
43499
  }
43379
43500
  function projectCodexTranscript(raw2, identityPrefix = "codex") {
43380
43501
  const out = [];
@@ -44577,7 +44698,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
44577
44698
  }
44578
44699
  function readCodexTranscriptFile(absPath, nativeId = absPath) {
44579
44700
  try {
44580
- return parseCodexTranscript(readFileSync19(absPath, "utf8"), `codex:${nativeId}`);
44701
+ return parseCodexTranscript(readFileSync20(absPath, "utf8"), `codex:${nativeId}`);
44581
44702
  } catch {
44582
44703
  return [];
44583
44704
  }
@@ -44671,7 +44792,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
44671
44792
  function readTranscriptFile(absPath) {
44672
44793
  try {
44673
44794
  const pathKey = createHash13("sha256").update(absPath).digest("base64url").slice(0, 16);
44674
- return parseTranscript(readFileSync19(absPath, "utf8"), `claude-file:${pathKey}`);
44795
+ return parseTranscript(readFileSync20(absPath, "utf8"), `claude-file:${pathKey}`);
44675
44796
  } catch {
44676
44797
  return [];
44677
44798
  }
@@ -44768,9 +44889,9 @@ var init_open_external = __esm({
44768
44889
 
44769
44890
  // packages/server/src/local-file.ts
44770
44891
  import { spawn as spawn6 } from "node:child_process";
44771
- import { readFileSync as readFileSync20, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
44892
+ import { readFileSync as readFileSync21, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
44772
44893
  import { homedir as homedir15 } from "node:os";
44773
- import { isAbsolute as isAbsolute3, join as join32, resolve as resolve7, sep } from "node:path";
44894
+ import { isAbsolute as isAbsolute3, join as join33, resolve as resolve7, sep } from "node:path";
44774
44895
  function isUnder(real, root) {
44775
44896
  let rootReal;
44776
44897
  try {
@@ -44800,7 +44921,7 @@ function resolveLocalFile(rawPath, roots) {
44800
44921
  function resolveOpenableFile(raw2, projectDir, roots, home = homedir15()) {
44801
44922
  const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
44802
44923
  if (!trimmed) return null;
44803
- const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join32(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
44924
+ const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join33(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
44804
44925
  try {
44805
44926
  return resolveLocalFile(abs, roots);
44806
44927
  } catch {
@@ -44811,7 +44932,7 @@ function readLocalMarkdown(rawPath, roots) {
44811
44932
  if (!MARKDOWN_FILE_EXT.test(rawPath.trim())) throw new Error("Local file is not a Markdown file");
44812
44933
  const path = resolveLocalFile(rawPath, roots);
44813
44934
  if (!MARKDOWN_FILE_EXT.test(path)) throw new Error("Local file is not a Markdown file");
44814
- const bytes = readFileSync20(path);
44935
+ const bytes = readFileSync21(path);
44815
44936
  if (bytes.length <= MARKDOWN_READ_LIMIT) return { path, markdown: bytes.toString("utf8"), truncated: false };
44816
44937
  const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
44817
44938
  const lastBreak = head.lastIndexOf(10);
@@ -45257,6 +45378,17 @@ function readBackgroundShellOutput(path, maxBytes = OUTPUT_TAIL_BYTES) {
45257
45378
  if (fd !== void 0) closeSync14(fd);
45258
45379
  }
45259
45380
  }
45381
+ function readHead2(fd, length) {
45382
+ if (length <= 0) return "";
45383
+ const buffer = Buffer.alloc(length);
45384
+ let read = 0;
45385
+ while (read < length) {
45386
+ const count = readSync8(fd, buffer, read, length - read, read);
45387
+ if (count === 0) break;
45388
+ read += count;
45389
+ }
45390
+ return buffer.subarray(0, read).toString("latin1");
45391
+ }
45260
45392
  function backgroundShellLineCount(path) {
45261
45393
  let fd;
45262
45394
  try {
@@ -45264,9 +45396,21 @@ function backgroundShellLineCount(path) {
45264
45396
  const stat2 = fstatSync4(fd);
45265
45397
  const size = stat2.size;
45266
45398
  let state = scans.get(path);
45267
- if (state && (state.bytes > size || state.ino !== stat2.ino)) state = void 0;
45399
+ if (state && (state.bytes > size || state.ino !== stat2.ino || state.birthtimeMs !== stat2.birthtimeMs)) state = void 0;
45400
+ if (state && state.fingerprint !== readHead2(fd, state.fingerprint.length)) state = void 0;
45268
45401
  if (state?.overflowed) return void 0;
45269
- if (!state) state = { ino: stat2.ino, bytes: 0, breaks: 0, pendingCR: false, trailing: false, overflowed: false };
45402
+ if (!state) {
45403
+ state = {
45404
+ ino: stat2.ino,
45405
+ birthtimeMs: stat2.birthtimeMs,
45406
+ fingerprint: readHead2(fd, Math.min(FINGERPRINT_BYTES, size)),
45407
+ bytes: 0,
45408
+ breaks: 0,
45409
+ pendingCR: false,
45410
+ trailing: false,
45411
+ overflowed: false
45412
+ };
45413
+ }
45270
45414
  if (size - state.bytes > SCAN_CEILING_BYTES) {
45271
45415
  scans.set(path, { ...state, overflowed: true });
45272
45416
  return void 0;
@@ -45302,7 +45446,7 @@ function backgroundShellLineCount(path) {
45302
45446
  if (fd !== void 0) closeSync14(fd);
45303
45447
  }
45304
45448
  }
45305
- var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, ANSI_ESCAPE_RE, scans;
45449
+ var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, FINGERPRINT_BYTES, ANSI_ESCAPE_RE, scans;
45306
45450
  var init_background_shell_output = __esm({
45307
45451
  "packages/server/src/background-shell-output.ts"() {
45308
45452
  "use strict";
@@ -45310,6 +45454,7 @@ var init_background_shell_output = __esm({
45310
45454
  SCAN_CHUNK_BYTES = 256 * 1024;
45311
45455
  SCAN_CEILING_BYTES = 128 * 1024 * 1024;
45312
45456
  SCAN_CACHE_LIMIT = 512;
45457
+ FINGERPRINT_BYTES = 64;
45313
45458
  ANSI_ESCAPE_RE = /\x1b(?:\][^\x07]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])/g;
45314
45459
  scans = /* @__PURE__ */ new Map();
45315
45460
  }
@@ -45318,7 +45463,7 @@ var init_background_shell_output = __esm({
45318
45463
  // packages/server/src/image-header.ts
45319
45464
  import { closeSync as closeSync15, openSync as openSync16, readSync as readSync9, statSync as statSync16 } from "node:fs";
45320
45465
  import { extname } from "node:path";
45321
- function readHead2(path, budget) {
45466
+ function readHead3(path, budget) {
45322
45467
  let fd;
45323
45468
  try {
45324
45469
  const size = statSync16(path).size;
@@ -45426,7 +45571,7 @@ function svg(head) {
45426
45571
  }
45427
45572
  function svgDeclaresColour(path) {
45428
45573
  if (extname(path).toLowerCase() !== ".svg") return void 0;
45429
- const head = readHead2(path, 512 * 1024);
45574
+ const head = readHead3(path, 512 * 1024);
45430
45575
  if (!head) return void 0;
45431
45576
  const source = head.toString("utf8");
45432
45577
  if (!/<svg\b/iu.test(source)) return void 0;
@@ -45439,7 +45584,7 @@ function svgDeclaresColour(path) {
45439
45584
  function imageDimensions(path) {
45440
45585
  const extension2 = extname(path).toLowerCase();
45441
45586
  const budget = extension2 === ".jpg" || extension2 === ".jpeg" ? JPEG_SCAN_BYTES : HEAD_BYTES2;
45442
- const head = readHead2(path, budget);
45587
+ const head = readHead3(path, budget);
45443
45588
  if (!head) return void 0;
45444
45589
  return png(head) ?? gif(head) ?? webp(head) ?? ico(head) ?? jpeg(head) ?? svg(head);
45445
45590
  }
@@ -45547,8 +45692,8 @@ var init_directory_picker = __esm({
45547
45692
  });
45548
45693
 
45549
45694
  // packages/server/src/router.ts
45550
- import { readFileSync as readFileSync21, statSync as statSync17 } from "node:fs";
45551
- import { join as join33, resolve as resolve8 } from "node:path";
45695
+ import { readFileSync as readFileSync22, statSync as statSync17 } from "node:fs";
45696
+ import { join as join34, resolve as resolve8 } from "node:path";
45552
45697
  import { randomUUID as randomUUID16 } from "node:crypto";
45553
45698
  import { basename as basename9, dirname as dirname14 } from "node:path";
45554
45699
  import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
@@ -45711,7 +45856,7 @@ function projectCard(entry, stale) {
45711
45856
  function addProjectAtPath(input) {
45712
45857
  const typed = input.trim();
45713
45858
  if (!typed) throw new Error("Enter a folder path.");
45714
- const expanded = typed === "~" || typed.startsWith("~/") ? join33(homedir16(), typed.slice(1)) : typed;
45859
+ const expanded = typed === "~" || typed.startsWith("~/") ? join34(homedir16(), typed.slice(1)) : typed;
45715
45860
  const absolute = resolve8(expanded);
45716
45861
  let stats;
45717
45862
  try {
@@ -45756,7 +45901,7 @@ function storeProjectIcon(id, name, bytes) {
45756
45901
  function setProjectIconFromFile(id, file) {
45757
45902
  let bytes;
45758
45903
  try {
45759
- bytes = readFileSync21(file);
45904
+ bytes = readFileSync22(file);
45760
45905
  } catch {
45761
45906
  throw new Error("That file could not be read.");
45762
45907
  }
@@ -45764,7 +45909,7 @@ function setProjectIconFromFile(id, file) {
45764
45909
  return storeProjectIcon(id, file, bytes);
45765
45910
  }
45766
45911
  function createRouter(ctx) {
45767
- const frizzDir = join33(ctx.project.dir, ".frizz");
45912
+ const frizzDir = join34(ctx.project.dir, ".frizz");
45768
45913
  const openRoots = openableFileRoots(ctx.project);
45769
45914
  function isAutoTitledSession(slug) {
45770
45915
  return ctx.storage.getSession(slug)?.title_auto === 1;
@@ -46396,15 +46541,16 @@ ${gapNote}` : input.message;
46396
46541
  )
46397
46542
  });
46398
46543
  if (input.freshProcess) retireOutstandingDeliveries(ctx.storage, input.slug);
46399
- if (input.interrupt) bridge.interruptTurn({ threadSlug: input.slug, sessionId: row.session_id });
46544
+ const preempted = input.interrupt === true && bridge.interruptTurn({ threadSlug: input.slug, sessionId: row.session_id });
46400
46545
  if (input.deliveryId) {
46401
46546
  appendDelivery(ctx.storage, input.slug, {
46402
46547
  id: input.deliveryId,
46403
46548
  text: input.message,
46404
46549
  state: midTurn && input.freshProcess !== true ? "enqueued" : "delivered"
46405
46550
  });
46406
- ctx.transcriptChange.emit([input.slug]);
46407
46551
  }
46552
+ if (preempted) deliverOutstandingDeliveries(ctx.storage, input.slug);
46553
+ if (input.deliveryId || preempted) ctx.transcriptChange.emit([input.slug]);
46408
46554
  ctx.board.refresh();
46409
46555
  return;
46410
46556
  }
@@ -46490,6 +46636,7 @@ ${gapNote}` : input.message;
46490
46636
  if (!bridge.interruptTurn({ threadSlug: input.slug, sessionId: row.session_id })) {
46491
46637
  return { interrupted: false, reason: "Nothing to interrupt \u2014 this thread has no turn running" };
46492
46638
  }
46639
+ if (deliverOutstandingDeliveries(ctx.storage, input.slug)) ctx.transcriptChange.emit([input.slug]);
46493
46640
  return { interrupted: true };
46494
46641
  }
46495
46642
  }),
@@ -47267,6 +47414,35 @@ ${gapNote}` : input.message;
47267
47414
  output: external_exports.array(ProjectCard),
47268
47415
  handler: async () => listProjects().map((entry) => projectCard(entry, entry.stale))
47269
47416
  }),
47417
+ /**
47418
+ * How many threads are in each project's queue, keyed by project id — the rail's badges.
47419
+ *
47420
+ * MACHINE-WIDE, answered from the boards this process has OPEN. A queue count is a board fact:
47421
+ * `needsYou` is derived from the tailer's live view of each session, so a project nobody has
47422
+ * opened since boot has no honest count, and it is left out rather than guessed at or opened for
47423
+ * the purpose (activating a project to badge it is exactly the cost lazy activation exists to
47424
+ * avoid — see tenants.ts). Absent ⇒ no badge; the project the operator is looking at is always
47425
+ * present, and the client draws THAT one from its own live board anyway.
47426
+ *
47427
+ * Kept OFF `projectsList` on purpose: that list is one registry-file read, cheap enough to be the
47428
+ * home page with forty projects, and this is a walk over live boards. The cached snapshot makes
47429
+ * it cheap too — but cheap-and-polled is a different budget from cheap-and-once.
47430
+ */
47431
+ projectsQueueCounts: query({
47432
+ output: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()),
47433
+ handler: async () => {
47434
+ const counts = {};
47435
+ const open = ctx.activeTenants?.() ?? [{ project: ctx.project, board: ctx.board }];
47436
+ for (const { project, board } of open) {
47437
+ try {
47438
+ const { threads } = await board.snapshot();
47439
+ counts[project.id] = threads.filter(queuedThread).length;
47440
+ } catch {
47441
+ }
47442
+ }
47443
+ return counts;
47444
+ }
47445
+ }),
47270
47446
  /**
47271
47447
  * Pin the rail's order.
47272
47448
  *
@@ -47388,7 +47564,7 @@ ${gapNote}` : input.message;
47388
47564
  for (const entry of listProjects()) {
47389
47565
  if (entry.stale) continue;
47390
47566
  try {
47391
- const db = new sqlite_default(join33(projectStateDir(entry.id), "ui.db"), { readonly: true });
47567
+ const db = new sqlite_default(join34(projectStateDir(entry.id), "ui.db"), { readonly: true });
47392
47568
  try {
47393
47569
  const hit = db.prepare("SELECT 1 FROM session WHERE slug = ? LIMIT 1").get(input.slug);
47394
47570
  if (hit) found.push({ projectSlug: entry.slug, projectName: entry.name ?? entry.slug });
@@ -47745,7 +47921,7 @@ var init_compression = __esm({
47745
47921
  });
47746
47922
 
47747
47923
  // packages/server/src/local-image.ts
47748
- import { readFileSync as readFileSync22, realpathSync as realpathSync9, statSync as statSync18 } from "node:fs";
47924
+ import { readFileSync as readFileSync23, realpathSync as realpathSync9, statSync as statSync18 } from "node:fs";
47749
47925
  import { extname as extname2, isAbsolute as isAbsolute4 } from "node:path";
47750
47926
  function resolveLocalImage(rawPath) {
47751
47927
  if (!rawPath || !isAbsolute4(rawPath)) return { status: 400 };
@@ -47759,7 +47935,7 @@ function resolveLocalImage(rawPath) {
47759
47935
  }
47760
47936
  try {
47761
47937
  if (!statSync18(real).isFile()) return { status: 404 };
47762
- return { status: 200, contentType, body: readFileSync22(real) };
47938
+ return { status: 200, contentType, body: readFileSync23(real) };
47763
47939
  } catch {
47764
47940
  return { status: 404 };
47765
47941
  }
@@ -47779,9 +47955,9 @@ var init_local_image = __esm({
47779
47955
  });
47780
47956
 
47781
47957
  // packages/server/src/project-icon.ts
47782
- import { readFileSync as readFileSync23, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
47958
+ import { readFileSync as readFileSync24, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
47783
47959
  import { homedir as homedir17 } from "node:os";
47784
- import { basename as basename10, dirname as dirname15, extname as extname3, join as join34, relative, sep as sep2 } from "node:path";
47960
+ import { basename as basename10, dirname as dirname15, extname as extname3, join as join35, relative, sep as sep2 } from "node:path";
47785
47961
  function normalizeStem(stem) {
47786
47962
  const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
47787
47963
  const normalized = sized.replace(VARIANT_SUFFIX, "");
@@ -47799,7 +47975,7 @@ function sizeScore(dimensions) {
47799
47975
  return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
47800
47976
  }
47801
47977
  function under(root, relativeDirectory) {
47802
- return relativeDirectory ? join34(root, relativeDirectory) : root;
47978
+ return relativeDirectory ? join35(root, relativeDirectory) : root;
47803
47979
  }
47804
47980
  function listFiles(directory) {
47805
47981
  try {
@@ -47821,19 +47997,19 @@ function iconDirectories(root) {
47821
47997
  for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
47822
47998
  for (const host of HOST_DIRECTORIES) {
47823
47999
  if (!children2.has(host)) continue;
47824
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join34(root, host), asset));
48000
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join35(root, host), asset));
47825
48001
  }
47826
48002
  for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
47827
48003
  for (const container of WORKSPACE_CONTAINERS) {
47828
48004
  if (!children2.has(container)) continue;
47829
48005
  let members;
47830
48006
  try {
47831
- members = readdirSync10(join34(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
48007
+ members = readdirSync10(join35(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
47832
48008
  } catch {
47833
48009
  continue;
47834
48010
  }
47835
48011
  for (const member of members) {
47836
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join34(root, container, member), asset));
48012
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join35(root, container, member), asset));
47837
48013
  }
47838
48014
  }
47839
48015
  return [...new Set(directories)];
@@ -47841,13 +48017,13 @@ function iconDirectories(root) {
47841
48017
  function manifestIcons(manifestPath) {
47842
48018
  let parsed;
47843
48019
  try {
47844
- parsed = JSON.parse(readFileSync23(manifestPath, "utf8"));
48020
+ parsed = JSON.parse(readFileSync24(manifestPath, "utf8"));
47845
48021
  } catch {
47846
48022
  return [];
47847
48023
  }
47848
48024
  if (!Array.isArray(parsed?.icons)) return [];
47849
48025
  const directory = dirname15(manifestPath);
47850
- return parsed.icons.map((icon) => typeof icon?.src === "string" ? icon.src : void 0).filter((src) => !!src && !/^(https?:)?\/\//u.test(src) && !src.startsWith("data:")).map((src) => join34(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
48026
+ return parsed.icons.map((icon) => typeof icon?.src === "string" ? icon.src : void 0).filter((src) => !!src && !/^(https?:)?\/\//u.test(src) && !src.startsWith("data:")).map((src) => join35(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
47851
48027
  }
47852
48028
  function projectIconCandidates(root) {
47853
48029
  const projectStem = normalizeStem(basename10(root)).normalized;
@@ -47866,7 +48042,7 @@ function projectIconCandidates(root) {
47866
48042
  for (const name of listFiles(directory)) {
47867
48043
  const extension2 = extname3(name).toLowerCase();
47868
48044
  if (MANIFEST_NAMES.includes(name.toLowerCase())) {
47869
- for (const icon of manifestIcons(join34(directory, name))) {
48045
+ for (const icon of manifestIcons(join35(directory, name))) {
47870
48046
  if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
47871
48047
  fromManifest.add(icon);
47872
48048
  files.push({ path: icon, directory: dirname15(icon) });
@@ -47877,7 +48053,7 @@ function projectIconCandidates(root) {
47877
48053
  if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
47878
48054
  const stem = name.slice(0, name.length - extension2.length);
47879
48055
  if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
47880
- files.push({ path: join34(directory, name), directory });
48056
+ files.push({ path: join35(directory, name), directory });
47881
48057
  if (files.length >= MAX_CANDIDATES) break;
47882
48058
  }
47883
48059
  }
@@ -47942,7 +48118,7 @@ function resolveProjectIconResponse(id, options = {}) {
47942
48118
  });
47943
48119
  if (!roots.some((root) => real === root || real.startsWith(root + sep2))) return { status: 404 };
47944
48120
  try {
47945
- return { status: 200, contentType, body: readFileSync23(real) };
48121
+ return { status: 200, contentType, body: readFileSync24(real) };
47946
48122
  } catch {
47947
48123
  return { status: 404 };
47948
48124
  }
@@ -48054,8 +48230,8 @@ var init_project_icon = __esm({
48054
48230
  });
48055
48231
 
48056
48232
  // packages/server/src/local-visualization.ts
48057
- import { readdirSync as readdirSync11, readFileSync as readFileSync24, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
48058
- import { join as join35, sep as sep3 } from "node:path";
48233
+ import { readdirSync as readdirSync11, readFileSync as readFileSync25, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
48234
+ import { join as join36, sep as sep3 } from "node:path";
48059
48235
  function children(path, pattern) {
48060
48236
  try {
48061
48237
  return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
@@ -48067,7 +48243,7 @@ function isUnder2(path, root) {
48067
48243
  return path === root || path.startsWith(root.endsWith(sep3) ? root : root + sep3);
48068
48244
  }
48069
48245
  function resolveFragment(projectDir, sessionId, file) {
48070
- const base = join35(projectDir, ".codex", "visualizations");
48246
+ const base = join36(projectDir, ".codex", "visualizations");
48071
48247
  let projectReal;
48072
48248
  let baseReal;
48073
48249
  try {
@@ -48078,12 +48254,12 @@ function resolveFragment(projectDir, sessionId, file) {
48078
48254
  }
48079
48255
  if (!isUnder2(baseReal, projectReal)) return null;
48080
48256
  for (const year of children(base, YEAR_PART)) {
48081
- const yearDir = join35(base, year);
48257
+ const yearDir = join36(base, year);
48082
48258
  for (const month of children(yearDir, DATE_PART)) {
48083
- const monthDir = join35(yearDir, month);
48259
+ const monthDir = join36(yearDir, month);
48084
48260
  for (const day of children(monthDir, DATE_PART)) {
48085
- const sessionRoot = join35(baseReal, year, month, day, sessionId);
48086
- const candidate = join35(monthDir, day, sessionId, file);
48261
+ const sessionRoot = join36(baseReal, year, month, day, sessionId);
48262
+ const candidate = join36(monthDir, day, sessionId, file);
48087
48263
  try {
48088
48264
  const real = realpathSync11(candidate);
48089
48265
  if (isUnder2(real, sessionRoot) && statSync20(real).isFile()) return real;
@@ -48169,7 +48345,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
48169
48345
  try {
48170
48346
  const size = statSync20(path).size;
48171
48347
  if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
48172
- fragment = readFileSync24(path, "utf8");
48348
+ fragment = readFileSync25(path, "utf8");
48173
48349
  } catch {
48174
48350
  return { status: 404 };
48175
48351
  }
@@ -48212,7 +48388,7 @@ var init_local_visualization = __esm({
48212
48388
 
48213
48389
  // packages/server/src/app.ts
48214
48390
  import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync14 } from "node:fs";
48215
- import { join as join36 } from "node:path";
48391
+ import { join as join37 } from "node:path";
48216
48392
  import { randomUUID as randomUUID17 } from "node:crypto";
48217
48393
  function createApp(ctx, options = {}) {
48218
48394
  const app = new Hono2();
@@ -48316,10 +48492,10 @@ function createApp(ctx, options = {}) {
48316
48492
  if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
48317
48493
  const ext = `.${attachmentExtension(name)}`;
48318
48494
  const buf = Buffer.from(body.data, "base64");
48319
- const dir = join36(ctx.project.stateDir, "attachments");
48495
+ const dir = join37(ctx.project.stateDir, "attachments");
48320
48496
  mkdirSync17(dir, { recursive: true });
48321
48497
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
48322
- const path = join36(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
48498
+ const path = join37(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
48323
48499
  writeFileSync14(path, buf);
48324
48500
  return c.json({ path });
48325
48501
  });
@@ -49558,10 +49734,10 @@ var init_app_socket = __esm({
49558
49734
  });
49559
49735
 
49560
49736
  // packages/server/src/boot-progress.ts
49561
- import { mkdirSync as mkdirSync18, readFileSync as readFileSync25, renameSync as renameSync10, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
49562
- import { basename as basename11, dirname as dirname16, join as join37 } from "node:path";
49737
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync26, renameSync as renameSync10, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
49738
+ import { basename as basename11, dirname as dirname16, join as join38 } from "node:path";
49563
49739
  function bootProgressPath(stateDir) {
49564
- return join37(stateDir, BOOT_PROGRESS_NAME);
49740
+ return join38(stateDir, BOOT_PROGRESS_NAME);
49565
49741
  }
49566
49742
  function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49567
49743
  if (!stateDir) {
@@ -49582,7 +49758,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49582
49758
  step++;
49583
49759
  try {
49584
49760
  mkdirSync18(dirname16(path), { recursive: true, mode: 448 });
49585
- const temp = join37(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49761
+ const temp = join38(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49586
49762
  writeFileSync15(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
49587
49763
  `, "utf8");
49588
49764
  renameSync10(temp, path);
@@ -49699,11 +49875,11 @@ __export(index_exports, {
49699
49875
  unknownProjectPage: () => unknownProjectPage
49700
49876
  });
49701
49877
  import { createServer } from "node:http";
49702
- import { readFileSync as readFileSync26, existsSync as existsSync15 } from "node:fs";
49703
- import { dirname as dirname17, join as join38, resolve as resolve9, extname as extname4, normalize } from "node:path";
49878
+ import { readFileSync as readFileSync27, existsSync as existsSync15 } from "node:fs";
49879
+ import { dirname as dirname17, join as join39, resolve as resolve9, extname as extname4, normalize } from "node:path";
49704
49880
  function readServerAddressHolder(path) {
49705
49881
  try {
49706
- const value = JSON.parse(readFileSync26(path, "utf8"));
49882
+ const value = JSON.parse(readFileSync27(path, "utf8"));
49707
49883
  if (typeof value?.pid !== "number") return void 0;
49708
49884
  return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
49709
49885
  } catch {
@@ -49803,11 +49979,11 @@ function createShutdownSignalHandler(options) {
49803
49979
  }
49804
49980
  function serveStatic(distDir, req, res) {
49805
49981
  const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
49806
- let file = join38(distDir, rel === "/" ? "index.html" : rel);
49807
- if (!file.startsWith(distDir)) file = join38(distDir, "index.html");
49808
- if (!existsSync15(file)) file = join38(distDir, "index.html");
49982
+ let file = join39(distDir, rel === "/" ? "index.html" : rel);
49983
+ if (!file.startsWith(distDir)) file = join39(distDir, "index.html");
49984
+ if (!existsSync15(file)) file = join39(distDir, "index.html");
49809
49985
  try {
49810
- const body = readFileSync26(file);
49986
+ const body = readFileSync27(file);
49811
49987
  res.writeHead(200, { "content-type": MIME[extname4(file)] ?? "application/octet-stream" });
49812
49988
  res.end(body);
49813
49989
  } catch {
@@ -49836,6 +50012,7 @@ async function startServer(opts = {}) {
49836
50012
  `${candidate.name} is already being served by another Frizz (pid ${other}). Stop that one first \u2014 two servers on one board would fire its timers and recurring prompts twice.`
49837
50013
  );
49838
50014
  };
50015
+ const activeTenants = () => tenants.active().map(({ project: open, ctx: openCtx }) => ({ project: open, board: openCtx.board }));
49839
50016
  const tenants = createTenantMap({
49840
50017
  createContext: (contextOptions) => {
49841
50018
  if (contextOptions.project) assertNotServedElsewhere(contextOptions.project);
@@ -49843,7 +50020,7 @@ async function startServer(opts = {}) {
49843
50020
  },
49844
50021
  // serverLockPath is the LAUNCHING project's: it is the only `server.lock` this process publishes
49845
50022
  // (see "status publication"), so it is the only file a tenant's worker can read the port out of.
49846
- contextOptions: { claudeBin: opts.claudeBin, serverLockPath: serverLockPathFor(project) },
50023
+ contextOptions: { claudeBin: opts.claudeBin, serverLockPath: serverLockPathFor(project), activeTenants },
49847
50024
  // Each project's app carries ITS OWN owner proof, so /health stays honest per project rather than
49848
50025
  // answering for whichever one happened to launch the server. The transports are per project for a
49849
50026
  // blunter reason: a socket is a live feed of ONE board, so sharing the launcher's would push its
@@ -50102,6 +50279,7 @@ async function startServer(opts = {}) {
50102
50279
  claudeBin: opts.claudeBin,
50103
50280
  project,
50104
50281
  serverLockPath: serverLockPathFor(project),
50282
+ activeTenants,
50105
50283
  startup: {
50106
50284
  afterPhase: (p) => {
50107
50285
  bootProgress(`context: ${p}`);
@@ -50154,7 +50332,7 @@ async function startServer(opts = {}) {
50154
50332
  }
50155
50333
  statusPath = serverLockPathFor(ctx.project);
50156
50334
  const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
50157
- const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join38(webRoot, "dist");
50335
+ const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join39(webRoot, "dist");
50158
50336
  startupPhase = "Vite";
50159
50337
  if (opts.dev) {
50160
50338
  try {
@@ -50230,7 +50408,7 @@ async function startServer(opts = {}) {
50230
50408
  if (vite) {
50231
50409
  vite.middlewares(req, res, () => {
50232
50410
  try {
50233
- const html = readFileSync26(join38(webRoot, "index.html"), "utf8");
50411
+ const html = readFileSync27(join39(webRoot, "index.html"), "utf8");
50234
50412
  void vite.transformIndexHtml(url, html).then((out) => {
50235
50413
  res.writeHead(200, { "content-type": "text/html" });
50236
50414
  res.end(out);
@@ -50422,7 +50600,7 @@ var init_index = __esm({
50422
50600
  }
50423
50601
  };
50424
50602
  isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
50425
- serverLockPathFor = (project) => join38(project.stateDir, "server.lock");
50603
+ serverLockPathFor = (project) => join39(project.stateDir, "server.lock");
50426
50604
  MIME = {
50427
50605
  ".html": "text/html",
50428
50606
  ".js": "text/javascript",
@@ -50441,7 +50619,7 @@ init_project_launch();
50441
50619
  init_shutdown();
50442
50620
  init_logging();
50443
50621
  import { existsSync as existsSync16 } from "node:fs";
50444
- import { join as join39 } from "node:path";
50622
+ import { join as join40 } from "node:path";
50445
50623
  process.on("uncaughtException", (error) => {
50446
50624
  log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
50447
50625
  process.exit(1);
@@ -50481,7 +50659,7 @@ try {
50481
50659
  ];
50482
50660
  if (!existsSync16(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
50483
50661
  for (const [name, directory, requiredFile] of required) {
50484
- if (!directory || !existsSync16(join39(directory, requiredFile)))
50662
+ if (!directory || !existsSync16(join40(directory, requiredFile)))
50485
50663
  throw new Error(`stable artifact launch is missing verified ${name}`);
50486
50664
  }
50487
50665
  }