frizz 0.7.1 → 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 (93) hide show
  1. package/dist/claude-agent-broker.js +9 -3
  2. package/dist/dev-child.js +241 -158
  3. package/dist/frizz.js +24 -3
  4. package/package.json +1 -1
  5. package/web-dist/assets/{TerminalPane-DBmtdVkV.js → TerminalPane-K-DhxpCR.js} +1 -1
  6. package/web-dist/assets/{abnfDiagram-VRR7QNED-s9x3PTMx.js → abnfDiagram-VRR7QNED-D1qyMYic.js} +1 -1
  7. package/web-dist/assets/architecture-TIHT7OUA-DhCDPuB9.js +1 -0
  8. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-CIFfgliT.js → architectureDiagram-ZJ3FMSHR-B7OHBGs-.js} +1 -1
  9. package/web-dist/assets/{blockDiagram-677ZJIJ3-BC-TeFao.js → blockDiagram-677ZJIJ3-BOkbWfnO.js} +1 -1
  10. package/web-dist/assets/{c4Diagram-LMCZKHZV-DoJ_Bulk.js → c4Diagram-LMCZKHZV-DcfWo37Z.js} +1 -1
  11. package/web-dist/assets/channel-C0ssx150.js +1 -0
  12. package/web-dist/assets/{chunk-32BRIVSS-BgchlScG.js → chunk-32BRIVSS-DG_MDBh7.js} +1 -1
  13. package/web-dist/assets/{chunk-52WLFC77-D94nMfY5.js → chunk-52WLFC77-HgYoNFkS.js} +1 -1
  14. package/web-dist/assets/{chunk-C7G6YPKG-BNU4g2Rm.js → chunk-C7G6YPKG-Dfpg508V.js} +1 -1
  15. package/web-dist/assets/{chunk-EX3LRPZG-DooNeZ0v.js → chunk-EX3LRPZG-zaEux9Wm.js} +1 -1
  16. package/web-dist/assets/{chunk-FWX5IMBZ-DuXYfpte.js → chunk-FWX5IMBZ-CpSICFGT.js} +2 -2
  17. package/web-dist/assets/{chunk-HOUHSVGY-DDtc0Lod.js → chunk-HOUHSVGY-CSwYs-ck.js} +1 -1
  18. package/web-dist/assets/{chunk-ICXQ74PX-D1soMHlW.js → chunk-ICXQ74PX-CkRfiAJk.js} +1 -1
  19. package/web-dist/assets/{chunk-MOJQB5TN-BYZZoPrO.js → chunk-MOJQB5TN-DFtJBynx.js} +1 -1
  20. package/web-dist/assets/{chunk-OGEWGWER-CSI1op21.js → chunk-OGEWGWER-B1ST2fth.js} +1 -1
  21. package/web-dist/assets/{chunk-PUDLZKDR-B2_qeHID.js → chunk-PUDLZKDR-B7ABSn_A.js} +1 -1
  22. package/web-dist/assets/{chunk-Q4XR5HBZ-BNiafbsU.js → chunk-Q4XR5HBZ-CivO3j1P.js} +1 -1
  23. package/web-dist/assets/{chunk-V7JOEXUC-D9aOhGjB.js → chunk-V7JOEXUC-BaM6_dmG.js} +1 -1
  24. package/web-dist/assets/{chunk-VAUOI2AC-mt04_MVl.js → chunk-VAUOI2AC-BY3O_FOQ.js} +1 -1
  25. package/web-dist/assets/{chunk-VR4S4FIN-CTbhzN9l.js → chunk-VR4S4FIN-BIV_iEar.js} +1 -1
  26. package/web-dist/assets/{chunk-WYO6CB5R-t-QJiLir.js → chunk-WYO6CB5R-CUi65Li4.js} +1 -1
  27. package/web-dist/assets/{chunk-ZGVPDNZ5-BNBiwqoz.js → chunk-ZGVPDNZ5-Dg0vMfMN.js} +1 -1
  28. package/web-dist/assets/classDiagram-OUVF2IWQ-DGsI7bj0.js +1 -0
  29. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DGsI7bj0.js +1 -0
  30. package/web-dist/assets/{cynefin-VYW2F7L2-CJzDWQw9.js → cynefin-VYW2F7L2-DWJeaT_t.js} +1 -1
  31. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-C_wWdWpO.js → cynefinDiagram-TSTJHNR4-ClaGZDTr.js} +1 -1
  32. package/web-dist/assets/{dagre-VKFMJZFB-JcoSMott.js → dagre-VKFMJZFB-C0pp3Xyc.js} +1 -1
  33. package/web-dist/assets/{diagram-FQU43EPY-DwPIrxvI.js → diagram-FQU43EPY-SSBAJs6v.js} +1 -1
  34. package/web-dist/assets/{diagram-G47NLZAW-Bs1Iyjn4.js → diagram-G47NLZAW-3GFBBF81.js} +1 -1
  35. package/web-dist/assets/{diagram-NH7WQ7WH-DFXMkDQZ.js → diagram-NH7WQ7WH-DqYwuzE7.js} +1 -1
  36. package/web-dist/assets/{diagram-OA4YK3LP-BdeEougN.js → diagram-OA4YK3LP-K6M4KioM.js} +1 -1
  37. package/web-dist/assets/{diagram-WEI45ONY-DOeCVBYO.js → diagram-WEI45ONY-ByTNMmJD.js} +1 -1
  38. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-Dm5CrqN3.js → ebnfDiagram-CCIWWBDH-Bl6rAFTA.js} +1 -1
  39. package/web-dist/assets/{erDiagram-Q63AITRT-B0ud7ncc.js → erDiagram-Q63AITRT-BGWlKkvA.js} +1 -1
  40. package/web-dist/assets/eventmodeling-45OFAUF4-CwE_bxam.js +1 -0
  41. package/web-dist/assets/flowDiagram-23GEKE2U-BY0J247Q.js +1 -0
  42. package/web-dist/assets/{ganttDiagram-NO4QXBWP-BdowNjAm.js → ganttDiagram-NO4QXBWP-C5eEoPLo.js} +1 -1
  43. package/web-dist/assets/{gitGraph-TEB2WS4Q-BSDXrBNB.js → gitGraph-TEB2WS4Q-BNmphrH5.js} +1 -1
  44. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-B3i3egZt.js → gitGraphDiagram-IHSO6WYX-zHU_D41b.js} +1 -1
  45. package/web-dist/assets/index-C-3lsl4q.css +1 -0
  46. package/web-dist/assets/{index-BUX0IseR.js → index-Kzg-vTmI.js} +117 -117
  47. package/web-dist/assets/{info-DKCQHKI2-B7CT3rc8.js → info-DKCQHKI2-BfD-7Xcw.js} +1 -1
  48. package/web-dist/assets/{infoDiagram-FWYZ7A6U-Bqmpgcu2.js → infoDiagram-FWYZ7A6U-CR3bcaik.js} +1 -1
  49. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-Bd5LBQOn.js → ishikawaDiagram-FXEZZL3T-VtEgUbJP.js} +1 -1
  50. package/web-dist/assets/{journeyDiagram-5HDEW3XC-lJOF3I7X.js → journeyDiagram-5HDEW3XC-DZ3fGB6L.js} +1 -1
  51. package/web-dist/assets/{kanban-definition-HUTT4EX6-D4E5PRAv.js → kanban-definition-HUTT4EX6-ChfTvN7D.js} +1 -1
  52. package/web-dist/assets/{line-C9ZcrRyz.js → line-B6kig2Co.js} +1 -1
  53. package/web-dist/assets/{mermaid-parser.core-DkaL73Gv.js → mermaid-parser.core-jyk1DbDV.js} +3 -3
  54. package/web-dist/assets/{mermaid.core-BQ89ySVU.js → mermaid.core-C5yyeZnx.js} +3 -3
  55. package/web-dist/assets/{mindmap-definition-LN4V7U3C-CB7JnCHh.js → mindmap-definition-LN4V7U3C-BcXFy-N9.js} +1 -1
  56. package/web-dist/assets/{packet-7NZHBO7P-BvyvpOhm.js → packet-7NZHBO7P-BXfwnw74.js} +1 -1
  57. package/web-dist/assets/{pegDiagram-2B236MQR-BoygVhix.js → pegDiagram-2B236MQR-BCD3YN2p.js} +1 -1
  58. package/web-dist/assets/{pie-RZYD4A2V-ChTjZLeC.js → pie-RZYD4A2V-AinCQhe4.js} +1 -1
  59. package/web-dist/assets/{pieDiagram-ENE6RG2P-B3UNPTpF.js → pieDiagram-ENE6RG2P-D91RCAtQ.js} +1 -1
  60. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DJdWJ4GS.js → quadrantDiagram-ABIIQ3AL-CiOs81pa.js} +1 -1
  61. package/web-dist/assets/{radar-I7S5WNFK-DHi5ReAY.js → radar-I7S5WNFK-PjwSEfhJ.js} +1 -1
  62. package/web-dist/assets/{railroad-3IZDKUUU-DcLJuGRW.js → railroad-3IZDKUUU-De7aPcv6.js} +1 -1
  63. package/web-dist/assets/railroad-abnf-AHOZXSZD-BdaR6aMg.js +1 -0
  64. package/web-dist/assets/railroad-ebnf-EBAXGLYW-BQ1i-m_V.js +1 -0
  65. package/web-dist/assets/railroad-peg-LSFZ7HO6-Bz7gY9Z5.js +1 -0
  66. package/web-dist/assets/{railroadDiagram-RFXS5EU6-W4vnMFZ2.js → railroadDiagram-RFXS5EU6-Ba5vfAy2.js} +1 -1
  67. package/web-dist/assets/{requirementDiagram-TGXJPOKE-CV_V-9DW.js → requirementDiagram-TGXJPOKE-cl6D_V6r.js} +1 -1
  68. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-DuIIsNBv.js → sankeyDiagram-HTMAVEWB-BiL7lO9N.js} +1 -1
  69. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DTT8ETnv.js → sequenceDiagram-DBY2YBRQ-DWwMnGgF.js} +1 -1
  70. package/web-dist/assets/{stateDiagram-2N3HPSRC-HVZaDROf.js → stateDiagram-2N3HPSRC-DyDSg9bX.js} +1 -1
  71. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DdKoRulX.js +1 -0
  72. package/web-dist/assets/{swimlanes-5IMT3BWC-DpGdPqRB.js → swimlanes-5IMT3BWC-DXcDUTKt.js} +1 -1
  73. package/web-dist/assets/swimlanesDiagram-G3AALYLV-e28nOYgP.js +8 -0
  74. package/web-dist/assets/{timeline-definition-FHXFAJF6-D9u3mgpd.js → timeline-definition-FHXFAJF6-BmhB--di.js} +1 -1
  75. package/web-dist/assets/{treeView-QDETBFTQ-Dga6MhEJ.js → treeView-QDETBFTQ-uZOu6XJp.js} +1 -1
  76. package/web-dist/assets/{treemap-6X3UGDF4-BwEXmcD6.js → treemap-6X3UGDF4-vvG-U9_8.js} +1 -1
  77. package/web-dist/assets/{vennDiagram-L72KCM5P-BMvodYUW.js → vennDiagram-L72KCM5P-1w9D4erz.js} +1 -1
  78. package/web-dist/assets/{wardley-OPB4EBWU-BzB6QK8X.js → wardley-OPB4EBWU-BJKEDRlS.js} +1 -1
  79. package/web-dist/assets/{wardleyDiagram-EHGQE667-4ID7QRJi.js → wardleyDiagram-EHGQE667-BZuQjgMm.js} +1 -1
  80. package/web-dist/assets/{xychartDiagram-FW5EYKEG-Ckob9hhW.js → xychartDiagram-FW5EYKEG-BuCgSm0a.js} +1 -1
  81. package/web-dist/index.html +2 -2
  82. package/web-dist/assets/architecture-TIHT7OUA-Eb73yePg.js +0 -1
  83. package/web-dist/assets/channel-CgSC9ikg.js +0 -1
  84. package/web-dist/assets/classDiagram-OUVF2IWQ-DrMJp1ua.js +0 -1
  85. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DrMJp1ua.js +0 -1
  86. package/web-dist/assets/eventmodeling-45OFAUF4-B52bjxMe.js +0 -1
  87. package/web-dist/assets/flowDiagram-23GEKE2U-DbFccp_w.js +0 -1
  88. package/web-dist/assets/index-CjEngYN7.css +0 -1
  89. package/web-dist/assets/railroad-abnf-AHOZXSZD-BJcLzkwL.js +0 -1
  90. package/web-dist/assets/railroad-ebnf-EBAXGLYW-B4jrlWYB.js +0 -1
  91. package/web-dist/assets/railroad-peg-LSFZ7HO6-BpIzbo9k.js +0 -1
  92. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DF9q3s7U.js +0 -1
  93. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BNeW4PCd.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"),
