frizz 0.7.4 → 0.7.7

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/README.md +28 -15
  2. package/dist/dev-child.js +376 -306
  3. package/dist/frizz.js +12908 -6474
  4. package/package.json +5 -3
  5. package/runtime/cc-worker/DECISIONS.md +11 -0
  6. package/web-dist/assets/{TerminalPane-Cyao7kTi.js → TerminalPane-Cb8jOFP9.js} +1 -1
  7. package/web-dist/assets/{abnfDiagram-VRR7QNED-D1U0Q_zY.js → abnfDiagram-VRR7QNED-Dtbg2eZ0.js} +1 -1
  8. package/web-dist/assets/architecture-TIHT7OUA-CTxVpl9_.js +1 -0
  9. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-CtUBwBcU.js → architectureDiagram-ZJ3FMSHR-DzQjWW7u.js} +1 -1
  10. package/web-dist/assets/{blockDiagram-677ZJIJ3-OzqrN18g.js → blockDiagram-677ZJIJ3-BJnpkLMt.js} +1 -1
  11. package/web-dist/assets/{c4Diagram-LMCZKHZV-DgYAtD7L.js → c4Diagram-LMCZKHZV-COdatsYu.js} +1 -1
  12. package/web-dist/assets/channel-COS0Ygbp.js +1 -0
  13. package/web-dist/assets/{chunk-32BRIVSS-CKwBruPa.js → chunk-32BRIVSS-CORMw4Vm.js} +1 -1
  14. package/web-dist/assets/{chunk-52WLFC77-gvoNW_ar.js → chunk-52WLFC77-C7lEadTg.js} +1 -1
  15. package/web-dist/assets/{chunk-C7G6YPKG-EJ5BdmRQ.js → chunk-C7G6YPKG-DZy4F97l.js} +1 -1
  16. package/web-dist/assets/{chunk-EX3LRPZG-DJQF-VwN.js → chunk-EX3LRPZG-HynlfV9p.js} +1 -1
  17. package/web-dist/assets/{chunk-FWX5IMBZ-CXBLvjvR.js → chunk-FWX5IMBZ-BbwKNhKm.js} +2 -2
  18. package/web-dist/assets/{chunk-HOUHSVGY-De3ULdBq.js → chunk-HOUHSVGY-lIhOZSmL.js} +1 -1
  19. package/web-dist/assets/{chunk-ICXQ74PX-aUbMdGsl.js → chunk-ICXQ74PX-WGxaMO8c.js} +1 -1
  20. package/web-dist/assets/{chunk-MOJQB5TN-BLK44SUW.js → chunk-MOJQB5TN-B-cx0f3u.js} +1 -1
  21. package/web-dist/assets/{chunk-OGEWGWER-CQZ3zQ2q.js → chunk-OGEWGWER-DJceVwZH.js} +1 -1
  22. package/web-dist/assets/{chunk-PUDLZKDR-DcdN44K2.js → chunk-PUDLZKDR-CGwHZns8.js} +1 -1
  23. package/web-dist/assets/{chunk-Q4XR5HBZ-Db2ge7fW.js → chunk-Q4XR5HBZ-PTSWtmk1.js} +1 -1
  24. package/web-dist/assets/{chunk-V7JOEXUC-D80jxcmB.js → chunk-V7JOEXUC-VNxHZPcf.js} +1 -1
  25. package/web-dist/assets/{chunk-VAUOI2AC-nDGsXZZE.js → chunk-VAUOI2AC-ZXYCz_Aw.js} +1 -1
  26. package/web-dist/assets/{chunk-VR4S4FIN-BGXgLAsD.js → chunk-VR4S4FIN-9WCtmFJp.js} +1 -1
  27. package/web-dist/assets/{chunk-WYO6CB5R-BbGEK50o.js → chunk-WYO6CB5R-V4EBjpmt.js} +1 -1
  28. package/web-dist/assets/{chunk-ZGVPDNZ5-CjEI23Vu.js → chunk-ZGVPDNZ5-CPW0Z0ae.js} +1 -1
  29. package/web-dist/assets/classDiagram-OUVF2IWQ-Df5TLnrN.js +1 -0
  30. package/web-dist/assets/classDiagram-v2-EOCWNBFH-Df5TLnrN.js +1 -0
  31. package/web-dist/assets/{cynefin-VYW2F7L2-CR69iDgw.js → cynefin-VYW2F7L2-E7PklfJD.js} +1 -1
  32. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Le_FSC65.js → cynefinDiagram-TSTJHNR4-JIXAPjDf.js} +1 -1
  33. package/web-dist/assets/{dagre-VKFMJZFB-CxAlFDI9.js → dagre-VKFMJZFB-DjXrdcNx.js} +1 -1
  34. package/web-dist/assets/{diagram-FQU43EPY-BFMwv6Pj.js → diagram-FQU43EPY--i9i0qhm.js} +1 -1
  35. package/web-dist/assets/{diagram-G47NLZAW-mWAc5hJ0.js → diagram-G47NLZAW-DxgcENZ_.js} +1 -1
  36. package/web-dist/assets/{diagram-NH7WQ7WH-CC-QXuir.js → diagram-NH7WQ7WH-CUy9Nr90.js} +1 -1
  37. package/web-dist/assets/{diagram-OA4YK3LP-Cqs5o39q.js → diagram-OA4YK3LP-DbTbUaCb.js} +1 -1
  38. package/web-dist/assets/{diagram-WEI45ONY-B9PF6IpG.js → diagram-WEI45ONY-2gk6xhOq.js} +1 -1
  39. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-C1DkTGUE.js → ebnfDiagram-CCIWWBDH-uE2iDETg.js} +1 -1
  40. package/web-dist/assets/{erDiagram-Q63AITRT-CbCG5w3K.js → erDiagram-Q63AITRT-dztd4MUw.js} +1 -1
  41. package/web-dist/assets/eventmodeling-45OFAUF4-DPVPOEaJ.js +1 -0
  42. package/web-dist/assets/flowDiagram-23GEKE2U-BMIMgVYd.js +1 -0
  43. package/web-dist/assets/{ganttDiagram-NO4QXBWP-CaywKz56.js → ganttDiagram-NO4QXBWP-DAds6Aht.js} +1 -1
  44. package/web-dist/assets/{gitGraph-TEB2WS4Q-DhbijOBs.js → gitGraph-TEB2WS4Q-Ci0XVvIa.js} +1 -1
  45. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-DHngf1QZ.js → gitGraphDiagram-IHSO6WYX-C6FULyt8.js} +1 -1
  46. package/web-dist/assets/{index-CxwWndgM.js → index-CNy5uOpI.js} +116 -111
  47. package/web-dist/assets/{index-C-3lsl4q.css → index-D6LsViUY.css} +1 -1
  48. package/web-dist/assets/{info-DKCQHKI2-D2uo8Yq_.js → info-DKCQHKI2-9N77dOiw.js} +1 -1
  49. package/web-dist/assets/{infoDiagram-FWYZ7A6U-Bixn1mvJ.js → infoDiagram-FWYZ7A6U-BymP3PgG.js} +1 -1
  50. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DG48ASOp.js → ishikawaDiagram-FXEZZL3T-CU_kQBz1.js} +1 -1
  51. package/web-dist/assets/{journeyDiagram-5HDEW3XC-DpQOwYAS.js → journeyDiagram-5HDEW3XC-DZN15HSd.js} +1 -1
  52. package/web-dist/assets/{kanban-definition-HUTT4EX6-Dph0AMZo.js → kanban-definition-HUTT4EX6-J4wR5g_3.js} +1 -1
  53. package/web-dist/assets/{line-hnYRfUMr.js → line-SRzGpiDr.js} +1 -1
  54. package/web-dist/assets/{mermaid-parser.core-DdD3ClpS.js → mermaid-parser.core-CGBscNGo.js} +3 -3
  55. package/web-dist/assets/{mermaid.core-C2DMq9ss.js → mermaid.core-xNdwXb1r.js} +3 -3
  56. package/web-dist/assets/{mindmap-definition-LN4V7U3C-CirJBG-x.js → mindmap-definition-LN4V7U3C-gR2dbzrj.js} +1 -1
  57. package/web-dist/assets/{packet-7NZHBO7P-kD-OtFAF.js → packet-7NZHBO7P-DrR4W6I3.js} +1 -1
  58. package/web-dist/assets/{pegDiagram-2B236MQR-DGmi8fl-.js → pegDiagram-2B236MQR-DN7R-_t4.js} +1 -1
  59. package/web-dist/assets/{pie-RZYD4A2V-DpKplj-N.js → pie-RZYD4A2V-C8VjQAFZ.js} +1 -1
  60. package/web-dist/assets/{pieDiagram-ENE6RG2P-CW-zVLyR.js → pieDiagram-ENE6RG2P-5w64zdD1.js} +1 -1
  61. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-fxSaIvo2.js → quadrantDiagram-ABIIQ3AL-B4rbezq_.js} +1 -1
  62. package/web-dist/assets/{radar-I7S5WNFK-BPu7ClHP.js → radar-I7S5WNFK-CTbbPB8m.js} +1 -1
  63. package/web-dist/assets/{railroad-3IZDKUUU-CoQXFYm6.js → railroad-3IZDKUUU-CY1er15b.js} +1 -1
  64. package/web-dist/assets/railroad-abnf-AHOZXSZD-DfEpkrtJ.js +1 -0
  65. package/web-dist/assets/railroad-ebnf-EBAXGLYW-Csunejgu.js +1 -0
  66. package/web-dist/assets/railroad-peg-LSFZ7HO6-BgRslbM_.js +1 -0
  67. package/web-dist/assets/{railroadDiagram-RFXS5EU6-Bqnz_3Bc.js → railroadDiagram-RFXS5EU6-Bx2HJ3yT.js} +1 -1
  68. package/web-dist/assets/{requirementDiagram-TGXJPOKE-DJHMdBhh.js → requirementDiagram-TGXJPOKE-BLK-Y2rx.js} +1 -1
  69. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-BlxzmT-W.js → sankeyDiagram-HTMAVEWB-Dk-8Miv-.js} +1 -1
  70. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-BT7Rn1Uo.js → sequenceDiagram-DBY2YBRQ-DL2alfR-.js} +1 -1
  71. package/web-dist/assets/{stateDiagram-2N3HPSRC-CDoiFcke.js → stateDiagram-2N3HPSRC-Bka44wf1.js} +1 -1
  72. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-6KcScVPX.js +1 -0
  73. package/web-dist/assets/{swimlanes-5IMT3BWC-DtzTgSSP.js → swimlanes-5IMT3BWC-e0GbMwIr.js} +1 -1
  74. package/web-dist/assets/swimlanesDiagram-G3AALYLV-jaJhlDbE.js +8 -0
  75. package/web-dist/assets/{timeline-definition-FHXFAJF6-Dn63VmSO.js → timeline-definition-FHXFAJF6-CT3GFq89.js} +1 -1
  76. package/web-dist/assets/{treeView-QDETBFTQ-DIfJIc9R.js → treeView-QDETBFTQ-BJauJ0bm.js} +1 -1
  77. package/web-dist/assets/{treemap-6X3UGDF4-n9Fwqngl.js → treemap-6X3UGDF4-DCX7A-nx.js} +1 -1
  78. package/web-dist/assets/{vennDiagram-L72KCM5P-C1thEMxE.js → vennDiagram-L72KCM5P-D4dm2iTR.js} +1 -1
  79. package/web-dist/assets/{wardley-OPB4EBWU-Dl6RiScD.js → wardley-OPB4EBWU-DklTDSId.js} +1 -1
  80. package/web-dist/assets/{wardleyDiagram-EHGQE667-DBelgTwB.js → wardleyDiagram-EHGQE667-CikP5hBd.js} +1 -1
  81. package/web-dist/assets/{xychartDiagram-FW5EYKEG-DFGVnPLj.js → xychartDiagram-FW5EYKEG-FXuOAFpz.js} +1 -1
  82. package/web-dist/index.html +2 -2
  83. package/web-dist/assets/architecture-TIHT7OUA-BS8x9TQa.js +0 -1
  84. package/web-dist/assets/channel-DHZV3ADN.js +0 -1
  85. package/web-dist/assets/classDiagram-OUVF2IWQ-Dcx3TDdU.js +0 -1
  86. package/web-dist/assets/classDiagram-v2-EOCWNBFH-Dcx3TDdU.js +0 -1
  87. package/web-dist/assets/eventmodeling-45OFAUF4-DAhP7KCX.js +0 -1
  88. package/web-dist/assets/flowDiagram-23GEKE2U-Be2iuqwq.js +0 -1
  89. package/web-dist/assets/railroad-abnf-AHOZXSZD-BiqkuXNr.js +0 -1
  90. package/web-dist/assets/railroad-ebnf-EBAXGLYW-CDaukY4Z.js +0 -1
  91. package/web-dist/assets/railroad-peg-LSFZ7HO6-CsUPdvVL.js +0 -1
  92. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DiLnjG8k.js +0 -1
  93. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BqvWOcR2.js +0 -8