@@ -13072,6 +13078,9 @@ function prWatchExpiredWakeMessage(ref) {
13072
13078
 
13073
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.`;
13074
13080
  }
13081
+ function queuedThread(t) {
13082
+ return t.kind === "session" && t.foreign !== true && t.needsYou === true && t.state !== "archived";
13083
+ }
13075
13084
  function formatElapsed(ms) {
13076
13085
  if (!Number.isFinite(ms) || ms < 0) return "an unknown time";
13077
13086
  const s = Math.floor(ms / 1e3);
@@ -14037,8 +14046,8 @@ var init_src = __esm({
14037
14046
  PermissionMode = external_exports.enum(["auto", "default", "acceptEdits", "plan", "bypassPermissions"]);
14038
14047
  LocalFileOpener = external_exports.enum(["system", "cursor", "vscode", "finder", "copy"]);
14039
14048
  Settings = external_exports.object({
14040
- // The mode NEW Claude workers launch in. Settings surfaces exactly two of them — `auto` (the shipped
14041
- // 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
14042
14051
  // an unattended worker can actually run in; the server's workerDispatchPermission enforces that same
14043
14052
  // floor, so a restrictive value left here by an older build cannot reach a spawn.
14044
14053
  permissionMode: PermissionMode,
@@ -19542,11 +19551,13 @@ var init_settings = __esm({
19542
19551
  SETTINGS_KEY = "settings";
19543
19552
  MACHINE_KEYS = ["font", "notifications", "localFileOpener", "projectRail"];
19544
19553
  defaultSettings = () => ({
19545
- // `auto` = the CLI's classifier mode: safe actions auto-approve, risky ones still surface an approval
19546
- // card. Fewer invisible permission stalls than acceptEdits/default. The Settings "Claude permissions"
19547
- // control can raise this to `bypassPermissions` (--dangerously-skip-permissions) — the only other
19548
- // value a headless worker can run in, and the only deviation workerDispatchPermission honors.
19549
- 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",
19550
19561
  model: void 0,
19551
19562
  effort: void 0,
19552
19563
  notifications: true,
@@ -20602,11 +20613,23 @@ var init_detached_daemons = __esm({
20602
20613
  }
20603
20614
  });
20604
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
+
20605
20628
  // packages/server/src/backend/claude-broker-host.ts
20606
20629
  import { spawn } from "node:child_process";
20607
20630
  import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
20608
20631
  import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
20609
- 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";
20610
20633
  function windowsShimTarget(shimPath) {
20611
20634
  let body;
20612
20635
  try {
@@ -20616,7 +20639,7 @@ function windowsShimTarget(shimPath) {
20616
20639
  }
20617
20640
  const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
20618
20641
  if (!target) return void 0;
20619
- const full = join13(dirname8(shimPath), target);
20642
+ const full = join14(dirname8(shimPath), target);
20620
20643
  try {
20621
20644
  accessSync(full, fsConstants.F_OK);
20622
20645
  return full;
@@ -20631,17 +20654,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
20631
20654
  for (const dir of (env.PATH ?? "").split(delimiter)) {
20632
20655
  if (!dir) continue;
20633
20656
  if (windows) {
20634
- const exe = join13(dir, `${candidate}.exe`);
20657
+ const exe = join14(dir, `${candidate}.exe`);
20635
20658
  try {
20636
20659
  accessSync(exe, fsConstants.F_OK);
20637
20660
  return exe;
20638
20661
  } catch {
20639
20662
  }
20640
- const viaShim = windowsShimTarget(join13(dir, `${candidate}.cmd`));
20663
+ const viaShim = windowsShimTarget(join14(dir, `${candidate}.cmd`));
20641
20664
  if (viaShim) return viaShim;
20642
20665
  continue;
20643
20666
  }
20644
- const full = join13(dir, candidate);
20667
+ const full = join14(dir, candidate);
20645
20668
  try {
20646
20669
  accessSync(full, fsConstants.X_OK);
20647
20670
  return full;
@@ -20652,16 +20675,15 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
20652
20675
  }
20653
20676
  function claudeBrokerSocketPath(stateDir, sessionId) {
20654
20677
  const key = createHash5("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
20655
- if (process.platform === "win32") return `\\\\.\\pipe\\frizz-claude-${key}`;
20656
- return join13(process.env.TMPDIR ?? "/tmp", `frizz-claude-${key}.sock`);
20678
+ return frizzIpcPath(`frizz-claude-${key}`);
20657
20679
  }
20658
20680
  function claudeBrokerRecordPath(stateDir, sessionId) {
20659
20681
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
20660
- return join13(stateDir, "claude-broker", `${key}.json`);
20682
+ return join14(stateDir, "claude-broker", `${key}.json`);
20661
20683
  }
20662
20684
  function claudeBrokerRetirementPath(stateDir, sessionId) {
20663
20685
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
20664
- return join13(stateDir, "claude-broker", `${key}.retired`);
20686
+ return join14(stateDir, "claude-broker", `${key}.retired`);
20665
20687
  }
20666
20688
  function markBrokerRetired(stateDir, sessionId, reason, generation) {
20667
20689
  const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
@@ -20728,7 +20750,7 @@ function liveBrokerRecord(recordPath2) {
20728
20750
  return null;
20729
20751
  }
20730
20752
  function liveBrokerRecords(stateDir) {
20731
- const dir = join13(stateDir, "claude-broker");
20753
+ const dir = join14(stateDir, "claude-broker");
20732
20754
  let names;
20733
20755
  try {
20734
20756
  names = readdirSync4(dir);
@@ -20738,7 +20760,7 @@ function liveBrokerRecords(stateDir) {
20738
20760
  const out = [];
20739
20761
  for (const name of names) {
20740
20762
  if (!name.endsWith(".json")) continue;
20741
- const record = liveBrokerRecord(join13(dir, name));
20763
+ const record = liveBrokerRecord(join14(dir, name));
20742
20764
  if (record) out.push(record);
20743
20765
  }
20744
20766
  return out;
@@ -20818,6 +20840,7 @@ var init_claude_broker_host = __esm({
20818
20840
  "use strict";
20819
20841
  init_detached_daemons();
20820
20842
  init_claude_broker_diagnostics();
20843
+ init_ipc_path();
20821
20844
  WINDOWS_SHIM_TARGET = /^\s*"%dp0%\\(.+?)"/mu;
20822
20845
  }
20823
20846
  });
@@ -21546,14 +21569,14 @@ var init_completion_relay = __esm({
21546
21569
  // packages/server/src/tail-cache.ts
21547
21570
  import { createHash as createHash6 } from "node:crypto";
21548
21571
  import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync10, readSync as readSync3, statSync as statSync7 } from "node:fs";
21549
- import { join as join14 } from "node:path";
21572
+ import { join as join15 } from "node:path";
21550
21573
  function foldSchemaDigest(dir = import.meta.dirname) {
21551
21574
  if (foldSchemaMemo) return foldSchemaMemo;
21552
21575
  const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
21553
21576
  let read = 0;
21554
21577
  for (const name of FOLD_SOURCES) {
21555
21578
  try {
21556
- hash.update(name).update("\0").update(readFileSync10(join14(dir, name)));
21579
+ hash.update(name).update("\0").update(readFileSync10(join15(dir, name)));
21557
21580
  read++;
21558
21581
  } catch {
21559
21582
  hash.update(name).update("\0missing\0");
@@ -21751,7 +21774,7 @@ var init_tail_cache = __esm({
21751
21774
  // packages/server/src/tailer.ts
21752
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";
21753
21776
  import { execFileSync as execFileSync4 } from "node:child_process";
21754
- import { basename as basename4, join as join15 } from "node:path";
21777
+ import { basename as basename4, join as join16 } from "node:path";
21755
21778
  import { homedir as homedir7 } from "node:os";
21756
21779
  function probeShellAlive(outputFile) {
21757
21780
  if (!existsSync5(outputFile)) return void 0;
@@ -22013,7 +22036,7 @@ function launchTaskId(text) {
22013
22036
  function readDescendantSidecars(sessionDir, mtimeMs) {
22014
22037
  let names;
22015
22038
  try {
22016
- names = readdirSync5(join15(sessionDir, "subagents"));
22039
+ names = readdirSync5(join16(sessionDir, "subagents"));
22017
22040
  } catch {
22018
22041
  return [];
22019
22042
  }
@@ -22024,7 +22047,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
22024
22047
  if (!agentId) continue;
22025
22048
  let parsed;
22026
22049
  try {
22027
- parsed = JSON.parse(readFileSync11(join15(sessionDir, "subagents", name), "utf8"));
22050
+ parsed = JSON.parse(readFileSync11(join16(sessionDir, "subagents", name), "utf8"));
22028
22051
  } catch {
22029
22052
  continue;
22030
22053
  }
@@ -22038,7 +22061,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
22038
22061
  agentType: text(meta.agentType),
22039
22062
  parentAgentId: text(meta.parentAgentId),
22040
22063
  spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
22041
- spawnedAtMs: mtimeMs(join15(sessionDir, "subagents", name))
22064
+ spawnedAtMs: mtimeMs(join16(sessionDir, "subagents", name))
22042
22065
  });
22043
22066
  }
22044
22067
  return out;
@@ -22518,7 +22541,7 @@ function defaultMtimeMs(path) {
22518
22541
  }
22519
22542
  }
22520
22543
  function defaultLogDir(project) {
22521
- return join15(homedir7(), ".claude", "projects", project.cwdSlug);
22544
+ return join16(homedir7(), ".claude", "projects", project.cwdSlug);
22522
22545
  }
22523
22546
  function defaultReadPermMarker(project) {
22524
22547
  if (!project.stateDir) return () => void 0;
@@ -22649,7 +22672,7 @@ function createTailer(deps) {
22649
22672
  return paneDead(row.slug);
22650
22673
  }
22651
22674
  const defaultBackend = {
22652
- transcriptPath: (sessionId) => join15(logDir, `${sessionId}.jsonl`),
22675
+ transcriptPath: (sessionId) => join16(logDir, `${sessionId}.jsonl`),
22653
22676
  foldLine: (state, line) => {
22654
22677
  const rec = parseLine(line);
22655
22678
  if (rec) applyRecord(state, rec);
@@ -22774,7 +22797,7 @@ ${ask}`;
22774
22797
  return state.path.replace(/\.jsonl$/, "");
22775
22798
  }