package/dist/dev-child.js CHANGED
@@ -129,6 +129,7 @@ var init_frizz_paths = __esm({
129
129
  import { execFileSync } from "node:child_process";
130
130
  import { randomUUID } from "node:crypto";
131
131
  import { readFileSync } from "node:fs";
132
+ import { join as join2 } from "node:path";
132
133
  function errorCode(error) {
133
134
  return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
134
135
  }
@@ -169,6 +170,38 @@ function fixedPsGeneration(pid) {
169
170
  return null;
170
171
  }
171
172
  }
173
+ function windowsGeneration(pid) {
174
+ if (!Number.isInteger(pid) || pid <= 0) return null;
175
+ try {
176
+ const shell = join2(
177
+ process.env.SystemRoot ?? "C:\\Windows",
178
+ "System32",
179
+ "WindowsPowerShell",
180
+ "v1.0",
181
+ "powershell.exe"
182
+ );
183
+ const value = execFileSync(shell, [
184
+ "-NoProfile",
185
+ "-NonInteractive",
186
+ "-NoLogo",
187
+ "-Command",
188
+ // A vanished PID, a protected process and an access-denied StartTime all throw. Exit non-zero
189
+ // so execFileSync rejects, rather than letting PowerShell's error prose become a marker.
190
+ `try{[Console]::Out.Write((Get-Process -Id ${pid} -ErrorAction Stop).StartTime.ToFileTimeUtc())}catch{exit 1}`
191
+ ], {
192
+ encoding: "utf8",
193
+ stdio: ["ignore", "pipe", "ignore"],
194
+ // A wedged spawn must not hold a launcher's poll loop open forever; a timeout reads as
195
+ // unavailable, which retains the owner.
196
+ timeout: 5e3,
197
+ windowsHide: true
198
+ }).trim();
199
+ if (!/^\d{1,20}$/u.test(value)) return null;
200
+ return { processStart: `win32:${value}`, confidence: "exact" };
201
+ } catch {
202
+ return null;
203
+ }
204
+ }
172
205
  function observeDefault(pid) {
173
206
  if (!processAlive(pid)) return { confidence: "unavailable" };
174
207
  if (process.platform === "linux") {
@@ -178,6 +211,7 @@ function observeDefault(pid) {
178
211
  return fallback ?? { confidence: "unavailable" };
179
212
  }
180
213
  if (process.platform === "darwin") return fixedPsGeneration(pid) ?? { confidence: "unavailable" };
214
+ if (process.platform === "win32") return windowsGeneration(pid) ?? { confidence: "unavailable" };
181
215
  return { confidence: "unavailable" };
182
216
  }
183
217
  function observeProcessGeneration(generation, adapter = defaultProcessPlatformAdapter) {
@@ -185,7 +219,7 @@ function observeProcessGeneration(generation, adapter = defaultProcessPlatformAd
185
219
  const self = adapter.current();
186
220
  if (generation.pid === self.pid && generation.processStart === self.processStart) return "exact";
187
221
  if (generation.processStart.startsWith("opaque:")) return "unavailable";
188
- if (!/^(?:linux|ps-utc|opaque):/u.test(generation.processStart)) return "unavailable";
222
+ if (!/^(?:linux|ps-utc|win32|opaque):/u.test(generation.processStart)) return "unavailable";
189
223
  const observed = adapter.observe(generation.pid);
190
224
  if (!observed.processStart || observed.confidence === "unavailable") return "unavailable";
191
225
  if (observed.processStart.split(":", 1)[0] !== generation.processStart.split(":", 1)[0]) {
@@ -241,7 +275,7 @@ import {
241
275
  writeFileSync
242
276
  } from "node:fs";
243
277
  import { homedir as homedir2 } from "node:os";
244
- import { dirname as dirname2, join as join2, resolve } from "node:path";
278
+ import { dirname as dirname2, join as join3, resolve } from "node:path";
245
279
  function errorCode2(error) {
246
280
  return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
247
281
  }
@@ -256,7 +290,7 @@ function canonicalHome(home) {
256
290
  }
257
291
  }
258
292
  function namedLaunchLockPath(home, name) {
259
- return join2(frizzPaths({ home: canonicalHome(home) }).state, name);
293
+ return join3(frizzPaths({ home: canonicalHome(home) }).state, name);
260
294
  }
261
295
  function pidIsAlive(pid) {
262
296
  if (!Number.isInteger(pid) || pid <= 0) return false;
@@ -284,7 +318,7 @@ function syncDirectory(path) {
284
318
  }
285
319
  function lockOwnerPath(lockPath) {
286
320
  try {
287
- return statSync(lockPath).isDirectory() ? join2(lockPath, GLOBAL_LOCK_OWNER) : lockPath;
321
+ return statSync(lockPath).isDirectory() ? join3(lockPath, GLOBAL_LOCK_OWNER) : lockPath;
288
322
  } catch {
289
323
  return lockPath;
290
324
  }
@@ -446,7 +480,7 @@ function resolveGitWorktree(dir) {
446
480
  // Do not enable Git's repository-wide `extensions.worktreeConfig` merely to hold one private Frizz
447
481
  // value. A config file inside the linked worktree's own administrative directory has Git's atomic
448
482
  // config-lock behavior, survives `git worktree move`, and disappears with `git worktree remove`.
449
- ...scope === "worktree" ? { identityConfig: join2(gitDir, "frizz.config") } : {}
483
+ ...scope === "worktree" ? { identityConfig: join3(gitDir, "frizz.config") } : {}
450
484
  };
451
485
  }
452
486
  function readProjectIdConfig(dir, args, description) {
@@ -615,9 +649,9 @@ var init_project_identity = __esm({
615
649
  import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
616
650
  import { closeSync as closeSync2, existsSync as existsSync2, fsyncSync as fsyncSync2, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync3, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
617
651
  import { homedir as homedir3 } from "node:os";
618
- import { dirname as dirname3, join as join3, parse, resolve as resolve2 } from "node:path";
652
+ import { dirname as dirname3, join as join4, parse, resolve as resolve2 } from "node:path";
619
653
  function projectIdPath(root) {
620
- return join3(root, FRIZZ_DIR, ID_FILE);
654
+ return join4(root, FRIZZ_DIR, ID_FILE);
621
655
  }
622
656
  function readProjectIdFile(root) {
623
657
  let raw2;
@@ -633,9 +667,9 @@ function readProjectIdFile(root) {
633
667
  }
634
668
  }
635
669
  function writeProjectIdFile(root, id) {
636
- const dir = join3(root, FRIZZ_DIR);
670
+ const dir = join4(root, FRIZZ_DIR);
637
671
  mkdirSync2(dir, { recursive: true });
638
- const ignore = join3(dir, SELF_IGNORE);
672
+ const ignore = join4(dir, SELF_IGNORE);
639
673
  if (!existsSync2(ignore)) {
640
674
  try {
641
675
  writeFileSync2(ignore, "*\n", { flag: "wx" });
@@ -643,7 +677,7 @@ function writeProjectIdFile(root, id) {
643
677
  }
644
678
  }
645
679
  const path = projectIdPath(root);
646
- const temp = join3(dir, `.${ID_FILE}.${process.pid}.${randomUUID3()}.tmp`);
680
+ const temp = join4(dir, `.${ID_FILE}.${process.pid}.${randomUUID3()}.tmp`);
647
681
  let fd;
648
682
  try {
649
683
  fd = openSync2(temp, "wx", 384);
@@ -684,7 +718,7 @@ function ensureProjectIdFile(root, home = homedir3(), seed) {
684
718
  }
685
719
  }
686
720
  function hasAny(dir, names) {
687
- return names.some((name) => existsSync2(join3(dir, name)));
721
+ return names.some((name) => existsSync2(join4(dir, name)));
688
722
  }
689
723
  function existingProjectId(dir) {
690
724
  const fromFile = readProjectIdFile(dir);
@@ -12871,6 +12905,16 @@ var init_receipt_bus = __esm({
12871
12905
  }
12872
12906
  });
12873
12907
 
12908
+ // packages/shared/src/relay-protocol.ts
12909
+ var RELAY_MAX_FRAME_BODY, RELAY_MAX_WS_CHUNK;
12910
+ var init_relay_protocol = __esm({
12911
+ "packages/shared/src/relay-protocol.ts"() {
12912
+ "use strict";
12913
+ RELAY_MAX_FRAME_BODY = 512 * 1024;
12914
+ RELAY_MAX_WS_CHUNK = 64 * 1024;
12915
+ }
12916
+ });
12917
+
12874
12918
  // packages/shared/src/index.ts
12875
12919
  function attachmentExtension(name) {
12876
12920
  const m = /\.([a-zA-Z0-9]+)$/.exec(name.trim());
@@ -13233,6 +13277,7 @@ var init_src = __esm({
13233
13277
  init_drainable_worker();
13234
13278
  init_interactions();
13235
13279
  init_receipt_bus();
13280
+ init_relay_protocol();
13236
13281
  init_thread_slug();
13237
13282
  ATTACHMENT_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "webp"];
13238
13283
  ATTACHMENT_DOC_EXTENSIONS = [
@@ -14925,9 +14970,9 @@ ${DISPATCH_TASK_BANNER}
14925
14970
  // packages/server/src/project-registry.ts
14926
14971
  import { closeSync as closeSync3, existsSync as existsSync3, fsyncSync as fsyncSync3, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync4, readdirSync, realpathSync as realpathSync3, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
14927
14972
  import { homedir as homedir4 } from "node:os";
14928
- import { basename, dirname as dirname4, join as join4 } from "node:path";
14973
+ import { basename, dirname as dirname4, join as join5 } from "node:path";
14929
14974
  function registryPath(home = homedir4()) {
14930
- return join4(frizzPaths({ home }).data, "registry.json");
14975
+ return join5(frizzPaths({ home }).data, "registry.json");
14931
14976
  }
14932
14977
  function readRegistry(home = homedir4()) {
14933
14978
  let raw2;
@@ -15016,7 +15061,7 @@ function registerProject(input, home = homedir4()) {
15016
15061
  writeRegistry(registry, home);
15017
15062
  return { entry: byId, action: "reopened" };
15018
15063
  }
15019
- if (existsSync3(join4(byId.path, ".frizz", ".id"))) return { action: "duplicate" };
15064
+ if (existsSync3(join5(byId.path, ".frizz", ".id"))) return { action: "duplicate" };
15020
15065
  byId.path = input.dir;
15021
15066
  byId.lastOpenedAt = at;
15022
15067
  writeRegistry(registry, home);
@@ -15043,14 +15088,14 @@ function registerProject(input, home = homedir4()) {
15043
15088
  function backfillRegistry(home = homedir4(), read = existingProjectId) {
15044
15089
  let dirs;
15045
15090
  try {
15046
- dirs = readdirSync(join4(frizzPaths({ home }).data, "projects"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
15091
+ dirs = readdirSync(join5(frizzPaths({ home }).data, "projects"), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
15047
15092
  } catch {
15048
15093
  return 0;
15049
15094
  }
15050
15095
  const known = new Set(readRegistry(home).projects.map((p) => p.path));
15051
15096
  let added = 0;
15052
15097
  for (const id of dirs) {
15053
- const recorded = recordedProjectDir(join4(frizzPaths({ home }).data, "projects", id));
15098
+ const recorded = recordedProjectDir(join5(frizzPaths({ home }).data, "projects", id));
15054
15099
  const dir = recorded ? canonicalPath(recorded) : void 0;
15055
15100
  if (!dir || known.has(dir)) continue;
15056
15101
  if (read(dir) !== id) continue;
@@ -15068,7 +15113,7 @@ function backfillRegistry(home = homedir4(), read = existingProjectId) {
15068
15113
  function recordedProjectDir(stateDir) {
15069
15114
  for (const name of ["launcher.json", "server.lock", "project-launch.owner"]) {
15070
15115
  try {
15071
- const value = JSON.parse(readFileSync4(join4(stateDir, name), "utf8")).projectDir;
15116
+ const value = JSON.parse(readFileSync4(join5(stateDir, name), "utf8")).projectDir;
15072
15117
  if (typeof value === "string" && value.length > 0 && existsSync3(value)) return value;
15073
15118
  } catch {
15074
15119
  }
@@ -15111,7 +15156,7 @@ function findProjectBySegment(segment, home = homedir4()) {
15111
15156
  return findBySlug(segment, home) ?? findById(segment, home);
15112
15157
  }
15113
15158
  function customIconPath(id, extension2, home = homedir4()) {
15114
- return join4(frizzPaths({ home }).data, "projects", id, `icon${extension2}`);
15159
+ return join5(frizzPaths({ home }).data, "projects", id, `icon${extension2}`);
15115
15160
  }
15116
15161
  function updateEntry(id, apply, home) {
15117
15162
  const registry = readRegistry(home);
@@ -15576,7 +15621,7 @@ CI (PRs): \`gh pr checks {n} -R {repo}\``;
15576
15621
  import { execFileSync as execFileSync3 } from "node:child_process";
15577
15622
  import { mkdirSync as mkdirSync4, realpathSync as realpathSync4 } from "node:fs";
15578
15623
  import { homedir as homedir5, tmpdir as tmpdir2 } from "node:os";
15579
- import { basename as basename2, join as join5, resolve as resolve3 } from "node:path";
15624
+ import { basename as basename2, join as join6, resolve as resolve3 } from "node:path";
15580
15625
  import { randomUUID as randomUUID4 } from "node:crypto";
15581
15626
  function projectRepoIdentity(dir, name) {
15582
15627
  const url = originRemoteUrl(dir);
@@ -15585,7 +15630,7 @@ function projectRepoIdentity(dir, name) {
15585
15630
  return { label: parseRepoLabel(url) ?? name, ...githubRepo ? { githubRepo } : {} };
15586
15631
  }
15587
15632
  function trustedLocalFileRoots(project) {
15588
- return [project.dir, tmpdir2(), "/tmp", resolve3(homedir5(), "Screenshots"), join5(project.stateDir, "attachments")];
15633
+ return [project.dir, tmpdir2(), "/tmp", resolve3(homedir5(), "Screenshots"), join6(project.stateDir, "attachments")];
15589
15634
  }
15590
15635
  function openableFileRoots(project) {
15591
15636
  return [homedir5(), ...trustedLocalFileRoots(project)];
@@ -15691,10 +15736,10 @@ function resolveProject(cwd = process.cwd(), home = homedir5(), env = process.en
15691
15736
  };
15692
15737
  }
15693
15738
  function permRequestDir(project) {
15694
- return join5(project.stateDir, "perm-requests");
15739
+ return join6(project.stateDir, "perm-requests");
15695
15740
  }
15696
15741
  function permMarkerPath(project, slug) {
15697
- return join5(permRequestDir(project), `${slug}.json`);
15742
+ return join6(permRequestDir(project), `${slug}.json`);
15698
15743
  }
15699
15744
  function projectLaunchTarget(project) {
15700
15745
  return {
@@ -15749,7 +15794,7 @@ import {
15749
15794
  statSync as statSync2,
15750
15795
  writeFileSync as writeFileSync4
15751
15796
  } from "node:fs";
15752
- import { basename as basename3, dirname as dirname5, isAbsolute, join as join6 } from "node:path";
15797
+ import { basename as basename3, dirname as dirname5, isAbsolute, join as join7 } from "node:path";
15753
15798
  function errorCode3(error) {
15754
15799
  return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
15755
15800
  }
@@ -15773,7 +15818,7 @@ function syncDirectory2(path) {
15773
15818
  }
15774
15819
  function atomicJson(path, value) {
15775
15820
  mkdirSync5(dirname5(path), { recursive: true, mode: 448 });
15776
- const temp = join6(dirname5(path), `.${basename3(path)}.${process.pid}.${randomUUID5()}.tmp`);
15821
+ const temp = join7(dirname5(path), `.${basename3(path)}.${process.pid}.${randomUUID5()}.tmp`);
15777
15822
  let fd;
15778
15823
  try {
15779
15824
  fd = openSync4(temp, "wx", 384);
@@ -15832,7 +15877,7 @@ function parseGuard(path) {
15832
15877
  }
15833
15878
  }
15834
15879
  function acquireMutationGuard(stateDir, timeoutMs = GUARD_TIMEOUT_MS, adapter = defaultProcessPlatformAdapter) {
15835
- const path = join6(stateDir, MUTATION_GUARD_NAME);
15880
+ const path = join7(stateDir, MUTATION_GUARD_NAME);
15836
15881
  mkdirSync5(stateDir, { recursive: true, mode: 448 });
15837
15882
  const deadline = adapter.now() + Math.max(0, timeoutMs);
15838
15883
  for (; ; ) {
@@ -15926,7 +15971,7 @@ function parseOwner(path) {
15926
15971
  }
15927
15972
  }
15928
15973
  function projectLaunchOwnerPath(stateDir) {
15929
- return join6(stateDir, OWNER_NAME);
15974
+ return join7(stateDir, OWNER_NAME);
15930
15975
  }
15931
15976
  function servedByAnotherProcess(stateDir, projectId, self = process.pid, alive = pidIsAlive) {
15932
15977
  const owner = readProjectLaunchOwner(stateDir);
@@ -15949,7 +15994,7 @@ function projectLaunchTokenProof(target, token) {
15949
15994
  }
15950
15995
  function removeStatusesForToken(stateDir, token) {
15951
15996
  for (const name of ["dev-supervisor.lock", "server.lock"]) {
15952
- const path = join6(stateDir, name);
15997
+ const path = join7(stateDir, name);
15953
15998
  try {
15954
15999
  const value = JSON.parse(readFileSync5(path, "utf8"));
15955
16000
  if (value.ownerToken === token) quarantine(path, "stale");
@@ -16450,9 +16495,9 @@ import {
16450
16495
  writeSync
16451
16496
  } from "node:fs";
16452
16497
  import { homedir as homedir6 } from "node:os";
16453
- import { join as join7 } from "node:path";
16498
+ import { join as join8 } from "node:path";
16454
16499
  function defaultLogRoot(stateDir, home = homedir6()) {
16455
- return stateDir ? join7(stateDir, "logs") : join7(frizzPaths({ home }).state, "logs");
16500
+ return stateDir ? join8(stateDir, "logs") : join8(frizzPaths({ home }).state, "logs");
16456
16501
  }
16457
16502
  function runStamp(at) {
16458
16503
  const pad = (value) => String(value).padStart(2, "0");
@@ -16461,11 +16506,11 @@ function runStamp(at) {
16461
16506
  function runLogPath(stateDir, at = /* @__PURE__ */ new Date(), pid = process.pid, home = homedir6(), env = process.env) {
16462
16507
  const name = `frizz-${runStamp(at)}-${pid}.log`;
16463
16508
  const override = env[LOG_PATH_ENV]?.trim();
16464
- if (override) return override.endsWith(".log") ? override : join7(override, name);
16465
- return join7(defaultLogRoot(stateDir, home), name);
16509
+ if (override) return override.endsWith(".log") ? override : join8(override, name);
16510
+ return join8(defaultLogRoot(stateDir, home), name);
16466
16511
  }
16467
16512
  function latestLogPath(dir) {
16468
- return join7(dir, "latest.log");
16513
+ return join8(dir, "latest.log");
16469
16514
  }
16470
16515
  function linkLatest(dir, target) {
16471
16516
  const link = latestLogPath(dir);
@@ -16489,7 +16534,7 @@ function pruneRunLogs(dir, keep = RETAINED_RUNS, days = RETAINED_DAYS, now = Dat
16489
16534
  }
16490
16535
  const dated = entries.map((name) => {
16491
16536
  try {
16492
- return { name, at: statSync3(join7(dir, name)).mtimeMs };
16537
+ return { name, at: statSync3(join8(dir, name)).mtimeMs };
16493
16538
  } catch {
16494
16539
  return { name, at: 0 };
16495
16540
  }
@@ -16498,7 +16543,7 @@ function pruneRunLogs(dir, keep = RETAINED_RUNS, days = RETAINED_DAYS, now = Dat
16498
16543
  const stale = dated.filter((entry, index) => index >= keep || entry.at < cutoff);
16499
16544
  for (const entry of stale) {
16500
16545
  try {
16501
- rmSync5(join7(dir, entry.name), { force: true });
16546
+ rmSync5(join8(dir, entry.name), { force: true });
16502
16547
  } catch {
16503
16548
  }
16504
16549
  }
@@ -16512,7 +16557,7 @@ function formatDiskLine(record) {
16512
16557
  }
16513
16558
  function openLogFile(path) {
16514
16559
  try {
16515
- mkdirSync6(join7(path, ".."), { recursive: true, mode: 448 });
16560
+ mkdirSync6(join8(path, ".."), { recursive: true, mode: 448 });
16516
16561
  return openSync5(path, "a", 384);
16517
16562
  } catch {
16518
16563
  return null;
@@ -16526,7 +16571,7 @@ function createLogger(options = {}) {
16526
16571
  const maxBytes = options.maxBytes ?? MAX_LOG_BYTES;
16527
16572
  let fd = path === null ? null : openLogFile(path);
16528
16573
  if (fd !== null && path !== null && options.owner !== false) {
16529
- const dir = join7(path, "..");
16574
+ const dir = join8(path, "..");
16530
16575
  pruneRunLogs(dir);
16531
16576
  linkLatest(dir, path);
16532
16577
  }
@@ -19475,9 +19520,9 @@ var init_storage = __esm({
19475
19520
 
19476
19521
  // packages/server/src/settings.ts
19477
19522
  import { closeSync as closeSync5, fsyncSync as fsyncSync5, mkdirSync as mkdirSync7, openSync as openSync6, readFileSync as readFileSync6, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "node:fs";
19478
- import { dirname as dirname6, join as join8 } from "node:path";
19523
+ import { dirname as dirname6, join as join9 } from "node:path";
19479
19524
  function machineSettingsPath(home) {
19480
- return join8(frizzPaths({ home }).data, "settings.json");
19525
+ return join9(frizzPaths({ home }).data, "settings.json");
19481
19526
  }
19482
19527
  function pickMachine(settings) {
19483
19528
  return Object.fromEntries(MACHINE_KEYS.map((key) => [key, settings[key]]));
@@ -19500,13 +19545,15 @@ function pickPresent(partial) {
19500
19545
  return out;
19501
19546
  }
19502
19547
  function writeMachineSettings(next, home) {
19503
- const path = machineSettingsPath(home);
19548
+ writeMachineFile(machineSettingsPath(home), next);
19549
+ }
19550
+ function writeMachineFile(path, value) {
19504
19551
  mkdirSync7(dirname6(path), { recursive: true });
19505
19552
  const temp = `${path}.${process.pid}.tmp`;
19506
19553
  let fd;
19507
19554
  try {
19508
19555
  fd = openSync6(temp, "w", 384);
19509
- writeFileSync6(fd, `${JSON.stringify(next, null, 2)}
19556
+ writeFileSync6(fd, `${JSON.stringify(value, null, 2)}
19510
19557
  `, "utf8");
19511
19558
  fsyncSync5(fd);
19512
19559
  closeSync5(fd);
@@ -19569,9 +19616,90 @@ var init_settings = __esm({
19569
19616
  }
19570
19617
  });
19571
19618
 
19619
+ // packages/server/src/dispatch-preferences.ts
19620
+ import { readFileSync as readFileSync7 } from "node:fs";
19621
+ import { join as join10 } from "node:path";
19622
+ function machineDispatchPreferencesPath(home) {
19623
+ return join10(frizzPaths({ home }).data, "dispatch-preferences.json");
19624
+ }
19625
+ function readMachineDispatchPreferences(home) {
19626
+ let raw2;
19627
+ try {
19628
+ raw2 = JSON.parse(readFileSync7(machineDispatchPreferencesPath(home), "utf8"));
19629
+ } catch {
19630
+ return void 0;
19631
+ }
19632
+ const parsed = DispatchPreferences.safeParse(raw2);
19633
+ return parsed.success ? parsed.data : void 0;
19634
+ }
19635
+ function permissionFor(backend, mode) {
19636
+ if (backend === "codex") {
19637
+ if (mode === "plan" || mode === "bypassPermissions") return mode;
19638
+ return "default";
19639
+ }
19640
+ return mode === "plan" ? "auto" : mode;
19641
+ }
19642
+ function defaultDispatchPreferences(settings, codexModels = []) {
19643
+ const backend = settings.backend ?? (codexModels.some((model) => model.slug === settings.model) ? "codex" : "claude");
19644
+ const selected = {
19645
+ ...settings.model ? { model: settings.model } : {},
19646
+ ...settings.effort ? { effort: settings.effort } : {},
19647
+ permissionMode: permissionFor(backend, settings.permissionMode)
19648
+ };
19649
+ return {
19650
+ backend,
19651
+ claude: backend === "claude" ? selected : { permissionMode: "auto" },
19652
+ codex: backend === "codex" ? selected : { permissionMode: "default" }
19653
+ };
19654
+ }
19655
+ function getDispatchPreferences(storage, settings, home, codexModels = []) {
19656
+ const machine = readMachineDispatchPreferences(home);
19657
+ if (machine) return machine;
19658
+ const parsed = DispatchPreferences.safeParse(storage.getSetting(KEY));
19659
+ return parsed.success ? parsed.data : defaultDispatchPreferences(settings, codexModels);
19660
+ }
19661
+ function setDispatchPreference(storage, settings, home, update, codexModels = []) {
19662
+ const current = getDispatchPreferences(storage, settings, home, codexModels);
19663
+ let next;
19664
+ if (update.field === "backend") {
19665
+ next = { ...current, backend: update.value };
19666
+ } else if (update.field === "profile") {
19667
+ next = {
19668
+ ...current,
19669
+ backend: update.backend,
19670
+ [update.backend]: {
19671
+ ...current[update.backend],
19672
+ model: update.model,
19673
+ effort: update.effort
19674
+ }
19675
+ };
19676
+ } else {
19677
+ const profile = current[update.backend];
19678
+ next = {
19679
+ ...current,
19680
+ ...update.field === "model" ? { backend: update.backend } : {},
19681
+ [update.backend]: { ...profile, [update.field]: update.value }
19682
+ };
19683
+ }
19684
+ const validated = DispatchPreferences.parse(next);
19685
+ writeMachineFile(machineDispatchPreferencesPath(home), validated);
19686
+ storage.setSetting(KEY, validated);
19687
+ return validated;
19688
+ }
19689
+ var KEY;
19690
+ var init_dispatch_preferences = __esm({
19691
+ "packages/server/src/dispatch-preferences.ts"() {
19692
+ "use strict";
19693
+ init_src();
19694
+ init_frizz_paths();
19695
+ init_settings();
19696
+ KEY = "dispatch-preferences.v1";
19697
+ }
19698
+ });
19699
+
19572
19700
  // packages/server/src/discover.ts
19573
19701
  import { readdirSync as readdirSync3, statSync as statSync4, openSync as openSync7, readSync, closeSync as closeSync6 } from "node:fs";
19574
- import { dirname as dirname7, join as join9 } from "node:path";
19702
+ import { dirname as dirname7, join as join11 } from "node:path";
19575
19703
  function sentinelFor(sessionId) {
19576
19704
  return `threads/${sessionId}/`;
19577
19705
  }
@@ -19608,7 +19736,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
19608
19736
  if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
19609
19737
  const id = name.slice(0, -".jsonl".length);
19610
19738
  if (!id || id === sessionId || exclude?.has(id)) continue;
19611
- const path = join9(logDir, name);
19739
+ const path = join11(logDir, name);
19612
19740
  let mtime;
19613
19741
  try {
19614
19742
  mtime = statSync4(path).mtimeMs;
@@ -19636,7 +19764,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
19636
19764
  const name = `${sessionId}.jsonl`;
19637
19765
  const better = (best2, dir) => {
19638
19766
  if (dir === logDir) return best2;
19639
- const at = mtimeOfNonEmpty(join9(dir, name));
19767
+ const at = mtimeOfNonEmpty(join11(dir, name));
19640
19768
  if (at === void 0) return best2;
19641
19769
  return !best2 || at > best2.mtimeMs ? { dir, mtimeMs: at } : best2;
19642
19770
  };
@@ -19649,7 +19777,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
19649
19777
  } catch {
19650
19778
  return void 0;
19651
19779
  }
19652
- for (const entry of entries) best = better(best, join9(dirname7(logDir), entry));
19780
+ for (const entry of entries) best = better(best, join11(dirname7(logDir), entry));
19653
19781
  if (!best) return void 0;
19654
19782
  memo3.add(best.dir);
19655
19783
  return best.dir;
@@ -19668,10 +19796,10 @@ var init_discover = __esm({
19668
19796
 
19669
19797
  // packages/server/src/session-files.ts
19670
19798
  import { lstatSync, rmSync as rmSync7 } from "node:fs";
19671
- import { join as join10 } from "node:path";
19799
+ import { join as join12 } from "node:path";
19672
19800
  function systemPromptPath(sessionId) {
19673
19801
  if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
19674
- return join10(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
19802
+ return join12(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
19675
19803
  }
19676
19804
  function isDirectDirectory(path) {
19677
19805
  try {
@@ -19691,7 +19819,7 @@ function pathAbsent(path) {
19691
19819
  }
19692
19820
  function unlinkDirectChild(parent, filename) {
19693
19821
  if (!isDirectDirectory(parent)) return pathAbsent(parent);
19694
- const child = join10(parent, filename);
19822
+ const child = join12(parent, filename);
19695
19823
  try {
19696
19824
  rmSync7(child, { force: true });
19697
19825
  } catch {
@@ -19701,12 +19829,12 @@ function unlinkDirectChild(parent, filename) {
19701
19829
  }
19702
19830
  function cleanupAdoptionSessionFiles(projectDir, sessionId) {
19703
19831
  if (!SESSION_ID_RE.test(sessionId)) return false;
19704
- const frizzDir = join10(projectDir, ".frizz");
19832
+ const frizzDir = join12(projectDir, ".frizz");
19705
19833
  let clean = true;
19706
19834
  if (isDirectDirectory(frizzDir)) {
19707
- const threads = join10(frizzDir, "threads");
19835
+ const threads = join12(frizzDir, "threads");
19708
19836
  if (isDirectDirectory(threads)) {
19709
- const child = join10(threads, sessionId);
19837
+ const child = join12(threads, sessionId);
19710
19838
  try {
19711
19839
  rmSync7(child, { recursive: true, force: true });
19712
19840
  } catch {
@@ -19958,10 +20086,10 @@ var init_adoption_recovery = __esm({
19958
20086
  });
19959
20087
 
19960
20088
  // packages/server/src/backend/codex-models.ts
19961
- import { join as join11 } from "node:path";
19962
- import { readFileSync as readFileSync7 } from "node:fs";
20089
+ import { join as join13 } from "node:path";
20090
+ import { readFileSync as readFileSync8 } from "node:fs";
19963
20091
  function cachePath(codexHome) {
19964
- return join11(codexHome, "models_cache.json");
20092
+ return join13(codexHome, "models_cache.json");
19965
20093
  }
19966
20094
  function toCodexModel(raw2) {
19967
20095
  if (!raw2 || typeof raw2 !== "object") return void 0;
@@ -19997,7 +20125,7 @@ function readCodexModels(codexHome = defaultCodexHome()) {
19997
20125
  if (hit && now - hit.at < TTL_MS) return hit.models;
19998
20126
  let models;
19999
20127
  try {
20000
- models = parseCodexModelsCache(readFileSync7(path, "utf8"));
20128
+ models = parseCodexModelsCache(readFileSync8(path, "utf8"));
20001
20129
  } catch {
20002
20130
  models = CODEX_MODELS_FALLBACK;
20003
20131
  }
@@ -20539,10 +20667,10 @@ var init_claude_agent_sdk_protocol = __esm({
20539
20667
  });
20540
20668
 
20541
20669
  // packages/server/src/backend/claude-broker-diagnostics.ts
20542
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, readFileSync as readFileSync8, renameSync as renameSync6, statSync as statSync5 } from "node:fs";
20543
- import { join as join12 } from "node:path";
20670
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, readFileSync as readFileSync9, renameSync as renameSync6, statSync as statSync5 } from "node:fs";
20671
+ import { join as join14 } from "node:path";
20544
20672
  function claudeBrokerDiagnosticLogPath(stateDir, sessionId) {
20545
- return join12(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
20673
+ return join14(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
20546
20674
  }
20547
20675
  function readClaudeBrokerExit(stateDir, sessionId, generation) {
20548
20676
  if (!generation) return null;
@@ -20550,7 +20678,7 @@ function readClaudeBrokerExit(stateDir, sessionId, generation) {
20550
20678
  for (const path of [`${claudeBrokerDiagnosticLogPath(stateDir, sessionId)}.1`, claudeBrokerDiagnosticLogPath(stateDir, sessionId)]) {
20551
20679
  let text;
20552
20680
  try {
20553
- text = readFileSync8(path, "utf8");
20681
+ text = readFileSync9(path, "utf8");
20554
20682
  } catch {
20555
20683
  continue;
20556
20684
  }
@@ -20614,10 +20742,10 @@ var init_detached_daemons = __esm({
20614
20742
  });
20615
20743
 
20616
20744
  // packages/server/src/backend/ipc-path.ts
20617
- import { join as join13 } from "node:path";
20745
+ import { join as join15 } from "node:path";
20618
20746
  function frizzIpcPath(name) {
20619
20747
  if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
20620
- return join13(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
20748
+ return join15(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
20621
20749
  }
20622
20750
  var init_ipc_path = __esm({
20623
20751
  "packages/server/src/backend/ipc-path.ts"() {
@@ -20628,18 +20756,18 @@ var init_ipc_path = __esm({
20628
20756
  // packages/server/src/backend/claude-broker-host.ts
20629
20757
  import { spawn } from "node:child_process";
20630
20758
  import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
20631
- import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
20632
- import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as join14 } from "node:path";
20759
+ import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as readFileSync10, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
20760
+ import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as join16 } from "node:path";
20633
20761
  function windowsShimTarget(shimPath) {
20634
20762
  let body;
20635
20763
  try {
20636
- body = readFileSync9(shimPath, "utf8");
20764
+ body = readFileSync10(shimPath, "utf8");
20637
20765
  } catch {
20638
20766
  return void 0;
20639
20767
  }
20640
20768
  const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
20641
20769
  if (!target) return void 0;
20642
- const full = join14(dirname8(shimPath), target);
20770
+ const full = join16(dirname8(shimPath), target);
20643
20771
  try {
20644
20772
  accessSync(full, fsConstants.F_OK);
20645
20773
  return full;
@@ -20660,17 +20788,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
20660
20788
  for (const dir of searchPath(env).split(delimiter)) {
20661
20789
  if (!dir) continue;
20662
20790
  if (windows) {
20663
- const exe = join14(dir, `${candidate}.exe`);
20791
+ const exe = join16(dir, `${candidate}.exe`);
20664
20792
  try {
20665
20793
  accessSync(exe, fsConstants.F_OK);
20666
20794
  return exe;
20667
20795
  } catch {
20668
20796
  }
20669
- const viaShim = windowsShimTarget(join14(dir, `${candidate}.cmd`));
20797
+ const viaShim = windowsShimTarget(join16(dir, `${candidate}.cmd`));
20670
20798
  if (viaShim) return viaShim;
20671
20799
  continue;
20672
20800
  }
20673
- const full = join14(dir, candidate);
20801
+ const full = join16(dir, candidate);
20674
20802
  try {
20675
20803
  accessSync(full, fsConstants.X_OK);
20676
20804
  return full;
@@ -20685,11 +20813,11 @@ function claudeBrokerSocketPath(stateDir, sessionId) {
20685
20813
  }
20686
20814
  function claudeBrokerRecordPath(stateDir, sessionId) {
20687
20815
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
20688
- return join14(stateDir, "claude-broker", `${key}.json`);
20816
+ return join16(stateDir, "claude-broker", `${key}.json`);
20689
20817
  }
20690
20818
  function claudeBrokerRetirementPath(stateDir, sessionId) {
20691
20819
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
20692
- return join14(stateDir, "claude-broker", `${key}.retired`);
20820
+ return join16(stateDir, "claude-broker", `${key}.retired`);
20693
20821
  }
20694
20822
  function markBrokerRetired(stateDir, sessionId, reason, generation) {
20695
20823
  const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
@@ -20704,7 +20832,7 @@ function takeBrokerRetirement(stateDir, sessionId) {
20704
20832
  const path = claudeBrokerRetirementPath(stateDir, sessionId);
20705
20833
  let mark = null;
20706
20834
  try {
20707
- const parsed = JSON.parse(readFileSync9(path, "utf8"));
20835
+ const parsed = JSON.parse(readFileSync10(path, "utf8"));
20708
20836
  if (typeof parsed?.at === "string" && typeof parsed.generation === "string" && typeof parsed.reason === "string") {
20709
20837
  mark = { at: parsed.at, generation: parsed.generation, reason: parsed.reason };
20710
20838
  }
@@ -20726,7 +20854,7 @@ function pidAlive(pid) {
20726
20854
  }
20727
20855
  function readBrokerRecord(recordPath2) {
20728
20856
  try {
20729
- return JSON.parse(readFileSync9(recordPath2, "utf8"));
20857
+ return JSON.parse(readFileSync10(recordPath2, "utf8"));
20730
20858
  } catch {
20731
20859
  return null;
20732
20860
  }
@@ -20756,7 +20884,7 @@ function liveBrokerRecord(recordPath2) {
20756
20884
  return null;
20757
20885
  }
20758
20886
  function liveBrokerRecords(stateDir) {
20759
- const dir = join14(stateDir, "claude-broker");
20887
+ const dir = join16(stateDir, "claude-broker");
20760
20888
  let names;
20761
20889
  try {
20762
20890
  names = readdirSync4(dir);
@@ -20766,7 +20894,7 @@ function liveBrokerRecords(stateDir) {
20766
20894
  const out = [];
20767
20895
  for (const name of names) {
20768
20896
  if (!name.endsWith(".json")) continue;
20769
- const record = liveBrokerRecord(join14(dir, name));
20897
+ const record = liveBrokerRecord(join16(dir, name));
20770
20898
  if (record) out.push(record);
20771
20899
  }
20772
20900
  return out;
@@ -21574,15 +21702,15 @@ var init_completion_relay = __esm({
21574
21702
 
21575
21703
  // packages/server/src/tail-cache.ts
21576
21704
  import { createHash as createHash6 } from "node:crypto";
21577
- import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync10, readSync as readSync3, statSync as statSync7 } from "node:fs";
21578
- import { join as join15 } from "node:path";
21705
+ import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync11, readSync as readSync3, statSync as statSync7 } from "node:fs";
21706
+ import { join as join17 } from "node:path";
21579
21707
  function foldSchemaDigest(dir = import.meta.dirname) {
21580
21708
  if (foldSchemaMemo) return foldSchemaMemo;
21581
21709
  const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
21582
21710
  let read = 0;
21583
21711
  for (const name of FOLD_SOURCES) {
21584
21712
  try {
21585
- hash.update(name).update("\0").update(readFileSync10(join15(dir, name)));
21713
+ hash.update(name).update("\0").update(readFileSync11(join17(dir, name)));
21586
21714
  read++;
21587
21715
  } catch {
21588
21716
  hash.update(name).update("\0missing\0");
@@ -21778,9 +21906,9 @@ var init_tail_cache = __esm({
21778
21906
  });
21779
21907
 
21780
21908
  // packages/server/src/tailer.ts
21781
- 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";
21909
+ import { statSync as statSync8, openSync as openSync10, readSync as readSync4, closeSync as closeSync9, readdirSync as readdirSync5, realpathSync as realpathSync5, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as readFileSync12, existsSync as existsSync5 } from "node:fs";
21782
21910
  import { execFileSync as execFileSync4 } from "node:child_process";
21783
- import { basename as basename4, join as join16 } from "node:path";
21911
+ import { basename as basename4, join as join18 } from "node:path";
21784
21912
  import { homedir as homedir7 } from "node:os";
21785
21913
  function probeShellAlive(outputFile) {
21786
21914
  if (!existsSync5(outputFile)) return void 0;
@@ -22042,7 +22170,7 @@ function launchTaskId(text) {
22042
22170
  function readDescendantSidecars(sessionDir, mtimeMs) {
22043
22171
  let names;
22044
22172
  try {
22045
- names = readdirSync5(join16(sessionDir, "subagents"));
22173
+ names = readdirSync5(join18(sessionDir, "subagents"));
22046
22174
  } catch {
22047
22175
  return [];
22048
22176
  }
@@ -22053,7 +22181,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
22053
22181
  if (!agentId) continue;
22054
22182
  let parsed;
22055
22183
  try {
22056
- parsed = JSON.parse(readFileSync11(join16(sessionDir, "subagents", name), "utf8"));
22184
+ parsed = JSON.parse(readFileSync12(join18(sessionDir, "subagents", name), "utf8"));
22057
22185
  } catch {
22058
22186
  continue;
22059
22187
  }
@@ -22067,7 +22195,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
22067
22195
  agentType: text(meta.agentType),
22068
22196
  parentAgentId: text(meta.parentAgentId),
22069
22197
  spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
22070
- spawnedAtMs: mtimeMs(join16(sessionDir, "subagents", name))
22198
+ spawnedAtMs: mtimeMs(join18(sessionDir, "subagents", name))
22071
22199
  });
22072
22200
  }
22073
22201
  return out;
@@ -22547,13 +22675,13 @@ function defaultMtimeMs(path) {
22547
22675
  }
22548
22676
  }
22549
22677
  function defaultLogDir(project) {
22550
- return join16(homedir7(), ".claude", "projects", project.cwdSlug);
22678
+ return join18(homedir7(), ".claude", "projects", project.cwdSlug);
22551
22679
  }
22552
22680
  function defaultReadPermMarker(project) {
22553
22681
  if (!project.stateDir) return () => void 0;
22554
22682
  return (slug) => {
22555
22683
  try {
22556
- const parsed = JSON.parse(readFileSync11(permMarkerPath(project, slug), "utf8"));
22684
+ const parsed = JSON.parse(readFileSync12(permMarkerPath(project, slug), "utf8"));
22557
22685
  return isPermMarker(parsed) ? parsed : void 0;
22558
22686
  } catch {
22559
22687
  return void 0;
@@ -22593,6 +22721,7 @@ function rowIsArchived(row) {
22593
22721
  }
22594
22722
  function createTailer(deps) {
22595
22723
  const now = deps.now ?? Date.now;
22724
+ const monotonicNow = deps.monotonicNow ?? (() => performance.now());
22596
22725
  const paneDead = deps.paneDead ?? (() => true);
22597
22726
  const brokerDaemonAlive = deps.brokerDaemonAlive ?? defaultBrokerDaemonAlive(deps.project, now);
22598
22727
  const logDir = deps.sessionLogDir ?? defaultLogDir(deps.project);
@@ -22678,7 +22807,7 @@ function createTailer(deps) {
22678
22807
  return paneDead(row.slug);
22679
22808
  }
22680
22809
  const defaultBackend = {
22681
- transcriptPath: (sessionId) => join16(logDir, `${sessionId}.jsonl`),
22810
+ transcriptPath: (sessionId) => join18(logDir, `${sessionId}.jsonl`),
22682
22811
  foldLine: (state, line) => {
22683
22812
  const rec = parseLine(line);
22684
22813
  if (rec) applyRecord(state, rec);
@@ -22803,7 +22932,7 @@ ${ask}`;
22803
22932
  return state.path.replace(/\.jsonl$/, "");
22804
22933
  }
22805
22934
  function descendantSidecars(state) {
22806
- const at = mtimeMs(join16(sessionDirOf(state), "subagents"));
22935
+ const at = mtimeMs(join18(sessionDirOf(state), "subagents"));
22807
22936
  const cached2 = descendantIndex.get(state.slug);
22808
22937
  if (cached2 && cached2.at === at) return cached2.all;
22809
22938
  const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
@@ -22817,7 +22946,7 @@ ${ask}`;
22817
22946
  return descendantIndex.get(state.slug)?.byToolUse.get(id);
22818
22947
  }
22819
22948
  function descendantTranscript(state, meta) {
22820
- return join16(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
22949
+ return join18(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
22821
22950
  }
22822
22951
  function subAgentDescendantTasks(slug, id) {
22823
22952
  const state = states.get(slug);
@@ -23131,7 +23260,7 @@ ${ask}`;
23131
23260
  if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
23132
23261
  const id = name.slice(0, -".jsonl".length);
23133
23262
  if (!id || registered.has(id)) continue;
23134
- const path = join16(logDir, name);
23263
+ const path = join18(logDir, name);
23135
23264
  let mtime;
23136
23265
  try {
23137
23266
  mtime = statSync8(path).mtimeMs;
@@ -23403,7 +23532,7 @@ ${ask}`;
23403
23532
  );
23404
23533
  try {
23405
23534
  mkdirSync10(stallLogDir, { recursive: true });
23406
- writeFileSync8(join16(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
23535
+ writeFileSync8(join18(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
23407
23536
  captured_at: ${new Date(now()).toISOString()}
23408
23537
 
23409
23538
  ${detail}
@@ -23431,7 +23560,7 @@ ${detail}
23431
23560
  state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
23432
23561
  const strandedDir = discoverTranscriptDir(logDir, row.session_id);
23433
23562
  if (strandedDir) {
23434
- state.path = join16(strandedDir, `${row.session_id}.jsonl`);
23563
+ state.path = join18(strandedDir, `${row.session_id}.jsonl`);
23435
23564
  state.offset = 0;
23436
23565
  state.partial = "";
23437
23566
  state.primed = false;
@@ -23454,7 +23583,7 @@ ${detail}
23454
23583
  committed = false;
23455
23584
  }
23456
23585
  if (!committed) return false;
23457
- state.path = join16(logDir, `${found}.jsonl`);
23586
+ state.path = join18(logDir, `${found}.jsonl`);
23458
23587
  state.offset = 0;
23459
23588
  state.partial = "";
23460
23589
  state.primed = false;
@@ -23490,7 +23619,7 @@ ${detail}
23490
23619
  }
23491
23620
  let primed = 0;
23492
23621
  let primedRows = 0;
23493
- const tickStartedMs = performance.now();
23622
+ const tickStartedMs = monotonicNow();
23494
23623
  primeIncomplete = false;
23495
23624
  for (const row of rows) {
23496
23625
  if (primeProgress && primed % PRIME_PROGRESS_EVERY === 0) primeProgress(primed, rows.length);
@@ -23500,7 +23629,7 @@ ${detail}
23500
23629
  let state = states.get(row.slug);
23501
23630
  const runtimeGeneration = row.runtime_generation ?? 0;
23502
23631
  if (!state || state.sessionId !== row.session_id || state.nativeSessionId !== nativeId || state.runtimeGeneration !== runtimeGeneration) {
23503
- const path = backend.transcriptPath(nativeId) ?? join16(logDir, `${nativeId}.jsonl`);
23632
+ const path = backend.transcriptPath(nativeId) ?? join18(logDir, `${nativeId}.jsonl`);
23504
23633
  state = newTailState(row.slug, row.session_id, path, false, nativeId, runtimeGeneration);
23505
23634
  state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
23506
23635
  hydrateFromCache(state, row, nativeId);
@@ -23518,7 +23647,7 @@ ${detail}
23518
23647
  // guarantee below. `primedRows > 0` keeps the archive advancing by at least one row per tick
23519
23648
  // even if a visible row were somehow to stay cold indefinitely, so deferral can never become
23520
23649
  // starvation. The visible row still primes on this same tick; it just is not necessarily first.
23521
- coldVisibleRow && primedRows > 0 && rowIsArchived(row) || primedRows >= MAX_PRIME_ROWS_PER_TICK || primedRows > 0 && performance.now() - tickStartedMs > PRIME_BUDGET_MS
23650
+ coldVisibleRow && primedRows > 0 && rowIsArchived(row) || primedRows >= MAX_PRIME_ROWS_PER_TICK || primedRows > 0 && monotonicNow() - tickStartedMs > PRIME_BUDGET_MS
23522
23651
  ) {
23523
23652
  primeIncomplete = true;
23524
23653
  continue;
@@ -23721,11 +23850,11 @@ ${detail}
23721
23850
  let lastTickMs = 0;
23722
23851
  let primeIncomplete = false;
23723
23852
  function tickWithBudget() {
23724
- const started = performance.now();
23853
+ const started = monotonicNow();
23725
23854
  try {
23726
23855
  tick();
23727
23856
  } finally {
23728
- const elapsed = performance.now() - started;
23857
+ const elapsed = monotonicNow() - started;
23729
23858
  lastTickMs = elapsed;
23730
23859
  lastTickEndedAtMs = now();
23731
23860
  if (elapsed > POLL_MS2) {
@@ -23949,14 +24078,14 @@ var init_tailer = __esm({
23949
24078
  });
23950
24079
 
23951
24080
  // packages/server/src/backend/codex.ts
23952
- import { join as join17 } from "node:path";
24081
+ import { join as join19 } from "node:path";
23953
24082
  import { homedir as homedir8 } from "node:os";
23954
- import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync12, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
24083
+ import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync13, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
23955
24084
  function defaultCodexHome() {
23956
- return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join17(homedir8(), ".codex");
24085
+ return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join19(homedir8(), ".codex");
23957
24086
  }
23958
24087
  function sessionsDir(codexHome) {
23959
- return join17(codexHome, "sessions");
24088
+ return join19(codexHome, "sessions");
23960
24089
  }
23961
24090
  function codexSandbox(mode) {
23962
24091
  switch (mode) {
@@ -24337,17 +24466,17 @@ function collectRollouts(dir, out, budget) {
24337
24466
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).sort(descByName);
24338
24467
  for (const d of dirs) {
24339
24468
  if (budget.n <= 0) return;
24340
- collectRollouts(join17(dir, d.name), out, budget);
24469
+ collectRollouts(join19(dir, d.name), out, budget);
24341
24470
  }
24342
24471
  for (const f of files) {
24343
24472
  if (budget.n <= 0) return;
24344
24473
  let mtimeMs;
24345
24474
  try {
24346
- mtimeMs = statSync9(join17(dir, f.name)).mtimeMs;
24475
+ mtimeMs = statSync9(join19(dir, f.name)).mtimeMs;
24347
24476
  } catch {
24348
24477
  continue;
24349
24478
  }
24350
- out.push({ path: join17(dir, f.name), mtimeMs });
24479
+ out.push({ path: join19(dir, f.name), mtimeMs });
24351
24480
  budget.n--;
24352
24481
  }
24353
24482
  }
@@ -24391,9 +24520,9 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
24391
24520
  const out = /* @__PURE__ */ new Map();
24392
24521
  let raw2;
24393
24522
  try {
24394
- const path = join17(codexHome, "session_index.jsonl");
24523
+ const path = join19(codexHome, "session_index.jsonl");
24395
24524
  if (statSync9(path).size > SESSION_INDEX_MAX_BYTES) return out;
24396
- raw2 = readFileSync12(path, "utf8");
24525
+ raw2 = readFileSync13(path, "utf8");
24397
24526
  } catch {
24398
24527
  return out;
24399
24528
  }
@@ -28429,16 +28558,16 @@ var init_wrapper = __esm({
28429
28558
 
28430
28559
  // packages/server/src/worker-plugin-dir.ts
28431
28560
  import { existsSync as existsSync6 } from "node:fs";
28432
- import { dirname as dirname9, join as join18 } from "node:path";
28561
+ import { dirname as dirname9, join as join20 } from "node:path";
28433
28562
  import { fileURLToPath as fileURLToPath2 } from "node:url";
28434
28563
  function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
28435
28564
  const override = env.FRIZZ_WORKER_PLUGIN_DIR;
28436
- if (override && existsSync6(join18(override, ".claude-plugin", "plugin.json")))
28565
+ if (override && existsSync6(join20(override, ".claude-plugin", "plugin.json")))
28437
28566
  return override;
28438
28567
  let current = dirname9(fileURLToPath2(moduleUrl));
28439
28568
  for (; ; ) {
28440
- const candidate = join18(current, "cc-worker");
28441
- if (existsSync6(join18(candidate, ".claude-plugin", "plugin.json"))) return candidate;
28569
+ const candidate = join20(current, "cc-worker");
28570
+ if (existsSync6(join20(candidate, ".claude-plugin", "plugin.json"))) return candidate;
28442
28571
  const parent = dirname9(current);
28443
28572
  if (parent === current) return void 0;
28444
28573
  current = parent;
@@ -28452,7 +28581,7 @@ var init_worker_plugin_dir = __esm({
28452
28581
 
28453
28582
  // packages/server/src/backend/types.ts
28454
28583
  import { existsSync as existsSync7 } from "node:fs";
28455
- import { join as join19 } from "node:path";
28584
+ import { join as join21 } from "node:path";
28456
28585
  function frizzMcpEnv(mcp) {
28457
28586
  return {
28458
28587
  FRIZZ_STATE_DIR: mcp.stateDir,
@@ -28476,7 +28605,7 @@ function chromeDevtoolsMcpMount() {
28476
28605
  function resolveBrowserMcpScript(moduleUrl = import.meta.url, env = process.env) {
28477
28606
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
28478
28607
  if (!pluginDir) return void 0;
28479
- const scriptPath = join19(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28608
+ const scriptPath = join21(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28480
28609
  return existsSync7(scriptPath) ? scriptPath : void 0;
28481
28610
  }
28482
28611
  function workerCap(name, lifted, env) {
@@ -28574,15 +28703,15 @@ import { spawn as spawn2 } from "node:child_process";
28574
28703
  import { connect } from "node:net";
28575
28704
  import { Agent as HttpAgent } from "node:http";
28576
28705
  import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
28577
- import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync13, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
28578
- import { join as join20 } from "node:path";
28706
+ import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
28707
+ import { join as join22 } from "node:path";
28579
28708
  import { PassThrough, Writable } from "node:stream";
28580
28709
  import { StringDecoder } from "node:string_decoder";
28581
28710
  function nativeDir(stateDir) {
28582
- return join20(stateDir, "codex-app-server-native");
28711
+ return join22(stateDir, "codex-app-server-native");
28583
28712
  }
28584
28713
  function nativeRecordPath(stateDir, projectId) {
28585
- return join20(nativeDir(stateDir), `${projectId}.json`);
28714
+ return join22(nativeDir(stateDir), `${projectId}.json`);
28586
28715
  }
28587
28716
  function nativeListenSocketPath(stateDir, projectId) {
28588
28717
  const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
@@ -28598,7 +28727,7 @@ function pidAlive2(pid) {
28598
28727
  }
28599
28728
  function readNativeRecord(stateDir, projectId) {
28600
28729
  try {
28601
- const value = JSON.parse(readFileSync13(nativeRecordPath(stateDir, projectId), "utf8"));
28730
+ const value = JSON.parse(readFileSync14(nativeRecordPath(stateDir, projectId), "utf8"));
28602
28731
  if (typeof value.listenerPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
28603
28732
  return {
28604
28733
  projectId,
@@ -28846,15 +28975,15 @@ var init_codex_app_server_native = __esm({
28846
28975
  import { spawn as spawn3, spawnSync } from "node:child_process";
28847
28976
  import { createConnection } from "node:net";
28848
28977
  import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
28849
- import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "node:fs";
28850
- import { join as join21 } from "node:path";
28978
+ import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync3 } from "node:fs";
28979
+ import { join as join23 } from "node:path";
28851
28980
  import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
28852
28981
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
28853
28982
  function daemonDir(stateDir) {
28854
- return join21(stateDir, "codex-app-server");
28983
+ return join23(stateDir, "codex-app-server");
28855
28984
  }
28856
28985
  function recordPath(stateDir, projectId) {
28857
- return join21(daemonDir(stateDir), `${projectId}.json`);
28986
+ return join23(daemonDir(stateDir), `${projectId}.json`);
28858
28987
  }
28859
28988
  function codexAppServerSocketPath(stateDir, projectId) {
28860
28989
  const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
@@ -28870,7 +28999,7 @@ function pidAlive3(pid) {
28870
28999
  }
28871
29000
  function readDaemonRecord(stateDir, projectId) {
28872
29001
  try {
28873
- const value = JSON.parse(readFileSync14(recordPath(stateDir, projectId), "utf8"));
29002
+ const value = JSON.parse(readFileSync15(recordPath(stateDir, projectId), "utf8"));
28874
29003
  if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
28875
29004
  return {
28876
29005
  projectId,
@@ -28886,7 +29015,7 @@ function readDaemonRecord(stateDir, projectId) {
28886
29015
  }
28887
29016
  function readDaemonExitBreadcrumb(stateDir, projectId) {
28888
29017
  try {
28889
- const value = JSON.parse(readFileSync14(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
29018
+ const value = JSON.parse(readFileSync15(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
28890
29019
  if (typeof value.generation !== "string" || typeof value.reason !== "string") return null;
28891
29020
  return {
28892
29021
  generation: value.generation,
@@ -32082,11 +32211,11 @@ var init_codex_app_server = __esm({
32082
32211
  });
32083
32212
 
32084
32213
  // packages/server/src/backend/codex-quota.ts
32085
- import { join as join22 } from "node:path";
32214
+ import { join as join24 } from "node:path";
32086
32215
  import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
32087
32216
  import { spawn as spawn4 } from "node:child_process";
32088
32217
  function sessionsDir2(codexHome) {
32089
- return join22(codexHome, "sessions");
32218
+ return join24(codexHome, "sessions");
32090
32219
  }
32091
32220
  function newestRollouts(dir, out, budget) {
32092
32221
  if (budget.n <= 0) return;
@@ -32100,11 +32229,11 @@ function newestRollouts(dir, out, budget) {
32100
32229
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
32101
32230
  for (const d of dirs) {
32102
32231
  if (budget.n <= 0) return;
32103
- newestRollouts(join22(dir, d), out, budget);
32232
+ newestRollouts(join24(dir, d), out, budget);
32104
32233
  }
32105
32234
  for (const f of files) {
32106
32235
  if (budget.n <= 0) return;
32107
- out.push(join22(dir, f));
32236
+ out.push(join24(dir, f));
32108
32237
  budget.n--;
32109
32238
  }
32110
32239
  }
@@ -32304,7 +32433,7 @@ var init_codex_quota = __esm({
32304
32433
  });
32305
32434
 
32306
32435
  // packages/server/src/backend/claude-quota.ts
32307
- import { join as join23 } from "node:path";
32436
+ import { join as join25 } from "node:path";
32308
32437
  import { homedir as homedir9, platform } from "node:os";
32309
32438
  import { createHash as createHash10 } from "node:crypto";
32310
32439
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -32312,7 +32441,7 @@ import { execFile as execFile2 } from "node:child_process";
32312
32441
  import { promisify as promisify2 } from "node:util";
32313
32442
  function claudeConfigDir() {
32314
32443
  const override = process.env.CLAUDE_CONFIG_DIR;
32315
- return override && override.trim() ? override : join23(homedir9(), ".claude");
32444
+ return override && override.trim() ? override : join25(homedir9(), ".claude");
32316
32445
  }
32317
32446
  function tokenFromCredentialsJson(raw2) {
32318
32447
  let doc;
@@ -32341,7 +32470,7 @@ async function readKeychainToken() {
32341
32470
  }
32342
32471
  async function readAccessToken(configDir) {
32343
32472
  try {
32344
- const fromFile = tokenFromCredentialsJson(await readFile(join23(configDir, ".credentials.json"), "utf8"));
32473
+ const fromFile = tokenFromCredentialsJson(await readFile(join25(configDir, ".credentials.json"), "utf8"));
32345
32474
  if (fromFile) return fromFile;
32346
32475
  } catch {
32347
32476
  }
@@ -32410,8 +32539,8 @@ function parseClaudeUsage(body, planType) {
32410
32539
  function cachePaths(cacheDir, configDir) {
32411
32540
  const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
32412
32541
  return {
32413
- data: join23(cacheDir, `claude-${profile}.json`),
32414
- lock: join23(cacheDir, `claude-${profile}.lock`)
32542
+ data: join25(cacheDir, `claude-${profile}.json`),
32543
+ lock: join25(cacheDir, `claude-${profile}.lock`)
32415
32544
  };
32416
32545
  }
32417
32546
  async function readShared(path) {
@@ -32607,7 +32736,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
32607
32736
  async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32608
32737
  const now = (deps.now ?? Date.now)();
32609
32738
  const configDir = claudeConfigDir();
32610
- const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32739
+ const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
32611
32740
  try {
32612
32741
  await mkdir(cacheDir, { recursive: true, mode: 448 });
32613
32742
  } catch {
@@ -32618,7 +32747,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32618
32747
  async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
32619
32748
  const now = (deps.now ?? Date.now)();
32620
32749
  const configDir = claudeConfigDir();
32621
- const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32750
+ const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
32622
32751
  const paths = cachePaths(cacheDir, configDir);
32623
32752
  try {
32624
32753
  await mkdir(cacheDir, { recursive: true, mode: 448 });
@@ -32778,7 +32907,7 @@ var init_quota = __esm({
32778
32907
  // packages/server/src/frizz.ts
32779
32908
  import { execFile as execFile3 } from "node:child_process";
32780
32909
  import { lstatSync as lstatSync2, realpathSync as realpathSync6 } from "node:fs";
32781
- import { basename as basename5, dirname as dirname10, join as join24, resolve as resolve4 } from "node:path";
32910
+ import { basename as basename5, dirname as dirname10, join as join26, resolve as resolve4 } from "node:path";
32782
32911
  import { promisify as promisify3 } from "node:util";
32783
32912
  function frizzScriptsDir() {
32784
32913
  if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
@@ -32787,7 +32916,7 @@ function frizzScriptsDir() {
32787
32916
  function directFrizzRoot(projectDir) {
32788
32917
  try {
32789
32918
  const projectRoot = realpathSync6(projectDir);
32790
- const path = join24(projectRoot, ".frizz");
32919
+ const path = join26(projectRoot, ".frizz");
32791
32920
  const stat2 = lstatSync2(path);
32792
32921
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
32793
32922
  const real = realpathSync6(path);
@@ -32801,7 +32930,7 @@ function frizzDirExists(projectDir) {
32801
32930
  }
32802
32931
  async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32803
32932
  if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
32804
- const { stdout } = await execFileP("node", [join24(scriptsDir, "index.mjs"), "--json"], {
32933
+ const { stdout } = await execFileP("node", [join26(scriptsDir, "index.mjs"), "--json"], {
32805
32934
  cwd: projectDir,
32806
32935
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
32807
32936
  maxBuffer: 32 * 1024 * 1024
@@ -32826,7 +32955,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32826
32955
  };
32827
32956
  }
32828
32957
  async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
32829
- await execFileP("node", [join24(scriptsDir, "thread-update.mjs"), slug, ...args], {
32958
+ await execFileP("node", [join26(scriptsDir, "thread-update.mjs"), slug, ...args], {
32830
32959
  cwd: projectDir,
32831
32960
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
32832
32961
  });
@@ -34711,19 +34840,19 @@ var init_claude_agent_broker_bridge = __esm({
34711
34840
  });
34712
34841
 
34713
34842
  // packages/server/src/backend/auth-status.ts
34714
- import { join as join25 } from "node:path";
34843
+ import { join as join27 } from "node:path";
34715
34844
  import { homedir as homedir11, platform as platform2 } from "node:os";
34716
- import { readFileSync as readFileSync15, statSync as statSync11 } from "node:fs";
34845
+ import { readFileSync as readFileSync16, statSync as statSync11 } from "node:fs";
34717
34846
  import { execFile as execFile4 } from "node:child_process";
34718
34847
  import { promisify as promisify4 } from "node:util";
34719
34848
  function claudeConfigDir2() {
34720
34849
  const override = process.env.CLAUDE_CONFIG_DIR;
34721
- return override && override.trim() ? override : join25(homedir11(), ".claude");
34850
+ return override && override.trim() ? override : join27(homedir11(), ".claude");
34722
34851
  }
34723
34852
  function claudeFileState(configDir) {
34724
34853
  let raw2;
34725
34854
  try {
34726
- raw2 = readFileSync15(join25(configDir, ".credentials.json"), "utf8");
34855
+ raw2 = readFileSync16(join27(configDir, ".credentials.json"), "utf8");
34727
34856
  } catch (err) {
34728
34857
  return err.code === "ENOENT" ? "absent" : "error";
34729
34858
  }
@@ -34756,7 +34885,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
34756
34885
  if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
34757
34886
  let raw2;
34758
34887
  try {
34759
- raw2 = readFileSync15(join25(codexHome, "auth.json"), "utf8");
34888
+ raw2 = readFileSync16(join27(codexHome, "auth.json"), "utf8");
34760
34889
  } catch (err) {
34761
34890
  return err.code === "ENOENT" ? "signed-out" : "unknown";
34762
34891
  }
@@ -34821,7 +34950,7 @@ function asEmail(value) {
34821
34950
  }
34822
34951
  function claudeAccountFile() {
34823
34952
  const override = process.env.CLAUDE_CONFIG_DIR;
34824
- return override && override.trim() ? join25(override, ".claude.json") : join25(homedir11(), ".claude.json");
34953
+ return override && override.trim() ? join27(override, ".claude.json") : join27(homedir11(), ".claude.json");
34825
34954
  }
34826
34955
  function readClaudeAccountEmail(path = claudeAccountFile()) {
34827
34956
  let stat2;
@@ -34834,7 +34963,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
34834
34963
  if (memo3 && memo3.path === path && memo3.mtimeMs === stat2.mtimeMs && memo3.size === stat2.size) return memo3.email;
34835
34964
  let email;
34836
34965
  try {
34837
- const doc = JSON.parse(readFileSync15(path, "utf8"));
34966
+ const doc = JSON.parse(readFileSync16(path, "utf8"));
34838
34967
  email = asEmail(doc?.oauthAccount?.emailAddress);
34839
34968
  } catch {
34840
34969
  email = void 0;
@@ -34845,7 +34974,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
34845
34974
  function readCodexAccountEmail(codexHome = defaultCodexHome()) {
34846
34975
  let doc;
34847
34976
  try {
34848
- doc = JSON.parse(readFileSync15(join25(codexHome, "auth.json"), "utf8"));
34977
+ doc = JSON.parse(readFileSync16(join27(codexHome, "auth.json"), "utf8"));
34849
34978
  } catch {
34850
34979
  return void 0;
34851
34980
  }
@@ -34913,8 +35042,8 @@ var init_auth_status = __esm({
34913
35042
  });
34914
35043
 
34915
35044
  // packages/server/src/dispatch.ts
34916
- 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";
34917
- import { basename as basename6, join as join26, dirname as dirname11 } from "node:path";
35045
+ import { closeSync as closeSync12, constants, existsSync as existsSync10, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync17, realpathSync as realpathSync7, statSync as statSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync8 } from "node:fs";
35046
+ import { basename as basename6, join as join28, dirname as dirname11 } from "node:path";
34918
35047
  import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
34919
35048
  function fallbackTitle(prompt) {
34920
35049
  const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
@@ -34933,7 +35062,7 @@ function fallbackTitle(prompt) {
34933
35062
  }
34934
35063
  function resolveSlug(frizzDir, base, taken) {
34935
35064
  base = ThreadSlug.parse(base);
34936
- const isTaken = (slug) => existsSync10(join26(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
35065
+ const isTaken = (slug) => existsSync10(join28(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
34937
35066
  if (!isTaken(base)) return base;
34938
35067
  for (let n = 2; ; n++) {
34939
35068
  const suffix = `-${n}`;
@@ -34950,12 +35079,12 @@ function resolveLegacyThreadFile(projectDir, value) {
34950
35079
  if (!parsed.success) return null;
34951
35080
  try {
34952
35081
  const projectRoot = realpathSync7(projectDir);
34953
- const frizzPath = join26(projectRoot, ".frizz");
35082
+ const frizzPath = join28(projectRoot, ".frizz");
34954
35083
  const frizzStat = lstatSync3(frizzPath);
34955
35084
  if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
34956
35085
  const realFrizz = realpathSync7(frizzPath);
34957
35086
  if (dirname11(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
34958
- const path = join26(realFrizz, `${parsed.data}.md`);
35087
+ const path = join28(realFrizz, `${parsed.data}.md`);
34959
35088
  const before = lstatSync3(path);
34960
35089
  if (!before.isFile() || before.isSymbolicLink()) return null;
34961
35090
  const realPath = realpathSync7(path);
@@ -34966,7 +35095,7 @@ function resolveLegacyThreadFile(projectDir, value) {
34966
35095
  const fd = openSync13(path, constants.O_RDONLY | constants.O_NOFOLLOW);
34967
35096
  try {
34968
35097
  openedBefore = fstatSync2(fd);
34969
- contents = readFileSync16(fd);
35098
+ contents = readFileSync17(fd);
34970
35099
  openedAfter = fstatSync2(fd);
34971
35100
  } finally {
34972
35101
  closeSync12(fd);
@@ -34999,7 +35128,7 @@ function boardAuthorizesAdoption(board, slug) {
34999
35128
  return !board.errorItems.some((item) => item.file === `${slug}.md`);
35000
35129
  }
35001
35130
  function ensureSafeDirectDirectory(parent, name) {
35002
- const path = join26(parent, name);
35131
+ const path = join28(parent, name);
35003
35132
  try {
35004
35133
  mkdirSync13(path);
35005
35134
  } catch (error) {
@@ -35029,8 +35158,8 @@ function loadWorkerPrompt(kind = "claude") {
35029
35158
  function monitorScriptsDir() {
35030
35159
  const plugin = workerPluginDir();
35031
35160
  if (!plugin) return void 0;
35032
- const dir = join26(plugin, "skills", "gh", "scripts");
35033
- return existsSync10(join26(dir, "ci-watch.mjs")) ? dir : void 0;
35161
+ const dir = join28(plugin, "skills", "gh", "scripts");
35162
+ return existsSync10(join28(dir, "ci-watch.mjs")) ? dir : void 0;
35034
35163
  }
35035
35164
  function codexScratchpadHookConfig(hookScript, sessionId) {
35036
35165
  if (!hookScript || !sessionId) return {};
@@ -35042,7 +35171,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
35042
35171
  }
35043
35172
  ]
35044
35173
  });
35045
- const bashBackgroundHook = join26(dirname11(hookScript), "bash-background.mjs");
35174
+ const bashBackgroundHook = join28(dirname11(hookScript), "bash-background.mjs");
35046
35175
  return {
35047
35176
  bypass_hook_trust: true,
35048
35177
  hooks: {
@@ -35068,7 +35197,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
35068
35197
  }
35069
35198
  function scratchpadHookScript() {
35070
35199
  const plugin = workerPluginDir();
35071
- return plugin ? join26(plugin, "hooks", "scratchpad.mjs") : void 0;
35200
+ return plugin ? join28(plugin, "hooks", "scratchpad.mjs") : void 0;
35072
35201
  }
35073
35202
  function composePrompt(sessionId, prompt, kind = "claude") {
35074
35203
  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.";
@@ -35084,12 +35213,12 @@ function scratchpadOrientation(sessionId, kind = "claude") {
35084
35213
  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.`;
35085
35214
  }
35086
35215
  function frizzConfigBlock(projectDir) {
35087
- const path = join26(projectDir, "FRIZZ.md");
35216
+ const path = join28(projectDir, "FRIZZ.md");
35088
35217
  let body;
35089
35218
  try {
35090
35219
  const st = statSync12(path);
35091
35220
  if (!st.isFile() || st.size > FRIZZ_MD_MAX_BYTES) return "";
35092
- body = readFileSync16(path, "utf8").trim();
35221
+ body = readFileSync17(path, "utf8").trim();
35093
35222
  } catch {
35094
35223
  return "";
35095
35224
  }
@@ -35124,7 +35253,7 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
35124
35253
  const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
35125
35254
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
35126
35255
  if (!pluginDir) return void 0;
35127
- const scriptPath = join26(pluginDir, "bin", FRIZZ_MCP.script);
35256
+ const scriptPath = join28(pluginDir, "bin", FRIZZ_MCP.script);
35128
35257
  if (!existsSync10(scriptPath)) return void 0;
35129
35258
  return {
35130
35259
  scriptPath,
@@ -35207,7 +35336,7 @@ function buildClaudeResumeCommand(opts) {
35207
35336
  }
35208
35337
  function createDispatcher(deps) {
35209
35338
  const readBoardSource = deps.readBoard ?? readBoard;
35210
- const frizzDir = join26(deps.project.dir, ".frizz");
35339
+ const frizzDir = join28(deps.project.dir, ".frizz");
35211
35340
  const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
35212
35341
  function cleanupPrewrites(built) {
35213
35342
  for (const path of new Set(built.prewrite.map((file) => file.path))) {
@@ -35220,7 +35349,7 @@ function createDispatcher(deps) {
35220
35349
  function cleanupDispatchFiles(scratchRel, built, sessionId) {
35221
35350
  cleanupPrewrites(built);
35222
35351
  try {
35223
- rmSync8(join26(deps.project.dir, scratchRel), { force: true, recursive: true });
35352
+ rmSync8(join28(deps.project.dir, scratchRel), { force: true, recursive: true });
35224
35353
  } catch {
35225
35354
  }
35226
35355
  cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
@@ -35653,7 +35782,7 @@ import {
35653
35782
  watch as fsWatch
35654
35783
  } from "node:fs";
35655
35784
  import { homedir as homedir12 } from "node:os";
35656
- import { join as join27 } from "node:path";
35785
+ import { join as join29 } from "node:path";
35657
35786
  import watcher from "@parcel/watcher";
35658
35787
  function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
35659
35788
  if (!liveness) return false;
@@ -36338,7 +36467,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
36338
36467
  if (parcelSub || stopped) return Promise.resolve();
36339
36468
  if (watchSetup) return watchSetup;
36340
36469
  const setup = (async () => {
36341
- const next = await subscribe(join27(project.dir, ".frizz"), () => scheduleRebuild());
36470
+ const next = await subscribe(join29(project.dir, ".frizz"), () => scheduleRebuild());
36342
36471
  if (stopped) {
36343
36472
  await next.unsubscribe();
36344
36473
  return;
@@ -38272,7 +38401,7 @@ var init_resume = __esm({
38272
38401
  });
38273
38402
 
38274
38403
  // packages/server/src/backend/claude.ts
38275
- import { join as join28 } from "node:path";
38404
+ import { join as join30 } from "node:path";
38276
38405
  function toolResultText2(content) {
38277
38406
  if (typeof content === "string") return content;
38278
38407
  if (!Array.isArray(content)) return "";
@@ -38361,7 +38490,7 @@ function createClaudeBackend(opts) {
38361
38490
  return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
38362
38491
  },
38363
38492
  transcriptPath(sessionId) {
38364
- return join28(opts.logDir, `${sessionId}.jsonl`);
38493
+ return join30(opts.logDir, `${sessionId}.jsonl`);
38365
38494
  },
38366
38495
  parseLine(line) {
38367
38496
  return parseClaudeLine(line);
@@ -38531,12 +38660,12 @@ var init_login_utility = __esm({
38531
38660
 
38532
38661
  // packages/server/src/backend/codex-app-server-diagnostics.ts
38533
38662
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync14, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
38534
- import { join as join29 } from "node:path";
38663
+ import { join as join31 } from "node:path";
38535
38664
  function codexDiagnosticLogPath(stateDir, projectId) {
38536
- return join29(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38665
+ return join31(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38537
38666
  }
38538
38667
  function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
38539
- const dir = join29(stateDir, "codex-app-server");
38668
+ const dir = join31(stateDir, "codex-app-server");
38540
38669
  const path = codexDiagnosticLogPath(stateDir, projectId);
38541
38670
  let ensured = false;
38542
38671
  return (event) => {
@@ -38568,7 +38697,7 @@ var init_codex_app_server_diagnostics = __esm({
38568
38697
  import { execFile as execFile7 } from "node:child_process";
38569
38698
  import { readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
38570
38699
  import { connect as connectSocket } from "node:net";
38571
- import { join as join30 } from "node:path";
38700
+ import { join as join32 } from "node:path";
38572
38701
  function parseLsofSocketNames(stdout) {
38573
38702
  const referenced = /* @__PURE__ */ new Set();
38574
38703
  for (const line of stdout.split("\n")) {
@@ -38585,7 +38714,7 @@ function sweepStaleSockets(options, deps = {}) {
38585
38714
  const keep = new Set(options.keep ?? []);
38586
38715
  let candidates;
38587
38716
  try {
38588
- 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));
38717
+ candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join32(options.dir, name)).filter((path) => !keep.has(path));
38589
38718
  } catch {
38590
38719
  return;
38591
38720
  }
@@ -38635,7 +38764,7 @@ var init_stale_socket_sweep = __esm({
38635
38764
 
38636
38765
  // packages/server/src/orphan-reaper.ts
38637
38766
  import { execFileSync as execFileSync5 } from "node:child_process";
38638
- import { readFileSync as readFileSync17 } from "node:fs";
38767
+ import { readFileSync as readFileSync18 } from "node:fs";
38639
38768
  import { dirname as dirname12 } from "node:path";
38640
38769
  function firstTokenBasename(command) {
38641
38770
  const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
@@ -38902,7 +39031,7 @@ var init_orphan_reaper = __esm({
38902
39031
  defaultExec = (file, args) => execFileSync5(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 });
38903
39032
  defaultReadEnv = (pid) => {
38904
39033
  try {
38905
- return readFileSync17(`/proc/${pid}/environ`, "utf8");
39034
+ return readFileSync18(`/proc/${pid}/environ`, "utf8");
38906
39035
  } catch {
38907
39036
  return null;
38908
39037
  }
@@ -39049,7 +39178,7 @@ var init_thread_hibernation = __esm({
39049
39178
  });
39050
39179
 
39051
39180
  // packages/server/src/context.ts
39052
- import { join as join31 } from "node:path";
39181
+ import { join as join33 } from "node:path";
39053
39182
  import { randomUUID as randomUUID15 } from "node:crypto";
39054
39183
  import { homedir as homedir13 } from "node:os";
39055
39184
  function reconcileSessions(storage) {
@@ -39207,7 +39336,7 @@ async function createContext(opts = {}) {
39207
39336
  function createContextUnchecked(opts, resources) {
39208
39337
  const home = opts.home ?? homedir13();
39209
39338
  const project = opts.project ?? resolveProject();
39210
- const dbPath = join31(project.stateDir, "ui.db");
39339
+ const dbPath = join33(project.stateDir, "ui.db");
39211
39340
  const storage = createStorage(dbPath);
39212
39341
  resources.storage = storage;
39213
39342
  const bus = new Bus();
@@ -39535,6 +39664,8 @@ ${wakeDeliveryToken(deliveryId)}`;
39535
39664
  getSettings: () => getSettings(storage, home),
39536
39665
  setSettings: (s) => setSettings(storage, s, home),
39537
39666
  resetSettings: () => resetSettings(storage, home),
39667
+ getDispatchPreferences: (codexModels) => getDispatchPreferences(storage, getSettings(storage, home), home, codexModels),
39668
+ setDispatchPreference: (update, codexModels) => setDispatchPreference(storage, getSettings(storage, home), home, update, codexModels),
39538
39669
  activeTenants: opts.activeTenants,
39539
39670
  claudeBin: opts.claudeBin,
39540
39671
  codexBin: opts.codexBin,
@@ -39550,6 +39681,7 @@ var init_context = __esm({
39550
39681
  init_project();
39551
39682
  init_storage();
39552
39683
  init_settings();
39684
+ init_dispatch_preferences();
39553
39685
  init_quota();
39554
39686
  init_claude_quota();
39555
39687
  init_board();
@@ -42235,7 +42367,7 @@ var init_server = __esm({
42235
42367
  });
42236
42368
 
42237
42369
  // packages/server/src/repair.ts
42238
- import { existsSync as existsSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "node:fs";
42370
+ import { existsSync as existsSync12, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "node:fs";
42239
42371
  import { basename as basename7, dirname as dirname13, resolve as resolve6 } from "node:path";
42240
42372
  function quoteValue(v) {
42241
42373
  if (/^[\w./#:+-]+$/.test(v)) return v;
@@ -42251,7 +42383,7 @@ function repairThreadFile(frizzDir, file) {
42251
42383
  if (dirname13(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
42252
42384
  if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
42253
42385
  if (!existsSync12(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
42254
- const content = readFileSync18(abs, "utf8");
42386
+ const content = readFileSync19(abs, "utf8");
42255
42387
  const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
42256
42388
  if (firstLine2?.trim() === "---") {
42257
42389
  throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
@@ -42284,7 +42416,7 @@ var init_repair = __esm({
42284
42416
  });
42285
42417
 
42286
42418
  // cc-worker/hooks/bash-background.mjs
42287
- import { readFileSync as readFileSync19 } from "node:fs";
42419
+ import { readFileSync as readFileSync20 } from "node:fs";
42288
42420
  import { basename as basename8 } from "node:path";
42289
42421
  import { pathToFileURL } from "node:url";
42290
42422
  function emit(obj) {
@@ -42433,7 +42565,7 @@ var init_bash_background = __esm({
42433
42565
  if (isDirectHookExecution(process.argv[1], import.meta.url)) {
42434
42566
  try {
42435
42567
  const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
42436
- emit(evaluateBashBackgroundHook(JSON.parse(readFileSync19(0, "utf8")), env));
42568
+ emit(evaluateBashBackgroundHook(JSON.parse(readFileSync20(0, "utf8")), env));
42437
42569
  } catch {
42438
42570
  emit({});
42439
42571
  }
@@ -42442,10 +42574,10 @@ var init_bash_background = __esm({
42442
42574
  });
42443
42575
 
42444
42576
  // packages/server/src/transcript.ts
42445
- 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";
42577
+ import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync21, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
42446
42578
  import { createHash as createHash13 } from "node:crypto";
42447
42579
  import { StringDecoder as StringDecoder4 } from "node:string_decoder";
42448
- import { join as join32 } from "node:path";
42580
+ import { join as join34 } from "node:path";
42449
42581
  import { homedir as homedir14 } from "node:os";
42450
42582
  function formatTokens(n) {
42451
42583
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
@@ -42995,14 +43127,14 @@ function pruneScreenshotCache() {
42995
43127
  if (entries.length <= SCREENSHOT_CACHE_MAX) return;
42996
43128
  const byMtime = entries.map((n) => {
42997
43129
  try {
42998
- return { n, m: statSync14(join32(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
43130
+ return { n, m: statSync14(join34(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
42999
43131
  } catch {
43000
43132
  return { n, m: 0 };
43001
43133
  }
43002
43134
  }).sort((a, b) => b.m - a.m);
43003
43135
  for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
43004
43136
  try {
43005
- unlinkSync5(join32(SCREENSHOT_CACHE_DIR, n));
43137
+ unlinkSync5(join34(SCREENSHOT_CACHE_DIR, n));
43006
43138
  } catch {
43007
43139
  }
43008
43140
  }
@@ -43032,14 +43164,14 @@ function persistBase64Image(mediaType, data, idKey) {
43032
43164
  const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
43033
43165
  if (!ext || !data) return void 0;
43034
43166
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
43035
- const path = join32(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
43167
+ const path = join34(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
43036
43168
  try {
43037
43169
  if (existsSync13(path)) return path;
43038
43170
  if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
43039
43171
  const buf = Buffer.from(data, "base64");
43040
43172
  if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
43041
43173
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
43042
- const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43174
+ const tmp = join34(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43043
43175
  writeFileSync12(tmp, buf);
43044
43176
  renameSync9(tmp, path);
43045
43177
  pruneScreenshotCache();
@@ -43054,14 +43186,14 @@ function persistSentFile(srcPath, idKey) {
43054
43186
  const outExt = ext === "jpeg" ? "jpg" : ext;
43055
43187
  try {
43056
43188
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
43057
- const dest = join32(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
43189
+ const dest = join34(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
43058
43190
  if (existsSync13(dest)) return dest;
43059
43191
  const size = statSync14(srcPath).size;
43060
43192
  if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
43061
- const buf = readFileSync20(srcPath);
43193
+ const buf = readFileSync21(srcPath);
43062
43194
  if (!looksLikeImage(buf, outExt)) return void 0;
43063
43195
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
43064
- const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43196
+ const tmp = join34(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43065
43197
  writeFileSync12(tmp, buf);
43066
43198
  renameSync9(tmp, dest);
43067
43199
  pruneScreenshotCache();
@@ -43478,7 +43610,7 @@ function readTranscript(project, sessionId) {
43478
43610
  }
43479
43611
  function verifyIncrementalParse(path, identityPrefix, incremental) {
43480
43612
  try {
43481
- const fresh = parseTranscript(readFileSync20(path, "utf8"), identityPrefix);
43613
+ const fresh = parseTranscript(readFileSync21(path, "utf8"), identityPrefix);
43482
43614
  const a = JSON.stringify(incremental);
43483
43615
  const b = JSON.stringify(fresh);
43484
43616
  if (a !== b) {
@@ -43498,16 +43630,16 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
43498
43630
  }
43499
43631
  }
43500
43632
  function logDirOf(project) {
43501
- return join32(homedir14(), ".claude", "projects", project.cwdSlug);
43633
+ return join34(homedir14(), ".claude", "projects", project.cwdSlug);
43502
43634
  }
43503
43635
  function resolveTranscriptPath(project, sessionId) {
43504
- const path = join32(logDirOf(project), `${sessionId}.jsonl`);
43636
+ const path = join34(logDirOf(project), `${sessionId}.jsonl`);
43505
43637
  try {
43506
43638
  if (statSync14(path).size > 0) return path;
43507
43639
  } catch {
43508
43640
  }
43509
43641
  const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
43510
- return stranded ? join32(stranded, `${sessionId}.jsonl`) : path;
43642
+ return stranded ? join34(stranded, `${sessionId}.jsonl`) : path;
43511
43643
  }
43512
43644
  function projectCodexTranscript(raw2, identityPrefix = "codex") {
43513
43645
  const out = [];
@@ -44710,7 +44842,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
44710
44842
  }
44711
44843
  function readCodexTranscriptFile(absPath, nativeId = absPath) {
44712
44844
  try {
44713
- return parseCodexTranscript(readFileSync20(absPath, "utf8"), `codex:${nativeId}`);
44845
+ return parseCodexTranscript(readFileSync21(absPath, "utf8"), `codex:${nativeId}`);
44714
44846
  } catch {
44715
44847
  return [];
44716
44848
  }
@@ -44808,7 +44940,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
44808
44940
  function readTranscriptFile(absPath) {
44809
44941
  try {
44810
44942
  const pathKey = createHash13("sha256").update(absPath).digest("base64url").slice(0, 16);
44811
- return parseTranscript(readFileSync20(absPath, "utf8"), `claude-file:${pathKey}`);
44943
+ return parseTranscript(readFileSync21(absPath, "utf8"), `claude-file:${pathKey}`);
44812
44944
  } catch {
44813
44945
  return [];
44814
44946
  }
@@ -44905,9 +45037,9 @@ var init_open_external = __esm({
44905
45037
 
44906
45038
  // packages/server/src/local-file.ts
44907
45039
  import { spawn as spawn6 } from "node:child_process";
44908
- import { readFileSync as readFileSync21, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
45040
+ import { readFileSync as readFileSync22, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
44909
45041
  import { homedir as homedir15 } from "node:os";
44910
- import { isAbsolute as isAbsolute3, join as join33, resolve as resolve7, sep } from "node:path";
45042
+ import { isAbsolute as isAbsolute3, join as join35, resolve as resolve7, sep } from "node:path";
44911
45043
  function isUnder(real, root) {
44912
45044
  let rootReal;
44913
45045
  try {
@@ -44937,7 +45069,7 @@ function resolveLocalFile(rawPath, roots) {
44937
45069
  function resolveOpenableFile(raw2, projectDir, roots, home = homedir15()) {
44938
45070
  const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
44939
45071
  if (!trimmed) return null;
44940
- const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join33(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
45072
+ const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join35(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
44941
45073
  try {
44942
45074
  return resolveLocalFile(abs, roots);
44943
45075
  } catch {
@@ -44948,7 +45080,7 @@ function readLocalMarkdown(rawPath, roots) {
44948
45080
  if (!MARKDOWN_FILE_EXT.test(rawPath.trim())) throw new Error("Local file is not a Markdown file");
44949
45081
  const path = resolveLocalFile(rawPath, roots);
44950
45082
  if (!MARKDOWN_FILE_EXT.test(path)) throw new Error("Local file is not a Markdown file");
44951
- const bytes = readFileSync21(path);
45083
+ const bytes = readFileSync22(path);
44952
45084
  if (bytes.length <= MARKDOWN_READ_LIMIT) return { path, markdown: bytes.toString("utf8"), truncated: false };
44953
45085
  const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
44954
45086
  const lastBreak = head.lastIndexOf(10);
@@ -45295,67 +45427,6 @@ var init_account_actions = __esm({
45295
45427
  }
45296
45428
  });
45297
45429
 
45298
- // packages/server/src/dispatch-preferences.ts
45299
- function permissionFor(backend, mode) {
45300
- if (backend === "codex") {
45301
- if (mode === "plan" || mode === "bypassPermissions") return mode;
45302
- return "default";
45303
- }
45304
- return mode === "plan" ? "auto" : mode;
45305
- }
45306
- function defaultDispatchPreferences(settings, codexModels = []) {
45307
- const backend = settings.backend ?? (codexModels.some((model) => model.slug === settings.model) ? "codex" : "claude");
45308
- const selected = {
45309
- ...settings.model ? { model: settings.model } : {},
45310
- ...settings.effort ? { effort: settings.effort } : {},
45311
- permissionMode: permissionFor(backend, settings.permissionMode)
45312
- };
45313
- return {
45314
- backend,
45315
- claude: backend === "claude" ? selected : { permissionMode: "auto" },
45316
- codex: backend === "codex" ? selected : { permissionMode: "default" }
45317
- };
45318
- }
45319
- function getDispatchPreferences(storage, settings, codexModels = []) {
45320
- const parsed = DispatchPreferences.safeParse(storage.getSetting(KEY));
45321
- return parsed.success ? parsed.data : defaultDispatchPreferences(settings, codexModels);
45322
- }
45323
- function setDispatchPreference(storage, settings, update, codexModels = []) {
45324
- const current = getDispatchPreferences(storage, settings, codexModels);
45325
- let next;
45326
- if (update.field === "backend") {
45327
- next = { ...current, backend: update.value };
45328
- } else if (update.field === "profile") {
45329
- next = {
45330
- ...current,
45331
- backend: update.backend,
45332
- [update.backend]: {
45333
- ...current[update.backend],
45334
- model: update.model,
45335
- effort: update.effort
45336
- }
45337
- };
45338
- } else {
45339
- const profile = current[update.backend];
45340
- next = {
45341
- ...current,
45342
- ...update.field === "model" ? { backend: update.backend } : {},
45343
- [update.backend]: { ...profile, [update.field]: update.value }
45344
- };
45345
- }
45346
- const validated = DispatchPreferences.parse(next);
45347
- storage.setSetting(KEY, validated);
45348
- return validated;
45349
- }
45350
- var KEY;
45351
- var init_dispatch_preferences = __esm({
45352
- "packages/server/src/dispatch-preferences.ts"() {
45353
- "use strict";
45354
- init_src();
45355
- KEY = "dispatch-preferences.v1";
45356
- }
45357
- });
45358
-
45359
45430
  // packages/server/src/external-terminal.ts
45360
45431
  function shellQuote(value) {
45361
45432
  return `'${value.replace(/'/g, `'"'"'`)}'`;
@@ -45708,8 +45779,8 @@ var init_directory_picker = __esm({
45708
45779
  });
45709
45780
 
45710
45781
  // packages/server/src/router.ts
45711
- import { readFileSync as readFileSync22, statSync as statSync17 } from "node:fs";
45712
- import { join as join34, resolve as resolve8 } from "node:path";
45782
+ import { readFileSync as readFileSync23, statSync as statSync17 } from "node:fs";
45783
+ import { join as join36, resolve as resolve8 } from "node:path";
45713
45784
  import { randomUUID as randomUUID16 } from "node:crypto";
45714
45785
  import { basename as basename9, dirname as dirname14 } from "node:path";
45715
45786
  import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
@@ -45872,7 +45943,7 @@ function projectCard(entry, stale) {
45872
45943
  function addProjectAtPath(input) {
45873
45944
  const typed = input.trim();
45874
45945
  if (!typed) throw new Error("Enter a folder path.");
45875
- const expanded = typed === "~" || typed.startsWith("~/") ? join34(homedir16(), typed.slice(1)) : typed;
45946
+ const expanded = typed === "~" || typed.startsWith("~/") ? join36(homedir16(), typed.slice(1)) : typed;
45876
45947
  const absolute = resolve8(expanded);
45877
45948
  let stats;
45878
45949
  try {
@@ -45917,7 +45988,7 @@ function storeProjectIcon(id, name, bytes) {
45917
45988
  function setProjectIconFromFile(id, file) {
45918
45989
  let bytes;
45919
45990
  try {
45920
- bytes = readFileSync22(file);
45991
+ bytes = readFileSync23(file);
45921
45992
  } catch {
45922
45993
  throw new Error("That file could not be read.");
45923
45994
  }
@@ -45925,7 +45996,7 @@ function setProjectIconFromFile(id, file) {
45925
45996
  return storeProjectIcon(id, file, bytes);
45926
45997
  }
45927
45998
  function createRouter(ctx) {
45928
- const frizzDir = join34(ctx.project.dir, ".frizz");
45999
+ const frizzDir = join36(ctx.project.dir, ".frizz");
45929
46000
  const openRoots = openableFileRoots(ctx.project);
45930
46001
  function isAutoTitledSession(slug) {
45931
46002
  return ctx.storage.getSession(slug)?.title_auto === 1;
@@ -47580,7 +47651,7 @@ ${gapNote}` : input.message;
47580
47651
  for (const entry of listProjects()) {
47581
47652
  if (entry.stale) continue;
47582
47653
  try {
47583
- const db = new sqlite_default(join34(projectStateDir(entry.id), "ui.db"), { readonly: true });
47654
+ const db = new sqlite_default(join36(projectStateDir(entry.id), "ui.db"), { readonly: true });
47584
47655
  try {
47585
47656
  const hit = db.prepare("SELECT 1 FROM session WHERE slug = ? LIMIT 1").get(input.slug);
47586
47657
  if (hit) found.push({ projectSlug: entry.slug, projectName: entry.name ?? entry.slug });
@@ -47610,12 +47681,12 @@ ${gapNote}` : input.message;
47610
47681
  }),
47611
47682
  dispatchPreferencesGet: query({
47612
47683
  output: DispatchPreferences,
47613
- handler: async () => getDispatchPreferences(ctx.storage, ctx.getSettings(), readCodexModels())
47684
+ handler: async () => ctx.getDispatchPreferences(readCodexModels())
47614
47685
  }),
47615
47686
  dispatchPreferenceSet: mutation({
47616
47687
  input: SetDispatchPreferenceInput,
47617
47688
  output: DispatchPreferences,
47618
- handler: async ({ input }) => setDispatchPreference(ctx.storage, ctx.getSettings(), input, readCodexModels())
47689
+ handler: async ({ input }) => ctx.setDispatchPreference(input, readCodexModels())
47619
47690
  }),
47620
47691
  // The shipped GitHub batch-dispatch prompt template (single source of truth: server/github.ts).
47621
47692
  // The Settings UI reads it to prefill the editor and to power "reset to default"; an empty/unset
@@ -47726,7 +47797,6 @@ var init_router5 = __esm({
47726
47797
  init_thread_profiles();
47727
47798
  init_adoption_recovery();
47728
47799
  init_awaiting();
47729
- init_dispatch_preferences();
47730
47800
  init_storage();
47731
47801
  init_external_terminal();
47732
47802
  init_background_shell_output();
@@ -47937,7 +48007,7 @@ var init_compression = __esm({
47937
48007
  });
47938
48008
 
47939
48009
  // packages/server/src/local-image.ts
47940
- import { readFileSync as readFileSync23, realpathSync as realpathSync9, statSync as statSync18 } from "node:fs";
48010
+ import { readFileSync as readFileSync24, realpathSync as realpathSync9, statSync as statSync18 } from "node:fs";
47941
48011
  import { extname as extname2, isAbsolute as isAbsolute4 } from "node:path";
47942
48012
  function resolveLocalImage(rawPath) {
47943
48013
  if (!rawPath || !isAbsolute4(rawPath)) return { status: 400 };
@@ -47951,7 +48021,7 @@ function resolveLocalImage(rawPath) {
47951
48021
  }
47952
48022
  try {
47953
48023
  if (!statSync18(real).isFile()) return { status: 404 };
47954
- return { status: 200, contentType, body: readFileSync23(real) };
48024
+ return { status: 200, contentType, body: readFileSync24(real) };
47955
48025
  } catch {
47956
48026
  return { status: 404 };
47957
48027
  }
@@ -47971,9 +48041,9 @@ var init_local_image = __esm({
47971
48041
  });
47972
48042
 
47973
48043
  // packages/server/src/project-icon.ts
47974
- import { readFileSync as readFileSync24, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
48044
+ import { readFileSync as readFileSync25, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
47975
48045
  import { homedir as homedir17 } from "node:os";
47976
- import { basename as basename10, dirname as dirname15, extname as extname3, join as join35, relative, sep as sep2 } from "node:path";
48046
+ import { basename as basename10, dirname as dirname15, extname as extname3, join as join37, relative, sep as sep2 } from "node:path";
47977
48047
  function normalizeStem(stem) {
47978
48048
  const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
47979
48049
  const normalized = sized.replace(VARIANT_SUFFIX, "");
@@ -47991,7 +48061,7 @@ function sizeScore(dimensions) {
47991
48061
  return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
47992
48062
  }
47993
48063
  function under(root, relativeDirectory) {
47994
- return relativeDirectory ? join35(root, relativeDirectory) : root;
48064
+ return relativeDirectory ? join37(root, relativeDirectory) : root;
47995
48065
  }
47996
48066
  function listFiles(directory) {
47997
48067
  try {
@@ -48013,19 +48083,19 @@ function iconDirectories(root) {
48013
48083
  for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
48014
48084
  for (const host of HOST_DIRECTORIES) {
48015
48085
  if (!children2.has(host)) continue;
48016
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join35(root, host), asset));
48086
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join37(root, host), asset));
48017
48087
  }
48018
48088
  for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
48019
48089
  for (const container of WORKSPACE_CONTAINERS) {
48020
48090
  if (!children2.has(container)) continue;
48021
48091
  let members;
48022
48092
  try {
48023
- members = readdirSync10(join35(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
48093
+ members = readdirSync10(join37(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
48024
48094
  } catch {
48025
48095
  continue;
48026
48096
  }
48027
48097
  for (const member of members) {
48028
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join35(root, container, member), asset));
48098
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join37(root, container, member), asset));
48029
48099
  }
48030
48100
  }
48031
48101
  return [...new Set(directories)];
@@ -48033,13 +48103,13 @@ function iconDirectories(root) {
48033
48103
  function manifestIcons(manifestPath) {
48034
48104
  let parsed;
48035
48105
  try {
48036
- parsed = JSON.parse(readFileSync24(manifestPath, "utf8"));
48106
+ parsed = JSON.parse(readFileSync25(manifestPath, "utf8"));
48037
48107
  } catch {
48038
48108
  return [];
48039
48109
  }
48040
48110
  if (!Array.isArray(parsed?.icons)) return [];
48041
48111
  const directory = dirname15(manifestPath);
48042
- 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, "")));
48112
+ 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) => join37(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
48043
48113
  }
48044
48114
  function projectIconCandidates(root) {
48045
48115
  const projectStem = normalizeStem(basename10(root)).normalized;
@@ -48058,7 +48128,7 @@ function projectIconCandidates(root) {
48058
48128
  for (const name of listFiles(directory)) {
48059
48129
  const extension2 = extname3(name).toLowerCase();
48060
48130
  if (MANIFEST_NAMES.includes(name.toLowerCase())) {
48061
- for (const icon of manifestIcons(join35(directory, name))) {
48131
+ for (const icon of manifestIcons(join37(directory, name))) {
48062
48132
  if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
48063
48133
  fromManifest.add(icon);
48064
48134
  files.push({ path: icon, directory: dirname15(icon) });
@@ -48069,7 +48139,7 @@ function projectIconCandidates(root) {
48069
48139
  if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
48070
48140
  const stem = name.slice(0, name.length - extension2.length);
48071
48141
  if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
48072
- files.push({ path: join35(directory, name), directory });
48142
+ files.push({ path: join37(directory, name), directory });
48073
48143
  if (files.length >= MAX_CANDIDATES) break;
48074
48144
  }
48075
48145
  }
@@ -48134,7 +48204,7 @@ function resolveProjectIconResponse(id, options = {}) {
48134
48204
  });
48135
48205
  if (!roots.some((root) => real === root || real.startsWith(root + sep2))) return { status: 404 };
48136
48206
  try {
48137
- return { status: 200, contentType, body: readFileSync24(real) };
48207
+ return { status: 200, contentType, body: readFileSync25(real) };
48138
48208
  } catch {
48139
48209
  return { status: 404 };
48140
48210
  }
@@ -48246,8 +48316,8 @@ var init_project_icon = __esm({
48246
48316
  });
48247
48317
 
48248
48318
  // packages/server/src/local-visualization.ts
48249
- import { readdirSync as readdirSync11, readFileSync as readFileSync25, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
48250
- import { join as join36, sep as sep3 } from "node:path";
48319
+ import { readdirSync as readdirSync11, readFileSync as readFileSync26, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
48320
+ import { join as join38, sep as sep3 } from "node:path";
48251
48321
  function children(path, pattern) {
48252
48322
  try {
48253
48323
  return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
@@ -48259,7 +48329,7 @@ function isUnder2(path, root) {
48259
48329
  return path === root || path.startsWith(root.endsWith(sep3) ? root : root + sep3);
48260
48330
  }
48261
48331
  function resolveFragment(projectDir, sessionId, file) {
48262
- const base = join36(projectDir, ".codex", "visualizations");
48332
+ const base = join38(projectDir, ".codex", "visualizations");
48263
48333
  let projectReal;
48264
48334
  let baseReal;
48265
48335
  try {
@@ -48270,12 +48340,12 @@ function resolveFragment(projectDir, sessionId, file) {
48270
48340
  }
48271
48341
  if (!isUnder2(baseReal, projectReal)) return null;
48272
48342
  for (const year of children(base, YEAR_PART)) {
48273
- const yearDir = join36(base, year);
48343
+ const yearDir = join38(base, year);
48274
48344
  for (const month of children(yearDir, DATE_PART)) {
48275
- const monthDir = join36(yearDir, month);
48345
+ const monthDir = join38(yearDir, month);
48276
48346
  for (const day of children(monthDir, DATE_PART)) {
48277
- const sessionRoot = join36(baseReal, year, month, day, sessionId);
48278
- const candidate = join36(monthDir, day, sessionId, file);
48347
+ const sessionRoot = join38(baseReal, year, month, day, sessionId);
48348
+ const candidate = join38(monthDir, day, sessionId, file);
48279
48349
  try {
48280
48350
  const real = realpathSync11(candidate);
48281
48351
  if (isUnder2(real, sessionRoot) && statSync20(real).isFile()) return real;
@@ -48361,7 +48431,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
48361
48431
  try {
48362
48432
  const size = statSync20(path).size;
48363
48433
  if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
48364
- fragment = readFileSync25(path, "utf8");
48434
+ fragment = readFileSync26(path, "utf8");
48365
48435
  } catch {
48366
48436
  return { status: 404 };
48367
48437
  }
@@ -48404,7 +48474,7 @@ var init_local_visualization = __esm({
48404
48474
 
48405
48475
  // packages/server/src/app.ts
48406
48476
  import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync14 } from "node:fs";
48407
- import { join as join37 } from "node:path";
48477
+ import { join as join39 } from "node:path";
48408
48478
  import { randomUUID as randomUUID17 } from "node:crypto";
48409
48479
  function createApp(ctx, options = {}) {
48410
48480
  const app = new Hono2();
@@ -48508,10 +48578,10 @@ function createApp(ctx, options = {}) {
48508
48578
  if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
48509
48579
  const ext = `.${attachmentExtension(name)}`;
48510
48580
  const buf = Buffer.from(body.data, "base64");
48511
- const dir = join37(ctx.project.stateDir, "attachments");
48581
+ const dir = join39(ctx.project.stateDir, "attachments");
48512
48582
  mkdirSync17(dir, { recursive: true });
48513
48583
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
48514
- const path = join37(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
48584
+ const path = join39(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
48515
48585
  writeFileSync14(path, buf);
48516
48586
  return c.json({ path });
48517
48587
  });
@@ -49750,10 +49820,10 @@ var init_app_socket = __esm({
49750
49820
  });
49751
49821
 
49752
49822
  // packages/server/src/boot-progress.ts
49753
- import { mkdirSync as mkdirSync18, readFileSync as readFileSync26, renameSync as renameSync10, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
49754
- import { basename as basename11, dirname as dirname16, join as join38 } from "node:path";
49823
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync27, renameSync as renameSync10, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
49824
+ import { basename as basename11, dirname as dirname16, join as join40 } from "node:path";
49755
49825
  function bootProgressPath(stateDir) {
49756
- return join38(stateDir, BOOT_PROGRESS_NAME);
49826
+ return join40(stateDir, BOOT_PROGRESS_NAME);
49757
49827
  }
49758
49828
  function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49759
49829
  if (!stateDir) {
@@ -49774,7 +49844,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49774
49844
  step++;
49775
49845
  try {
49776
49846
  mkdirSync18(dirname16(path), { recursive: true, mode: 448 });
49777
- const temp = join38(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49847
+ const temp = join40(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49778
49848
  writeFileSync15(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
49779
49849
  `, "utf8");
49780
49850
  renameSync10(temp, path);
@@ -49891,11 +49961,11 @@ __export(index_exports, {
49891
49961
  unknownProjectPage: () => unknownProjectPage
49892
49962
  });
49893
49963
  import { createServer } from "node:http";
49894
- import { readFileSync as readFileSync27, existsSync as existsSync15 } from "node:fs";
49895
- import { dirname as dirname17, join as join39, resolve as resolve9, extname as extname4, normalize } from "node:path";
49964
+ import { readFileSync as readFileSync28, existsSync as existsSync15 } from "node:fs";
49965
+ import { dirname as dirname17, join as join41, resolve as resolve9, extname as extname4, normalize } from "node:path";
49896
49966
  function readServerAddressHolder(path) {
49897
49967
  try {
49898
- const value = JSON.parse(readFileSync27(path, "utf8"));
49968
+ const value = JSON.parse(readFileSync28(path, "utf8"));
49899
49969
  if (typeof value?.pid !== "number") return void 0;
49900
49970
  return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
49901
49971
  } catch {
@@ -49995,11 +50065,11 @@ function createShutdownSignalHandler(options) {
49995
50065
  }
49996
50066
  function serveStatic(distDir, req, res) {
49997
50067
  const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
49998
- let file = join39(distDir, rel === "/" ? "index.html" : rel);
49999
- if (!file.startsWith(distDir)) file = join39(distDir, "index.html");
50000
- if (!existsSync15(file)) file = join39(distDir, "index.html");
50068
+ let file = join41(distDir, rel === "/" ? "index.html" : rel);
50069
+ if (!file.startsWith(distDir)) file = join41(distDir, "index.html");
50070
+ if (!existsSync15(file)) file = join41(distDir, "index.html");
50001
50071
  try {
50002
- const body = readFileSync27(file);
50072
+ const body = readFileSync28(file);
50003
50073
  res.writeHead(200, { "content-type": MIME[extname4(file)] ?? "application/octet-stream" });
50004
50074
  res.end(body);
50005
50075
  } catch {
@@ -50348,7 +50418,7 @@ async function startServer(opts = {}) {
50348
50418
  }
50349
50419
  statusPath = serverLockPathFor(ctx.project);
50350
50420
  const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
50351
- const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join39(webRoot, "dist");
50421
+ const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join41(webRoot, "dist");
50352
50422
  startupPhase = "Vite";
50353
50423
  if (opts.dev) {
50354
50424
  try {
@@ -50424,7 +50494,7 @@ async function startServer(opts = {}) {
50424
50494
  if (vite) {
50425
50495
  vite.middlewares(req, res, () => {
50426
50496
  try {
50427
- const html = readFileSync27(join39(webRoot, "index.html"), "utf8");
50497
+ const html = readFileSync28(join41(webRoot, "index.html"), "utf8");
50428
50498
  void vite.transformIndexHtml(url, html).then((out) => {
50429
50499
  res.writeHead(200, { "content-type": "text/html" });
50430
50500
  res.end(out);
@@ -50616,7 +50686,7 @@ var init_index = __esm({
50616
50686
  }
50617
50687
  };
50618
50688
  isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
50619
- serverLockPathFor = (project) => join39(project.stateDir, "server.lock");
50689
+ serverLockPathFor = (project) => join41(project.stateDir, "server.lock");
50620
50690
  MIME = {
50621
50691
  ".html": "text/html",
50622
50692
  ".js": "text/javascript",
@@ -50635,7 +50705,7 @@ init_project_launch();
50635
50705
  init_shutdown();
50636
50706
  init_logging();
50637
50707
  import { existsSync as existsSync16 } from "node:fs";
50638
- import { join as join40 } from "node:path";
50708
+ import { join as join42 } from "node:path";
50639
50709
  process.on("uncaughtException", (error) => {
50640
50710
  log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
50641
50711
  process.exit(1);
@@ -50675,7 +50745,7 @@ try {
50675
50745
  ];
50676
50746
  if (!existsSync16(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
50677
50747
  for (const [name, directory, requiredFile] of required) {
50678
- if (!directory || !existsSync16(join40(directory, requiredFile)))
50748
+ if (!directory || !existsSync16(join42(directory, requiredFile)))
50679
50749
  throw new Error(`stable artifact launch is missing verified ${name}`);
50680
50750
  }
50681
50751
  }