22776
22799
  function descendantSidecars(state) {
22777
- const at = mtimeMs(join15(sessionDirOf(state), "subagents"));
22800
+ const at = mtimeMs(join16(sessionDirOf(state), "subagents"));
22778
22801
  const cached2 = descendantIndex.get(state.slug);
22779
22802
  if (cached2 && cached2.at === at) return cached2.all;
22780
22803
  const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
@@ -22788,7 +22811,7 @@ ${ask}`;
22788
22811
  return descendantIndex.get(state.slug)?.byToolUse.get(id);
22789
22812
  }
22790
22813
  function descendantTranscript(state, meta) {
22791
- return join15(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
22814
+ return join16(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
22792
22815
  }
22793
22816
  function subAgentDescendantTasks(slug, id) {
22794
22817
  const state = states.get(slug);
@@ -23102,7 +23125,7 @@ ${ask}`;
23102
23125
  if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
23103
23126
  const id = name.slice(0, -".jsonl".length);
23104
23127
  if (!id || registered.has(id)) continue;
23105
- const path = join15(logDir, name);
23128
+ const path = join16(logDir, name);
23106
23129
  let mtime;
23107
23130
  try {
23108
23131
  mtime = statSync8(path).mtimeMs;
@@ -23374,7 +23397,7 @@ ${ask}`;
23374
23397
  );
23375
23398
  try {
23376
23399
  mkdirSync10(stallLogDir, { recursive: true });
23377
- 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}
23378
23401
  captured_at: ${new Date(now()).toISOString()}
23379
23402
 
23380
23403
  ${detail}
@@ -23402,7 +23425,7 @@ ${detail}
23402
23425
  state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
23403
23426
  const strandedDir = discoverTranscriptDir(logDir, row.session_id);
23404
23427
  if (strandedDir) {
23405
- state.path = join15(strandedDir, `${row.session_id}.jsonl`);
23428
+ state.path = join16(strandedDir, `${row.session_id}.jsonl`);
23406
23429
  state.offset = 0;
23407
23430
  state.partial = "";
23408
23431
  state.primed = false;
@@ -23425,7 +23448,7 @@ ${detail}
23425
23448
  committed = false;
23426
23449
  }
23427
23450
  if (!committed) return false;
23428
- state.path = join15(logDir, `${found}.jsonl`);
23451
+ state.path = join16(logDir, `${found}.jsonl`);
23429
23452
  state.offset = 0;
23430
23453
  state.partial = "";
23431
23454
  state.primed = false;
@@ -23471,7 +23494,7 @@ ${detail}
23471
23494
  let state = states.get(row.slug);
23472
23495
  const runtimeGeneration = row.runtime_generation ?? 0;
23473
23496
  if (!state || state.sessionId !== row.session_id || state.nativeSessionId !== nativeId || state.runtimeGeneration !== runtimeGeneration) {
23474
- const path = backend.transcriptPath(nativeId) ?? join15(logDir, `${nativeId}.jsonl`);
23497
+ const path = backend.transcriptPath(nativeId) ?? join16(logDir, `${nativeId}.jsonl`);
23475
23498
  state = newTailState(row.slug, row.session_id, path, false, nativeId, runtimeGeneration);
23476
23499
  state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
23477
23500
  hydrateFromCache(state, row, nativeId);
@@ -23920,14 +23943,14 @@ var init_tailer = __esm({
23920
23943
  });
23921
23944
 
23922
23945
  // packages/server/src/backend/codex.ts
23923
- import { join as join16 } from "node:path";
23946
+ import { join as join17 } from "node:path";
23924
23947
  import { homedir as homedir8 } from "node:os";
23925
23948
  import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync12, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
23926
23949
  function defaultCodexHome() {
23927
- 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");
23928
23951
  }
23929
23952
  function sessionsDir(codexHome) {
23930
- return join16(codexHome, "sessions");
23953
+ return join17(codexHome, "sessions");
23931
23954
  }
23932
23955
  function codexSandbox(mode) {
23933
23956
  switch (mode) {
@@ -24308,17 +24331,17 @@ function collectRollouts(dir, out, budget) {
24308
24331
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).sort(descByName);
24309
24332
  for (const d of dirs) {
24310
24333
  if (budget.n <= 0) return;
24311
- collectRollouts(join16(dir, d.name), out, budget);
24334
+ collectRollouts(join17(dir, d.name), out, budget);
24312
24335
  }
24313
24336
  for (const f of files) {
24314
24337
  if (budget.n <= 0) return;
24315
24338
  let mtimeMs;
24316
24339
  try {
24317
- mtimeMs = statSync9(join16(dir, f.name)).mtimeMs;
24340
+ mtimeMs = statSync9(join17(dir, f.name)).mtimeMs;
24318
24341
  } catch {
24319
24342
  continue;
24320
24343
  }
24321
- out.push({ path: join16(dir, f.name), mtimeMs });
24344
+ out.push({ path: join17(dir, f.name), mtimeMs });
24322
24345
  budget.n--;
24323
24346
  }
24324
24347
  }
@@ -24362,7 +24385,7 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
24362
24385
  const out = /* @__PURE__ */ new Map();
24363
24386
  let raw2;
24364
24387
  try {
24365
- const path = join16(codexHome, "session_index.jsonl");
24388
+ const path = join17(codexHome, "session_index.jsonl");
24366
24389
  if (statSync9(path).size > SESSION_INDEX_MAX_BYTES) return out;
24367
24390
  raw2 = readFileSync12(path, "utf8");
24368
24391
  } catch {
@@ -28400,16 +28423,16 @@ var init_wrapper = __esm({
28400
28423
 
28401
28424
  // packages/server/src/worker-plugin-dir.ts
28402
28425
  import { existsSync as existsSync6 } from "node:fs";
28403
- import { dirname as dirname9, join as join17 } from "node:path";
28426
+ import { dirname as dirname9, join as join18 } from "node:path";
28404
28427
  import { fileURLToPath as fileURLToPath2 } from "node:url";
28405
28428
  function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
28406
28429
  const override = env.FRIZZ_WORKER_PLUGIN_DIR;
28407
- if (override && existsSync6(join17(override, ".claude-plugin", "plugin.json")))
28430
+ if (override && existsSync6(join18(override, ".claude-plugin", "plugin.json")))
28408
28431
  return override;
28409
28432
  let current = dirname9(fileURLToPath2(moduleUrl));
28410
28433
  for (; ; ) {
28411
- const candidate = join17(current, "cc-worker");
28412
- 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;
28413
28436
  const parent = dirname9(current);
28414
28437
  if (parent === current) return void 0;
28415
28438
  current = parent;
@@ -28423,7 +28446,7 @@ var init_worker_plugin_dir = __esm({
28423
28446
 
28424
28447
  // packages/server/src/backend/types.ts
28425
28448
  import { existsSync as existsSync7 } from "node:fs";
28426
- import { join as join18 } from "node:path";
28449
+ import { join as join19 } from "node:path";
28427
28450
  function frizzMcpEnv(mcp) {
28428
28451
  return {
28429
28452
  FRIZZ_STATE_DIR: mcp.stateDir,
@@ -28447,7 +28470,7 @@ function chromeDevtoolsMcpMount() {
28447
28470
  function resolveBrowserMcpScript(moduleUrl = import.meta.url, env = process.env) {
28448
28471
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
28449
28472
  if (!pluginDir) return void 0;
28450
- const scriptPath = join18(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28473
+ const scriptPath = join19(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28451
28474
  return existsSync7(scriptPath) ? scriptPath : void 0;
28452
28475
  }
28453
28476
  function workerCap(name, lifted, env) {
@@ -28543,21 +28566,21 @@ var init_codex_mcp = __esm({
28543
28566
  // packages/server/src/backend/codex-app-server-native.ts
28544
28567
  import { spawn as spawn2 } from "node:child_process";
28545
28568
  import { connect } from "node:net";
28569
+ import { Agent as HttpAgent } from "node:http";
28546
28570
  import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
28547
28571
  import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync13, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
28548
- import { join as join19 } from "node:path";
28572
+ import { join as join20 } from "node:path";
28549
28573
  import { PassThrough, Writable } from "node:stream";
28550
28574
  import { StringDecoder } from "node:string_decoder";
28551
28575
  function nativeDir(stateDir) {
28552
- return join19(stateDir, "codex-app-server-native");
28576
+ return join20(stateDir, "codex-app-server-native");
28553
28577
  }
28554
28578
  function nativeRecordPath(stateDir, projectId) {
28555
- return join19(nativeDir(stateDir), `${projectId}.json`);
28579
+ return join20(nativeDir(stateDir), `${projectId}.json`);
28556
28580
  }
28557
28581
  function nativeListenSocketPath(stateDir, projectId) {
28558
28582
  const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
28559
- if (process.platform === "win32") return `\\\\.\\pipe\\frizz-codex-native-${key}`;
28560
- return join19(process.env.TMPDIR ?? "/tmp", `frizz-codex-native-${key}.sock`);
28583
+ return frizzIpcPath(`frizz-codex-native-${key}`);
28561
28584
  }
28562
28585
  function pidAlive2(pid) {
28563
28586
  try {
@@ -28634,9 +28657,18 @@ function socketAccepting(socketPath) {
28634
28657
  setTimeout(() => done(false), 2e3).unref?.();
28635
28658
  });
28636
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
+ }
28637
28669
  function attach(record, timeoutMs) {
28638
28670
  return new Promise((resolve10, reject) => {
28639
- const socket = new import_websocket.default(`ws+unix://${record.socketPath}:/`, { perMessageDeflate: false });
28671
+ const socket = ipcWebSocket(record.socketPath);
28640
28672
  const stdout = new PassThrough();
28641
28673
  const stderr = new PassThrough();
28642
28674
  const listeners = { exit: [], error: [] };
@@ -28753,6 +28785,7 @@ var init_codex_app_server_native = __esm({
28753
28785
  "packages/server/src/backend/codex-app-server-native.ts"() {
28754
28786
  "use strict";
28755
28787
  init_wrapper();
28788
+ init_ipc_path();
28756
28789
  init_codex_mcp();
28757
28790
  init_logging();
28758
28791
  PRESUMED_LOSSY_REJOIN = 1;
@@ -28804,23 +28837,22 @@ var init_codex_app_server_native = __esm({
28804
28837
  });
28805
28838
 
28806
28839
  // packages/server/src/backend/codex-app-server-host.ts
28807
- import { spawn as spawn3 } from "node:child_process";
28840
+ import { spawn as spawn3, spawnSync } from "node:child_process";
28808
28841
  import { createConnection } from "node:net";
28809
28842
  import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
28810
28843
  import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "node:fs";
28811
- import { join as join20 } from "node:path";
28844
+ import { join as join21 } from "node:path";
28812
28845
  import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
28813
28846
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
28814
28847
  function daemonDir(stateDir) {
28815
- return join20(stateDir, "codex-app-server");
28848
+ return join21(stateDir, "codex-app-server");
28816
28849
  }
28817
28850
  function recordPath(stateDir, projectId) {
28818
- return join20(daemonDir(stateDir), `${projectId}.json`);
28851
+ return join21(daemonDir(stateDir), `${projectId}.json`);
28819
28852
  }
28820
28853
  function codexAppServerSocketPath(stateDir, projectId) {
28821
28854
  const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
28822
- if (process.platform === "win32") return `\\\\.\\pipe\\frizz-codex-${key}`;
28823
- return join20(process.env.TMPDIR ?? "/tmp", `frizz-codex-${key}.sock`);
28855
+ return frizzIpcPath(`frizz-codex-${key}`);
28824
28856
  }
28825
28857
  function pidAlive3(pid) {
28826
28858
  try {
@@ -28871,13 +28903,26 @@ function liveDaemonRecord(stateDir, projectId) {
28871
28903
  }
28872
28904
  return null;
28873
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
+ }
28874
28922
  function killCodexAppServerDaemon(stateDir, projectId) {
28875
28923
  const record = liveDaemonRecord(stateDir, projectId);
28876
28924
  if (!record) return;
28877
- try {
28878
- process.kill(record.daemonPid, "SIGTERM");
28879
- } catch {
28880
- }
28925
+ endDaemonTree(record.daemonPid, "SIGTERM");
28881
28926
  try {
28882
28927
  unlinkSync3(recordPath(stateDir, projectId));
28883
28928
  } catch {
@@ -28893,10 +28938,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
28893
28938
  await new Promise((resolve10) => setTimeout(resolve10, 25));
28894
28939
  }
28895
28940
  if (pidAlive3(record.daemonPid)) {
28896
- try {
28897
- process.kill(record.daemonPid, "SIGKILL");
28898
- } catch {
28899
- }
28941
+ endDaemonTree(record.daemonPid, "SIGKILL");
28900
28942
  while (pidAlive3(record.daemonPid) && Date.now() < deadline + 2e3) {
28901
28943
  await new Promise((resolve10) => setTimeout(resolve10, 25));
28902
28944
  }
@@ -29043,6 +29085,14 @@ function inProcessCodexAppServer(options) {
29043
29085
  env: options.env,
29044
29086
  stdio: ["pipe", "pipe", "pipe"]
29045
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
+ });
29046
29096
  return { process: child, generation: randomUUID10(), reattached: false, daemonPid: process.pid, droppedWhileDetached: 0 };
29047
29097
  }
29048
29098
  function directChildHost(spawnChild, generationId = randomUUID10) {
@@ -29060,6 +29110,7 @@ var init_codex_app_server_host = __esm({
29060
29110
  "use strict";
29061
29111
  init_detached_daemons();
29062
29112
  init_codex_app_server_native();
29113
+ init_ipc_path();
29063
29114
  init_codex_mcp();
29064
29115
  init_logging();
29065
29116
  daemonEntry = () => resolveDetachedDaemonEntry(import.meta.url, "codex-app-server-daemon");
@@ -32025,11 +32076,11 @@ var init_codex_app_server = __esm({
32025
32076
  });
32026
32077
 
32027
32078
  // packages/server/src/backend/codex-quota.ts
32028
- import { join as join21 } from "node:path";
32079
+ import { join as join22 } from "node:path";
32029
32080
  import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
32030
32081
  import { spawn as spawn4 } from "node:child_process";
32031
32082
  function sessionsDir2(codexHome) {
32032
- return join21(codexHome, "sessions");
32083
+ return join22(codexHome, "sessions");
32033
32084
  }
32034
32085
  function newestRollouts(dir, out, budget) {
32035
32086
  if (budget.n <= 0) return;
@@ -32043,11 +32094,11 @@ function newestRollouts(dir, out, budget) {
32043
32094
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
32044
32095
  for (const d of dirs) {
32045
32096
  if (budget.n <= 0) return;
32046
- newestRollouts(join21(dir, d), out, budget);
32097
+ newestRollouts(join22(dir, d), out, budget);
32047
32098
  }
32048
32099
  for (const f of files) {
32049
32100
  if (budget.n <= 0) return;
32050
- out.push(join21(dir, f));
32101
+ out.push(join22(dir, f));
32051
32102
  budget.n--;
32052
32103
  }
32053
32104
  }
@@ -32247,7 +32298,7 @@ var init_codex_quota = __esm({
32247
32298
  });
32248
32299
 
32249
32300
  // packages/server/src/backend/claude-quota.ts
32250
- import { join as join22 } from "node:path";
32301
+ import { join as join23 } from "node:path";
32251
32302
  import { homedir as homedir9, platform } from "node:os";
32252
32303
  import { createHash as createHash10 } from "node:crypto";
32253
32304
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -32255,7 +32306,7 @@ import { execFile as execFile2 } from "node:child_process";
32255
32306
  import { promisify as promisify2 } from "node:util";
32256
32307
  function claudeConfigDir() {
32257
32308
  const override = process.env.CLAUDE_CONFIG_DIR;
32258
- return override && override.trim() ? override : join22(homedir9(), ".claude");
32309
+ return override && override.trim() ? override : join23(homedir9(), ".claude");
32259
32310
  }
32260
32311
  function tokenFromCredentialsJson(raw2) {
32261
32312
  let doc;
@@ -32284,7 +32335,7 @@ async function readKeychainToken() {
32284
32335
  }
32285
32336
  async function readAccessToken(configDir) {
32286
32337
  try {
32287
- const fromFile = tokenFromCredentialsJson(await readFile(join22(configDir, ".credentials.json"), "utf8"));
32338
+ const fromFile = tokenFromCredentialsJson(await readFile(join23(configDir, ".credentials.json"), "utf8"));
32288
32339
  if (fromFile) return fromFile;
32289
32340
  } catch {
32290
32341
  }
@@ -32353,8 +32404,8 @@ function parseClaudeUsage(body, planType) {
32353
32404
  function cachePaths(cacheDir, configDir) {
32354
32405
  const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
32355
32406
  return {
32356
- data: join22(cacheDir, `claude-${profile}.json`),
32357
- lock: join22(cacheDir, `claude-${profile}.lock`)
32407
+ data: join23(cacheDir, `claude-${profile}.json`),
32408
+ lock: join23(cacheDir, `claude-${profile}.lock`)
32358
32409
  };
32359
32410
  }
32360
32411
  async function readShared(path) {
@@ -32546,7 +32597,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
32546
32597
  async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32547
32598
  const now = (deps.now ?? Date.now)();
32548
32599
  const configDir = claudeConfigDir();
32549
- const cacheDir = deps.cacheDir ?? join22(frizzRoots().cache, "quota-cache");
32600
+ const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32550
32601
  try {
32551
32602
  await mkdir(cacheDir, { recursive: true, mode: 448 });
32552
32603
  } catch {
@@ -32557,7 +32608,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32557
32608
  async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
32558
32609
  const now = (deps.now ?? Date.now)();
32559
32610
  const configDir = claudeConfigDir();
32560
- const cacheDir = deps.cacheDir ?? join22(frizzRoots().cache, "quota-cache");
32611
+ const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32561
32612
  const paths = cachePaths(cacheDir, configDir);
32562
32613
  try {
32563
32614
  await mkdir(cacheDir, { recursive: true, mode: 448 });
@@ -32716,7 +32767,7 @@ var init_quota = __esm({
32716
32767
  // packages/server/src/frizz.ts
32717
32768
  import { execFile as execFile3 } from "node:child_process";
32718
32769
  import { lstatSync as lstatSync2, realpathSync as realpathSync6 } from "node:fs";
32719
- 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";
32720
32771
  import { promisify as promisify3 } from "node:util";
32721
32772
  function frizzScriptsDir() {
32722
32773
  if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
@@ -32725,7 +32776,7 @@ function frizzScriptsDir() {
32725
32776
  function directFrizzRoot(projectDir) {
32726
32777
  try {
32727
32778
  const projectRoot = realpathSync6(projectDir);
32728
- const path = join23(projectRoot, ".frizz");
32779
+ const path = join24(projectRoot, ".frizz");
32729
32780
  const stat2 = lstatSync2(path);
32730
32781
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
32731
32782
  const real = realpathSync6(path);
@@ -32739,7 +32790,7 @@ function frizzDirExists(projectDir) {
32739
32790
  }
32740
32791
  async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32741
32792
  if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
32742
- const { stdout } = await execFileP("node", [join23(scriptsDir, "index.mjs"), "--json"], {
32793
+ const { stdout } = await execFileP("node", [join24(scriptsDir, "index.mjs"), "--json"], {
32743
32794
  cwd: projectDir,
32744
32795
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
32745
32796
  maxBuffer: 32 * 1024 * 1024
@@ -32764,7 +32815,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32764
32815
  };
32765
32816
  }
32766
32817
  async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
32767
- await execFileP("node", [join23(scriptsDir, "thread-update.mjs"), slug, ...args], {
32818
+ await execFileP("node", [join24(scriptsDir, "thread-update.mjs"), slug, ...args], {
32768
32819
  cwd: projectDir,
32769
32820
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
32770
32821
  });
@@ -34649,19 +34700,19 @@ var init_claude_agent_broker_bridge = __esm({
34649
34700
  });
34650
34701
 
34651
34702
  // packages/server/src/backend/auth-status.ts
34652
- import { join as join24 } from "node:path";
34703
+ import { join as join25 } from "node:path";
34653
34704
  import { homedir as homedir11, platform as platform2 } from "node:os";
34654
34705
  import { readFileSync as readFileSync15, statSync as statSync11 } from "node:fs";
34655
34706
  import { execFile as execFile4 } from "node:child_process";
34656
34707
  import { promisify as promisify4 } from "node:util";
34657
34708
  function claudeConfigDir2() {
34658
34709
  const override = process.env.CLAUDE_CONFIG_DIR;
34659
- return override && override.trim() ? override : join24(homedir11(), ".claude");
34710
+ return override && override.trim() ? override : join25(homedir11(), ".claude");
34660
34711
  }
34661
34712
  function claudeFileState(configDir) {
34662
34713
  let raw2;
34663
34714
  try {
34664
- raw2 = readFileSync15(join24(configDir, ".credentials.json"), "utf8");
34715
+ raw2 = readFileSync15(join25(configDir, ".credentials.json"), "utf8");
34665
34716
  } catch (err) {
34666
34717
  return err.code === "ENOENT" ? "absent" : "error";
34667
34718
  }
@@ -34694,7 +34745,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
34694
34745
  if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
34695
34746
  let raw2;
34696
34747
  try {
34697
- raw2 = readFileSync15(join24(codexHome, "auth.json"), "utf8");
34748
+ raw2 = readFileSync15(join25(codexHome, "auth.json"), "utf8");
34698
34749
  } catch (err) {
34699
34750
  return err.code === "ENOENT" ? "signed-out" : "unknown";
34700
34751
  }
@@ -34759,7 +34810,7 @@ function asEmail(value) {
34759
34810
  }
34760
34811
  function claudeAccountFile() {
34761
34812
  const override = process.env.CLAUDE_CONFIG_DIR;
34762
- 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");
34763
34814
  }
34764
34815
  function readClaudeAccountEmail(path = claudeAccountFile()) {
34765
34816
  let stat2;
@@ -34783,7 +34834,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
34783
34834
  function readCodexAccountEmail(codexHome = defaultCodexHome()) {
34784
34835
  let doc;
34785
34836
  try {
34786
- doc = JSON.parse(readFileSync15(join24(codexHome, "auth.json"), "utf8"));
34837
+ doc = JSON.parse(readFileSync15(join25(codexHome, "auth.json"), "utf8"));
34787
34838
  } catch {
34788
34839
  return void 0;
34789
34840
  }
@@ -34851,7 +34902,7 @@ var init_auth_status = __esm({
34851
34902
 
34852
34903
  // packages/server/src/dispatch.ts
34853
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";
34854
- 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";
34855
34906
  import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
34856
34907
  function fallbackTitle(prompt) {
34857
34908
  const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
@@ -34870,7 +34921,7 @@ function fallbackTitle(prompt) {
34870
34921
  }
34871
34922
  function resolveSlug(frizzDir, base, taken) {
34872
34923
  base = ThreadSlug.parse(base);
34873
- const isTaken = (slug) => existsSync10(join25(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
34924
+ const isTaken = (slug) => existsSync10(join26(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
34874
34925
  if (!isTaken(base)) return base;
34875
34926
  for (let n = 2; ; n++) {
34876
34927
  const suffix = `-${n}`;
@@ -34887,12 +34938,12 @@ function resolveLegacyThreadFile(projectDir, value) {
34887
34938
  if (!parsed.success) return null;
34888
34939
  try {
34889
34940
  const projectRoot = realpathSync7(projectDir);
34890
- const frizzPath = join25(projectRoot, ".frizz");
34941
+ const frizzPath = join26(projectRoot, ".frizz");
34891
34942
  const frizzStat = lstatSync3(frizzPath);
34892
34943
  if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
34893
34944
  const realFrizz = realpathSync7(frizzPath);
34894
34945
  if (dirname11(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
34895
- const path = join25(realFrizz, `${parsed.data}.md`);
34946
+ const path = join26(realFrizz, `${parsed.data}.md`);
34896
34947
  const before = lstatSync3(path);
34897
34948
  if (!before.isFile() || before.isSymbolicLink()) return null;
34898
34949
  const realPath = realpathSync7(path);
@@ -34936,7 +34987,7 @@ function boardAuthorizesAdoption(board, slug) {
34936
34987
  return !board.errorItems.some((item) => item.file === `${slug}.md`);
34937
34988
  }
34938
34989
  function ensureSafeDirectDirectory(parent, name) {
34939
- const path = join25(parent, name);
34990
+ const path = join26(parent, name);
34940
34991
  try {
34941
34992
  mkdirSync13(path);
34942
34993
  } catch (error) {
@@ -34966,8 +35017,8 @@ function loadWorkerPrompt(kind = "claude") {
34966
35017
  function monitorScriptsDir() {
34967
35018
  const plugin = workerPluginDir();
34968
35019
  if (!plugin) return void 0;
34969
- const dir = join25(plugin, "skills", "gh", "scripts");
34970
- 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;
34971
35022
  }
34972
35023
  function codexScratchpadHookConfig(hookScript, sessionId) {
34973
35024
  if (!hookScript || !sessionId) return {};
@@ -34979,7 +35030,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
34979
35030
  }
34980
35031
  ]
34981
35032
  });
34982
- const bashBackgroundHook = join25(dirname11(hookScript), "bash-background.mjs");
35033
+ const bashBackgroundHook = join26(dirname11(hookScript), "bash-background.mjs");
34983
35034
  return {
34984
35035
  bypass_hook_trust: true,
34985
35036
  hooks: {
@@ -35005,7 +35056,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
35005
35056
  }
35006
35057
  function scratchpadHookScript() {
35007
35058
  const plugin = workerPluginDir();
35008
- return plugin ? join25(plugin, "hooks", "scratchpad.mjs") : void 0;
35059
+ return plugin ? join26(plugin, "hooks", "scratchpad.mjs") : void 0;
35009
35060
  }
35010
35061
  function composePrompt(sessionId, prompt, kind = "claude") {
35011
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.";
@@ -35021,7 +35072,7 @@ function scratchpadOrientation(sessionId, kind = "claude") {
35021
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.`;
35022
35073
  }
35023
35074
  function frizzConfigBlock(projectDir) {
35024
- const path = join25(projectDir, "FRIZZ.md");
35075
+ const path = join26(projectDir, "FRIZZ.md");
35025
35076
  let body;
35026
35077
  try {
35027
35078
  const st = statSync12(path);
@@ -35061,7 +35112,7 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
35061
35112
  const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
35062
35113
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
35063
35114
  if (!pluginDir) return void 0;
35064
- const scriptPath = join25(pluginDir, "bin", FRIZZ_MCP.script);
35115
+ const scriptPath = join26(pluginDir, "bin", FRIZZ_MCP.script);
35065
35116
  if (!existsSync10(scriptPath)) return void 0;
35066
35117
  return {
35067
35118
  scriptPath,
@@ -35144,7 +35195,7 @@ function buildClaudeResumeCommand(opts) {
35144
35195
  }
35145
35196
  function createDispatcher(deps) {
35146
35197
  const readBoardSource = deps.readBoard ?? readBoard;
35147
- const frizzDir = join25(deps.project.dir, ".frizz");
35198
+ const frizzDir = join26(deps.project.dir, ".frizz");
35148
35199
  const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
35149
35200
  function cleanupPrewrites(built) {
35150
35201
  for (const path of new Set(built.prewrite.map((file) => file.path))) {
@@ -35157,7 +35208,7 @@ function createDispatcher(deps) {
35157
35208
  function cleanupDispatchFiles(scratchRel, built, sessionId) {
35158
35209
  cleanupPrewrites(built);
35159
35210
  try {
35160
- rmSync8(join25(deps.project.dir, scratchRel), { force: true, recursive: true });
35211
+ rmSync8(join26(deps.project.dir, scratchRel), { force: true, recursive: true });
35161
35212
  } catch {
35162
35213
  }
35163
35214
  cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
@@ -35590,7 +35641,7 @@ import {
35590
35641
  watch as fsWatch
35591
35642
  } from "node:fs";
35592
35643
  import { homedir as homedir12 } from "node:os";
35593
- import { join as join26 } from "node:path";
35644
+ import { join as join27 } from "node:path";
35594
35645
  import watcher from "@parcel/watcher";
35595
35646
  function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
35596
35647
  if (!liveness) return false;
@@ -36275,7 +36326,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
36275
36326
  if (parcelSub || stopped) return Promise.resolve();
36276
36327
  if (watchSetup) return watchSetup;
36277
36328
  const setup = (async () => {
36278
- const next = await subscribe(join26(project.dir, ".frizz"), () => scheduleRebuild());
36329
+ const next = await subscribe(join27(project.dir, ".frizz"), () => scheduleRebuild());
36279
36330
  if (stopped) {
36280
36331
  await next.unsubscribe();
36281
36332
  return;
@@ -38209,7 +38260,7 @@ var init_resume = __esm({
38209
38260
  });
38210
38261
 
38211
38262
  // packages/server/src/backend/claude.ts
38212
- import { join as join27 } from "node:path";
38263
+ import { join as join28 } from "node:path";
38213
38264
  function toolResultText2(content) {
38214
38265
  if (typeof content === "string") return content;
38215
38266
  if (!Array.isArray(content)) return "";
@@ -38298,7 +38349,7 @@ function createClaudeBackend(opts) {
38298
38349
  return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
38299
38350
  },
38300
38351
  transcriptPath(sessionId) {
38301
- return join27(opts.logDir, `${sessionId}.jsonl`);
38352
+ return join28(opts.logDir, `${sessionId}.jsonl`);
38302
38353
  },
38303
38354
  parseLine(line) {
38304
38355
  return parseClaudeLine(line);
@@ -38468,12 +38519,12 @@ var init_login_utility = __esm({
38468
38519
 
38469
38520
  // packages/server/src/backend/codex-app-server-diagnostics.ts
38470
38521
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync14, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
38471
- import { join as join28 } from "node:path";
38522
+ import { join as join29 } from "node:path";
38472
38523
  function codexDiagnosticLogPath(stateDir, projectId) {
38473
- return join28(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38524
+ return join29(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38474
38525
  }
38475
38526
  function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
38476
- const dir = join28(stateDir, "codex-app-server");
38527
+ const dir = join29(stateDir, "codex-app-server");
38477
38528
  const path = codexDiagnosticLogPath(stateDir, projectId);
38478
38529
  let ensured = false;
38479
38530
  return (event) => {
@@ -38505,7 +38556,7 @@ var init_codex_app_server_diagnostics = __esm({
38505
38556
  import { execFile as execFile7 } from "node:child_process";
38506
38557
  import { readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
38507
38558
  import { connect as connectSocket } from "node:net";
38508
- import { join as join29 } from "node:path";
38559
+ import { join as join30 } from "node:path";
38509
38560
  function parseLsofSocketNames(stdout) {
38510
38561
  const referenced = /* @__PURE__ */ new Set();
38511
38562
  for (const line of stdout.split("\n")) {
@@ -38522,7 +38573,7 @@ function sweepStaleSockets(options, deps = {}) {
38522
38573
  const keep = new Set(options.keep ?? []);
38523
38574
  let candidates;
38524
38575
  try {
38525
- 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));
38526
38577
  } catch {
38527
38578
  return;
38528
38579
  }
@@ -38986,7 +39037,7 @@ var init_thread_hibernation = __esm({
38986
39037
  });
38987
39038
 
38988
39039
  // packages/server/src/context.ts
38989
- import { join as join30 } from "node:path";
39040
+ import { join as join31 } from "node:path";
38990
39041
  import { randomUUID as randomUUID15 } from "node:crypto";
38991
39042
  import { homedir as homedir13 } from "node:os";
38992
39043
  function reconcileSessions(storage) {
@@ -39144,7 +39195,7 @@ async function createContext(opts = {}) {
39144
39195
  function createContextUnchecked(opts, resources) {
39145
39196
  const home = opts.home ?? homedir13();
39146
39197
  const project = opts.project ?? resolveProject();
39147
- const dbPath = join30(project.stateDir, "ui.db");
39198
+ const dbPath = join31(project.stateDir, "ui.db");
39148
39199
  const storage = createStorage(dbPath);
39149
39200
  resources.storage = storage;
39150
39201
  const bus = new Bus();
@@ -39472,6 +39523,7 @@ ${wakeDeliveryToken(deliveryId)}`;
39472
39523
  getSettings: () => getSettings(storage, home),
39473
39524
  setSettings: (s) => setSettings(storage, s, home),
39474
39525
  resetSettings: () => resetSettings(storage, home),
39526
+ activeTenants: opts.activeTenants,
39475
39527
  claudeBin: opts.claudeBin,
39476
39528
  codexBin: opts.codexBin,
39477
39529
  loginUtility: createLoginUtility({ claudeBin: opts.claudeBin, codexBin: opts.codexBin, cwd: project.dir })
@@ -42381,7 +42433,7 @@ var init_bash_background = __esm({
42381
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";
42382
42434
  import { createHash as createHash13 } from "node:crypto";
42383
42435
  import { StringDecoder as StringDecoder4 } from "node:string_decoder";
42384
- import { join as join31 } from "node:path";
42436
+ import { join as join32 } from "node:path";
42385
42437
  import { homedir as homedir14 } from "node:os";
42386
42438
  function formatTokens(n) {
42387
42439
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
@@ -42931,14 +42983,14 @@ function pruneScreenshotCache() {
42931
42983
  if (entries.length <= SCREENSHOT_CACHE_MAX) return;
42932
42984
  const byMtime = entries.map((n) => {
42933
42985
  try {
42934
- return { n, m: statSync14(join31(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
42986
+ return { n, m: statSync14(join32(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
42935
42987
  } catch {
42936
42988
  return { n, m: 0 };
42937
42989
  }
42938
42990
  }).sort((a, b) => b.m - a.m);
42939
42991
  for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
42940
42992
  try {
42941
- unlinkSync5(join31(SCREENSHOT_CACHE_DIR, n));
42993
+ unlinkSync5(join32(SCREENSHOT_CACHE_DIR, n));
42942
42994
  } catch {
42943
42995
  }
42944
42996
  }
@@ -42968,14 +43020,14 @@ function persistBase64Image(mediaType, data, idKey) {
42968
43020
  const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
42969
43021
  if (!ext || !data) return void 0;
42970
43022
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
42971
- const path = join31(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
43023
+ const path = join32(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
42972
43024
  try {
42973
43025
  if (existsSync13(path)) return path;
42974
43026
  if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
42975
43027
  const buf = Buffer.from(data, "base64");
42976
43028
  if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
42977
43029
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
42978
- const tmp = join31(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43030
+ const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
42979
43031
  writeFileSync12(tmp, buf);
42980
43032
  renameSync9(tmp, path);
42981
43033
  pruneScreenshotCache();
@@ -42990,14 +43042,14 @@ function persistSentFile(srcPath, idKey) {
42990
43042
  const outExt = ext === "jpeg" ? "jpg" : ext;
42991
43043
  try {
42992
43044
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
42993
- const dest = join31(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
43045
+ const dest = join32(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
42994
43046
  if (existsSync13(dest)) return dest;
42995
43047
  const size = statSync14(srcPath).size;
42996
43048
  if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
42997
43049
  const buf = readFileSync20(srcPath);
42998
43050
  if (!looksLikeImage(buf, outExt)) return void 0;
42999
43051
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
43000
- const tmp = join31(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43052
+ const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43001
43053
  writeFileSync12(tmp, buf);
43002
43054
  renameSync9(tmp, dest);
43003
43055
  pruneScreenshotCache();
@@ -43434,16 +43486,16 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
43434
43486
  }
43435
43487
  }
43436
43488
  function logDirOf(project) {
43437
- return join31(homedir14(), ".claude", "projects", project.cwdSlug);
43489
+ return join32(homedir14(), ".claude", "projects", project.cwdSlug);
43438
43490
  }
43439
43491
  function resolveTranscriptPath(project, sessionId) {
43440
- const path = join31(logDirOf(project), `${sessionId}.jsonl`);
43492
+ const path = join32(logDirOf(project), `${sessionId}.jsonl`);
43441
43493
  try {
43442
43494
  if (statSync14(path).size > 0) return path;
43443
43495
  } catch {
43444
43496
  }
43445
43497
  const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
43446
- return stranded ? join31(stranded, `${sessionId}.jsonl`) : path;
43498
+ return stranded ? join32(stranded, `${sessionId}.jsonl`) : path;
43447
43499
  }
43448
43500
  function projectCodexTranscript(raw2, identityPrefix = "codex") {
43449
43501
  const out = [];
@@ -44839,7 +44891,7 @@ var init_open_external = __esm({
44839
44891
  import { spawn as spawn6 } from "node:child_process";
44840
44892
  import { readFileSync as readFileSync21, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
44841
44893
  import { homedir as homedir15 } from "node:os";
44842
- 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";
44843
44895
  function isUnder(real, root) {
44844
44896
  let rootReal;
44845
44897
  try {
@@ -44869,7 +44921,7 @@ function resolveLocalFile(rawPath, roots) {
44869
44921
  function resolveOpenableFile(raw2, projectDir, roots, home = homedir15()) {
44870
44922
  const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
44871
44923
  if (!trimmed) return null;
44872
- 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);
44873
44925
  try {
44874
44926
  return resolveLocalFile(abs, roots);
44875
44927
  } catch {
@@ -45641,7 +45693,7 @@ var init_directory_picker = __esm({
45641
45693
 
45642
45694
  // packages/server/src/router.ts
45643
45695
  import { readFileSync as readFileSync22, statSync as statSync17 } from "node:fs";
45644
- import { join as join33, resolve as resolve8 } from "node:path";
45696
+ import { join as join34, resolve as resolve8 } from "node:path";
45645
45697
  import { randomUUID as randomUUID16 } from "node:crypto";
45646
45698
  import { basename as basename9, dirname as dirname14 } from "node:path";
45647
45699
  import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
@@ -45804,7 +45856,7 @@ function projectCard(entry, stale) {
45804
45856
  function addProjectAtPath(input) {
45805
45857
  const typed = input.trim();
45806
45858
  if (!typed) throw new Error("Enter a folder path.");
45807
- const expanded = typed === "~" || typed.startsWith("~/") ? join33(homedir16(), typed.slice(1)) : typed;
45859
+ const expanded = typed === "~" || typed.startsWith("~/") ? join34(homedir16(), typed.slice(1)) : typed;
45808
45860
  const absolute = resolve8(expanded);
45809
45861
  let stats;
45810
45862
  try {
@@ -45857,7 +45909,7 @@ function setProjectIconFromFile(id, file) {
45857
45909
  return storeProjectIcon(id, file, bytes);
45858
45910
  }
45859
45911
  function createRouter(ctx) {
45860
- const frizzDir = join33(ctx.project.dir, ".frizz");
45912
+ const frizzDir = join34(ctx.project.dir, ".frizz");
45861
45913
  const openRoots = openableFileRoots(ctx.project);
45862
45914
  function isAutoTitledSession(slug) {
45863
45915
  return ctx.storage.getSession(slug)?.title_auto === 1;
@@ -47362,6 +47414,35 @@ ${gapNote}` : input.message;
47362
47414
  output: external_exports.array(ProjectCard),
47363
47415
  handler: async () => listProjects().map((entry) => projectCard(entry, entry.stale))
47364
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
+ }),
47365
47446
  /**
47366
47447
  * Pin the rail's order.
47367
47448
  *
@@ -47483,7 +47564,7 @@ ${gapNote}` : input.message;
47483
47564
  for (const entry of listProjects()) {
47484
47565
  if (entry.stale) continue;
47485
47566
  try {
47486
- 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 });
47487
47568
  try {
47488
47569
  const hit = db.prepare("SELECT 1 FROM session WHERE slug = ? LIMIT 1").get(input.slug);
47489
47570
  if (hit) found.push({ projectSlug: entry.slug, projectName: entry.name ?? entry.slug });
@@ -47876,7 +47957,7 @@ var init_local_image = __esm({
47876
47957
  // packages/server/src/project-icon.ts
47877
47958
  import { readFileSync as readFileSync24, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
47878
47959
  import { homedir as homedir17 } from "node:os";
47879
- 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";
47880
47961
  function normalizeStem(stem) {
47881
47962
  const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
47882
47963
  const normalized = sized.replace(VARIANT_SUFFIX, "");
@@ -47894,7 +47975,7 @@ function sizeScore(dimensions) {
47894
47975
  return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
47895
47976
  }
47896
47977
  function under(root, relativeDirectory) {
47897
- return relativeDirectory ? join34(root, relativeDirectory) : root;
47978
+ return relativeDirectory ? join35(root, relativeDirectory) : root;
47898
47979
  }
47899
47980
  function listFiles(directory) {
47900
47981
  try {
@@ -47916,19 +47997,19 @@ function iconDirectories(root) {
47916
47997
  for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
47917
47998
  for (const host of HOST_DIRECTORIES) {
47918
47999
  if (!children2.has(host)) continue;
47919
- 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));
47920
48001
  }
47921
48002
  for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
47922
48003
  for (const container of WORKSPACE_CONTAINERS) {
47923
48004
  if (!children2.has(container)) continue;
47924
48005
  let members;
47925
48006
  try {
47926
- 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);
47927
48008
  } catch {
47928
48009
  continue;
47929
48010
  }
47930
48011
  for (const member of members) {
47931
- 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));
47932
48013
  }
47933
48014
  }
47934
48015
  return [...new Set(directories)];
@@ -47942,7 +48023,7 @@ function manifestIcons(manifestPath) {
47942
48023
  }
47943
48024
  if (!Array.isArray(parsed?.icons)) return [];
47944
48025
  const directory = dirname15(manifestPath);
47945
- 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, "")));
47946
48027
  }
47947
48028
  function projectIconCandidates(root) {
47948
48029
  const projectStem = normalizeStem(basename10(root)).normalized;
@@ -47961,7 +48042,7 @@ function projectIconCandidates(root) {
47961
48042
  for (const name of listFiles(directory)) {
47962
48043
  const extension2 = extname3(name).toLowerCase();
47963
48044
  if (MANIFEST_NAMES.includes(name.toLowerCase())) {
47964
- for (const icon of manifestIcons(join34(directory, name))) {
48045
+ for (const icon of manifestIcons(join35(directory, name))) {
47965
48046
  if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
47966
48047
  fromManifest.add(icon);
47967
48048
  files.push({ path: icon, directory: dirname15(icon) });
@@ -47972,7 +48053,7 @@ function projectIconCandidates(root) {
47972
48053
  if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
47973
48054
  const stem = name.slice(0, name.length - extension2.length);
47974
48055
  if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
47975
- files.push({ path: join34(directory, name), directory });
48056
+ files.push({ path: join35(directory, name), directory });
47976
48057
  if (files.length >= MAX_CANDIDATES) break;
47977
48058
  }
47978
48059
  }
@@ -48150,7 +48231,7 @@ var init_project_icon = __esm({
48150
48231
 
48151
48232
  // packages/server/src/local-visualization.ts
48152
48233
  import { readdirSync as readdirSync11, readFileSync as readFileSync25, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
48153
- import { join as join35, sep as sep3 } from "node:path";
48234
+ import { join as join36, sep as sep3 } from "node:path";
48154
48235
  function children(path, pattern) {
48155
48236
  try {
48156
48237
  return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
@@ -48162,7 +48243,7 @@ function isUnder2(path, root) {
48162
48243
  return path === root || path.startsWith(root.endsWith(sep3) ? root : root + sep3);
48163
48244
  }
48164
48245
  function resolveFragment(projectDir, sessionId, file) {
48165
- const base = join35(projectDir, ".codex", "visualizations");
48246
+ const base = join36(projectDir, ".codex", "visualizations");
48166
48247
  let projectReal;
48167
48248
  let baseReal;
48168
48249
  try {
@@ -48173,12 +48254,12 @@ function resolveFragment(projectDir, sessionId, file) {
48173
48254
  }
48174
48255
  if (!isUnder2(baseReal, projectReal)) return null;
48175
48256
  for (const year of children(base, YEAR_PART)) {
48176
- const yearDir = join35(base, year);
48257
+ const yearDir = join36(base, year);
48177
48258
  for (const month of children(yearDir, DATE_PART)) {
48178
- const monthDir = join35(yearDir, month);
48259
+ const monthDir = join36(yearDir, month);
48179
48260
  for (const day of children(monthDir, DATE_PART)) {
48180
- const sessionRoot = join35(baseReal, year, month, day, sessionId);
48181
- const candidate = join35(monthDir, day, sessionId, file);
48261
+ const sessionRoot = join36(baseReal, year, month, day, sessionId);
48262
+ const candidate = join36(monthDir, day, sessionId, file);
48182
48263
  try {
48183
48264
  const real = realpathSync11(candidate);
48184
48265
  if (isUnder2(real, sessionRoot) && statSync20(real).isFile()) return real;
@@ -48307,7 +48388,7 @@ var init_local_visualization = __esm({
48307
48388
 
48308
48389
  // packages/server/src/app.ts
48309
48390
  import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync14 } from "node:fs";
48310
- import { join as join36 } from "node:path";
48391
+ import { join as join37 } from "node:path";
48311
48392
  import { randomUUID as randomUUID17 } from "node:crypto";
48312
48393
  function createApp(ctx, options = {}) {
48313
48394
  const app = new Hono2();
@@ -48411,10 +48492,10 @@ function createApp(ctx, options = {}) {
48411
48492
  if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
48412
48493
  const ext = `.${attachmentExtension(name)}`;
48413
48494
  const buf = Buffer.from(body.data, "base64");
48414
- const dir = join36(ctx.project.stateDir, "attachments");
48495
+ const dir = join37(ctx.project.stateDir, "attachments");
48415
48496
  mkdirSync17(dir, { recursive: true });
48416
48497
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
48417
- 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}`);
48418
48499
  writeFileSync14(path, buf);
48419
48500
  return c.json({ path });
48420
48501
  });
@@ -49654,9 +49735,9 @@ var init_app_socket = __esm({
49654
49735
 
49655
49736
  // packages/server/src/boot-progress.ts
49656
49737
  import { mkdirSync as mkdirSync18, readFileSync as readFileSync26, renameSync as renameSync10, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
49657
- import { basename as basename11, dirname as dirname16, join as join37 } from "node:path";
49738
+ import { basename as basename11, dirname as dirname16, join as join38 } from "node:path";
49658
49739
  function bootProgressPath(stateDir) {
49659
- return join37(stateDir, BOOT_PROGRESS_NAME);
49740
+ return join38(stateDir, BOOT_PROGRESS_NAME);
49660
49741
  }
49661
49742
  function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49662
49743
  if (!stateDir) {
@@ -49677,7 +49758,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49677
49758
  step++;
49678
49759
  try {
49679
49760
  mkdirSync18(dirname16(path), { recursive: true, mode: 448 });
49680
- const temp = join37(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49761
+ const temp = join38(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49681
49762
  writeFileSync15(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
49682
49763
  `, "utf8");
49683
49764
  renameSync10(temp, path);
@@ -49795,7 +49876,7 @@ __export(index_exports, {
49795
49876
  });
49796
49877
  import { createServer } from "node:http";
49797
49878
  import { readFileSync as readFileSync27, existsSync as existsSync15 } from "node:fs";
49798
- import { dirname as dirname17, join as join38, resolve as resolve9, extname as extname4, normalize } from "node:path";
49879
+ import { dirname as dirname17, join as join39, resolve as resolve9, extname as extname4, normalize } from "node:path";
49799
49880
  function readServerAddressHolder(path) {
49800
49881
  try {
49801
49882
  const value = JSON.parse(readFileSync27(path, "utf8"));
@@ -49898,9 +49979,9 @@ function createShutdownSignalHandler(options) {
49898
49979
  }
49899
49980
  function serveStatic(distDir, req, res) {
49900
49981
  const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
49901
- let file = join38(distDir, rel === "/" ? "index.html" : rel);
49902
- if (!file.startsWith(distDir)) file = join38(distDir, "index.html");
49903
- 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");
49904
49985
  try {
49905
49986
  const body = readFileSync27(file);
49906
49987
  res.writeHead(200, { "content-type": MIME[extname4(file)] ?? "application/octet-stream" });
@@ -49931,6 +50012,7 @@ async function startServer(opts = {}) {
49931
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.`
49932
50013
  );
49933
50014
  };
50015
+ const activeTenants = () => tenants.active().map(({ project: open, ctx: openCtx }) => ({ project: open, board: openCtx.board }));
49934
50016
  const tenants = createTenantMap({
49935
50017
  createContext: (contextOptions) => {
49936
50018
  if (contextOptions.project) assertNotServedElsewhere(contextOptions.project);
@@ -49938,7 +50020,7 @@ async function startServer(opts = {}) {
49938
50020
  },
49939
50021
  // serverLockPath is the LAUNCHING project's: it is the only `server.lock` this process publishes
49940
50022
  // (see "status publication"), so it is the only file a tenant's worker can read the port out of.
49941
- contextOptions: { claudeBin: opts.claudeBin, serverLockPath: serverLockPathFor(project) },
50023
+ contextOptions: { claudeBin: opts.claudeBin, serverLockPath: serverLockPathFor(project), activeTenants },
49942
50024
  // Each project's app carries ITS OWN owner proof, so /health stays honest per project rather than
49943
50025
  // answering for whichever one happened to launch the server. The transports are per project for a
49944
50026
  // blunter reason: a socket is a live feed of ONE board, so sharing the launcher's would push its
@@ -50197,6 +50279,7 @@ async function startServer(opts = {}) {
50197
50279
  claudeBin: opts.claudeBin,
50198
50280
  project,
50199
50281
  serverLockPath: serverLockPathFor(project),
50282
+ activeTenants,
50200
50283
  startup: {
50201
50284
  afterPhase: (p) => {
50202
50285
  bootProgress(`context: ${p}`);
@@ -50249,7 +50332,7 @@ async function startServer(opts = {}) {
50249
50332
  }
50250
50333
  statusPath = serverLockPathFor(ctx.project);
50251
50334
  const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
50252
- const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join38(webRoot, "dist");
50335
+ const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join39(webRoot, "dist");
50253
50336
  startupPhase = "Vite";
50254
50337
  if (opts.dev) {
50255
50338
  try {
@@ -50325,7 +50408,7 @@ async function startServer(opts = {}) {
50325
50408
  if (vite) {
50326
50409
  vite.middlewares(req, res, () => {
50327
50410
  try {
50328
- const html = readFileSync27(join38(webRoot, "index.html"), "utf8");
50411
+ const html = readFileSync27(join39(webRoot, "index.html"), "utf8");
50329
50412
  void vite.transformIndexHtml(url, html).then((out) => {
50330
50413
  res.writeHead(200, { "content-type": "text/html" });
50331
50414
  res.end(out);
@@ -50517,7 +50600,7 @@ var init_index = __esm({
50517
50600
  }
50518
50601
  };
50519
50602
  isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
50520
- serverLockPathFor = (project) => join38(project.stateDir, "server.lock");
50603
+ serverLockPathFor = (project) => join39(project.stateDir, "server.lock");
50521
50604
  MIME = {
50522
50605
  ".html": "text/html",
50523
50606
  ".js": "text/javascript",
@@ -50536,7 +50619,7 @@ init_project_launch();
50536
50619
  init_shutdown();
50537
50620
  init_logging();
50538
50621
  import { existsSync as existsSync16 } from "node:fs";
50539
- import { join as join39 } from "node:path";
50622
+ import { join as join40 } from "node:path";
50540
50623
  process.on("uncaughtException", (error) => {
50541
50624
  log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
50542
50625
  process.exit(1);
@@ -50576,7 +50659,7 @@ try {
50576
50659
  ];
50577
50660
  if (!existsSync16(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
50578
50661
  for (const [name, directory, requiredFile] of required) {
50579
- if (!directory || !existsSync16(join39(directory, requiredFile)))
50662
+ if (!directory || !existsSync16(join40(directory, requiredFile)))
50580
50663
  throw new Error(`stable artifact launch is missing verified ${name}`);
50581
50664
  }
50582
50665
  }