frizz-server 0.15.15 → 0.15.17

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 (99) hide show
  1. package/dist/dev-child.js +1393 -784
  2. package/package.json +1 -1
  3. package/runtime/cc-worker/bin/frizz-mcp.mjs +67 -2
  4. package/web-dist/assets/{abnfDiagram-VRR7QNED-DhfveBnK.js → abnfDiagram-VRR7QNED-BCWz80uN.js} +1 -1
  5. package/web-dist/assets/{arc-CyAhw_PT.js → arc-DDtkTWyk.js} +1 -1
  6. package/web-dist/assets/architecture-TIHT7OUA-BSM-tgTt.js +1 -0
  7. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-DwWGlWWh.js → architectureDiagram-ZJ3FMSHR-BpRbm_s5.js} +1 -1
  8. package/web-dist/assets/{blockDiagram-677ZJIJ3-DaZjGZtu.js → blockDiagram-677ZJIJ3-_kGtJSW2.js} +1 -1
  9. package/web-dist/assets/{c4Diagram-LMCZKHZV-BRMup1j9.js → c4Diagram-LMCZKHZV-D8XwDoiY.js} +1 -1
  10. package/web-dist/assets/channel-BwwaRyUv.js +1 -0
  11. package/web-dist/assets/{chunk-32BRIVSS-DQwcDwtE.js → chunk-32BRIVSS-BUGbBNz_.js} +1 -1
  12. package/web-dist/assets/{chunk-52WLFC77-CgGBFwno.js → chunk-52WLFC77-Dc0eyYJe.js} +1 -1
  13. package/web-dist/assets/{chunk-C7G6YPKG-CuxheuT5.js → chunk-C7G6YPKG-CNP8apQ_.js} +1 -1
  14. package/web-dist/assets/{chunk-EX3LRPZG-BUJla0kp.js → chunk-EX3LRPZG-m5klG9uB.js} +1 -1
  15. package/web-dist/assets/{chunk-FWX5IMBZ-B0zpcsgr.js → chunk-FWX5IMBZ-CHO58JFl.js} +2 -2
  16. package/web-dist/assets/{chunk-HOUHSVGY-Rmt15rW3.js → chunk-HOUHSVGY-DjH-r82r.js} +1 -1
  17. package/web-dist/assets/{chunk-ICXQ74PX-DhfK6S2X.js → chunk-ICXQ74PX-DkYjEd46.js} +1 -1
  18. package/web-dist/assets/{chunk-MOJQB5TN-DPeso190.js → chunk-MOJQB5TN-D89rLIxX.js} +1 -1
  19. package/web-dist/assets/{chunk-OGEWGWER-Dnxu3oeq.js → chunk-OGEWGWER-Db2MBETv.js} +1 -1
  20. package/web-dist/assets/{chunk-PUDLZKDR-JzuUO3j2.js → chunk-PUDLZKDR-Dtdx_z8j.js} +1 -1
  21. package/web-dist/assets/{chunk-Q4XR5HBZ-CM6ZXGkW.js → chunk-Q4XR5HBZ-XYvD_xYq.js} +1 -1
  22. package/web-dist/assets/{chunk-RYQCIY6F--6BdDOKZ.js → chunk-RYQCIY6F-CZ7RTprX.js} +1 -1
  23. package/web-dist/assets/{chunk-V7JOEXUC-Dq3E-pJp.js → chunk-V7JOEXUC-CoAVJiNJ.js} +1 -1
  24. package/web-dist/assets/{chunk-VAUOI2AC-Cd8PGNlH.js → chunk-VAUOI2AC-DbjEHErZ.js} +1 -1
  25. package/web-dist/assets/{chunk-VR4S4FIN-dwYLlPtI.js → chunk-VR4S4FIN-4BB6eLCK.js} +1 -1
  26. package/web-dist/assets/{chunk-WYO6CB5R-CycRCrJb.js → chunk-WYO6CB5R-Cuvm_fLi.js} +1 -1
  27. package/web-dist/assets/{chunk-XXDRQBXY-BHkd_B7T.js → chunk-XXDRQBXY-CvLzx99l.js} +1 -1
  28. package/web-dist/assets/{chunk-ZGVPDNZ5-w1E_2-n0.js → chunk-ZGVPDNZ5-BccJcRbi.js} +1 -1
  29. package/web-dist/assets/classDiagram-OUVF2IWQ-DTgWbehh.js +1 -0
  30. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DTgWbehh.js +1 -0
  31. package/web-dist/assets/{cose-bilkent-JH36ORCC-DT58QUJH.js → cose-bilkent-JH36ORCC-BfwT-16i.js} +1 -1
  32. package/web-dist/assets/{cynefin-VYW2F7L2-DJBWvYfG.js → cynefin-VYW2F7L2-DbZ1V36t.js} +1 -1
  33. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-BgZsBMC5.js → cynefinDiagram-TSTJHNR4-mFI_mDt-.js} +1 -1
  34. package/web-dist/assets/{dagre-VKFMJZFB-BsUdprP7.js → dagre-VKFMJZFB-BldEgHyl.js} +1 -1
  35. package/web-dist/assets/{diagram-FQU43EPY-AYwXc4ap.js → diagram-FQU43EPY-CWSdOHjN.js} +1 -1
  36. package/web-dist/assets/{diagram-G47NLZAW--4o6VVV_.js → diagram-G47NLZAW-CohHPpmC.js} +1 -1
  37. package/web-dist/assets/{diagram-NH7WQ7WH-B0_Gu4SY.js → diagram-NH7WQ7WH-CY9SIr04.js} +1 -1
  38. package/web-dist/assets/{diagram-OA4YK3LP-DIdSWxbC.js → diagram-OA4YK3LP-D1ChaJcq.js} +1 -1
  39. package/web-dist/assets/{diagram-WEI45ONY-ZggLbvMN.js → diagram-WEI45ONY-Bng85j-O.js} +1 -1
  40. package/web-dist/assets/{dist-Bx4dBZZj.js → dist-Dn2m7SMF.js} +1 -1
  41. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-D4mwPGRz.js → ebnfDiagram-CCIWWBDH-CcHfTwsR.js} +1 -1
  42. package/web-dist/assets/{erDiagram-Q63AITRT-BdVxVYVS.js → erDiagram-Q63AITRT-D9XptUTi.js} +1 -1
  43. package/web-dist/assets/eventmodeling-45OFAUF4-vqzohKbi.js +1 -0
  44. package/web-dist/assets/flowDiagram-23GEKE2U-CYPLykok.js +1 -0
  45. package/web-dist/assets/{ganttDiagram-NO4QXBWP-1ch3s-Lp.js → ganttDiagram-NO4QXBWP-CpDcHWNC.js} +1 -1
  46. package/web-dist/assets/{gitGraph-TEB2WS4Q-OYci86fv.js → gitGraph-TEB2WS4Q-dskxWshP.js} +1 -1
  47. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-C0vyzUeM.js → gitGraphDiagram-IHSO6WYX-Gm-g6rXY.js} +1 -1
  48. package/web-dist/assets/index-Bi4vNYho.css +2 -0
  49. package/web-dist/assets/index-C5sCt0eh.js +334 -0
  50. package/web-dist/assets/{info-DKCQHKI2-Di5Jz1rS.js → info-DKCQHKI2-DfBWPig9.js} +1 -1
  51. package/web-dist/assets/{infoDiagram-FWYZ7A6U-CFb6Kd3F.js → infoDiagram-FWYZ7A6U-RA1gm_5G.js} +1 -1
  52. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DcfyEKeu.js → ishikawaDiagram-FXEZZL3T-DMO4tlB7.js} +1 -1
  53. package/web-dist/assets/{journeyDiagram-5HDEW3XC-DKXBMkLI.js → journeyDiagram-5HDEW3XC-CGn0Vfft.js} +1 -1
  54. package/web-dist/assets/{kanban-definition-HUTT4EX6-B369XB3j.js → kanban-definition-HUTT4EX6-qRxs3pxC.js} +1 -1
  55. package/web-dist/assets/{line-CHcvip-O.js → line-BihkNjKV.js} +1 -1
  56. package/web-dist/assets/{linear-DQNyozJe.js → linear-CbcYjraG.js} +1 -1
  57. package/web-dist/assets/{mermaid-parser.core-BjxGpEg5.js → mermaid-parser.core-CstJtBOd.js} +3 -3
  58. package/web-dist/assets/{mermaid.core-DrLahovt.js → mermaid.core-CAoFTj5o.js} +3 -3
  59. package/web-dist/assets/{mindmap-definition-LN4V7U3C-MZ52F91o.js → mindmap-definition-LN4V7U3C-Dobyf2TY.js} +1 -1
  60. package/web-dist/assets/{packet-7NZHBO7P-CjyAw65k.js → packet-7NZHBO7P-BV-_zRVl.js} +1 -1
  61. package/web-dist/assets/{pegDiagram-2B236MQR-DLWhOQnL.js → pegDiagram-2B236MQR-CoWfyvfk.js} +1 -1
  62. package/web-dist/assets/{pie-RZYD4A2V-Bo059ddI.js → pie-RZYD4A2V-ptQFpYwJ.js} +1 -1
  63. package/web-dist/assets/{pieDiagram-ENE6RG2P-Bn4xh59c.js → pieDiagram-ENE6RG2P-DCYSn0kJ.js} +1 -1
  64. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-yL39XUy5.js → quadrantDiagram-ABIIQ3AL-D-IhKJdt.js} +1 -1
  65. package/web-dist/assets/{radar-I7S5WNFK-Ck7WdZik.js → radar-I7S5WNFK-CqtSeYcU.js} +1 -1
  66. package/web-dist/assets/{railroad-3IZDKUUU-iyRvRPSM.js → railroad-3IZDKUUU-CejeX1m0.js} +1 -1
  67. package/web-dist/assets/railroad-abnf-AHOZXSZD-D858Ks1V.js +1 -0
  68. package/web-dist/assets/railroad-ebnf-EBAXGLYW-CnKN0qs5.js +1 -0
  69. package/web-dist/assets/railroad-peg-LSFZ7HO6-CG_oVFtv.js +1 -0
  70. package/web-dist/assets/{railroadDiagram-RFXS5EU6-BxVsxOmr.js → railroadDiagram-RFXS5EU6-CLMVsbkb.js} +1 -1
  71. package/web-dist/assets/{requirementDiagram-TGXJPOKE-D66pmX1H.js → requirementDiagram-TGXJPOKE-J6ovU2nZ.js} +1 -1
  72. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-BvgsAMO2.js → sankeyDiagram-HTMAVEWB-BN1Wcnxg.js} +1 -1
  73. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-BhNfNIv2.js → sequenceDiagram-DBY2YBRQ-CnDSUjeE.js} +1 -1
  74. package/web-dist/assets/{src-CjLI2OlU.js → src-ie67lQl7.js} +1 -1
  75. package/web-dist/assets/{stateDiagram-2N3HPSRC-vnAKWHvS.js → stateDiagram-2N3HPSRC-CDvDw5S6.js} +1 -1
  76. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-CWmRITC6.js +1 -0
  77. package/web-dist/assets/{swimlanes-5IMT3BWC-CB-Yj_fF.js → swimlanes-5IMT3BWC-BmljTUhI.js} +1 -1
  78. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BTxJqUkH.js +8 -0
  79. package/web-dist/assets/{timeline-definition-FHXFAJF6-CvLWFhRF.js → timeline-definition-FHXFAJF6-CjA-qR6O.js} +1 -1
  80. package/web-dist/assets/{treeView-QDETBFTQ-BDE_I1pO.js → treeView-QDETBFTQ-CHKGsZbS.js} +1 -1
  81. package/web-dist/assets/{treemap-6X3UGDF4-FQ6gU3Zd.js → treemap-6X3UGDF4-CqU-nL1w.js} +1 -1
  82. package/web-dist/assets/{vennDiagram-L72KCM5P-BVrnKEXl.js → vennDiagram-L72KCM5P-BwQcxcel.js} +1 -1
  83. package/web-dist/assets/{wardley-OPB4EBWU-BXDzR7qq.js → wardley-OPB4EBWU-Bo8e8N-h.js} +1 -1
  84. package/web-dist/assets/{wardleyDiagram-EHGQE667-DbUiehJp.js → wardleyDiagram-EHGQE667-ByioZC4m.js} +1 -1
  85. package/web-dist/assets/{xychartDiagram-FW5EYKEG-BTwgjd1B.js → xychartDiagram-FW5EYKEG-B48Vy_EL.js} +1 -1
  86. package/web-dist/index.html +2 -2
  87. package/web-dist/assets/architecture-TIHT7OUA-C1SxnjA-.js +0 -1
  88. package/web-dist/assets/channel-BF49lwbq.js +0 -1
  89. package/web-dist/assets/classDiagram-OUVF2IWQ-CBnpuahb.js +0 -1
  90. package/web-dist/assets/classDiagram-v2-EOCWNBFH-CBnpuahb.js +0 -1
  91. package/web-dist/assets/eventmodeling-45OFAUF4-DmV5Ki1T.js +0 -1
  92. package/web-dist/assets/flowDiagram-23GEKE2U-BIo9OVTK.js +0 -1
  93. package/web-dist/assets/index-DDIB2iVX.js +0 -330
  94. package/web-dist/assets/index-DcU5Cvjj.css +0 -2
  95. package/web-dist/assets/railroad-abnf-AHOZXSZD-CbUyyZcZ.js +0 -1
  96. package/web-dist/assets/railroad-ebnf-EBAXGLYW-Cw1S-tc2.js +0 -1
  97. package/web-dist/assets/railroad-peg-LSFZ7HO6-BEpXiF80.js +0 -1
  98. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-D-SWO5VU.js +0 -1
  99. package/web-dist/assets/swimlanesDiagram-G3AALYLV-PjEPG6SC.js +0 -8
package/dist/dev-child.js CHANGED
@@ -760,10 +760,10 @@ function discoverProjectRoot(cwd = process.cwd(), home = homedir3()) {
760
760
  } catch {
761
761
  return resolve3(cwd);
762
762
  }
763
- const stop = resolve3(home);
763
+ const stop2 = resolve3(home);
764
764
  const filesystemRoot = parse(dir).root;
765
765
  for (let at2 = dir; ; at2 = dirname3(at2)) {
766
- if (at2 === stop || at2 === filesystemRoot) break;
766
+ if (at2 === stop2 || at2 === filesystemRoot) break;
767
767
  if (existsSync2(projectIdPath(at2))) return at2;
768
768
  if (hasAny(at2, REPO_MARKERS)) return at2;
769
769
  if (hasAny(at2, PROJECT_MARKERS)) return at2;
@@ -12957,6 +12957,68 @@ var init_drainable_worker = __esm({
12957
12957
  }
12958
12958
  });
12959
12959
 
12960
+ // packages/shared/src/frizz-md.ts
12961
+ function landingRule(landing, branch) {
12962
+ const b = `\`${branch}\``;
12963
+ switch (landing) {
12964
+ case "pull-request":
12965
+ return `Never commit directly to ${b}. Put each change on its own branch, push it, and open a pull request against ${b}. Never merge a pull request yourself: a human reviews and merges it. Your work is not finished until the pull request is open with its checks passing.`;
12966
+ case "main":
12967
+ return `Commit finished work directly to the local ${b} branch. Do not open pull requests, and do not push to the remote: a human pushes. Commit at each coherent checkpoint, and always commit completed work before you stop.`;
12968
+ case "main-push":
12969
+ return `Commit finished work directly to ${b} and push it to the remote. Do not open pull requests. Run the project's checks before every push, and never force-push.`;
12970
+ case "branch":
12971
+ return `Never commit directly to ${b}, and do not push to the remote. Commit each change to its own local branch and say which branch in your write-up: a human reviews and merges it.`;
12972
+ }
12973
+ }
12974
+ function autonomyRule(autonomy) {
12975
+ switch (autonomy) {
12976
+ case "decide":
12977
+ return "Decide and proceed. Make every reversible call yourself \u2014 names, defaults, error messages, which of two equivalent designs \u2014 and say in your write-up which way you went. Ask only before something destructive or irreversible, an external-facing action, or a product decision that is genuinely the human's to make.";
12978
+ case "balanced":
12979
+ return "Make routine implementation calls yourself and say which way you went. Ask before a significant design choice, a change of scope, or anything destructive or irreversible.";
12980
+ case "check-in":
12981
+ return "Check in before acting. Confirm your plan with the human before you write substantial code, and ask about any decision the task does not make obvious.";
12982
+ }
12983
+ }
12984
+ function composeFrizzMd(answers, defaultBranch2) {
12985
+ const sections = [
12986
+ "# Frizz worker norms",
12987
+ "Frizz adds this file to the system prompt of every agent it starts in this project. No other coding-agent session reads it: Claude Code, Codex or any other agent you start yourself is unaffected. Edit it freely; the next agent Frizz starts reads the new version.",
12988
+ "## Landing changes",
12989
+ landingRule(answers.landing, defaultBranch2),
12990
+ "## Working independently",
12991
+ autonomyRule(answers.autonomy)
12992
+ ];
12993
+ const notes = answers.notes.trim();
12994
+ if (notes) sections.push("## Project notes", notes);
12995
+ return `${sections.join("\n\n")}
12996
+ `;
12997
+ }
12998
+ var FrizzMdLanding, FrizzMdAutonomy, FRIZZ_MD_NOTES_MAX, FrizzMdAnswers, FrizzMdStatus;
12999
+ var init_frizz_md = __esm({
13000
+ "packages/shared/src/frizz-md.ts"() {
13001
+ "use strict";
13002
+ init_zod();
13003
+ FrizzMdLanding = external_exports.enum(["pull-request", "main", "main-push", "branch"]);
13004
+ FrizzMdAutonomy = external_exports.enum(["decide", "balanced", "check-in"]);
13005
+ FRIZZ_MD_NOTES_MAX = 8e3;
13006
+ FrizzMdAnswers = external_exports.object({
13007
+ landing: FrizzMdLanding,
13008
+ autonomy: FrizzMdAutonomy,
13009
+ notes: external_exports.string().max(FRIZZ_MD_NOTES_MAX)
13010
+ }).strict();
13011
+ FrizzMdStatus = external_exports.object({
13012
+ /** A FRIZZ.md is already at the project root: the project has its rules, so nothing is asked. */
13013
+ exists: external_exports.boolean(),
13014
+ /** The operator skipped the questionnaire for this project: it is not asked again. */
13015
+ skipped: external_exports.boolean(),
13016
+ /** The branch the landing rules name — the remote's default, else the checked-out one, else `main`. */
13017
+ defaultBranch: external_exports.string()
13018
+ });
13019
+ }
13020
+ });
13021
+
12960
13022
  // packages/shared/src/receipt-bus.ts
12961
13023
  var init_receipt_bus = __esm({
12962
13024
  "packages/shared/src/receipt-bus.ts"() {
@@ -13669,9 +13731,10 @@ function signoffNudgeText(needsInput) {
13669
13731
  " `mcp__frizz__timer`; `mcp__frizz__activity` reads back everything you have running, with its id.",
13670
13732
  "- `` ```awaiting `` with `steps:` \u2014 the human must PERFORM something you cannot: sign in, approve,",
13671
13733
  " merge, press a button you may not. List each step as a `- ` line under `steps:`, written to be",
13672
- " followed cold; frizz reads them verbatim. Steps name the HUMAN as the wait, so the fence needs no",
13673
- " other name and no `for:`, and the thread goes into their queue. Their Done comes back to you as",
13674
- " their reply; anything else they need to say comes as a message of their own.",
13734
+ " followed cold: a real Markdown link to every page and file it names, every command in a code span,",
13735
+ " every value the act needs written in. Frizz reads them verbatim. Steps name the HUMAN as the wait,",
13736
+ " so the fence needs no other name and no `for:`, and the thread goes into their queue. Their Done",
13737
+ " comes back to you as their reply; anything else they need to say comes as a message of their own.",
13675
13738
  "- `` ```awaiting `` with `questions:` \u2014 a question you registered at an EARLIER rest is still open and",
13676
13739
  " you still need its answer. Name every such question (`questions: [qst_\u2026]`) and withdraw the rest with",
13677
13740
  " `mcp__frizz__unask`: a fence that leaves an open question out is refused. A named card is drawn at",
@@ -13679,7 +13742,7 @@ function signoffNudgeText(needsInput) {
13679
13742
  "",
13680
13743
  "**STILL OWED counts things you are not going to do yourself.** A decision you are RECOMMENDING, a",
13681
13744
  "draft you wrote but did not send, follow-up work you discovered \u2014 all of it dies with the card, even",
13682
- "the part that is someone else's to do. Each ends on a question with your recommendation as option A,",
13745
+ "the part that is someone else's to do. Each ends on a question with your recommendation as option 1,",
13683
13746
  "or you DO it first \u2014 a sub-agent's result comes BACK to you, so it lands on your card; a new card via",
13684
13747
  "`mcp__frizz__spawn_thread` is the LAST resort, since nothing it learns returns to you or its siblings.",
13685
13748
  "None of them is a `done`. And what is not",
@@ -13792,6 +13855,8 @@ function askedQuestionFaults(q2) {
13792
13855
  const faults = [];
13793
13856
  const walk = (node, path3) => {
13794
13857
  const options = node.options ?? [];
13858
+ if (node.secret && options.length > 0) faults.push(`${path3}: a secret request takes no options \u2014 it is one masked box`);
13859
+ if (node.secret && path3 !== "question") faults.push(`${path3}: a secret request cannot be a follow-up \u2014 register it on its own`);
13795
13860
  if (node.kind === "multi" && options.length === 0) faults.push(`${path3}: \`kind: "multi"\` needs options \u2014 a question with none is free text`);
13796
13861
  if (options.filter((o) => o.recommended).length > 1) faults.push(`${path3}: only ONE option may be \`recommended\` \u2014 a recommendation on two of three choices says nothing`);
13797
13862
  for (const [i, option] of options.entries()) {
@@ -13808,6 +13873,12 @@ function askedQuestionFaults(q2) {
13808
13873
  }
13809
13874
  return faults;
13810
13875
  }
13876
+ function secretAnswerText(path3) {
13877
+ return `(secret ready at ${quotePath(path3)} \u2014 it can be read ONCE, within ${SECRET_TTL_MS / 6e4}m; never print it)`;
13878
+ }
13879
+ function quotePath(value) {
13880
+ return `'${value.replace(/'/g, `'\\''`)}'`;
13881
+ }
13811
13882
  function questionAnswerMessage(answers, dismissed = []) {
13812
13883
  if (answers.length === 0) return questionsCancelledWakeMessage(dismissed.length);
13813
13884
  const rows = [];
@@ -14056,7 +14127,7 @@ function parseGithubWakeSteer(text2) {
14056
14127
  function frizzRoute(path3) {
14057
14128
  return `${FRIZZ_ROUTE_PREFIX}${path3.startsWith("/") ? path3 : `/${path3}`}`;
14058
14129
  }
14059
- var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, CODEX_MODELS_FALLBACK, AcpAgent, ACP_MODEL_PREFIX, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, RETIRED_AWAITING_REPLACEMENT, AWAITING_KEY_RE, AWAITING_YAML_KEYS, AWAITING_SEQUENCE_KEYS, AWAITING_HINT_MAX, AWAITING_HINT_VALUE_MAX, AWAITING_SCALAR_KINDS, AWAITING_STEPS_MAX, AWAITING_STEP_VALUE_MAX, AWAITING_QUESTIONS_MAX, AWAITING_TITLE_MAX, AWAITING_STATUSES, AWAITING_ITEM_KINDS, AWAITING_DURATION_RE, DURATION_UNIT_MS, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, INTERRUPT_MARKERS, ALLDONE_SENTINEL, OPT_OUT_NOTE, OVER_QUESTION_NOTE, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TIMER_MAX_ARMED, TimerPromptText, PR_WATCH_SPENT_TRAILER, PR_WATCH_ARMED_TRAILER, SHELL_DONE_TRAILER, ISSUE_WATCH_SPENT_TRAILER, ISSUE_WATCH_ARMED_TRAILER, INTERRUPT_ENDED_LEAD, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, PARK_CORRECTION_NEEDS_INPUT_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, OWN_WATCH_MAX_ARMED, QUESTION_FENCE_RETIRED_AT, NEEDS_INPUT_REQUIRED_AT, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, WAKE_TIME_HEADER_TAIL, WAKE_TRAILERS, HUMAN_GAP_FLOOR_MS, HUMAN_GAP_NOTE_TAIL, WAKE_DELIVERY_TOKEN_TAIL, WAKE_DELIVERY_TOKEN_LINE, NOISE_PREFIXES, AGENT_MESSAGE_WRAPPER, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REVIEW_LEAD, WAKE_BACKLOG_TAIL, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, WAKE_ITEM, WAKE_MORE, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
14130
+ var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, CODEX_MODELS_FALLBACK, AcpAgent, ACP_MODEL_PREFIX, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, RETIRED_AWAITING_REPLACEMENT, AWAITING_KEY_RE, AWAITING_YAML_KEYS, AWAITING_SEQUENCE_KEYS, AWAITING_HINT_MAX, AWAITING_HINT_VALUE_MAX, AWAITING_SCALAR_KINDS, AWAITING_STEPS_MAX, AWAITING_STEP_VALUE_MAX, AWAITING_QUESTIONS_MAX, AWAITING_TITLE_MAX, AWAITING_STATUSES, AWAITING_ITEM_KINDS, AWAITING_DURATION_RE, DURATION_UNIT_MS, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, INTERRUPT_MARKERS, ALLDONE_SENTINEL, OPT_OUT_NOTE, OVER_QUESTION_NOTE, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TIMER_MAX_ARMED, TimerPromptText, PR_WATCH_SPENT_TRAILER, PR_WATCH_ARMED_TRAILER, SHELL_DONE_TRAILER, ISSUE_WATCH_SPENT_TRAILER, ISSUE_WATCH_ARMED_TRAILER, INTERRUPT_ENDED_LEAD, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, PARK_CORRECTION_NEEDS_INPUT_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, OWN_WATCH_MAX_ARMED, QUESTION_FENCE_RETIRED_AT, NEEDS_INPUT_REQUIRED_AT, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, SECRET_TTL_MS, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, WAKE_TIME_HEADER_TAIL, WAKE_TRAILERS, HUMAN_GAP_FLOOR_MS, HUMAN_GAP_NOTE_TAIL, WAKE_DELIVERY_TOKEN_TAIL, WAKE_DELIVERY_TOKEN_LINE, NOISE_PREFIXES, AGENT_MESSAGE_WRAPPER, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REVIEW_LEAD, WAKE_BACKLOG_TAIL, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, WAKE_ITEM, WAKE_MORE, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
14060
14131
  var init_src = __esm({
14061
14132
  "packages/shared/src/index.ts"() {
14062
14133
  "use strict";
@@ -14069,6 +14140,7 @@ var init_src = __esm({
14069
14140
  init_code_fences();
14070
14141
  init_delta();
14071
14142
  init_drainable_worker();
14143
+ init_frizz_md();
14072
14144
  init_interactions();
14073
14145
  init_receipt_bus();
14074
14146
  init_relay_protocol();
@@ -14731,10 +14803,11 @@ var init_src = __esm({
14731
14803
  header: external_exports.string().trim().max(24).optional(),
14732
14804
  kind: AskQuestionKind,
14733
14805
  danger: external_exports.boolean().optional(),
14806
+ secret: external_exports.boolean().optional(),
14734
14807
  // UNBOUNDED, deliberately. This carried `.max(8)` from launch until 2026-09-03, when the maintainer
14735
14808
  // asked for the cap to go ("allow arbitrary numbers of options"): a `multi` over a long list — which
14736
- // gates to run, which of twenty findings to act on — is a real shape, and the card letters past 26
14737
- // (`AA.`) already. The count is the worker's to choose; the answer's `chosen` is unbounded to match.
14809
+ // gates to run, which of twenty findings to act on — is a real shape, and the card numbers past 9
14810
+ // (only 1–9 are keys) already. The count is the worker's to choose; the answer's `chosen` is unbounded to match.
14738
14811
  options: external_exports.array(AskedOptionSchema).optional()
14739
14812
  }).strict());
14740
14813
  AskInput = external_exports.object({
@@ -14748,8 +14821,12 @@ var init_src = __esm({
14748
14821
  * an id alone cannot be correlated back to what was asked. */
14749
14822
  id: external_exports.string(),
14750
14823
  spec: AskedQuestionSchema,
14751
- askedAt: external_exports.string()
14824
+ askedAt: external_exports.string(),
14825
+ /** A `secret` question only: the path its value will be served at. Known at registration, so the
14826
+ * worker can prepare the command that reads it before the human has answered. */
14827
+ secretPath: external_exports.string().optional()
14752
14828
  }).strict();
14829
+ SECRET_TTL_MS = 15 * 6e4;
14753
14830
  AskResult = external_exports.object({
14754
14831
  registered: external_exports.array(RegisteredQuestionView),
14755
14832
  /** Everything still open on this thread afterwards, so a worker never needs a second call. */
@@ -17032,9 +17109,9 @@ function resolveProjectIdentity(dir, home = homedir5()) {
17032
17109
  throw new Error("unable to inspect Git repository identity");
17033
17110
  }
17034
17111
  }
17035
- const git2 = insideWorktree ? resolveGitProjectIdentity(dir, home) : void 0;
17036
- const root = git2?.root ?? dir;
17037
- return { id: ensureProjectIdFile(root, home, git2?.id), scope: git2?.scope ?? "repository", root };
17112
+ const git3 = insideWorktree ? resolveGitProjectIdentity(dir, home) : void 0;
17113
+ const root = git3?.root ?? dir;
17114
+ return { id: ensureProjectIdFile(root, home, git3?.id), scope: git3?.scope ?? "repository", root };
17038
17115
  }
17039
17116
  function cwdSlug(absPath) {
17040
17117
  const slug = absPath.replace(/[^A-Za-z0-9]/g, "-");
@@ -18024,6 +18101,229 @@ var init_logging = __esm({
18024
18101
  }
18025
18102
  });
18026
18103
 
18104
+ // packages/server/src/local-origin.ts
18105
+ import { isIP } from "node:net";
18106
+ function publicAuthority(policy) {
18107
+ const raw2 = policy?.publicOrigin;
18108
+ if (!raw2) return null;
18109
+ let url;
18110
+ try {
18111
+ url = new URL(raw2);
18112
+ } catch {
18113
+ return null;
18114
+ }
18115
+ if (url.origin !== raw2) return null;
18116
+ return {
18117
+ hostname: normalizedHostname(url.hostname),
18118
+ port: explicitPort(url),
18119
+ authority: url.host.toLowerCase(),
18120
+ scheme: url.protocol === "https:" ? "https" : "http"
18121
+ };
18122
+ }
18123
+ function acceptsHostname(hostname, policy) {
18124
+ if (LOCAL_HOSTNAMES.has(hostname)) return true;
18125
+ if (!policy?.exposed) return false;
18126
+ if (isIP(hostname) !== 0) return true;
18127
+ return (policy.allowedHosts ?? []).some((allowed) => allowed === "*" || allowed.toLowerCase() === hostname);
18128
+ }
18129
+ function oneHeader(value) {
18130
+ return typeof value === "string" && value.length > 0 ? value : void 0;
18131
+ }
18132
+ function normalizedHostname(hostname) {
18133
+ const lower = hostname.toLowerCase();
18134
+ return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
18135
+ }
18136
+ function explicitPort(url) {
18137
+ if (url.port) return Number(url.port);
18138
+ return url.protocol === "https:" ? 443 : 80;
18139
+ }
18140
+ function validExpectedPort(port2) {
18141
+ return Number.isInteger(port2) && port2 >= 1 && port2 <= 65535;
18142
+ }
18143
+ function parseLocalHttpOrigin(value, expectedPort, policy) {
18144
+ const raw2 = oneHeader(value);
18145
+ if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim()) return null;
18146
+ const declared = publicAuthority(policy);
18147
+ if (declared && raw2 === policy?.publicOrigin) return declared;
18148
+ let url;
18149
+ try {
18150
+ url = new URL(raw2);
18151
+ } catch {
18152
+ return null;
18153
+ }
18154
+ if (url.protocol !== "http:" || url.origin !== raw2) return null;
18155
+ const hostname = normalizedHostname(url.hostname);
18156
+ if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
18157
+ return { hostname, port: expectedPort, authority: url.host, scheme: "http" };
18158
+ }
18159
+ function parseLocalHost(value, expectedPort, policy) {
18160
+ const raw2 = oneHeader(value);
18161
+ if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim() || raw2.includes(",")) return null;
18162
+ let url;
18163
+ try {
18164
+ url = new URL(`http://${raw2}`);
18165
+ } catch {
18166
+ return null;
18167
+ }
18168
+ if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) return null;
18169
+ if (url.host.toLowerCase() !== raw2.toLowerCase()) return null;
18170
+ const hostname = normalizedHostname(url.hostname);
18171
+ const declared = publicAuthority(policy);
18172
+ if (declared && hostname === declared.hostname) {
18173
+ return url.port === "" || Number(url.port) === declared.port ? declared : null;
18174
+ }
18175
+ if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
18176
+ return { hostname, port: expectedPort, authority: url.host.toLowerCase(), scheme: "http" };
18177
+ }
18178
+ function hasForwardedAuthority(headers) {
18179
+ return FORWARDED_HEADERS.some((name) => headers[name] !== void 0);
18180
+ }
18181
+ function forwardedAuthorityAllowed(headers, host, policy) {
18182
+ if (!hasForwardedAuthority(headers)) return true;
18183
+ const declared = publicAuthority(policy);
18184
+ return !!declared && declared.hostname === host.hostname;
18185
+ }
18186
+ function isTrustedLocalHttpRequest(headers, expectedPort, allowMissingOrigin = false, policy) {
18187
+ const host = parseLocalHost(headers.host, expectedPort, policy);
18188
+ if (!host) return false;
18189
+ if (!forwardedAuthorityAllowed(headers, host, policy)) return false;
18190
+ if (headers.origin === void 0) return allowMissingOrigin;
18191
+ const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
18192
+ return !!origin && host.hostname === origin.hostname && host.port === origin.port;
18193
+ }
18194
+ function allowedLocalCorsOrigin(origin, expectedPort, policy) {
18195
+ return parseLocalHttpOrigin(origin, expectedPort, policy) ? origin : void 0;
18196
+ }
18197
+ function isTrustedLocalWebSocketRequest(req, expectedPort = req.socket.localPort, policy) {
18198
+ if (!validExpectedPort(expectedPort)) return false;
18199
+ const headers = req.headers;
18200
+ const host = parseLocalHost(headers.host, expectedPort, policy);
18201
+ if (!host || !forwardedAuthorityAllowed(headers, host, policy)) return false;
18202
+ const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
18203
+ return !!origin && host.hostname === origin.hostname && host.port === origin.port;
18204
+ }
18205
+ function rejectWebSocketUpgrade(socket, status = 403, reason = "Forbidden") {
18206
+ const body = `${reason}
18207
+ `;
18208
+ const response = [
18209
+ `HTTP/1.1 ${status} ${reason}`,
18210
+ "Connection: close",
18211
+ "Content-Type: text/plain; charset=utf-8",
18212
+ `Content-Length: ${Buffer.byteLength(body)}`,
18213
+ "",
18214
+ body
18215
+ ].join("\r\n");
18216
+ try {
18217
+ socket.end(response);
18218
+ } catch {
18219
+ try {
18220
+ socket.destroy();
18221
+ } catch {
18222
+ }
18223
+ }
18224
+ }
18225
+ var LOCAL_HOSTNAMES, FORWARDED_HEADERS;
18226
+ var init_local_origin = __esm({
18227
+ "packages/server/src/local-origin.ts"() {
18228
+ "use strict";
18229
+ LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
18230
+ FORWARDED_HEADERS = [
18231
+ "forwarded",
18232
+ "x-forwarded-for",
18233
+ "x-forwarded-host",
18234
+ "x-forwarded-port",
18235
+ "x-forwarded-proto"
18236
+ ];
18237
+ }
18238
+ });
18239
+
18240
+ // packages/server/src/local-path.ts
18241
+ function normalizeLocalPath(path3, platform3 = process.platform) {
18242
+ return platform3 === "win32" ? path3.replace(/^\/([a-zA-Z]:[\\/])/, "$1") : path3;
18243
+ }
18244
+ var init_local_path = __esm({
18245
+ "packages/server/src/local-path.ts"() {
18246
+ "use strict";
18247
+ }
18248
+ });
18249
+
18250
+ // packages/server/src/local-image.ts
18251
+ import { createReadStream, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
18252
+ import { extname, isAbsolute as isAbsolute3 } from "node:path";
18253
+ function resolveLocalImage(rawPath, range) {
18254
+ if (rawPath) rawPath = normalizeLocalPath(rawPath);
18255
+ if (!rawPath || !isAbsolute3(rawPath)) return { status: 400 };
18256
+ const contentType = CONTENT_TYPE[extname(rawPath).toLowerCase()];
18257
+ if (!contentType) return { status: 400 };
18258
+ let real;
18259
+ try {
18260
+ real = realpathSync5(rawPath);
18261
+ } catch {
18262
+ return { status: 404 };
18263
+ }
18264
+ let size;
18265
+ try {
18266
+ const stat2 = statSync4(real);
18267
+ if (!stat2.isFile()) return { status: 404 };
18268
+ size = stat2.size;
18269
+ } catch {
18270
+ return { status: 404 };
18271
+ }
18272
+ const span = range ? byteRange(range, size) : null;
18273
+ if (span === "unsatisfiable") return { status: 416, size };
18274
+ if (span) return { status: 206, contentType, file: real, size, start: span.start, end: span.end };
18275
+ return { status: 200, contentType, file: real, size, start: 0, end: size - 1 };
18276
+ }
18277
+ function byteRange(header, size) {
18278
+ const match2 = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
18279
+ if (!match2) return null;
18280
+ const [, first, last] = match2;
18281
+ if (first === "" && last === "") return null;
18282
+ if (first === "") {
18283
+ const suffix = Number(last);
18284
+ if (suffix === 0 || size === 0) return "unsatisfiable";
18285
+ return { start: Math.max(size - suffix, 0), end: size - 1 };
18286
+ }
18287
+ const start = Number(first);
18288
+ if (last !== "" && Number(last) < start) return null;
18289
+ if (start >= size) return "unsatisfiable";
18290
+ return { start, end: last === "" ? size - 1 : Math.min(Number(last), size - 1) };
18291
+ }
18292
+ function localImageHeaders(result) {
18293
+ return {
18294
+ "content-type": result.contentType,
18295
+ "content-length": String(result.end - result.start + 1),
18296
+ "accept-ranges": "bytes",
18297
+ "cache-control": "private, max-age=60",
18298
+ ...result.status === 206 ? { "content-range": `bytes ${result.start}-${result.end}/${result.size}` } : {}
18299
+ };
18300
+ }
18301
+ function localImageStream(result) {
18302
+ if (result.end < result.start) return null;
18303
+ return createReadStream(result.file, { start: result.start, end: result.end });
18304
+ }
18305
+ var IMAGE_CONTENT_TYPE, VIDEO_CONTENT_TYPE, CONTENT_TYPE;
18306
+ var init_local_image = __esm({
18307
+ "packages/server/src/local-image.ts"() {
18308
+ "use strict";
18309
+ init_local_path();
18310
+ IMAGE_CONTENT_TYPE = {
18311
+ ".png": "image/png",
18312
+ ".jpg": "image/jpeg",
18313
+ ".jpeg": "image/jpeg",
18314
+ ".gif": "image/gif",
18315
+ ".webp": "image/webp"
18316
+ };
18317
+ VIDEO_CONTENT_TYPE = {
18318
+ ".mp4": "video/mp4",
18319
+ ".m4v": "video/mp4",
18320
+ ".webm": "video/webm",
18321
+ ".mov": "video/quicktime"
18322
+ };
18323
+ CONTENT_TYPE = { ...IMAGE_CONTENT_TYPE, ...VIDEO_CONTENT_TYPE };
18324
+ }
18325
+ });
18326
+
18027
18327
  // packages/server/src/bus.ts
18028
18328
  var Bus, Emitter;
18029
18329
  var init_bus = __esm({
@@ -21166,16 +21466,122 @@ var init_storage = __esm({
21166
21466
  }
21167
21467
  });
21168
21468
 
21469
+ // packages/server/src/secret-files.ts
21470
+ import { execFileSync as execFileSync4 } from "node:child_process";
21471
+ import { chmodSync as chmodSync2, closeSync as closeSync5, constants, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync8, openSync as openSync6, readdirSync as readdirSync3, rmdirSync, rmSync as rmSync6, writeFileSync as writeFileSync7, writeSync as writeSync2 } from "node:fs";
21472
+ import { dirname as dirname7, join as join11 } from "node:path";
21473
+ function secretsRoot(stateDir) {
21474
+ return join11(stateDir, "secrets");
21475
+ }
21476
+ function secretFilePath(stateDir, slug, questionId) {
21477
+ return join11(secretsRoot(stateDir), slug, questionId);
21478
+ }
21479
+ function stop(path3) {
21480
+ const entry = served.get(path3);
21481
+ if (entry) clearInterval(entry.timer);
21482
+ served.delete(path3);
21483
+ rmSync6(path3, { force: true });
21484
+ try {
21485
+ rmdirSync(dirname7(path3));
21486
+ } catch {
21487
+ }
21488
+ }
21489
+ function serveSecret(stateDir, slug, questionId, value, opts = {}) {
21490
+ const now = opts.now ?? Date.now;
21491
+ const expiresAt = now() + (opts.ttlMs ?? SECRET_TTL_MS);
21492
+ const root = secretsRoot(stateDir);
21493
+ const dir = join11(root, slug);
21494
+ const path3 = secretFilePath(stateDir, slug, questionId);
21495
+ stop(path3);
21496
+ mkdirSync8(dir, { recursive: true, mode: 448 });
21497
+ chmodSync2(root, 448);
21498
+ chmodSync2(dir, 448);
21499
+ if ((opts.platform ?? process.platform) === "win32") {
21500
+ writeFileSync7(path3, value, { mode: 384 });
21501
+ const timer2 = setInterval(() => {
21502
+ if (now() >= expiresAt || !existsSync5(path3)) stop(path3);
21503
+ }, 1e3);
21504
+ timer2.unref();
21505
+ served.set(path3, { timer: timer2 });
21506
+ return path3;
21507
+ }
21508
+ execFileSync4("mkfifo", ["-m", "600", path3]);
21509
+ const bytes = Buffer.from(value, "utf8");
21510
+ const timer = setInterval(() => {
21511
+ if (now() >= expiresAt || !existsSync5(path3)) return stop(path3);
21512
+ let fd2;
21513
+ try {
21514
+ fd2 = openSync6(path3, constants.O_WRONLY | constants.O_NONBLOCK);
21515
+ } catch {
21516
+ return;
21517
+ }
21518
+ let delivered = false;
21519
+ try {
21520
+ delivered = writeSync2(fd2, bytes) === bytes.length;
21521
+ } catch {
21522
+ } finally {
21523
+ closeSync5(fd2);
21524
+ }
21525
+ if (delivered) stop(path3);
21526
+ }, POLL_MS2);
21527
+ timer.unref();
21528
+ served.set(path3, { timer });
21529
+ return path3;
21530
+ }
21531
+ function clearSecrets(stateDir) {
21532
+ const root = secretsRoot(stateDir);
21533
+ let removed = 0;
21534
+ let threads;
21535
+ try {
21536
+ threads = readdirSync3(root);
21537
+ } catch {
21538
+ return 0;
21539
+ }
21540
+ for (const thread of threads) {
21541
+ const dir = join11(root, thread);
21542
+ let entries2;
21543
+ try {
21544
+ if (!lstatSync(dir).isDirectory()) {
21545
+ rmSync6(dir, { force: true });
21546
+ continue;
21547
+ }
21548
+ entries2 = readdirSync3(dir);
21549
+ } catch {
21550
+ continue;
21551
+ }
21552
+ for (const entry of entries2) {
21553
+ const path3 = join11(dir, entry);
21554
+ if (served.has(path3)) continue;
21555
+ rmSync6(path3, { force: true });
21556
+ removed++;
21557
+ }
21558
+ try {
21559
+ if (readdirSync3(dir).length === 0) rmSync6(dir, { recursive: true, force: true });
21560
+ } catch {
21561
+ }
21562
+ }
21563
+ return removed;
21564
+ }
21565
+ var POLL_MS2, served;
21566
+ var init_secret_files = __esm({
21567
+ "packages/server/src/secret-files.ts"() {
21568
+ "use strict";
21569
+ init_src();
21570
+ POLL_MS2 = 100;
21571
+ served = /* @__PURE__ */ new Map();
21572
+ }
21573
+ });
21574
+
21169
21575
  // packages/server/src/machine-config.ts
21170
- 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";
21171
- import { dirname as dirname6, join as join9 } from "node:path";
21576
+ import { closeSync as closeSync6, fsyncSync as fsyncSync5, mkdirSync as mkdirSync9, openSync as openSync7, readFileSync as readFileSync8, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync8 } from "node:fs";
21577
+ import { dirname as dirname8, join as join12 } from "node:path";
21172
21578
  function machineConfigPath(home) {
21173
- return join9(frizzPaths({ home }).data, "config.json");
21579
+ return join12(frizzPaths({ home }).data, "config.json");
21174
21580
  }
21175
21581
  function readAll(home) {
21176
21582
  let raw2;
21177
21583
  try {
21178
- raw2 = JSON.parse(readFileSync6(machineConfigPath(home), "utf8"));
21584
+ raw2 = JSON.parse(readFileSync8(machineConfigPath(home), "utf8"));
21179
21585
  } catch {
21180
21586
  return {};
21181
21587
  }
@@ -21183,24 +21589,24 @@ function readAll(home) {
21183
21589
  }
21184
21590
  function writeAll(home, all) {
21185
21591
  const path3 = machineConfigPath(home);
21186
- mkdirSync7(dirname6(path3), { recursive: true });
21592
+ mkdirSync9(dirname8(path3), { recursive: true });
21187
21593
  const temp = `${path3}.${process.pid}.tmp`;
21188
21594
  let fd2;
21189
21595
  try {
21190
- fd2 = openSync6(temp, "w", 384);
21191
- writeFileSync6(fd2, `${JSON.stringify(all, null, 2)}
21596
+ fd2 = openSync7(temp, "w", 384);
21597
+ writeFileSync8(fd2, `${JSON.stringify(all, null, 2)}
21192
21598
  `, "utf8");
21193
21599
  fsyncSync5(fd2);
21194
- closeSync5(fd2);
21600
+ closeSync6(fd2);
21195
21601
  fd2 = void 0;
21196
21602
  renameSync5(temp, path3);
21197
21603
  } catch {
21198
21604
  if (fd2 !== void 0) try {
21199
- closeSync5(fd2);
21605
+ closeSync6(fd2);
21200
21606
  } catch {
21201
21607
  }
21202
21608
  try {
21203
- rmSync6(temp, { force: true });
21609
+ rmSync7(temp, { force: true });
21204
21610
  } catch {
21205
21611
  }
21206
21612
  }
@@ -21228,10 +21634,10 @@ var init_machine_config = __esm({
21228
21634
  });
21229
21635
 
21230
21636
  // packages/server/src/settings.ts
21231
- import { readFileSync as readFileSync7, rmSync as rmSync7 } from "node:fs";
21232
- import { join as join10 } from "node:path";
21637
+ import { readFileSync as readFileSync9, rmSync as rmSync8 } from "node:fs";
21638
+ import { join as join13 } from "node:path";
21233
21639
  function legacyMachineSettingsPath(home) {
21234
- return join10(frizzPaths({ home }).data, "settings.json");
21640
+ return join13(frizzPaths({ home }).data, "settings.json");
21235
21641
  }
21236
21642
  function pickMachine(settings) {
21237
21643
  return Object.fromEntries(MACHINE_KEYS.map((key) => [key, settings[key]]));
@@ -21241,7 +21647,7 @@ function readMachineSettings(home) {
21241
21647
  if (stored) return pickPresent(stored);
21242
21648
  let raw2;
21243
21649
  try {
21244
- raw2 = JSON.parse(readFileSync7(legacyMachineSettingsPath(home), "utf8"));
21650
+ raw2 = JSON.parse(readFileSync9(legacyMachineSettingsPath(home), "utf8"));
21245
21651
  } catch {
21246
21652
  return {};
21247
21653
  }
@@ -21272,7 +21678,7 @@ function resetSettings(storage, home) {
21272
21678
  storage.deleteSetting(SETTINGS_KEY);
21273
21679
  deleteMachineConfig(home, SETTINGS_KEY);
21274
21680
  try {
21275
- rmSync7(legacyMachineSettingsPath(home), { force: true });
21681
+ rmSync8(legacyMachineSettingsPath(home), { force: true });
21276
21682
  } catch {
21277
21683
  }
21278
21684
  return defaultSettings();
@@ -21572,15 +21978,15 @@ var init_codex_error = __esm({
21572
21978
  });
21573
21979
 
21574
21980
  // packages/server/src/discover.ts
21575
- import { readdirSync as readdirSync3, statSync as statSync4, openSync as openSync7, readSync, closeSync as closeSync6 } from "node:fs";
21576
- import { dirname as dirname7, join as join11 } from "node:path";
21981
+ import { readdirSync as readdirSync4, statSync as statSync5, openSync as openSync8, readSync, closeSync as closeSync7 } from "node:fs";
21982
+ import { dirname as dirname9, join as join14 } from "node:path";
21577
21983
  function sentinelFor(sessionId) {
21578
21984
  return `threads/${sessionId}/`;
21579
21985
  }
21580
21986
  function readHead(path3) {
21581
21987
  let fd2;
21582
21988
  try {
21583
- fd2 = openSync7(path3, "r");
21989
+ fd2 = openSync8(path3, "r");
21584
21990
  const buf = Buffer.allocUnsafe(HEAD_BYTES);
21585
21991
  const n = readSync(fd2, buf, 0, HEAD_BYTES, 0);
21586
21992
  return buf.toString("utf8", 0, n);
@@ -21589,7 +21995,7 @@ function readHead(path3) {
21589
21995
  } finally {
21590
21996
  if (fd2 !== void 0) {
21591
21997
  try {
21592
- closeSync6(fd2);
21998
+ closeSync7(fd2);
21593
21999
  } catch {
21594
22000
  }
21595
22001
  }
@@ -21601,7 +22007,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
21601
22007
  const sentinel = sentinelFor(sessionId);
21602
22008
  let names;
21603
22009
  try {
21604
- names = readdirSync3(logDir);
22010
+ names = readdirSync4(logDir);
21605
22011
  } catch {
21606
22012
  return void 0;
21607
22013
  }
@@ -21610,10 +22016,10 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
21610
22016
  if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
21611
22017
  const id2 = name.slice(0, -".jsonl".length);
21612
22018
  if (!id2 || id2 === sessionId || exclude?.has(id2)) continue;
21613
- const path3 = join11(logDir, name);
22019
+ const path3 = join14(logDir, name);
21614
22020
  let mtime;
21615
22021
  try {
21616
- mtime = statSync4(path3).mtimeMs;
22022
+ mtime = statSync5(path3).mtimeMs;
21617
22023
  } catch {
21618
22024
  continue;
21619
22025
  }
@@ -21628,7 +22034,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
21628
22034
  }
21629
22035
  function mtimeOfNonEmpty(path3) {
21630
22036
  try {
21631
- const st2 = statSync4(path3, { throwIfNoEntry: false });
22037
+ const st2 = statSync5(path3, { throwIfNoEntry: false });
21632
22038
  return st2 && st2.size > 0 ? st2.mtimeMs : void 0;
21633
22039
  } catch {
21634
22040
  return void 0;
@@ -21638,7 +22044,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
21638
22044
  const name = `${sessionId}.jsonl`;
21639
22045
  const better = (best2, dir) => {
21640
22046
  if (dir === logDir) return best2;
21641
- const at2 = mtimeOfNonEmpty(join11(dir, name));
22047
+ const at2 = mtimeOfNonEmpty(join14(dir, name));
21642
22048
  if (at2 === void 0) return best2;
21643
22049
  return !best2 || at2 > best2.mtimeMs ? { dir, mtimeMs: at2 } : best2;
21644
22050
  };
@@ -21647,11 +22053,11 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
21647
22053
  if (best) return best.dir;
21648
22054
  let entries2;
21649
22055
  try {
21650
- entries2 = readdirSync3(dirname7(logDir), { withFileTypes: true }).filter((e14) => e14.isDirectory()).map((e14) => e14.name);
22056
+ entries2 = readdirSync4(dirname9(logDir), { withFileTypes: true }).filter((e14) => e14.isDirectory()).map((e14) => e14.name);
21651
22057
  } catch {
21652
22058
  return void 0;
21653
22059
  }
21654
- for (const entry of entries2) best = better(best, join11(dirname7(logDir), entry));
22060
+ for (const entry of entries2) best = better(best, join14(dirname9(logDir), entry));
21655
22061
  if (!best) return void 0;
21656
22062
  memo3.add(best.dir);
21657
22063
  return best.dir;
@@ -21737,27 +22143,27 @@ var init_types2 = __esm({
21737
22143
  });
21738
22144
 
21739
22145
  // packages/server/src/session-files.ts
21740
- import { chmodSync, lstatSync, mkdirSync as mkdirSync8, rmSync as rmSync8, writeFileSync as writeFileSync7 } from "node:fs";
21741
- import { join as join12 } from "node:path";
22146
+ import { chmodSync as chmodSync3, lstatSync as lstatSync2, mkdirSync as mkdirSync10, rmSync as rmSync9, writeFileSync as writeFileSync9 } from "node:fs";
22147
+ import { join as join15 } from "node:path";
21742
22148
  function systemPromptPath(sessionId) {
21743
22149
  if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
21744
- return join12(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
22150
+ return join15(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
21745
22151
  }
21746
22152
  function mcpConfigPath(sessionId) {
21747
22153
  if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
21748
- return join12(MCP_CONFIG_DIR, `${sessionId}.json`);
22154
+ return join15(MCP_CONFIG_DIR, `${sessionId}.json`);
21749
22155
  }
21750
22156
  function writeMcpConfigFile(sessionId, mcpServers) {
21751
22157
  const path3 = mcpConfigPath(sessionId);
21752
- mkdirSync8(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
21753
- chmodSync(MCP_CONFIG_DIR, 448);
21754
- writeFileSync7(path3, JSON.stringify({ mcpServers }), { mode: 384 });
21755
- chmodSync(path3, 384);
22158
+ mkdirSync10(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
22159
+ chmodSync3(MCP_CONFIG_DIR, 448);
22160
+ writeFileSync9(path3, JSON.stringify({ mcpServers }), { mode: 384 });
22161
+ chmodSync3(path3, 384);
21756
22162
  return path3;
21757
22163
  }
21758
22164
  function isDirectDirectory(path3) {
21759
22165
  try {
21760
- const stat2 = lstatSync(path3);
22166
+ const stat2 = lstatSync2(path3);
21761
22167
  return stat2.isDirectory() && !stat2.isSymbolicLink();
21762
22168
  } catch {
21763
22169
  return false;
@@ -21765,7 +22171,7 @@ function isDirectDirectory(path3) {
21765
22171
  }
21766
22172
  function pathAbsent(path3) {
21767
22173
  try {
21768
- lstatSync(path3);
22174
+ lstatSync2(path3);
21769
22175
  return false;
21770
22176
  } catch (error) {
21771
22177
  return error.code === "ENOENT";
@@ -21773,9 +22179,9 @@ function pathAbsent(path3) {
21773
22179
  }
21774
22180
  function unlinkDirectChild(parent, filename) {
21775
22181
  if (!isDirectDirectory(parent)) return pathAbsent(parent);
21776
- const child = join12(parent, filename);
22182
+ const child = join15(parent, filename);
21777
22183
  try {
21778
- rmSync8(child, { force: true });
22184
+ rmSync9(child, { force: true });
21779
22185
  } catch {
21780
22186
  return false;
21781
22187
  }
@@ -21783,14 +22189,14 @@ function unlinkDirectChild(parent, filename) {
21783
22189
  }
21784
22190
  function cleanupAdoptionSessionFiles(projectDir, sessionId) {
21785
22191
  if (!SESSION_ID_RE.test(sessionId)) return false;
21786
- const frizzDir = join12(projectDir, ".frizz");
22192
+ const frizzDir = join15(projectDir, ".frizz");
21787
22193
  let clean = true;
21788
22194
  if (isDirectDirectory(frizzDir)) {
21789
- const threads = join12(frizzDir, "threads");
22195
+ const threads = join15(frizzDir, "threads");
21790
22196
  if (isDirectDirectory(threads)) {
21791
- const child = join12(threads, sessionId);
22197
+ const child = join15(threads, sessionId);
21792
22198
  try {
21793
- rmSync8(child, { recursive: true, force: true });
22199
+ rmSync9(child, { recursive: true, force: true });
21794
22200
  } catch {
21795
22201
  clean = false;
21796
22202
  }
@@ -22042,10 +22448,10 @@ var init_adoption_recovery = __esm({
22042
22448
  });
22043
22449
 
22044
22450
  // packages/server/src/backend/codex-models.ts
22045
- import { join as join13 } from "node:path";
22046
- import { readFileSync as readFileSync8 } from "node:fs";
22451
+ import { join as join16 } from "node:path";
22452
+ import { readFileSync as readFileSync10 } from "node:fs";
22047
22453
  function cachePath(codexHome) {
22048
- return join13(codexHome, "models_cache.json");
22454
+ return join16(codexHome, "models_cache.json");
22049
22455
  }
22050
22456
  function toCodexModel(raw2) {
22051
22457
  if (!raw2 || typeof raw2 !== "object") return void 0;
@@ -22099,7 +22505,7 @@ function readCodexModels(codexHome = defaultCodexHome(), expectedClientVersion,
22099
22505
  if (hit && nowMs - hit.at < TTL_MS) return hit.models;
22100
22506
  let models;
22101
22507
  try {
22102
- const raw2 = readFileSync8(path3, "utf8");
22508
+ const raw2 = readFileSync10(path3, "utf8");
22103
22509
  models = parseCodexModelsCache(raw2, expectedClientVersion, trusted.get(key));
22104
22510
  let writer;
22105
22511
  try {
@@ -22776,10 +23182,10 @@ var init_claude_agent_sdk_protocol = __esm({
22776
23182
  });
22777
23183
 
22778
23184
  // packages/server/src/backend/claude-broker-diagnostics.ts
22779
- import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9, readFileSync as readFileSync9, renameSync as renameSync6, statSync as statSync5 } from "node:fs";
22780
- import { join as join14 } from "node:path";
23185
+ import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync11, readFileSync as readFileSync11, renameSync as renameSync6, statSync as statSync6 } from "node:fs";
23186
+ import { join as join17 } from "node:path";
22781
23187
  function claudeBrokerDiagnosticLogPath(stateDir, sessionId) {
22782
- return join14(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
23188
+ return join17(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
22783
23189
  }
22784
23190
  function readClaudeBrokerExit(stateDir, sessionId, generation) {
22785
23191
  if (!generation) return null;
@@ -22787,7 +23193,7 @@ function readClaudeBrokerExit(stateDir, sessionId, generation) {
22787
23193
  for (const path3 of [`${claudeBrokerDiagnosticLogPath(stateDir, sessionId)}.1`, claudeBrokerDiagnosticLogPath(stateDir, sessionId)]) {
22788
23194
  let text2;
22789
23195
  try {
22790
- text2 = readFileSync9(path3, "utf8");
23196
+ text2 = readFileSync11(path3, "utf8");
22791
23197
  } catch {
22792
23198
  continue;
22793
23199
  }
@@ -22840,11 +23246,11 @@ var init_claude_broker_diagnostics = __esm({
22840
23246
  });
22841
23247
 
22842
23248
  // packages/server/src/detached-daemons.ts
22843
- import { existsSync as existsSync4 } from "node:fs";
23249
+ import { existsSync as existsSync6 } from "node:fs";
22844
23250
  import { fileURLToPath } from "node:url";
22845
23251
  function resolveDetachedDaemonEntry(moduleUrl, basename14) {
22846
23252
  const candidates = [`./${basename14}.js`, `./${basename14}.ts`].map((rel) => fileURLToPath(new URL(rel, moduleUrl)));
22847
- const found = candidates.find((path3) => existsSync4(path3));
23253
+ const found = candidates.find((path3) => existsSync6(path3));
22848
23254
  if (!found) throw new Error(`frizz is missing the ${basename14} entry \u2014 looked for ${candidates.join(" and ")}`);
22849
23255
  return found;
22850
23256
  }
@@ -22884,10 +23290,10 @@ var init_daemon_tree = __esm({
22884
23290
  });
22885
23291
 
22886
23292
  // packages/server/src/backend/ipc-path.ts
22887
- import { join as join15 } from "node:path";
23293
+ import { join as join18 } from "node:path";
22888
23294
  function frizzIpcPath(name) {
22889
23295
  if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
22890
- return join15(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
23296
+ return join18(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
22891
23297
  }
22892
23298
  var init_ipc_path = __esm({
22893
23299
  "packages/server/src/backend/ipc-path.ts"() {
@@ -22898,18 +23304,18 @@ var init_ipc_path = __esm({
22898
23304
  // packages/server/src/backend/claude-broker-host.ts
22899
23305
  import { spawn } from "node:child_process";
22900
23306
  import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
22901
- import { accessSync, constants as fsConstants, mkdirSync as mkdirSync10, readFileSync as readFileSync10, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync8 } from "node:fs";
22902
- import { delimiter, dirname as dirname8, isAbsolute as isAbsolute3, join as join16 } from "node:path";
23307
+ import { accessSync, constants as fsConstants, mkdirSync as mkdirSync12, readFileSync as readFileSync12, readdirSync as readdirSync5, unlinkSync, writeFileSync as writeFileSync10 } from "node:fs";
23308
+ import { delimiter, dirname as dirname10, isAbsolute as isAbsolute4, join as join19 } from "node:path";
22903
23309
  function windowsShimTarget(shimPath) {
22904
23310
  let body;
22905
23311
  try {
22906
- body = readFileSync10(shimPath, "utf8");
23312
+ body = readFileSync12(shimPath, "utf8");
22907
23313
  } catch {
22908
23314
  return void 0;
22909
23315
  }
22910
23316
  const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
22911
23317
  if (!target) return void 0;
22912
- const full = join16(dirname8(shimPath), target);
23318
+ const full = join19(dirname10(shimPath), target);
22913
23319
  try {
22914
23320
  accessSync(full, fsConstants.F_OK);
22915
23321
  return full;
@@ -22925,22 +23331,22 @@ function searchPath(env) {
22925
23331
  }
22926
23332
  function resolveClaudeExecutableAbsolute(bin, env = process.env) {
22927
23333
  const candidate = bin && bin.length > 0 ? bin : "claude";
22928
- if (isAbsolute3(candidate)) return candidate;
23334
+ if (isAbsolute4(candidate)) return candidate;
22929
23335
  const windows = process.platform === "win32";
22930
23336
  for (const dir of searchPath(env).split(delimiter)) {
22931
23337
  if (!dir) continue;
22932
23338
  if (windows) {
22933
- const exe2 = join16(dir, `${candidate}.exe`);
23339
+ const exe2 = join19(dir, `${candidate}.exe`);
22934
23340
  try {
22935
23341
  accessSync(exe2, fsConstants.F_OK);
22936
23342
  return exe2;
22937
23343
  } catch {
22938
23344
  }
22939
- const viaShim = windowsShimTarget(join16(dir, `${candidate}.cmd`));
23345
+ const viaShim = windowsShimTarget(join19(dir, `${candidate}.cmd`));
22940
23346
  if (viaShim) return viaShim;
22941
23347
  continue;
22942
23348
  }
22943
- const full = join16(dir, candidate);
23349
+ const full = join19(dir, candidate);
22944
23350
  try {
22945
23351
  accessSync(full, fsConstants.X_OK);
22946
23352
  return full;
@@ -22955,18 +23361,18 @@ function claudeBrokerSocketPath(stateDir, sessionId) {
22955
23361
  }
22956
23362
  function claudeBrokerRecordPath(stateDir, sessionId) {
22957
23363
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
22958
- return join16(stateDir, "claude-broker", `${key}.json`);
23364
+ return join19(stateDir, "claude-broker", `${key}.json`);
22959
23365
  }
22960
23366
  function claudeBrokerRetirementPath(stateDir, sessionId) {
22961
23367
  const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
22962
- return join16(stateDir, "claude-broker", `${key}.retired`);
23368
+ return join19(stateDir, "claude-broker", `${key}.retired`);
22963
23369
  }
22964
23370
  function markBrokerRetired(stateDir, sessionId, reason, generation) {
22965
23371
  const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
22966
23372
  try {
22967
23373
  const path3 = claudeBrokerRetirementPath(stateDir, sessionId);
22968
- mkdirSync10(dirname8(path3), { recursive: true });
22969
- writeFileSync8(path3, JSON.stringify(mark));
23374
+ mkdirSync12(dirname10(path3), { recursive: true });
23375
+ writeFileSync10(path3, JSON.stringify(mark));
22970
23376
  } catch {
22971
23377
  }
22972
23378
  }
@@ -22974,7 +23380,7 @@ function takeBrokerRetirement(stateDir, sessionId) {
22974
23380
  const path3 = claudeBrokerRetirementPath(stateDir, sessionId);
22975
23381
  let mark = null;
22976
23382
  try {
22977
- const parsed = JSON.parse(readFileSync10(path3, "utf8"));
23383
+ const parsed = JSON.parse(readFileSync12(path3, "utf8"));
22978
23384
  if (typeof parsed?.at === "string" && typeof parsed.generation === "string" && typeof parsed.reason === "string") {
22979
23385
  mark = { at: parsed.at, generation: parsed.generation, reason: parsed.reason };
22980
23386
  }
@@ -22996,7 +23402,7 @@ function pidAlive(pid) {
22996
23402
  }
22997
23403
  function readBrokerRecord(recordPath2) {
22998
23404
  try {
22999
- return JSON.parse(readFileSync10(recordPath2, "utf8"));
23405
+ return JSON.parse(readFileSync12(recordPath2, "utf8"));
23000
23406
  } catch {
23001
23407
  return null;
23002
23408
  }
@@ -23009,7 +23415,7 @@ function lastKnownBrokerDaemon(stateDir, sessionId) {
23009
23415
  }
23010
23416
  function rememberBrokerIdentity(recordPath2, record) {
23011
23417
  try {
23012
- writeFileSync8(brokerLastKnownPath(recordPath2), JSON.stringify(record));
23418
+ writeFileSync10(brokerLastKnownPath(recordPath2), JSON.stringify(record));
23013
23419
  } catch {
23014
23420
  }
23015
23421
  }
@@ -23026,17 +23432,17 @@ function liveBrokerRecord(recordPath2) {
23026
23432
  return null;
23027
23433
  }
23028
23434
  function liveBrokerRecords(stateDir) {
23029
- const dir = join16(stateDir, "claude-broker");
23435
+ const dir = join19(stateDir, "claude-broker");
23030
23436
  let names;
23031
23437
  try {
23032
- names = readdirSync4(dir);
23438
+ names = readdirSync5(dir);
23033
23439
  } catch {
23034
23440
  return [];
23035
23441
  }
23036
23442
  const out = [];
23037
23443
  for (const name of names) {
23038
23444
  if (!name.endsWith(".json")) continue;
23039
- const record = liveBrokerRecord(join16(dir, name));
23445
+ const record = liveBrokerRecord(join19(dir, name));
23040
23446
  if (record) out.push(record);
23041
23447
  }
23042
23448
  return out;
@@ -23044,7 +23450,7 @@ function liveBrokerRecords(stateDir) {
23044
23450
  function forkBroker(options) {
23045
23451
  const socketPath = claudeBrokerSocketPath(options.stateDir, options.sessionId);
23046
23452
  const recordPath2 = claudeBrokerRecordPath(options.stateDir, options.sessionId);
23047
- mkdirSync10(dirname8(recordPath2), { recursive: true });
23453
+ mkdirSync12(dirname10(recordPath2), { recursive: true });
23048
23454
  const generation = randomUUID8();
23049
23455
  const config = {
23050
23456
  socketPath,
@@ -23654,7 +24060,7 @@ var init_delivery_ledger = __esm({
23654
24060
  });
23655
24061
 
23656
24062
  // packages/server/src/codex-subagents.ts
23657
- import { closeSync as closeSync7, openSync as openSync8, readSync as readSync2, statSync as statSync6 } from "node:fs";
24063
+ import { closeSync as closeSync8, openSync as openSync9, readSync as readSync2, statSync as statSync7 } from "node:fs";
23658
24064
  function createCodexSubAgentTracker(deps) {
23659
24065
  const findRollouts = deps.findRollouts ?? ((ids) => findRolloutsByIds(ids, deps.codexHome));
23660
24066
  const readAppended = deps.readAppended ?? defaultReadAppended;
@@ -23846,7 +24252,7 @@ function agentLabel(path3) {
23846
24252
  function defaultReadAppended(path3, offset) {
23847
24253
  let size;
23848
24254
  try {
23849
- size = statSync6(path3).size;
24255
+ size = statSync7(path3).size;
23850
24256
  } catch {
23851
24257
  return void 0;
23852
24258
  }
@@ -23854,7 +24260,7 @@ function defaultReadAppended(path3, offset) {
23854
24260
  const from = restarted ? 0 : offset;
23855
24261
  if (size <= from) return { text: "", offset: from, restarted };
23856
24262
  try {
23857
- const fd2 = openSync8(path3, "r");
24263
+ const fd2 = openSync9(path3, "r");
23858
24264
  try {
23859
24265
  const want = Math.min(ROLLOUT_READ_WINDOW, size - from);
23860
24266
  const buf = Buffer.allocUnsafe(want);
@@ -23863,7 +24269,7 @@ function defaultReadAppended(path3, offset) {
23863
24269
  const end = read < size - from && lastNl >= 0 ? lastNl + 1 : read;
23864
24270
  return { text: buf.toString("utf8", 0, end), offset: from + end, restarted };
23865
24271
  } finally {
23866
- closeSync7(fd2);
24272
+ closeSync8(fd2);
23867
24273
  }
23868
24274
  } catch {
23869
24275
  return void 0;
@@ -23988,15 +24394,15 @@ var init_completion_relay = __esm({
23988
24394
 
23989
24395
  // packages/server/src/tail-cache.ts
23990
24396
  import { createHash as createHash6 } from "node:crypto";
23991
- import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync11, readSync as readSync3, statSync as statSync7 } from "node:fs";
23992
- import { join as join17 } from "node:path";
24397
+ import { closeSync as closeSync9, openSync as openSync10, readFileSync as readFileSync13, readSync as readSync3, statSync as statSync8 } from "node:fs";
24398
+ import { join as join20 } from "node:path";
23993
24399
  function foldSchemaDigest(dir = import.meta.dirname) {
23994
24400
  if (foldSchemaMemo) return foldSchemaMemo;
23995
24401
  const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
23996
24402
  let read = 0;
23997
24403
  for (const name of FOLD_SOURCES) {
23998
24404
  try {
23999
- hash.update(name).update("\0").update(readFileSync11(join17(dir, name)));
24405
+ hash.update(name).update("\0").update(readFileSync13(join20(dir, name)));
24000
24406
  read++;
24001
24407
  } catch {
24002
24408
  hash.update(name).update("\0missing\0");
@@ -24026,9 +24432,9 @@ function measureFence(path3, offset) {
24026
24432
  if (!Number.isSafeInteger(offset) || offset <= 0) return null;
24027
24433
  let fd2;
24028
24434
  try {
24029
- const stat2 = statSync7(path3);
24435
+ const stat2 = statSync8(path3);
24030
24436
  if (stat2.size < offset) return null;
24031
- fd2 = openSync9(path3, "r");
24437
+ fd2 = openSync10(path3, "r");
24032
24438
  const window = Math.min(SAMPLE_BYTES, offset);
24033
24439
  const head = Buffer.allocUnsafe(window);
24034
24440
  const headRead = readSync3(fd2, head, 0, window, 0);
@@ -24048,7 +24454,7 @@ function measureFence(path3, offset) {
24048
24454
  } finally {
24049
24455
  if (fd2 !== void 0) {
24050
24456
  try {
24051
- closeSync8(fd2);
24457
+ closeSync9(fd2);
24052
24458
  } catch {
24053
24459
  }
24054
24460
  }
@@ -24199,11 +24605,11 @@ var init_tail_cache = __esm({
24199
24605
  });
24200
24606
 
24201
24607
  // packages/server/src/tailer.ts
24202
- import { statSync as statSync8, openSync as openSync10, readSync as readSync4, closeSync as closeSync9, readdirSync as readdirSync5, realpathSync as realpathSync5, mkdirSync as mkdirSync11, writeFileSync as writeFileSync9, readFileSync as readFileSync12, existsSync as existsSync5 } from "node:fs";
24608
+ import { statSync as statSync9, openSync as openSync11, readSync as readSync4, closeSync as closeSync10, readdirSync as readdirSync6, realpathSync as realpathSync6, mkdirSync as mkdirSync13, writeFileSync as writeFileSync11, readFileSync as readFileSync14, existsSync as existsSync7 } from "node:fs";
24203
24609
  import { execFile as execFile2 } from "node:child_process";
24204
24610
  import { createHash as createHash7 } from "node:crypto";
24205
24611
  import { promisify as promisify2 } from "node:util";
24206
- import { basename as basename4, join as join18, win32 } from "node:path";
24612
+ import { basename as basename4, join as join21, win32 } from "node:path";
24207
24613
  import { homedir as homedir7 } from "node:os";
24208
24614
  function pendingCallDeadline(tail) {
24209
24615
  const resolved2 = /* @__PURE__ */ new Set();
@@ -24250,7 +24656,7 @@ function readTranscriptTail(path3, size, window) {
24250
24656
  const length = Math.min(size, window);
24251
24657
  let fd2;
24252
24658
  try {
24253
- fd2 = openSync10(path3, "r");
24659
+ fd2 = openSync11(path3, "r");
24254
24660
  const buffer = Buffer.alloc(length);
24255
24661
  const read = readSync4(fd2, buffer, 0, length, size - length);
24256
24662
  const text2 = buffer.toString("utf8", 0, read);
@@ -24260,7 +24666,7 @@ function readTranscriptTail(path3, size, window) {
24260
24666
  } finally {
24261
24667
  if (fd2 !== void 0) {
24262
24668
  try {
24263
- closeSync9(fd2);
24669
+ closeSync10(fd2);
24264
24670
  } catch {
24265
24671
  }
24266
24672
  }
@@ -24274,7 +24680,7 @@ async function probeShellsAlive(shells, opts = {}) {
24274
24680
  const verdicts = /* @__PURE__ */ new Map();
24275
24681
  if (platform3 === "win32") {
24276
24682
  const present = outputFiles.filter((file) => {
24277
- if (existsSync5(file)) return true;
24683
+ if (existsSync7(file)) return true;
24278
24684
  verdicts.set(file, void 0);
24279
24685
  return false;
24280
24686
  });
@@ -24292,12 +24698,12 @@ async function probeShellsAlive(shells, opts = {}) {
24292
24698
  }
24293
24699
  const live = [];
24294
24700
  for (const file of outputFiles) {
24295
- if (!existsSync5(file)) {
24701
+ if (!existsSync7(file)) {
24296
24702
  verdicts.set(file, void 0);
24297
24703
  continue;
24298
24704
  }
24299
24705
  try {
24300
- live.push({ requested: file, real: realpathSync5(file) });
24706
+ live.push({ requested: file, real: realpathSync6(file) });
24301
24707
  } catch {
24302
24708
  verdicts.set(file, void 0);
24303
24709
  }
@@ -24730,7 +25136,7 @@ function launchTaskId(text2) {
24730
25136
  function readDescendantSidecars(sessionDir, mtimeMs) {
24731
25137
  let names;
24732
25138
  try {
24733
- names = readdirSync5(join18(sessionDir, "subagents"));
25139
+ names = readdirSync6(join21(sessionDir, "subagents"));
24734
25140
  } catch {
24735
25141
  return [];
24736
25142
  }
@@ -24741,7 +25147,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
24741
25147
  if (!agentId) continue;
24742
25148
  let parsed;
24743
25149
  try {
24744
- parsed = JSON.parse(readFileSync12(join18(sessionDir, "subagents", name), "utf8"));
25150
+ parsed = JSON.parse(readFileSync14(join21(sessionDir, "subagents", name), "utf8"));
24745
25151
  } catch {
24746
25152
  continue;
24747
25153
  }
@@ -24755,7 +25161,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
24755
25161
  agentType: text2(meta.agentType),
24756
25162
  parentAgentId: text2(meta.parentAgentId),
24757
25163
  spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
24758
- spawnedAtMs: mtimeMs(join18(sessionDir, "subagents", name))
25164
+ spawnedAtMs: mtimeMs(join21(sessionDir, "subagents", name))
24759
25165
  });
24760
25166
  }
24761
25167
  return out;
@@ -25244,19 +25650,19 @@ function isPermMarker(v) {
25244
25650
  }
25245
25651
  function defaultMtimeMs(path3) {
25246
25652
  try {
25247
- return statSync8(path3).mtimeMs;
25653
+ return statSync9(path3).mtimeMs;
25248
25654
  } catch {
25249
25655
  return void 0;
25250
25656
  }
25251
25657
  }
25252
25658
  function defaultLogDir(project) {
25253
- return join18(homedir7(), ".claude", "projects", project.cwdSlug);
25659
+ return join21(homedir7(), ".claude", "projects", project.cwdSlug);
25254
25660
  }
25255
25661
  function defaultReadPermMarker(project) {
25256
25662
  if (!project.stateDir) return () => void 0;
25257
25663
  return (slug) => {
25258
25664
  try {
25259
- const parsed = JSON.parse(readFileSync12(permMarkerPath(project, slug), "utf8"));
25665
+ const parsed = JSON.parse(readFileSync14(permMarkerPath(project, slug), "utf8"));
25260
25666
  return isPermMarker(parsed) ? parsed : void 0;
25261
25667
  } catch {
25262
25668
  return void 0;
@@ -25274,7 +25680,7 @@ function defaultBrokerDaemonAlive(project, now) {
25274
25680
  try {
25275
25681
  const path3 = claudeBrokerRecordPath(project.stateDir, sessionId);
25276
25682
  const record = readBrokerRecord(path3);
25277
- if (!record) alive = existsSync5(path3);
25683
+ if (!record) alive = existsSync7(path3);
25278
25684
  else if (typeof record.daemonPid !== "number") alive = true;
25279
25685
  else {
25280
25686
  try {
@@ -25382,7 +25788,7 @@ function createTailer(deps) {
25382
25788
  return paneDead(row.slug);
25383
25789
  }
25384
25790
  const defaultBackend = {
25385
- transcriptPath: (sessionId) => join18(logDir, `${sessionId}.jsonl`),
25791
+ transcriptPath: (sessionId) => join21(logDir, `${sessionId}.jsonl`),
25386
25792
  foldLine: (state, line) => {
25387
25793
  const rec = parseLine(line);
25388
25794
  if (rec) applyRecord(state, rec);
@@ -25424,7 +25830,7 @@ function createTailer(deps) {
25424
25830
  function blockedUntil(path3, m) {
25425
25831
  let size;
25426
25832
  try {
25427
- size = statSync8(path3).size;
25833
+ size = statSync9(path3).size;
25428
25834
  } catch {
25429
25835
  return void 0;
25430
25836
  }
@@ -25550,7 +25956,7 @@ ${ask}`;
25550
25956
  return state.path.replace(/\.jsonl$/, "");
25551
25957
  }
25552
25958
  function descendantSidecars(state) {
25553
- const at2 = mtimeMs(join18(sessionDirOf(state), "subagents"));
25959
+ const at2 = mtimeMs(join21(sessionDirOf(state), "subagents"));
25554
25960
  const cached2 = descendantIndex.get(state.slug);
25555
25961
  if (cached2 && cached2.at === at2) return cached2.all;
25556
25962
  const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
@@ -25564,7 +25970,7 @@ ${ask}`;
25564
25970
  return descendantIndex.get(state.slug)?.byToolUse.get(id2);
25565
25971
  }
25566
25972
  function descendantTranscript(state, meta) {
25567
- return join18(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
25973
+ return join21(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
25568
25974
  }
25569
25975
  function subAgentDescendantTasks(slug, id2) {
25570
25976
  const state = states.get(slug);
@@ -25884,7 +26290,7 @@ ${ask}`;
25884
26290
  if (!deps.project.dir) return [];
25885
26291
  const cwds = /* @__PURE__ */ new Set([deps.project.dir]);
25886
26292
  try {
25887
- cwds.add(realpathSync5(deps.project.dir));
26293
+ cwds.add(realpathSync6(deps.project.dir));
25888
26294
  } catch {
25889
26295
  }
25890
26296
  try {
@@ -25902,7 +26308,7 @@ ${ask}`;
25902
26308
  function scanForeign(nowMs) {
25903
26309
  let names;
25904
26310
  try {
25905
- names = readdirSync5(logDir);
26311
+ names = readdirSync6(logDir);
25906
26312
  } catch {
25907
26313
  return [];
25908
26314
  }
@@ -25912,10 +26318,10 @@ ${ask}`;
25912
26318
  if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
25913
26319
  const id2 = name.slice(0, -".jsonl".length);
25914
26320
  if (!id2 || registered.has(id2)) continue;
25915
- const path3 = join18(logDir, name);
26321
+ const path3 = join21(logDir, name);
25916
26322
  let mtime;
25917
26323
  try {
25918
- mtime = statSync8(path3).mtimeMs;
26324
+ mtime = statSync9(path3).mtimeMs;
25919
26325
  } catch {
25920
26326
  continue;
25921
26327
  }
@@ -26068,7 +26474,7 @@ ${ask}`;
26068
26474
  if (entry.path !== state.path) {
26069
26475
  let derivedSize = 0;
26070
26476
  try {
26071
- derivedSize = statSync8(state.path).size;
26477
+ derivedSize = statSync9(state.path).size;
26072
26478
  } catch {
26073
26479
  derivedSize = 0;
26074
26480
  }
@@ -26125,7 +26531,7 @@ ${ask}`;
26125
26531
  function consume(state, backend, onLine) {
26126
26532
  let size;
26127
26533
  try {
26128
- size = statSync8(state.path).size;
26534
+ size = statSync9(state.path).size;
26129
26535
  } catch {
26130
26536
  return;
26131
26537
  }
@@ -26136,7 +26542,7 @@ ${ask}`;
26136
26542
  if (size <= state.offset) return;
26137
26543
  let carry = state.partial ? Buffer.from(state.partial, "utf8") : EMPTY_BUFFER;
26138
26544
  try {
26139
- const fd2 = openSync10(state.path, "r");
26545
+ const fd2 = openSync11(state.path, "r");
26140
26546
  try {
26141
26547
  const buf = Buffer.allocUnsafe(Math.min(TRANSCRIPT_READ_WINDOW, size - state.offset));
26142
26548
  while (state.offset < size) {
@@ -26156,7 +26562,7 @@ ${ask}`;
26156
26562
  carry = start < view.length ? Buffer.from(view.subarray(start)) : EMPTY_BUFFER;
26157
26563
  }
26158
26564
  } finally {
26159
- closeSync9(fd2);
26565
+ closeSync10(fd2);
26160
26566
  }
26161
26567
  } catch {
26162
26568
  state.partial = carry.toString("utf8");
@@ -26183,8 +26589,8 @@ ${ask}`;
26183
26589
  `thread ${row.slug} (session ${row.session_id}): no transcript ${DISCOVERY_GRACE_MS / 1e3}s after dispatch \u2014 likely a boot failure. ${detail2.slice(0, 4e3)}`
26184
26590
  );
26185
26591
  try {
26186
- mkdirSync11(stallLogDir, { recursive: true });
26187
- writeFileSync9(join18(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
26592
+ mkdirSync13(stallLogDir, { recursive: true });
26593
+ writeFileSync11(join21(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
26188
26594
  captured_at: ${new Date(now()).toISOString()}
26189
26595
 
26190
26596
  ${detail2}
@@ -26194,10 +26600,10 @@ ${detail2}
26194
26600
  }
26195
26601
  function relocatedTranscript(state) {
26196
26602
  const name = `${state.nativeSessionId}.jsonl`;
26197
- const home = join18(logDir, name);
26603
+ const home = join21(logDir, name);
26198
26604
  const homeAt = home === state.path ? void 0 : mtimeOfNonEmpty(home);
26199
26605
  const dir = discoverTranscriptDir(logDir, state.nativeSessionId);
26200
- const sibling = dir ? join18(dir, name) : void 0;
26606
+ const sibling = dir ? join21(dir, name) : void 0;
26201
26607
  const siblingAt = sibling && sibling !== state.path ? mtimeOfNonEmpty(sibling) : void 0;
26202
26608
  if (homeAt === void 0) return siblingAt === void 0 ? void 0 : sibling;
26203
26609
  if (siblingAt === void 0) return home;
@@ -26205,7 +26611,7 @@ ${detail2}
26205
26611
  }
26206
26612
  function resolveTranscript(state, row, nowMs) {
26207
26613
  if (state.offset > 0) {
26208
- if (existsSync5(state.path)) {
26614
+ if (existsSync7(state.path)) {
26209
26615
  state.discoverMisses = 0;
26210
26616
  state.nextDiscoverMs = 0;
26211
26617
  return true;
@@ -26232,7 +26638,7 @@ ${detail2}
26232
26638
  }
26233
26639
  let size = 0;
26234
26640
  try {
26235
- size = statSync8(state.path).size;
26641
+ size = statSync9(state.path).size;
26236
26642
  } catch {
26237
26643
  size = 0;
26238
26644
  }
@@ -26249,7 +26655,7 @@ ${detail2}
26249
26655
  state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
26250
26656
  const strandedDir = discoverTranscriptDir(logDir, row.session_id);
26251
26657
  if (strandedDir) {
26252
- state.path = join18(strandedDir, `${row.session_id}.jsonl`);
26658
+ state.path = join21(strandedDir, `${row.session_id}.jsonl`);
26253
26659
  state.offset = 0;
26254
26660
  state.partial = "";
26255
26661
  state.primed = false;
@@ -26273,7 +26679,7 @@ ${detail2}
26273
26679
  committed = false;
26274
26680
  }
26275
26681
  if (!committed) return false;
26276
- state.path = join18(logDir, `${found}.jsonl`);
26682
+ state.path = join21(logDir, `${found}.jsonl`);
26277
26683
  state.offset = 0;
26278
26684
  state.partial = "";
26279
26685
  state.primed = false;
@@ -26333,7 +26739,7 @@ ${detail2}
26333
26739
  continue;
26334
26740
  }
26335
26741
  if (!state) {
26336
- const path3 = backend.transcriptPath(nativeId) ?? join18(logDir, `${nativeId}.jsonl`);
26742
+ const path3 = backend.transcriptPath(nativeId) ?? join21(logDir, `${nativeId}.jsonl`);
26337
26743
  state = newTailState(row.slug, row.session_id, path3, false, nativeId, runtimeGeneration);
26338
26744
  state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
26339
26745
  hydrateFromCache(state, row, nativeId);
@@ -26568,12 +26974,12 @@ ${detail2}
26568
26974
  const elapsed = monotonicNow() - started;
26569
26975
  lastTickMs = elapsed;
26570
26976
  lastTickEndedAtMs = now();
26571
- if (elapsed > POLL_MS2) {
26977
+ if (elapsed > POLL_MS3) {
26572
26978
  overBudgetTicks++;
26573
26979
  if (overBudgetTicks === 1 || overBudgetTicks % 30 === 0) {
26574
26980
  log.warn(
26575
26981
  "tailer",
26576
- `tick took ${Math.round(elapsed)}ms (poll ${POLL_MS2}ms, ${states.size} sessions) \u2014 the event loop is blocked for that long, so RPCs and board pushes are delayed (occurrence ${overBudgetTicks})`
26982
+ `tick took ${Math.round(elapsed)}ms (poll ${POLL_MS3}ms, ${states.size} sessions) \u2014 the event loop is blocked for that long, so RPCs and board pushes are delayed (occurrence ${overBudgetTicks})`
26577
26983
  );
26578
26984
  }
26579
26985
  }
@@ -26587,7 +26993,7 @@ ${detail2}
26587
26993
  }
26588
26994
  }
26589
26995
  function scheduleTick() {
26590
- const delay2 = primeIncomplete ? 1 : Math.min(MAX_POLL_MS, Math.max(POLL_MS2, Math.round(lastTickMs)));
26996
+ const delay2 = primeIncomplete ? 1 : Math.min(MAX_POLL_MS, Math.max(POLL_MS3, Math.round(lastTickMs)));
26591
26997
  timer = setTimeout(() => {
26592
26998
  timer = null;
26593
26999
  try {
@@ -26691,7 +27097,7 @@ function landsAfterRead(eventAt, lastReadAt) {
26691
27097
  if (!Number.isFinite(e14) || !Number.isFinite(r)) return true;
26692
27098
  return e14 > r;
26693
27099
  }
26694
- var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS2, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, BASH_TIMEOUT_CEILING_MS, PENDING_CALL_TAIL_BYTES, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, LIVE_TOOLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, ASSISTANT_LINE_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, FOLDED_TERMINALS_MAX, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
27100
+ var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS3, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, BASH_TIMEOUT_CEILING_MS, PENDING_CALL_TAIL_BYTES, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, LIVE_TOOLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, ASSISTANT_LINE_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, FOLDED_TERMINALS_MAX, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
26695
27101
  var init_tailer = __esm({
26696
27102
  "packages/server/src/tailer.ts"() {
26697
27103
  "use strict";
@@ -26717,7 +27123,7 @@ var init_tailer = __esm({
26717
27123
  init_credential_redaction();
26718
27124
  IDLE_BACKSTOP_MS = 5e3;
26719
27125
  RUNTIME_CHASE_MAX = 20;
26720
- POLL_MS2 = 1e3;
27126
+ POLL_MS3 = 1e3;
26721
27127
  MAX_PRIME_ROWS_PER_TICK = 25;
26722
27128
  PRIME_BUDGET_MS = 200;
26723
27129
  TRANSCRIPT_READ_WINDOW = 16 * 1024 * 1024;
@@ -26801,14 +27207,14 @@ var init_tailer = __esm({
26801
27207
  });
26802
27208
 
26803
27209
  // packages/server/src/backend/codex.ts
26804
- import { join as join19 } from "node:path";
27210
+ import { join as join22 } from "node:path";
26805
27211
  import { homedir as homedir8 } from "node:os";
26806
- import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync13, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
27212
+ import { readdirSync as readdirSync7, statSync as statSync10, readFileSync as readFileSync15, openSync as openSync12, readSync as readSync5, closeSync as closeSync11 } from "node:fs";
26807
27213
  function defaultCodexHome() {
26808
- return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join19(homedir8(), ".codex");
27214
+ return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join22(homedir8(), ".codex");
26809
27215
  }
26810
27216
  function sessionsDir(codexHome) {
26811
- return join19(codexHome, "sessions");
27217
+ return join22(codexHome, "sessions");
26812
27218
  }
26813
27219
  function codexSandbox(mode) {
26814
27220
  switch (mode) {
@@ -27254,23 +27660,23 @@ function collectRollouts(dir, out, budget) {
27254
27660
  const files = entries2.filter((e14) => e14.isFile() && e14.name.startsWith("rollout-") && e14.name.endsWith(".jsonl")).sort(descByName);
27255
27661
  for (const d of dirs) {
27256
27662
  if (budget.n <= 0) return;
27257
- collectRollouts(join19(dir, d.name), out, budget);
27663
+ collectRollouts(join22(dir, d.name), out, budget);
27258
27664
  }
27259
27665
  for (const f of files) {
27260
27666
  if (budget.n <= 0) return;
27261
27667
  let mtimeMs;
27262
27668
  try {
27263
- mtimeMs = statSync9(join19(dir, f.name)).mtimeMs;
27669
+ mtimeMs = statSync10(join22(dir, f.name)).mtimeMs;
27264
27670
  } catch {
27265
27671
  continue;
27266
27672
  }
27267
- out.push({ path: join19(dir, f.name), mtimeMs });
27673
+ out.push({ path: join22(dir, f.name), mtimeMs });
27268
27674
  budget.n--;
27269
27675
  }
27270
27676
  }
27271
27677
  function safeReaddir(dir) {
27272
27678
  try {
27273
- return readdirSync6(dir, { withFileTypes: true });
27679
+ return readdirSync7(dir, { withFileTypes: true });
27274
27680
  } catch {
27275
27681
  return [];
27276
27682
  }
@@ -27308,9 +27714,9 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
27308
27714
  const out = /* @__PURE__ */ new Map();
27309
27715
  let raw2;
27310
27716
  try {
27311
- const path3 = join19(codexHome, "session_index.jsonl");
27312
- if (statSync9(path3).size > SESSION_INDEX_MAX_BYTES) return out;
27313
- raw2 = readFileSync13(path3, "utf8");
27717
+ const path3 = join22(codexHome, "session_index.jsonl");
27718
+ if (statSync10(path3).size > SESSION_INDEX_MAX_BYTES) return out;
27719
+ raw2 = readFileSync15(path3, "utf8");
27314
27720
  } catch {
27315
27721
  return out;
27316
27722
  }
@@ -27350,7 +27756,7 @@ function rolloutIdOf(path3) {
27350
27756
  function readSessionMeta(path3) {
27351
27757
  let fd2;
27352
27758
  try {
27353
- fd2 = openSync11(path3, "r");
27759
+ fd2 = openSync12(path3, "r");
27354
27760
  const buf = Buffer.allocUnsafe(FOREIGN_ROLLOUT_HEAD_BYTES);
27355
27761
  const n = readSync5(fd2, buf, 0, FOREIGN_ROLLOUT_HEAD_BYTES, 0);
27356
27762
  const line = buf.toString("utf8", 0, n).split("\n", 1)[0];
@@ -27367,7 +27773,7 @@ function readSessionMeta(path3) {
27367
27773
  } finally {
27368
27774
  if (fd2 !== void 0) {
27369
27775
  try {
27370
- closeSync10(fd2);
27776
+ closeSync11(fd2);
27371
27777
  } catch {
27372
27778
  }
27373
27779
  }
@@ -27486,7 +27892,7 @@ var init_codex = __esm({
27486
27892
  });
27487
27893
 
27488
27894
  // packages/server/src/backend/codex-executable.ts
27489
- import { accessSync as accessSync2, constants as fsConstants2, readFileSync as readFileSync14 } from "node:fs";
27895
+ import { accessSync as accessSync2, constants as fsConstants2, readFileSync as readFileSync16 } from "node:fs";
27490
27896
  import { posix, win32 as win322 } from "node:path";
27491
27897
  function defaultAccess(path3, mode) {
27492
27898
  try {
@@ -27498,7 +27904,7 @@ function defaultAccess(path3, mode) {
27498
27904
  }
27499
27905
  function defaultReadFile(path3) {
27500
27906
  try {
27501
- return readFileSync14(path3, "utf8");
27907
+ return readFileSync16(path3, "utf8");
27502
27908
  } catch {
27503
27909
  return void 0;
27504
27910
  }
@@ -27512,19 +27918,19 @@ function searchPath2(env) {
27512
27918
  function vendoredNativeBeside(launcherJs, arch, access) {
27513
27919
  const triple = WINDOWS_TRIPLE[arch];
27514
27920
  if (!triple) return void 0;
27515
- const { dirname: dirname27, join: join50 } = win322;
27516
- const pkgRoot = dirname27(dirname27(launcherJs));
27921
+ const { dirname: dirname29, join: join54 } = win322;
27922
+ const pkgRoot = dirname29(dirname29(launcherJs));
27517
27923
  const platformPkg = `codex-win32-${arch}`;
27518
27924
  const vendorRoots = [
27519
- join50(pkgRoot, "node_modules", "@openai", platformPkg, "vendor"),
27925
+ join54(pkgRoot, "node_modules", "@openai", platformPkg, "vendor"),
27520
27926
  // nested under the package
27521
- join50(dirname27(pkgRoot), platformPkg, "vendor"),
27927
+ join54(dirname29(pkgRoot), platformPkg, "vendor"),
27522
27928
  // hoisted beside it: <prefix>\node_modules\@openai\<pkg>
27523
- join50(pkgRoot, "vendor")
27929
+ join54(pkgRoot, "vendor")
27524
27930
  // the pre-platform-package layout, binaries inside @openai/codex itself
27525
27931
  ];
27526
27932
  for (const root of vendorRoots) {
27527
- const exe2 = join50(root, triple, "bin", "codex.exe");
27933
+ const exe2 = join54(root, triple, "bin", "codex.exe");
27528
27934
  if (access(exe2, "exists")) return exe2;
27529
27935
  }
27530
27936
  return void 0;
@@ -29848,7 +30254,7 @@ var require_websocket = __commonJS({
29848
30254
  var http = __require("http");
29849
30255
  var net2 = __require("net");
29850
30256
  var tls = __require("tls");
29851
- var { randomBytes, createHash: createHash18 } = __require("crypto");
30257
+ var { randomBytes: randomBytes2, createHash: createHash18 } = __require("crypto");
29852
30258
  var { Duplex, Readable: Readable3 } = __require("stream");
29853
30259
  var { URL: URL2 } = __require("url");
29854
30260
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -30386,7 +30792,7 @@ var require_websocket = __commonJS({
30386
30792
  }
30387
30793
  }
30388
30794
  const defaultPort = isSecure ? 443 : 80;
30389
- const key = randomBytes(16).toString("base64");
30795
+ const key = randomBytes2(16).toString("base64");
30390
30796
  const request = isSecure ? https.request : http.request;
30391
30797
  const protocolSet = /* @__PURE__ */ new Set();
30392
30798
  let perMessageDeflate;
@@ -31356,15 +31762,15 @@ import { spawn as spawn2 } from "node:child_process";
31356
31762
  import { connect } from "node:net";
31357
31763
  import { Agent as HttpAgent } from "node:http";
31358
31764
  import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
31359
- import { existsSync as existsSync6, mkdirSync as mkdirSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "node:fs";
31360
- import { join as join20 } from "node:path";
31765
+ import { existsSync as existsSync8, mkdirSync as mkdirSync14, readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync12 } from "node:fs";
31766
+ import { join as join23 } from "node:path";
31361
31767
  import { PassThrough, Writable } from "node:stream";
31362
31768
  import { StringDecoder } from "node:string_decoder";
31363
31769
  function nativeDir(stateDir) {
31364
- return join20(stateDir, "codex-app-server-native");
31770
+ return join23(stateDir, "codex-app-server-native");
31365
31771
  }
31366
31772
  function nativeRecordPath(stateDir, projectId) {
31367
- return join20(nativeDir(stateDir), `${projectId}.json`);
31773
+ return join23(nativeDir(stateDir), `${projectId}.json`);
31368
31774
  }
31369
31775
  function nativeListenSocketPath(stateDir, projectId) {
31370
31776
  const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
@@ -31380,7 +31786,7 @@ function pidAlive2(pid) {
31380
31786
  }
31381
31787
  function readNativeRecord(stateDir, projectId) {
31382
31788
  try {
31383
- const value = JSON.parse(readFileSync15(nativeRecordPath(stateDir, projectId), "utf8"));
31789
+ const value = JSON.parse(readFileSync17(nativeRecordPath(stateDir, projectId), "utf8"));
31384
31790
  if (typeof value.listenerPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
31385
31791
  return {
31386
31792
  projectId,
@@ -31397,7 +31803,7 @@ function readNativeRecord(stateDir, projectId) {
31397
31803
  function liveNativeRecord(stateDir, projectId) {
31398
31804
  const record = readNativeRecord(stateDir, projectId);
31399
31805
  if (!record) return null;
31400
- if (pidAlive2(record.listenerPid) && existsSync6(record.socketPath)) return record;
31806
+ if (pidAlive2(record.listenerPid) && existsSync8(record.socketPath)) return record;
31401
31807
  try {
31402
31808
  unlinkSync2(nativeRecordPath(stateDir, projectId));
31403
31809
  } catch {
@@ -31537,9 +31943,9 @@ function attach(record, timeoutMs) {
31537
31943
  }
31538
31944
  async function startListener(options) {
31539
31945
  const { stateDir, projectId } = options;
31540
- mkdirSync12(nativeDir(stateDir), { recursive: true });
31946
+ mkdirSync14(nativeDir(stateDir), { recursive: true });
31541
31947
  const socketPath = nativeListenSocketPath(stateDir, projectId);
31542
- if (existsSync6(socketPath) && !await socketAccepting(socketPath)) {
31948
+ if (existsSync8(socketPath) && !await socketAccepting(socketPath)) {
31543
31949
  try {
31544
31950
  unlinkSync2(socketPath);
31545
31951
  } catch {
@@ -31564,10 +31970,10 @@ async function startListener(options) {
31564
31970
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
31565
31971
  ...options.authAccountId ? { authAccountId: options.authAccountId } : {}
31566
31972
  };
31567
- writeFileSync10(nativeRecordPath(stateDir, projectId), JSON.stringify(record));
31973
+ writeFileSync12(nativeRecordPath(stateDir, projectId), JSON.stringify(record));
31568
31974
  const deadline = Date.now() + (options.timeoutMs ?? 3e4);
31569
31975
  for (; ; ) {
31570
- if (existsSync6(socketPath) && await socketAccepting(socketPath)) return record;
31976
+ if (existsSync8(socketPath) && await socketAccepting(socketPath)) return record;
31571
31977
  if (!pidAlive2(record.listenerPid)) throw new Error("codex app-server listener exited before it became ready");
31572
31978
  if (Date.now() > deadline) throw new Error("codex app-server listener did not become ready");
31573
31979
  await new Promise((resolve13) => setTimeout(resolve13, 50));
@@ -31636,15 +32042,15 @@ var init_codex_app_server_native = __esm({
31636
32042
  import { spawn as spawn3 } from "node:child_process";
31637
32043
  import { createConnection } from "node:net";
31638
32044
  import { createHash as createHash9, randomUUID as randomUUID10 } from "node:crypto";
31639
- import { existsSync as existsSync7, mkdirSync as mkdirSync13, readFileSync as readFileSync16, unlinkSync as unlinkSync3 } from "node:fs";
31640
- import { join as join21 } from "node:path";
32045
+ import { existsSync as existsSync9, mkdirSync as mkdirSync15, readFileSync as readFileSync18, unlinkSync as unlinkSync3 } from "node:fs";
32046
+ import { join as join24 } from "node:path";
31641
32047
  import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
31642
32048
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
31643
32049
  function daemonDir(stateDir) {
31644
- return join21(stateDir, "codex-app-server");
32050
+ return join24(stateDir, "codex-app-server");
31645
32051
  }
31646
32052
  function recordPath(stateDir, projectId) {
31647
- return join21(daemonDir(stateDir), `${projectId}.json`);
32053
+ return join24(daemonDir(stateDir), `${projectId}.json`);
31648
32054
  }
31649
32055
  function codexAppServerSocketPath(stateDir, projectId) {
31650
32056
  const key = createHash9("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
@@ -31660,7 +32066,7 @@ function pidAlive3(pid) {
31660
32066
  }
31661
32067
  function readDaemonRecord(stateDir, projectId) {
31662
32068
  try {
31663
- const value = JSON.parse(readFileSync16(recordPath(stateDir, projectId), "utf8"));
32069
+ const value = JSON.parse(readFileSync18(recordPath(stateDir, projectId), "utf8"));
31664
32070
  if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
31665
32071
  return {
31666
32072
  projectId,
@@ -31677,7 +32083,7 @@ function readDaemonRecord(stateDir, projectId) {
31677
32083
  }
31678
32084
  function readDaemonExitBreadcrumb(stateDir, projectId) {
31679
32085
  try {
31680
- const value = JSON.parse(readFileSync16(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
32086
+ const value = JSON.parse(readFileSync18(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
31681
32087
  if (typeof value.generation !== "string" || typeof value.reason !== "string") return null;
31682
32088
  return {
31683
32089
  generation: value.generation,
@@ -31727,7 +32133,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
31727
32133
  }
31728
32134
  function forkDaemon(options) {
31729
32135
  const { stateDir, projectId } = options;
31730
- mkdirSync13(daemonDir(stateDir), { recursive: true });
32136
+ mkdirSync15(daemonDir(stateDir), { recursive: true });
31731
32137
  const record = recordPath(stateDir, projectId);
31732
32138
  try {
31733
32139
  unlinkSync3(record);
@@ -31922,7 +32328,7 @@ var init_codex_app_server_host = __esm({
31922
32328
  }
31923
32329
  if (process.platform !== "win32") {
31924
32330
  const stale = codexAppServerSocketPath(options.stateDir, options.projectId);
31925
- if (existsSync7(stale) && !liveDaemonRecord(options.stateDir, options.projectId)) {
32331
+ if (existsSync9(stale) && !liveDaemonRecord(options.stateDir, options.projectId)) {
31926
32332
  try {
31927
32333
  unlinkSync3(stale);
31928
32334
  } catch {
@@ -31942,7 +32348,7 @@ var init_codex_app_server_host = __esm({
31942
32348
  });
31943
32349
 
31944
32350
  // packages/server/src/backend/claude-quota.ts
31945
- import { join as join22 } from "node:path";
32351
+ import { join as join25 } from "node:path";
31946
32352
  import { homedir as homedir9, platform } from "node:os";
31947
32353
  import { createHash as createHash10 } from "node:crypto";
31948
32354
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -31950,7 +32356,7 @@ import { execFile as execFile3 } from "node:child_process";
31950
32356
  import { promisify as promisify3 } from "node:util";
31951
32357
  function claudeConfigDir() {
31952
32358
  const override = process.env.CLAUDE_CONFIG_DIR;
31953
- return override && override.trim() ? override : join22(homedir9(), ".claude");
32359
+ return override && override.trim() ? override : join25(homedir9(), ".claude");
31954
32360
  }
31955
32361
  function tokenFromCredentialsJson(raw2) {
31956
32362
  let doc;
@@ -31979,7 +32385,7 @@ async function readKeychainToken() {
31979
32385
  }
31980
32386
  async function readAccessToken(configDir) {
31981
32387
  try {
31982
- const fromFile = tokenFromCredentialsJson(await readFile(join22(configDir, ".credentials.json"), "utf8"));
32388
+ const fromFile = tokenFromCredentialsJson(await readFile(join25(configDir, ".credentials.json"), "utf8"));
31983
32389
  if (fromFile) return fromFile;
31984
32390
  } catch {
31985
32391
  }
@@ -32053,8 +32459,8 @@ function retryAtFrom(res, now) {
32053
32459
  function cachePaths(cacheDir, configDir) {
32054
32460
  const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
32055
32461
  return {
32056
- data: join22(cacheDir, `claude-${profile}.json`),
32057
- lock: join22(cacheDir, `claude-${profile}.lock`)
32462
+ data: join25(cacheDir, `claude-${profile}.json`),
32463
+ lock: join25(cacheDir, `claude-${profile}.lock`)
32058
32464
  };
32059
32465
  }
32060
32466
  async function readShared(path3) {
@@ -32266,7 +32672,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
32266
32672
  async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32267
32673
  const now = (deps.now ?? Date.now)();
32268
32674
  const configDir = claudeConfigDir();
32269
- const cacheDir = deps.cacheDir ?? join22(frizzRoots().cache, "quota-cache");
32675
+ const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
32270
32676
  try {
32271
32677
  await mkdir(cacheDir, { recursive: true, mode: 448 });
32272
32678
  } catch {
@@ -32280,7 +32686,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32280
32686
  async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
32281
32687
  const now = (deps.now ?? Date.now)();
32282
32688
  const configDir = claudeConfigDir();
32283
- const cacheDir = deps.cacheDir ?? join22(frizzRoots().cache, "quota-cache");
32689
+ const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
32284
32690
  const paths = cachePaths(cacheDir, configDir);
32285
32691
  try {
32286
32692
  await mkdir(cacheDir, { recursive: true, mode: 448 });
@@ -32387,19 +32793,19 @@ var init_claude_quota = __esm({
32387
32793
  });
32388
32794
 
32389
32795
  // packages/server/src/backend/auth-status.ts
32390
- import { join as join23 } from "node:path";
32796
+ import { join as join26 } from "node:path";
32391
32797
  import { homedir as homedir10, platform as platform2 } from "node:os";
32392
- import { readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
32798
+ import { readFileSync as readFileSync19, statSync as statSync11 } from "node:fs";
32393
32799
  import { execFile as execFile4 } from "node:child_process";
32394
32800
  import { promisify as promisify4 } from "node:util";
32395
32801
  function claudeConfigDir2() {
32396
32802
  const override = process.env.CLAUDE_CONFIG_DIR;
32397
- return override && override.trim() ? override : join23(homedir10(), ".claude");
32803
+ return override && override.trim() ? override : join26(homedir10(), ".claude");
32398
32804
  }
32399
32805
  function claudeFileState(configDir) {
32400
32806
  let raw2;
32401
32807
  try {
32402
- raw2 = readFileSync17(join23(configDir, ".credentials.json"), "utf8");
32808
+ raw2 = readFileSync19(join26(configDir, ".credentials.json"), "utf8");
32403
32809
  } catch (err) {
32404
32810
  return err.code === "ENOENT" ? "absent" : "error";
32405
32811
  }
@@ -32432,7 +32838,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
32432
32838
  if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
32433
32839
  let raw2;
32434
32840
  try {
32435
- raw2 = readFileSync17(join23(codexHome, "auth.json"), "utf8");
32841
+ raw2 = readFileSync19(join26(codexHome, "auth.json"), "utf8");
32436
32842
  } catch (err) {
32437
32843
  return err.code === "ENOENT" ? "signed-out" : "unknown";
32438
32844
  }
@@ -32452,7 +32858,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
32452
32858
  function readCodexAccountId(codexHome = defaultCodexHome()) {
32453
32859
  if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return void 0;
32454
32860
  try {
32455
- const doc = JSON.parse(readFileSync17(join23(codexHome, "auth.json"), "utf8"));
32861
+ const doc = JSON.parse(readFileSync19(join26(codexHome, "auth.json"), "utf8"));
32456
32862
  if (!doc || typeof doc !== "object") return void 0;
32457
32863
  const tokens = doc.tokens;
32458
32864
  if (!tokens || typeof tokens !== "object") return void 0;
@@ -32511,12 +32917,12 @@ function asEmail(value) {
32511
32917
  }
32512
32918
  function claudeAccountFile() {
32513
32919
  const override = process.env.CLAUDE_CONFIG_DIR;
32514
- return override && override.trim() ? join23(override, ".claude.json") : join23(homedir10(), ".claude.json");
32920
+ return override && override.trim() ? join26(override, ".claude.json") : join26(homedir10(), ".claude.json");
32515
32921
  }
32516
32922
  function readClaudeAccountEmail(path3 = claudeAccountFile()) {
32517
32923
  let stat2;
32518
32924
  try {
32519
- stat2 = statSync10(path3);
32925
+ stat2 = statSync11(path3);
32520
32926
  } catch {
32521
32927
  return void 0;
32522
32928
  }
@@ -32524,7 +32930,7 @@ function readClaudeAccountEmail(path3 = claudeAccountFile()) {
32524
32930
  if (memo3 && memo3.path === path3 && memo3.mtimeMs === stat2.mtimeMs && memo3.size === stat2.size) return memo3.email;
32525
32931
  let email;
32526
32932
  try {
32527
- const doc = JSON.parse(readFileSync17(path3, "utf8"));
32933
+ const doc = JSON.parse(readFileSync19(path3, "utf8"));
32528
32934
  email = asEmail(doc?.oauthAccount?.emailAddress);
32529
32935
  } catch {
32530
32936
  email = void 0;
@@ -32535,7 +32941,7 @@ function readClaudeAccountEmail(path3 = claudeAccountFile()) {
32535
32941
  function readCodexAccountEmail(codexHome = defaultCodexHome()) {
32536
32942
  let doc;
32537
32943
  try {
32538
- doc = JSON.parse(readFileSync17(join23(codexHome, "auth.json"), "utf8"));
32944
+ doc = JSON.parse(readFileSync19(join26(codexHome, "auth.json"), "utf8"));
32539
32945
  } catch {
32540
32946
  return void 0;
32541
32947
  }
@@ -32661,7 +33067,7 @@ var init_codex_execution_health = __esm({
32661
33067
 
32662
33068
  // packages/server/src/backend/codex-app-server.ts
32663
33069
  import { createHash as createHash11, randomUUID as randomUUID11 } from "node:crypto";
32664
- import { existsSync as existsSync8 } from "node:fs";
33070
+ import { existsSync as existsSync10 } from "node:fs";
32665
33071
  import { StringDecoder as StringDecoder3 } from "node:string_decoder";
32666
33072
  function selectCodexHostKind(flagValue, platform3, hasSpawn) {
32667
33073
  if (hasSpawn) return "direct";
@@ -35111,7 +35517,7 @@ var init_codex_app_server = __esm({
35111
35517
  * external rollout may legitimately live somewhere else.
35112
35518
  */
35113
35519
  resumeCwdOverride(row) {
35114
- if (existsSync8(row.cwd)) return {};
35520
+ if (existsSync10(row.cwd)) return {};
35115
35521
  return { cwd: this.options.projectDir };
35116
35522
  }
35117
35523
  recordResumedCwd(row, override) {
@@ -35933,17 +36339,17 @@ var init_codex_app_server = __esm({
35933
36339
  });
35934
36340
 
35935
36341
  // packages/server/src/backend/codex-quota.ts
35936
- import { join as join24 } from "node:path";
35937
- import { readdirSync as readdirSync7, statSync as statSync11, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
36342
+ import { join as join27 } from "node:path";
36343
+ import { readdirSync as readdirSync8, statSync as statSync12, openSync as openSync13, readSync as readSync6, fstatSync, closeSync as closeSync12 } from "node:fs";
35938
36344
  import { spawn as spawn4 } from "node:child_process";
35939
36345
  function sessionsDir2(codexHome) {
35940
- return join24(codexHome, "sessions");
36346
+ return join27(codexHome, "sessions");
35941
36347
  }
35942
36348
  function newestRollouts(dir, out, budget) {
35943
36349
  if (budget.n <= 0) return;
35944
36350
  let entries2;
35945
36351
  try {
35946
- entries2 = readdirSync7(dir, { withFileTypes: true });
36352
+ entries2 = readdirSync8(dir, { withFileTypes: true });
35947
36353
  } catch {
35948
36354
  return;
35949
36355
  }
@@ -35951,18 +36357,18 @@ function newestRollouts(dir, out, budget) {
35951
36357
  const files = entries2.filter((e14) => e14.isFile() && e14.name.startsWith("rollout-") && e14.name.endsWith(".jsonl")).map((e14) => e14.name).sort(descByName2);
35952
36358
  for (const d of dirs) {
35953
36359
  if (budget.n <= 0) return;
35954
- newestRollouts(join24(dir, d), out, budget);
36360
+ newestRollouts(join27(dir, d), out, budget);
35955
36361
  }
35956
36362
  for (const f of files) {
35957
36363
  if (budget.n <= 0) return;
35958
- out.push(join24(dir, f));
36364
+ out.push(join27(dir, f));
35959
36365
  budget.n--;
35960
36366
  }
35961
36367
  }
35962
36368
  function readTail(path3) {
35963
36369
  let fd2;
35964
36370
  try {
35965
- fd2 = openSync12(path3, "r");
36371
+ fd2 = openSync13(path3, "r");
35966
36372
  const size = fstatSync(fd2).size;
35967
36373
  const start = Math.max(0, size - TAIL_BYTES);
35968
36374
  const len = size - start;
@@ -35979,7 +36385,7 @@ function readTail(path3) {
35979
36385
  } finally {
35980
36386
  if (fd2 !== void 0) {
35981
36387
  try {
35982
- closeSync11(fd2);
36388
+ closeSync12(fd2);
35983
36389
  } catch {
35984
36390
  }
35985
36391
  }
@@ -36027,7 +36433,7 @@ function readCodexQuotaFromRollouts(codexHome = defaultCodexHome()) {
36027
36433
  newestRollouts(sessionsDir2(codexHome), rollouts, { n: 8 });
36028
36434
  const byMtime = rollouts.map((path3) => {
36029
36435
  try {
36030
- return { path: path3, mtimeMs: statSync11(path3).mtimeMs };
36436
+ return { path: path3, mtimeMs: statSync12(path3).mtimeMs };
36031
36437
  } catch {
36032
36438
  return void 0;
36033
36439
  }
@@ -36226,25 +36632,15 @@ var init_quota = __esm({
36226
36632
  }
36227
36633
  });
36228
36634
 
36229
- // packages/server/src/local-path.ts
36230
- function normalizeLocalPath(path3, platform3 = process.platform) {
36231
- return platform3 === "win32" ? path3.replace(/^\/([a-zA-Z]:[\\/])/, "$1") : path3;
36232
- }
36233
- var init_local_path = __esm({
36234
- "packages/server/src/local-path.ts"() {
36235
- "use strict";
36236
- }
36237
- });
36238
-
36239
36635
  // packages/server/src/local-file.ts
36240
36636
  import { spawn as spawn5 } from "node:child_process";
36241
- import { existsSync as existsSync9, readFileSync as readFileSync18, realpathSync as realpathSync6, statSync as statSync12 } from "node:fs";
36637
+ import { existsSync as existsSync11, readFileSync as readFileSync20, realpathSync as realpathSync7, statSync as statSync13 } from "node:fs";
36242
36638
  import { homedir as homedir11 } from "node:os";
36243
- import { dirname as dirname9, isAbsolute as isAbsolute4, join as join25, resolve as resolve5, sep as sep2 } from "node:path";
36639
+ import { dirname as dirname11, isAbsolute as isAbsolute5, join as join28, resolve as resolve5, sep as sep2 } from "node:path";
36244
36640
  function isUnder(real, root) {
36245
36641
  let rootReal;
36246
36642
  try {
36247
- rootReal = realpathSync6(root);
36643
+ rootReal = realpathSync7(root);
36248
36644
  } catch {
36249
36645
  return false;
36250
36646
  }
@@ -36252,12 +36648,12 @@ function isUnder(real, root) {
36252
36648
  return real === rootReal || real.startsWith(rootReal.endsWith(sep2) ? rootReal : rootReal + sep2);
36253
36649
  }
36254
36650
  try {
36255
- const trusted2 = statSync12(rootReal, { bigint: true });
36651
+ const trusted2 = statSync13(rootReal, { bigint: true });
36256
36652
  if (!trusted2.isDirectory() || trusted2.ino === 0n) return false;
36257
36653
  for (let ancestor = real; ; ) {
36258
- const actual = statSync12(ancestor, { bigint: true });
36654
+ const actual = statSync13(ancestor, { bigint: true });
36259
36655
  if (actual.dev === trusted2.dev && actual.ino === trusted2.ino) return true;
36260
- const parent = dirname9(ancestor);
36656
+ const parent = dirname11(ancestor);
36261
36657
  if (parent === ancestor) return false;
36262
36658
  ancestor = parent;
36263
36659
  }
@@ -36267,16 +36663,16 @@ function isUnder(real, root) {
36267
36663
  }
36268
36664
  function resolveLocalFile(rawPath, roots) {
36269
36665
  rawPath = normalizeLocalPath(rawPath);
36270
- if (!isAbsolute4(rawPath)) throw new Error("Local path must be absolute");
36666
+ if (!isAbsolute5(rawPath)) throw new Error("Local path must be absolute");
36271
36667
  let real;
36272
36668
  try {
36273
- real = realpathSync6(rawPath);
36669
+ real = realpathSync7(rawPath);
36274
36670
  } catch {
36275
36671
  throw new Error("Local file was not found");
36276
36672
  }
36277
36673
  if (!roots.some((root) => isUnder(real, root))) throw new Error("Local file is outside Frizz's trusted roots");
36278
36674
  try {
36279
- if (!statSync12(real).isFile()) throw new Error("Local path is not a regular file");
36675
+ if (!statSync13(real).isFile()) throw new Error("Local path is not a regular file");
36280
36676
  } catch (error) {
36281
36677
  if (error instanceof Error && error.message === "Local path is not a regular file") throw error;
36282
36678
  throw new Error("Local file was not found");
@@ -36286,7 +36682,7 @@ function resolveLocalFile(rawPath, roots) {
36286
36682
  function resolveOpenableFile(raw2, projectDir, roots, home = homedir11()) {
36287
36683
  const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
36288
36684
  if (!trimmed) return null;
36289
- const abs = trimmed === "~" ? home : /^~[\/\\]/.test(trimmed) ? join25(home, trimmed.slice(2)) : isAbsolute4(trimmed) ? trimmed : resolve5(projectDir, trimmed);
36685
+ const abs = trimmed === "~" ? home : /^~[\/\\]/.test(trimmed) ? join28(home, trimmed.slice(2)) : isAbsolute5(trimmed) ? trimmed : resolve5(projectDir, trimmed);
36290
36686
  try {
36291
36687
  return resolveLocalFile(abs, roots);
36292
36688
  } catch {
@@ -36295,7 +36691,7 @@ function resolveOpenableFile(raw2, projectDir, roots, home = homedir11()) {
36295
36691
  }
36296
36692
  function readLocalTextFile(rawPath, roots) {
36297
36693
  const path3 = resolveLocalFile(rawPath, roots);
36298
- const bytes = readFileSync18(path3);
36694
+ const bytes = readFileSync20(path3);
36299
36695
  if (bytes.subarray(0, 8192).includes(0)) throw new Error("Local file is not a text file");
36300
36696
  if (bytes.length <= MARKDOWN_READ_LIMIT) return { path: path3, text: bytes.toString("utf8"), truncated: false };
36301
36697
  const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
@@ -36306,7 +36702,7 @@ function readLocalMarkdown(rawPath, roots) {
36306
36702
  if (!MARKDOWN_FILE_EXT.test(rawPath.trim())) throw new Error("Local file is not a Markdown file");
36307
36703
  const path3 = resolveLocalFile(rawPath, roots);
36308
36704
  if (!MARKDOWN_FILE_EXT.test(path3)) throw new Error("Local file is not a Markdown file");
36309
- const bytes = readFileSync18(path3);
36705
+ const bytes = readFileSync20(path3);
36310
36706
  if (bytes.length <= MARKDOWN_READ_LIMIT) return { path: path3, markdown: bytes.toString("utf8"), truncated: false };
36311
36707
  const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
36312
36708
  const lastBreak = head.lastIndexOf(10);
@@ -36341,10 +36737,10 @@ function localFileOpenCommand(path3, selected, options = {}) {
36341
36737
  if (selected === "finder") return { command: "explorer.exe", args: [`/select,${path3}`] };
36342
36738
  const editor = WINDOWS_EDITOR_EXE[selected];
36343
36739
  const env = options.env ?? process.env;
36344
- const exists = options.exists ?? existsSync9;
36740
+ const exists = options.exists ?? existsSync11;
36345
36741
  const localAppData = env.LOCALAPPDATA;
36346
36742
  if (localAppData) {
36347
- const exe2 = join25(localAppData, ...editor.exe);
36743
+ const exe2 = join28(localAppData, ...editor.exe);
36348
36744
  if (exists(exe2)) return { command: exe2, args: [path3] };
36349
36745
  }
36350
36746
  if (/["%\r\n]/u.test(path3)) throw new Error(`cannot hand ${path3} to the ${editor.shim} shim through cmd.exe`);
@@ -36382,7 +36778,7 @@ var init_local_file = __esm({
36382
36778
  });
36383
36779
 
36384
36780
  // packages/server/src/thread-links.ts
36385
- import { isAbsolute as isAbsolute5 } from "node:path";
36781
+ import { isAbsolute as isAbsolute6 } from "node:path";
36386
36782
  import { fileURLToPath as fileURLToPath2 } from "node:url";
36387
36783
  function threadLinkView(row) {
36388
36784
  return { id: row.id, kind: row.kind, label: row.label, target: row.target };
@@ -36398,7 +36794,7 @@ function resolveThreadLink(target, projectDir, roots) {
36398
36794
  const url = new URL(target);
36399
36795
  if (url.search || url.hash) throw new Error("File links must not contain a query or fragment");
36400
36796
  path3 = fileURLToPath2(url);
36401
- } else if (!isAbsolute5(target) && /^[a-z][a-z\d+.-]*:/i.test(target)) {
36797
+ } else if (!isAbsolute6(target) && /^[a-z][a-z\d+.-]*:/i.test(target)) {
36402
36798
  throw new Error("Register an HTTP(S) URL or a local file");
36403
36799
  }
36404
36800
  const resolved2 = resolveOpenableFile(path3, projectDir, roots);
@@ -36609,8 +37005,8 @@ var init_claude_model_upgrade = __esm({
36609
37005
 
36610
37006
  // packages/server/src/frizz.ts
36611
37007
  import { execFile as execFile6 } from "node:child_process";
36612
- import { lstatSync as lstatSync2, realpathSync as realpathSync7 } from "node:fs";
36613
- import { basename as basename5, dirname as dirname10, join as join26, resolve as resolve6 } from "node:path";
37008
+ import { lstatSync as lstatSync3, realpathSync as realpathSync8 } from "node:fs";
37009
+ import { basename as basename5, dirname as dirname12, join as join29, resolve as resolve6 } from "node:path";
36614
37010
  import { promisify as promisify5 } from "node:util";
36615
37011
  function frizzScriptsDir() {
36616
37012
  if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
@@ -36618,12 +37014,12 @@ function frizzScriptsDir() {
36618
37014
  }
36619
37015
  function directFrizzRoot(projectDir) {
36620
37016
  try {
36621
- const projectRoot = realpathSync7(projectDir);
36622
- const path3 = join26(projectRoot, ".frizz");
36623
- const stat2 = lstatSync2(path3);
37017
+ const projectRoot = realpathSync8(projectDir);
37018
+ const path3 = join29(projectRoot, ".frizz");
37019
+ const stat2 = lstatSync3(path3);
36624
37020
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
36625
- const real = realpathSync7(path3);
36626
- return dirname10(real) === projectRoot && basename5(real) === ".frizz" ? real : null;
37021
+ const real = realpathSync8(path3);
37022
+ return dirname12(real) === projectRoot && basename5(real) === ".frizz" ? real : null;
36627
37023
  } catch {
36628
37024
  return null;
36629
37025
  }
@@ -36633,7 +37029,7 @@ function frizzDirExists(projectDir) {
36633
37029
  }
36634
37030
  async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
36635
37031
  if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
36636
- const { stdout } = await execFileP("node", [join26(scriptsDir, "index.mjs"), "--json"], {
37032
+ const { stdout } = await execFileP("node", [join29(scriptsDir, "index.mjs"), "--json"], {
36637
37033
  cwd: projectDir,
36638
37034
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
36639
37035
  maxBuffer: 32 * 1024 * 1024
@@ -36658,7 +37054,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
36658
37054
  };
36659
37055
  }
36660
37056
  async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
36661
- await execFileP("node", [join26(scriptsDir, "thread-update.mjs"), slug, ...args], {
37057
+ await execFileP("node", [join29(scriptsDir, "thread-update.mjs"), slug, ...args], {
36662
37058
  cwd: projectDir,
36663
37059
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
36664
37060
  });
@@ -36792,12 +37188,12 @@ var init_awaiting = __esm({
36792
37188
  });
36793
37189
 
36794
37190
  // packages/server/src/backend/project-mcp-servers.ts
36795
- import { readFileSync as readFileSync19 } from "node:fs";
37191
+ import { readFileSync as readFileSync21 } from "node:fs";
36796
37192
  import { homedir as homedir12 } from "node:os";
36797
- import { join as join27 } from "node:path";
37193
+ import { join as join30 } from "node:path";
36798
37194
  function readJsonObject(path3) {
36799
37195
  try {
36800
- const parsed = JSON.parse(readFileSync19(path3, "utf8"));
37196
+ const parsed = JSON.parse(readFileSync21(path3, "utf8"));
36801
37197
  return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
36802
37198
  } catch {
36803
37199
  return void 0;
@@ -36890,15 +37286,15 @@ function projectMcpServers(cwd, options = {}) {
36890
37286
  const env = options.env ?? process.env;
36891
37287
  const home = options.home ?? homedir12();
36892
37288
  const configOverride = options.claudeConfigDir ?? (env.CLAUDE_CONFIG_DIR?.trim() ? env.CLAUDE_CONFIG_DIR.trim() : void 0);
36893
- const accountFile = configOverride ? join27(configOverride, ".claude.json") : join27(home, ".claude.json");
36894
- const userSettingsFile = join27(configOverride ?? join27(home, ".claude"), "settings.json");
37289
+ const accountFile = configOverride ? join30(configOverride, ".claude.json") : join30(home, ".claude.json");
37290
+ const userSettingsFile = join30(configOverride ?? join30(home, ".claude"), "settings.json");
36895
37291
  const account = readJsonObject(accountFile);
36896
37292
  const out = userScopeRemoteServers(account, cwd, env);
36897
- const declared = objectField(readJsonObject(join27(cwd, ".mcp.json")), "mcpServers");
37293
+ const declared = objectField(readJsonObject(join30(cwd, ".mcp.json")), "mcpServers");
36898
37294
  if (!declared) return out;
36899
37295
  const approval = collectApproval([
36900
- readJsonObject(join27(cwd, ".claude", "settings.json")),
36901
- readJsonObject(join27(cwd, ".claude", "settings.local.json")),
37296
+ readJsonObject(join30(cwd, ".claude", "settings.json")),
37297
+ readJsonObject(join30(cwd, ".claude", "settings.local.json")),
36902
37298
  readJsonObject(userSettingsFile),
36903
37299
  objectField(objectField(account, "projects"), cwd)
36904
37300
  ]);
@@ -36922,18 +37318,18 @@ var init_project_mcp_servers = __esm({
36922
37318
  });
36923
37319
 
36924
37320
  // packages/server/src/worker-plugin-dir.ts
36925
- import { existsSync as existsSync10 } from "node:fs";
36926
- import { dirname as dirname11, join as join28 } from "node:path";
37321
+ import { existsSync as existsSync12 } from "node:fs";
37322
+ import { dirname as dirname13, join as join31 } from "node:path";
36927
37323
  import { fileURLToPath as fileURLToPath3 } from "node:url";
36928
37324
  function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
36929
37325
  const override = env.FRIZZ_WORKER_PLUGIN_DIR;
36930
- if (override && existsSync10(join28(override, ".claude-plugin", "plugin.json")))
37326
+ if (override && existsSync12(join31(override, ".claude-plugin", "plugin.json")))
36931
37327
  return override;
36932
- let current = dirname11(fileURLToPath3(moduleUrl));
37328
+ let current = dirname13(fileURLToPath3(moduleUrl));
36933
37329
  for (; ; ) {
36934
- const candidate = join28(current, "cc-worker");
36935
- if (existsSync10(join28(candidate, ".claude-plugin", "plugin.json"))) return candidate;
36936
- const parent = dirname11(current);
37330
+ const candidate = join31(current, "cc-worker");
37331
+ if (existsSync12(join31(candidate, ".claude-plugin", "plugin.json"))) return candidate;
37332
+ const parent = dirname13(current);
36937
37333
  if (parent === current) return void 0;
36938
37334
  current = parent;
36939
37335
  }
@@ -37081,9 +37477,9 @@ reasoning around the ask, never a copy of it (see Questions for the human).
37081
37477
  **AT EVERY LATER REST, SAY WHERE EACH OLD QUESTION STANDS.** A question still open from an EARLIER rest
37082
37478
  is not your new rest's sign-off, and frizz does NOT redraw its card under your new handoff \u2014 it stays
37083
37479
  where you asked it. So a later rest either NAMES each one you still need under \`questions:\` in an
37084
- \` \`\`\`awaiting \` fence \u2014 its card is then drawn at this rest, under your fence \u2014 or WITHDRAWS it with
37085
- \`unask\`. A rest that does neither is bumped, and so is any \` \`\`\`awaiting \` fence that leaves an open
37086
- question out, at whichever rest it lands.
37480
+ \` \`\`\`awaiting \` fence \u2014 its card is then drawn at this rest, under your fence's prose \u2014 or WITHDRAWS
37481
+ it with \`unask\`. A rest that does neither is bumped, and so is any \` \`\`\`awaiting \` fence that leaves
37482
+ an open question out, at whichever rest it lands.
37087
37483
 
37088
37484
  Use at most ONE fenced signal block, at the very END (a question's PLACEMENT marker is not a signal
37089
37485
  block \u2014 see Questions for the human). The fence language is the state; the body is the card the human
@@ -37138,7 +37534,7 @@ exactly ONE of them.
37138
37534
  - **A RECOMMENDATION IS NOT A CONCLUSION, AND AN UNSENT DRAFT IS NOT A DELIVERABLE.** When the
37139
37535
  verdict is that SOMEONE SHOULD NOW DO SOMETHING \u2014 merge it, decline it, post this comment, pick
37140
37536
  one of these designs, press the button you are not allowed to press \u2014 that someone is the human,
37141
- so register the question with \`mcp__frizz__ask\`, your recommendation as option A, and rest on
37537
+ so register the question with \`mcp__frizz__ask\`, your recommendation as option 1, and rest on
37142
37538
  it. Once nothing is left to DECIDE and only the human's act remains, the steps go to them under
37143
37539
  \`steps:\` in an \` \`\`\`awaiting \` fence instead. Same for anything you WROTE
37144
37540
  but did not SEND (a drafted comment, reply, issue body or release note): \`done\` files that draft
@@ -37204,7 +37600,7 @@ exactly ONE of them.
37204
37600
  title: Sign in to npm so the release can publish
37205
37601
  steps:
37206
37602
  - Run \`npm login --auth-type=web\` in a terminal on this machine.
37207
- - Approve the browser prompt with the maintainer account.
37603
+ - Approve the browser prompt with the maintainer account; if no prompt opens, sign in at [npmjs.com/login](https://www.npmjs.com/login) and run the command again.
37208
37604
  ---
37209
37605
  The publish step runs as the maintainer, and no token for that account is available to this thread.
37210
37606
  \`\`\`
@@ -37289,12 +37685,34 @@ exactly ONE of them.
37289
37685
  \`Done\`, the same as anything they type; anything else they need to tell you \u2014 a step that failed,
37290
37686
  the account they used \u2014 comes as a message of their own. An act is not a decision: never ask
37291
37687
  WHETHER they will do it, and never call \`done\` while it is still owed.
37688
+ **EVERY STEP IS CLICKABLE AND COMPLETE \u2014 A STEP THAT MAKES THE HUMAN GO LOOKING IS A BROKEN STEP.**
37689
+ The steps are the most actionable thing you hand over, so write each one to be DONE, not
37690
+ researched: every page it names is a real Markdown link to that exact page (the settings screen,
37691
+ the audit log, the PR, the release run \u2014 never "in the dashboard" or "on GitHub"); every file is a
37692
+ real link; every command is a code span ready to paste; and every value the act needs \u2014 the account,
37693
+ the date range, the token or secret name, the exact button \u2014 is written into the step. Steps render
37694
+ as Markdown, so links click. Bad: \`Open the Cloudflare dashboard and check the audit log for the
37695
+ upload.\` Good: \`Open the [Frizz account audit log](https://dash.cloudflare.com/<account-id>/audit-log),
37696
+ filter to 2026-10-05 18:00\u201319:00 UTC, and note the actor and IP on the frizz-relay upload.\`
37697
+ Fill in every id you hold; when you cannot know a URL, link the nearest page you can and say what to
37698
+ click there. A step is cut at 500 characters, so keep each link inside that.
37699
+ (Maintainer 2026-10-08, after a security handoff listed seven to-dos with no link in any of them:
37700
+ *"Anytime you stop with a to-do block for the user, it needs to include clickable links. It needs to
37701
+ be as actionable as possible."*)
37702
+ **A VALUE ONLY THE HUMAN HOLDS IS NOT A STEP** \u2014 a 2FA code, a token, a password a command needs.
37703
+ Ask for it with \`mcp__frizz__secret\`: the human pastes it into a masked card, from any device, and
37704
+ it is served from memory through a private pipe whose path the tool returns. The path reads ONCE:
37705
+ use it inside the command (\`--otp "$(cat '<path>')"\`) and never print it. It is a registered
37706
+ question: name it under \`questions:\` at later rests.
37292
37707
  - \`questions:\` \u2014 your registered questions you are STILL waiting on, by id: \`questions: [qst_ab12cd34]\`.
37293
37708
  A fence beside open questions names EVERY one of them \u2014 withdraw any you no longer need with
37294
37709
  \`mcp__frizz__unask\` first \u2014 or frizz refuses the park and lists what it left out. Each named card is
37295
37710
  drawn at THIS rest, under your fence; to set it inside your prose instead, add its placement marker
37296
- (see Questions for the human). Like \`steps:\`, questions name the human as the wait: no other name
37297
- and no \`for:\` needed, and the thread stays in their queue.
37711
+ (see Questions for the human). A fence that names questions draws NO awaiting card of its own: the
37712
+ question cards are the rest's ending, its prose under \`---\` reads as plain handoff text, and the
37713
+ work it also names is listed beside the human's prompt box (a fence with \`steps:\` keeps its card).
37714
+ Like \`steps:\`, questions name the human as the wait: no other name and no \`for:\` needed, and the
37715
+ thread stays in their queue.
37298
37716
  - **REGISTERING IS NOT PARKING, AND PARKING IS NOT REGISTERING.** Your shells, sub-agents, timers
37299
37717
  and PR watchers are watched AUTOMATICALLY, fence or no fence \u2014 frizz wakes you when one finishes,
37300
37718
  every time. The fence only declares that you have STOPPED, names which of them you stopped for,
@@ -37453,10 +37871,11 @@ so, which?" without asking it of somebody who said no. Written out, one registra
37453
37871
  description: zero deps, human-editable, racy under concurrent writes
37454
37872
 
37455
37873
  Each question must stand alone: the specific question on ONE line, options each with a one-line
37456
- trade-off, and enough context to answer cold. The card letters the options A, B, C in the order you
37457
- give them, so put the one you would take FIRST and mark it \`recommended\`; mark exactly one. Several
37458
- independent questions are several entries of ONE \`ask\` call, never one bundled question. A bare
37459
- "which approach?" with no options is a broken handoff.
37874
+ trade-off, and enough context to answer cold. The card numbers the options 1, 2, 3 in the order you
37875
+ give them \u2014 the human picks one by pressing its number \u2014 so put the one you would take FIRST and mark
37876
+ it \`recommended\`; mark exactly one. Several independent questions are several entries of ONE
37877
+ \`ask\` call, never one bundled question. A bare "which approach?" with no options is a broken
37878
+ handoff.
37460
37879
 
37461
37880
  NO "I" AND NO "you" ANYWHERE IN A QUESTION \u2014 the question, its options, or any interactive prompt.
37462
37881
  Clicking an option is the HUMAN speaking, so first and second person flip between writer and reader: in
@@ -37564,7 +37983,7 @@ and reported, not offered. Only the ACT behind a command can earn a card (destru
37564
37983
  outside your boundary), and then the question is whether the thing happens, never who types it.
37565
37984
 
37566
37985
  **That test inverts when knowing the answer and being ABLE TO ACT ON IT come apart** \u2014 a read-only
37567
- boundary, a comment that goes out under the human's name, a merge, a close, a publish, a spend. It becomes the QUESTION, with the recommendation as option A and the act spelled out concretely
37986
+ boundary, a comment that goes out under the human's name, a merge, a close, a publish, a spend. It becomes the QUESTION, with the recommendation as option 1 and the act spelled out concretely
37568
37987
  enough to approve in one word. Never resolve that fork by fencing \` \`\`\`done \` on the investigation.
37569
37988
 
37570
37989
  Stop only when a wrong guess would be BOTH costly AND hard to undo: destructive or irreversible actions
@@ -38044,26 +38463,26 @@ checks. Depth scales with blast radius and yields to the project's conventions.`
38044
38463
  });
38045
38464
 
38046
38465
  // packages/server/src/backend/acp-agents.ts
38047
- import { accessSync as accessSync3, constants, statSync as statSync13 } from "node:fs";
38048
- import { delimiter as delimiter2, isAbsolute as isAbsolute6, join as join29 } from "node:path";
38466
+ import { accessSync as accessSync3, constants as constants2, statSync as statSync14 } from "node:fs";
38467
+ import { delimiter as delimiter2, isAbsolute as isAbsolute7, join as join32 } from "node:path";
38049
38468
  function isExecutableFile(path3) {
38050
38469
  try {
38051
- if (!statSync13(path3).isFile()) return false;
38052
- if (process.platform !== "win32") accessSync3(path3, constants.X_OK);
38470
+ if (!statSync14(path3).isFile()) return false;
38471
+ if (process.platform !== "win32") accessSync3(path3, constants2.X_OK);
38053
38472
  return true;
38054
38473
  } catch {
38055
38474
  return false;
38056
38475
  }
38057
38476
  }
38058
38477
  function findOnPath(command, env = process.env) {
38059
- if (isAbsolute6(command)) return isExecutableFile(command) ? command : void 0;
38478
+ if (isAbsolute7(command)) return isExecutableFile(command) ? command : void 0;
38060
38479
  const dirs = (env.PATH ?? env.Path ?? "").split(delimiter2).filter(Boolean);
38061
38480
  const exts = process.platform === "win32" ? ["", ...(env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")] : [""];
38062
38481
  for (const dir of dirs) {
38063
38482
  for (const ext of exts) {
38064
- const candidate = join29(dir, command + ext.toLowerCase());
38483
+ const candidate = join32(dir, command + ext.toLowerCase());
38065
38484
  if (isExecutableFile(candidate)) return candidate;
38066
- if (ext && isExecutableFile(join29(dir, command + ext))) return join29(dir, command + ext);
38485
+ if (ext && isExecutableFile(join32(dir, command + ext))) return join32(dir, command + ext);
38067
38486
  }
38068
38487
  }
38069
38488
  return void 0;
@@ -39080,8 +39499,8 @@ var init_claude_agent_broker_bridge = __esm({
39080
39499
  });
39081
39500
 
39082
39501
  // packages/server/src/dispatch.ts
39083
- import { closeSync as closeSync12, constants as constants2, existsSync as existsSync11, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync20, realpathSync as realpathSync8, statSync as statSync14, writeFileSync as writeFileSync11, mkdirSync as mkdirSync14, rmSync as rmSync9 } from "node:fs";
39084
- import { basename as basename6, join as join30, dirname as dirname12 } from "node:path";
39502
+ import { closeSync as closeSync13, constants as constants3, existsSync as existsSync13, fstatSync as fstatSync2, lstatSync as lstatSync4, openSync as openSync14, readFileSync as readFileSync22, realpathSync as realpathSync9, statSync as statSync15, writeFileSync as writeFileSync13, mkdirSync as mkdirSync16, rmSync as rmSync10 } from "node:fs";
39503
+ import { basename as basename6, join as join33, dirname as dirname14 } from "node:path";
39085
39504
  import { createHash as createHash12, randomUUID as randomUUID13 } from "node:crypto";
39086
39505
  function fallbackTitle(prompt) {
39087
39506
  const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
@@ -39100,7 +39519,7 @@ function fallbackTitle(prompt) {
39100
39519
  }
39101
39520
  function resolveSlug(frizzDir, base, taken) {
39102
39521
  base = ThreadSlug.parse(base);
39103
- const isTaken = (slug) => existsSync11(join30(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
39522
+ const isTaken = (slug) => existsSync13(join33(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
39104
39523
  if (!isTaken(base)) return base;
39105
39524
  for (let n = 2; ; n++) {
39106
39525
  const suffix = `-${n}`;
@@ -39116,29 +39535,29 @@ function resolveLegacyThreadFile(projectDir, value) {
39116
39535
  const parsed = ThreadSlug.safeParse(value);
39117
39536
  if (!parsed.success) return null;
39118
39537
  try {
39119
- const projectRoot = realpathSync8(projectDir);
39120
- const frizzPath = join30(projectRoot, ".frizz");
39121
- const frizzStat = lstatSync3(frizzPath);
39538
+ const projectRoot = realpathSync9(projectDir);
39539
+ const frizzPath = join33(projectRoot, ".frizz");
39540
+ const frizzStat = lstatSync4(frizzPath);
39122
39541
  if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
39123
- const realFrizz = realpathSync8(frizzPath);
39124
- if (dirname12(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
39125
- const path3 = join30(realFrizz, `${parsed.data}.md`);
39126
- const before = lstatSync3(path3);
39542
+ const realFrizz = realpathSync9(frizzPath);
39543
+ if (dirname14(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
39544
+ const path3 = join33(realFrizz, `${parsed.data}.md`);
39545
+ const before = lstatSync4(path3);
39127
39546
  if (!before.isFile() || before.isSymbolicLink()) return null;
39128
- const realPath = realpathSync8(path3);
39129
- if (dirname12(realPath) !== realFrizz || basename6(realPath) !== `${parsed.data}.md`) return null;
39547
+ const realPath = realpathSync9(path3);
39548
+ if (dirname14(realPath) !== realFrizz || basename6(realPath) !== `${parsed.data}.md`) return null;
39130
39549
  let contents;
39131
39550
  let openedBefore;
39132
39551
  let openedAfter;
39133
- const fd2 = openSync13(path3, constants2.O_RDONLY | constants2.O_NOFOLLOW);
39552
+ const fd2 = openSync14(path3, constants3.O_RDONLY | constants3.O_NOFOLLOW);
39134
39553
  try {
39135
39554
  openedBefore = fstatSync2(fd2);
39136
- contents = readFileSync20(fd2);
39555
+ contents = readFileSync22(fd2);
39137
39556
  openedAfter = fstatSync2(fd2);
39138
39557
  } finally {
39139
- closeSync12(fd2);
39558
+ closeSync13(fd2);
39140
39559
  }
39141
- const after = lstatSync3(path3);
39560
+ const after = lstatSync4(path3);
39142
39561
  if (before.dev !== openedBefore.dev || before.ino !== openedBefore.ino || openedBefore.dev !== openedAfter.dev || openedBefore.ino !== openedAfter.ino || openedBefore.size !== openedAfter.size || openedBefore.mtimeMs !== openedAfter.mtimeMs || openedBefore.ctimeMs !== openedAfter.ctimeMs || after.dev !== openedAfter.dev || after.ino !== openedAfter.ino || after.size !== openedAfter.size || after.mtimeMs !== openedAfter.mtimeMs || after.ctimeMs !== openedAfter.ctimeMs || !openedAfter.isFile() || !after.isFile() || after.isSymbolicLink()) {
39143
39562
  return null;
39144
39563
  }
@@ -39166,17 +39585,17 @@ function boardAuthorizesAdoption(board, slug) {
39166
39585
  return !board.errorItems.some((item) => item.file === `${slug}.md`);
39167
39586
  }
39168
39587
  function ensureSafeDirectDirectory(parent, name) {
39169
- const path3 = join30(parent, name);
39588
+ const path3 = join33(parent, name);
39170
39589
  try {
39171
- mkdirSync14(path3);
39590
+ mkdirSync16(path3);
39172
39591
  } catch (error) {
39173
39592
  const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
39174
39593
  if (code !== "EEXIST") throw error;
39175
39594
  }
39176
- const stat2 = lstatSync3(path3);
39595
+ const stat2 = lstatSync4(path3);
39177
39596
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("unsafe project directory");
39178
- const real = realpathSync8(path3);
39179
- if (dirname12(real) !== parent || basename6(real) !== name) throw new Error("unsafe project directory");
39597
+ const real = realpathSync9(path3);
39598
+ if (dirname14(real) !== parent || basename6(real) !== name) throw new Error("unsafe project directory");
39180
39599
  return real;
39181
39600
  }
39182
39601
  function scratchDirRelPath(sessionId) {
@@ -39184,7 +39603,7 @@ function scratchDirRelPath(sessionId) {
39184
39603
  }
39185
39604
  function writeScratchDir(projectDir, sessionId) {
39186
39605
  if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,199}$/.test(sessionId)) throw new Error("invalid session id");
39187
- const projectRoot = realpathSync8(projectDir);
39606
+ const projectRoot = realpathSync9(projectDir);
39188
39607
  const frizzDir = ensureSafeDirectDirectory(projectRoot, ".frizz");
39189
39608
  const threadsDir = ensureSafeDirectDirectory(frizzDir, "threads");
39190
39609
  ensureSafeDirectDirectory(threadsDir, sessionId);
@@ -39196,8 +39615,8 @@ function loadWorkerPrompt(kind = "claude") {
39196
39615
  function monitorScriptsDir() {
39197
39616
  const plugin = workerPluginDir();
39198
39617
  if (!plugin) return void 0;
39199
- const dir = join30(plugin, "skills", "gh", "scripts");
39200
- return existsSync11(join30(dir, "ci-watch.mjs")) ? dir : void 0;
39618
+ const dir = join33(plugin, "skills", "gh", "scripts");
39619
+ return existsSync13(join33(dir, "ci-watch.mjs")) ? dir : void 0;
39201
39620
  }
39202
39621
  function codexScratchpadHookConfig(hookScript, sessionId) {
39203
39622
  if (!hookScript || !sessionId) return {};
@@ -39209,7 +39628,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
39209
39628
  }
39210
39629
  ]
39211
39630
  });
39212
- const bashBackgroundHook = join30(dirname12(hookScript), "bash-background.mjs");
39631
+ const bashBackgroundHook = join33(dirname14(hookScript), "bash-background.mjs");
39213
39632
  return {
39214
39633
  bypass_hook_trust: true,
39215
39634
  hooks: {
@@ -39235,7 +39654,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
39235
39654
  }
39236
39655
  function scratchpadHookScript() {
39237
39656
  const plugin = workerPluginDir();
39238
- return plugin ? join30(plugin, "hooks", "scratchpad.mjs") : void 0;
39657
+ return plugin ? join33(plugin, "hooks", "scratchpad.mjs") : void 0;
39239
39658
  }
39240
39659
  function composePrompt(sessionId, prompt, kind = "claude") {
39241
39660
  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.";
@@ -39251,12 +39670,12 @@ function scratchpadOrientation(sessionId, kind = "claude") {
39251
39670
  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 (${children2}). Nothing in this directory is read automatically; if you want a note back after a compaction, mcp__frizz__goal with post_compaction: true re-sends a prompt of your choosing.`;
39252
39671
  }
39253
39672
  function frizzConfigBlock(projectDir) {
39254
- const path3 = join30(projectDir, "FRIZZ.md");
39673
+ const path3 = join33(projectDir, "FRIZZ.md");
39255
39674
  let body;
39256
39675
  try {
39257
- const st2 = statSync14(path3);
39676
+ const st2 = statSync15(path3);
39258
39677
  if (!st2.isFile() || st2.size > FRIZZ_MD_MAX_BYTES) return "";
39259
- body = readFileSync20(path3, "utf8").trim();
39678
+ body = readFileSync22(path3, "utf8").trim();
39260
39679
  } catch {
39261
39680
  return "";
39262
39681
  }
@@ -39286,17 +39705,17 @@ function effectivePermissionMode(kind, mode) {
39286
39705
  }
39287
39706
  function systemPromptFlags(sessionId, system) {
39288
39707
  if (!system) return [];
39289
- mkdirSync14(SYSTEM_PROMPT_DIR, { recursive: true });
39708
+ mkdirSync16(SYSTEM_PROMPT_DIR, { recursive: true });
39290
39709
  const path3 = systemPromptPath(sessionId);
39291
- writeFileSync11(path3, system);
39710
+ writeFileSync13(path3, system);
39292
39711
  return ["--append-system-prompt-file", path3];
39293
39712
  }
39294
39713
  function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env, slug) {
39295
39714
  const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
39296
39715
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
39297
39716
  if (!pluginDir) return void 0;
39298
- const scriptPath = join30(pluginDir, "bin", FRIZZ_MCP.script);
39299
- if (!existsSync11(scriptPath)) return void 0;
39717
+ const scriptPath = join33(pluginDir, "bin", FRIZZ_MCP.script);
39718
+ if (!existsSync13(scriptPath)) return void 0;
39300
39719
  return {
39301
39720
  scriptPath,
39302
39721
  stateDir,
@@ -39377,12 +39796,12 @@ function buildClaudeResumeCommand(opts) {
39377
39796
  }
39378
39797
  function createDispatcher(deps) {
39379
39798
  const readBoardSource = deps.readBoard ?? readBoard;
39380
- const frizzDir = join30(deps.project.dir, ".frizz");
39799
+ const frizzDir = join33(deps.project.dir, ".frizz");
39381
39800
  const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
39382
39801
  function cleanupPrewrites(built) {
39383
39802
  for (const path3 of new Set(built.prewrite.map((file) => file.path))) {
39384
39803
  try {
39385
- rmSync9(path3, { force: true });
39804
+ rmSync10(path3, { force: true });
39386
39805
  } catch {
39387
39806
  }
39388
39807
  }
@@ -39390,7 +39809,7 @@ function createDispatcher(deps) {
39390
39809
  function cleanupDispatchFiles(scratchRel, built, sessionId) {
39391
39810
  cleanupPrewrites(built);
39392
39811
  try {
39393
- rmSync9(join30(deps.project.dir, scratchRel), { force: true, recursive: true });
39812
+ rmSync10(join33(deps.project.dir, scratchRel), { force: true, recursive: true });
39394
39813
  } catch {
39395
39814
  }
39396
39815
  cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
@@ -39879,11 +40298,11 @@ var init_dispatch = __esm({
39879
40298
 
39880
40299
  // packages/server/src/board.ts
39881
40300
  import {
39882
- realpathSync as realpathSync9,
40301
+ realpathSync as realpathSync10,
39883
40302
  watch as fsWatch
39884
40303
  } from "node:fs";
39885
40304
  import { homedir as homedir14 } from "node:os";
39886
- import { dirname as dirname13, join as join31 } from "node:path";
40305
+ import { dirname as dirname15, join as join34 } from "node:path";
39887
40306
  import watcher from "@parcel/watcher";
39888
40307
  function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
39889
40308
  if (!liveness) return false;
@@ -39932,7 +40351,7 @@ function registeredLegacyFileIsTerminal(projectDir, slug) {
39932
40351
  return status === "done" || status === "dismissed";
39933
40352
  }
39934
40353
  function isBoardRelevantFrizzPath(roots, path3) {
39935
- return path3.endsWith(".md") && roots.has(dirname13(path3));
40354
+ return path3.endsWith(".md") && roots.has(dirname15(path3));
39936
40355
  }
39937
40356
  function futureSnooze(row, nowMs) {
39938
40357
  const parsed = SnoozeUntil.safeParse(row.snoozed_until);
@@ -40792,10 +41211,10 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
40792
41211
  if (parcelSub || stopped) return Promise.resolve();
40793
41212
  if (watchSetup) return watchSetup;
40794
41213
  const setup = (async () => {
40795
- const dir = join31(project.dir, ".frizz");
41214
+ const dir = join34(project.dir, ".frizz");
40796
41215
  const roots = /* @__PURE__ */ new Set([dir]);
40797
41216
  try {
40798
- roots.add(realpathSync9(dir));
41217
+ roots.add(realpathSync10(dir));
40799
41218
  } catch {
40800
41219
  }
40801
41220
  const next = await subscribe(
@@ -40807,7 +41226,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
40807
41226
  }
40808
41227
  if (events.some((event) => isBoardRelevantFrizzPath(roots, event.path))) scheduleRebuild();
40809
41228
  },
40810
- { ignore: FRIZZ_WATCH_IGNORED_DIRS.map((name) => join31(dir, name)) }
41229
+ { ignore: FRIZZ_WATCH_IGNORED_DIRS.map((name) => join34(dir, name)) }
40811
41230
  );
40812
41231
  if (stopped) {
40813
41232
  await next.unsubscribe();
@@ -43924,7 +44343,7 @@ var init_resume = __esm({
43924
44343
  });
43925
44344
 
43926
44345
  // packages/server/src/backend/claude.ts
43927
- import { join as join32 } from "node:path";
44346
+ import { join as join35 } from "node:path";
43928
44347
  function toolResultText2(content) {
43929
44348
  if (typeof content === "string") return content;
43930
44349
  if (!Array.isArray(content)) return "";
@@ -43943,7 +44362,7 @@ function parseClaudeLine(line) {
43943
44362
  const at2 = typeof rec.timestamp === "string" ? rec.timestamp : void 0;
43944
44363
  const out = [];
43945
44364
  if (rec.type === "assistant") {
43946
- const stop = typeof rec.message?.stop_reason === "string" ? rec.message.stop_reason : void 0;
44365
+ const stop2 = typeof rec.message?.stop_reason === "string" ? rec.message.stop_reason : void 0;
43947
44366
  const content = rec.message?.content;
43948
44367
  let lastText;
43949
44368
  if (Array.isArray(content)) {
@@ -43952,13 +44371,13 @@ function parseClaudeLine(line) {
43952
44371
  const b = block;
43953
44372
  if (b.type === "text" && typeof b.text === "string") {
43954
44373
  lastText = b.text;
43955
- out.push({ kind: "assistant-text", at: at2, text: b.text, final: stop === "end_turn" });
44374
+ out.push({ kind: "assistant-text", at: at2, text: b.text, final: stop2 === "end_turn" });
43956
44375
  } else if (b.type === "tool_use") {
43957
44376
  out.push({ kind: "tool-call", at: at2, id: typeof b.id === "string" ? b.id : "", name: typeof b.name === "string" ? b.name : "", input: b.input });
43958
44377
  }
43959
44378
  }
43960
44379
  }
43961
- if (stop === "end_turn") out.push({ kind: "turn-end", at: at2, finalText: lastText });
44380
+ if (stop2 === "end_turn") out.push({ kind: "turn-end", at: at2, finalText: lastText });
43962
44381
  return out;
43963
44382
  }
43964
44383
  if (rec.type === "user" && rec.isMeta !== true) {
@@ -44015,7 +44434,7 @@ function createClaudeBackend(opts) {
44015
44434
  return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
44016
44435
  },
44017
44436
  transcriptPath(sessionId) {
44018
- return join32(opts.logDir, `${sessionId}.jsonl`);
44437
+ return join35(opts.logDir, `${sessionId}.jsonl`);
44019
44438
  },
44020
44439
  parseLine(line) {
44021
44440
  return parseClaudeLine(line);
@@ -44040,10 +44459,10 @@ var init_claude = __esm({
44040
44459
  });
44041
44460
 
44042
44461
  // packages/server/src/backend/acp-transcript.ts
44043
- import { appendFileSync as appendFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync15, readFileSync as readFileSync21 } from "node:fs";
44044
- import { dirname as dirname14, join as join33 } from "node:path";
44462
+ import { appendFileSync as appendFileSync3, existsSync as existsSync15, mkdirSync as mkdirSync17, readFileSync as readFileSync23 } from "node:fs";
44463
+ import { dirname as dirname16, join as join36 } from "node:path";
44045
44464
  function acpTranscriptPath(stateDir, sessionId) {
44046
- return join33(stateDir, ACP_TRANSCRIPT_DIR, `${sessionId}.jsonl`);
44465
+ return join36(stateDir, ACP_TRANSCRIPT_DIR, `${sessionId}.jsonl`);
44047
44466
  }
44048
44467
  function parseAcpRecord(line) {
44049
44468
  if (!line.trim()) return void 0;
@@ -44244,8 +44663,8 @@ var init_acp_transcript = __esm({
44244
44663
  AcpTranscriptWriter = class {
44245
44664
  constructor(path3) {
44246
44665
  this.path = path3;
44247
- mkdirSync15(dirname14(path3), { recursive: true });
44248
- if (!existsSync13(path3)) appendFileSync3(path3, "");
44666
+ mkdirSync17(dirname16(path3), { recursive: true });
44667
+ if (!existsSync15(path3)) appendFileSync3(path3, "");
44249
44668
  }
44250
44669
  append(record) {
44251
44670
  appendFileSync3(this.path, JSON.stringify(record) + "\n");
@@ -44632,15 +45051,15 @@ var init_acp_rpc = __esm({
44632
45051
  import { spawn as spawn7 } from "node:child_process";
44633
45052
  import { createConnection as createConnection2 } from "node:net";
44634
45053
  import { createHash as createHash14, randomUUID as randomUUID15 } from "node:crypto";
44635
- import { existsSync as existsSync14, mkdirSync as mkdirSync16, readFileSync as readFileSync22, readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
44636
- import { join as join34 } from "node:path";
45054
+ import { existsSync as existsSync16, mkdirSync as mkdirSync18, readFileSync as readFileSync24, readdirSync as readdirSync9, unlinkSync as unlinkSync4 } from "node:fs";
45055
+ import { join as join37 } from "node:path";
44637
45056
  import { PassThrough as PassThrough3, Writable as Writable3 } from "node:stream";
44638
45057
  import { StringDecoder as StringDecoder5 } from "node:string_decoder";
44639
45058
  function daemonDir2(stateDir) {
44640
- return join34(stateDir, "acp-daemon");
45059
+ return join37(stateDir, "acp-daemon");
44641
45060
  }
44642
45061
  function acpDaemonRecordPath(stateDir, sessionId) {
44643
- return join34(daemonDir2(stateDir), `${sessionId}.json`);
45062
+ return join37(daemonDir2(stateDir), `${sessionId}.json`);
44644
45063
  }
44645
45064
  function acpDaemonSocketPath(stateDir, sessionId) {
44646
45065
  const key = createHash14("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
@@ -44656,7 +45075,7 @@ function pidAlive4(pid) {
44656
45075
  }
44657
45076
  function readAcpDaemonRecord(stateDir, sessionId) {
44658
45077
  try {
44659
- const value = JSON.parse(readFileSync22(acpDaemonRecordPath(stateDir, sessionId), "utf8"));
45078
+ const value = JSON.parse(readFileSync24(acpDaemonRecordPath(stateDir, sessionId), "utf8"));
44660
45079
  if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
44661
45080
  return {
44662
45081
  threadSlug: typeof value.threadSlug === "string" ? value.threadSlug : "",
@@ -44702,7 +45121,7 @@ async function stopAcpDaemon(stateDir, sessionId, timeoutMs = 1e4) {
44702
45121
  }
44703
45122
  function forkDaemon2(options) {
44704
45123
  const { stateDir, sessionId } = options;
44705
- mkdirSync16(daemonDir2(stateDir), { recursive: true });
45124
+ mkdirSync18(daemonDir2(stateDir), { recursive: true });
44706
45125
  const record = acpDaemonRecordPath(stateDir, sessionId);
44707
45126
  try {
44708
45127
  unlinkSync4(record);
@@ -44898,7 +45317,7 @@ var init_acp_host = __esm({
44898
45317
  }
44899
45318
  if (process.platform !== "win32") {
44900
45319
  const stale = acpDaemonSocketPath(stateDir, sessionId);
44901
- if (existsSync14(stale) && !liveAcpDaemonRecord(stateDir, sessionId)) {
45320
+ if (existsSync16(stale) && !liveAcpDaemonRecord(stateDir, sessionId)) {
44902
45321
  try {
44903
45322
  unlinkSync4(stale);
44904
45323
  } catch {
@@ -71590,7 +72009,7 @@ var init_claude_context_window = __esm({
71590
72009
  });
71591
72010
 
71592
72011
  // packages/server/src/backend/claude-agent-sdk.ts
71593
- import { delimiter as delimiter3, isAbsolute as isAbsolute8 } from "node:path";
72012
+ import { delimiter as delimiter3, isAbsolute as isAbsolute9 } from "node:path";
71594
72013
  function sanitizeProviderChildEnvironment(environment) {
71595
72014
  const sanitized = { ...environment };
71596
72015
  for (const key of Object.keys(sanitized)) {
@@ -71732,24 +72151,24 @@ var init_claude_models = __esm({
71732
72151
  });
71733
72152
 
71734
72153
  // packages/server/src/backend/codex-app-server-diagnostics.ts
71735
- import { appendFileSync as appendFileSync5, mkdirSync as mkdirSync18, renameSync as renameSync9, statSync as statSync16 } from "node:fs";
71736
- import { join as join36 } from "node:path";
72154
+ import { appendFileSync as appendFileSync5, mkdirSync as mkdirSync20, renameSync as renameSync9, statSync as statSync17 } from "node:fs";
72155
+ import { join as join39 } from "node:path";
71737
72156
  function codexDiagnosticLogPath(stateDir, projectId) {
71738
- return join36(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
72157
+ return join39(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
71739
72158
  }
71740
72159
  function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
71741
- const dir = join36(stateDir, "codex-app-server");
72160
+ const dir = join39(stateDir, "codex-app-server");
71742
72161
  const path3 = codexDiagnosticLogPath(stateDir, projectId);
71743
72162
  let ensured = false;
71744
72163
  return (event) => {
71745
72164
  if (event.event === "stderr") return;
71746
72165
  try {
71747
72166
  if (!ensured) {
71748
- mkdirSync18(dir, { recursive: true });
72167
+ mkdirSync20(dir, { recursive: true });
71749
72168
  ensured = true;
71750
72169
  }
71751
72170
  try {
71752
- if (statSync16(path3).size > MAX_BYTES2) renameSync9(path3, `${path3}.1`);
72171
+ if (statSync17(path3).size > MAX_BYTES2) renameSync9(path3, `${path3}.1`);
71753
72172
  } catch {
71754
72173
  }
71755
72174
  appendFileSync5(path3, `${JSON.stringify({ at: now().toISOString(), ...event })}
@@ -71768,9 +72187,9 @@ var init_codex_app_server_diagnostics = __esm({
71768
72187
 
71769
72188
  // packages/server/src/backend/stale-socket-sweep.ts
71770
72189
  import { execFile as execFile9 } from "node:child_process";
71771
- import { readdirSync as readdirSync10, unlinkSync as unlinkSync6 } from "node:fs";
72190
+ import { readdirSync as readdirSync11, unlinkSync as unlinkSync6 } from "node:fs";
71772
72191
  import { connect as connectSocket } from "node:net";
71773
- import { join as join37 } from "node:path";
72192
+ import { join as join40 } from "node:path";
71774
72193
  function parseLsofSocketNames(stdout) {
71775
72194
  const referenced = /* @__PURE__ */ new Set();
71776
72195
  for (const line of stdout.split("\n")) {
@@ -71787,7 +72206,7 @@ function sweepStaleSockets(options, deps = {}) {
71787
72206
  const keep = new Set(options.keep ?? []);
71788
72207
  let candidates;
71789
72208
  try {
71790
- candidates = (deps.readdir ?? readdirSync10)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join37(options.dir, name)).filter((path3) => !keep.has(path3));
72209
+ candidates = (deps.readdir ?? readdirSync11)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join40(options.dir, name)).filter((path3) => !keep.has(path3));
71791
72210
  } catch {
71792
72211
  return;
71793
72212
  }
@@ -71837,8 +72256,8 @@ var init_stale_socket_sweep = __esm({
71837
72256
 
71838
72257
  // packages/server/src/orphan-reaper.ts
71839
72258
  import { execFile as execFile10 } from "node:child_process";
71840
- import { readFileSync as readFileSync24 } from "node:fs";
71841
- import { dirname as dirname16 } from "node:path";
72259
+ import { readFileSync as readFileSync26 } from "node:fs";
72260
+ import { dirname as dirname18 } from "node:path";
71842
72261
  import { promisify as promisify8 } from "node:util";
71843
72262
  function firstTokenBasename(command) {
71844
72263
  const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
@@ -72067,7 +72486,7 @@ async function sweepOrphansOnce(deps = {}) {
72067
72486
  }
72068
72487
  function sweepStaleBrokerSockets() {
72069
72488
  try {
72070
- sweepStaleSockets({ dir: dirname16(claudeBrokerSocketPath("", "")), prefix: CLAUDE_BROKER_SOCKET_PREFIX });
72489
+ sweepStaleSockets({ dir: dirname18(claudeBrokerSocketPath("", "")), prefix: CLAUDE_BROKER_SOCKET_PREFIX });
72071
72490
  } catch {
72072
72491
  }
72073
72492
  }
@@ -72144,7 +72563,7 @@ var init_orphan_reaper = __esm({
72144
72563
  defaultExec = async (file, args) => (await execFileAsync6(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout;
72145
72564
  defaultReadEnv = (pid) => {
72146
72565
  try {
72147
- return readFileSync24(`/proc/${pid}/environ`, "utf8");
72566
+ return readFileSync26(`/proc/${pid}/environ`, "utf8");
72148
72567
  } catch {
72149
72568
  return null;
72150
72569
  }
@@ -72164,7 +72583,7 @@ var init_orphan_reaper = __esm({
72164
72583
  });
72165
72584
 
72166
72585
  // packages/server/src/context.ts
72167
- import { join as join38 } from "node:path";
72586
+ import { join as join41 } from "node:path";
72168
72587
  import { randomUUID as randomUUID16 } from "node:crypto";
72169
72588
  import { homedir as homedir15 } from "node:os";
72170
72589
  function reconcileSessions(storage) {
@@ -72316,8 +72735,9 @@ async function createContext(opts = {}) {
72316
72735
  function createContextUnchecked(opts, resources) {
72317
72736
  const home = opts.home ?? homedir15();
72318
72737
  const project = opts.project ?? resolveProject();
72319
- const storage = createStorage(opts.database ?? join38(project.stateDir, "ui.db"), project.id);
72738
+ const storage = createStorage(opts.database ?? join41(project.stateDir, "ui.db"), project.id);
72320
72739
  resources.storage = storage;
72740
+ clearSecrets(project.stateDir);
72321
72741
  const bus = new Bus();
72322
72742
  const transcriptChange = new Emitter();
72323
72743
  const bootId = randomUUID16();
@@ -72733,6 +73153,7 @@ var init_context = __esm({
72733
73153
  init_bus();
72734
73154
  init_project();
72735
73155
  init_storage();
73156
+ init_secret_files();
72736
73157
  init_settings();
72737
73158
  init_dispatch_preferences();
72738
73159
  init_quota();
@@ -75428,8 +75849,8 @@ var init_server = __esm({
75428
75849
  });
75429
75850
 
75430
75851
  // packages/server/src/repair.ts
75431
- import { existsSync as existsSync16, readFileSync as readFileSync25, writeFileSync as writeFileSync12 } from "node:fs";
75432
- import { basename as basename7, dirname as dirname17, resolve as resolve9 } from "node:path";
75852
+ import { existsSync as existsSync18, readFileSync as readFileSync27, writeFileSync as writeFileSync14 } from "node:fs";
75853
+ import { basename as basename7, dirname as dirname19, resolve as resolve9 } from "node:path";
75433
75854
  function quoteValue(v) {
75434
75855
  if (/^[\w./#:+-]+$/.test(v)) return v;
75435
75856
  return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
@@ -75441,10 +75862,10 @@ function deriveTitle(body, slug) {
75441
75862
  function repairThreadFile(frizzDir, file) {
75442
75863
  const root = resolve9(frizzDir);
75443
75864
  const abs = resolve9(root, file);
75444
- if (dirname17(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
75865
+ if (dirname19(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
75445
75866
  if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
75446
- if (!existsSync16(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
75447
- const content = readFileSync25(abs, "utf8");
75867
+ if (!existsSync18(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
75868
+ const content = readFileSync27(abs, "utf8");
75448
75869
  const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
75449
75870
  if (firstLine2?.trim() === "---") {
75450
75871
  throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
@@ -75459,7 +75880,7 @@ function repairThreadFile(frizzDir, file) {
75459
75880
  "---",
75460
75881
  ""
75461
75882
  ].join("\n");
75462
- writeFileSync12(abs, frontmatter + content);
75883
+ writeFileSync14(abs, frontmatter + content);
75463
75884
  return { slug };
75464
75885
  }
75465
75886
  var RepairError, REPAIR_STATUS_TEXT;
@@ -75601,10 +76022,10 @@ var init_edited_files = __esm({
75601
76022
  });
75602
76023
 
75603
76024
  // packages/server/src/repo-files.ts
75604
- import { execFileSync as execFileSync4 } from "node:child_process";
76025
+ import { execFileSync as execFileSync5 } from "node:child_process";
75605
76026
  import path2 from "node:path";
75606
76027
  function git(args, cwd) {
75607
- return execFileSync4("git", args, {
76028
+ return execFileSync5("git", args, {
75608
76029
  cwd,
75609
76030
  encoding: "utf8",
75610
76031
  env: { ...process.env, LC_ALL: "C" },
@@ -75645,7 +76066,7 @@ function probeIgnored(projectDir, inside) {
75645
76066
  return /* @__PURE__ */ new Set();
75646
76067
  }
75647
76068
  try {
75648
- const out = execFileSync4("git", ["check-ignore", "-z", "--stdin"], {
76069
+ const out = execFileSync5("git", ["check-ignore", "-z", "--stdin"], {
75649
76070
  cwd: projectDir,
75650
76071
  encoding: "utf8",
75651
76072
  env: { ...process.env, LC_ALL: "C" },
@@ -75672,7 +76093,7 @@ var init_repo_files = __esm({
75672
76093
  });
75673
76094
 
75674
76095
  // cc-worker/hooks/bash-background.mjs
75675
- import { readFileSync as readFileSync26, realpathSync as realpathSync11 } from "node:fs";
76096
+ import { readFileSync as readFileSync28, realpathSync as realpathSync12 } from "node:fs";
75676
76097
  import { basename as basename8 } from "node:path";
75677
76098
  import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
75678
76099
  function emit(obj) {
@@ -75810,7 +76231,7 @@ function evaluateBashBackgroundHook(input, env = process.env) {
75810
76231
  }
75811
76232
  };
75812
76233
  }
75813
- function isDirectHookExecution(argv1, moduleUrl, realpath = realpathSync11) {
76234
+ function isDirectHookExecution(argv1, moduleUrl, realpath = realpathSync12) {
75814
76235
  if (typeof argv1 !== "string" || basename8(argv1) !== "bash-background.mjs") return false;
75815
76236
  if (pathToFileURL(argv1).href === moduleUrl) return true;
75816
76237
  try {
@@ -75827,7 +76248,7 @@ var init_bash_background = __esm({
75827
76248
  if (isDirectHookExecution(process.argv[1], import.meta.url)) {
75828
76249
  try {
75829
76250
  const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
75830
- emit(evaluateBashBackgroundHook(JSON.parse(readFileSync26(0, "utf8")), env));
76251
+ emit(evaluateBashBackgroundHook(JSON.parse(readFileSync28(0, "utf8")), env));
75831
76252
  } catch {
75832
76253
  emit({});
75833
76254
  }
@@ -75836,10 +76257,10 @@ var init_bash_background = __esm({
75836
76257
  });
75837
76258
 
75838
76259
  // packages/server/src/transcript.ts
75839
- import { closeSync as closeSync14, existsSync as existsSync17, fstatSync as fstatSync3, mkdirSync as mkdirSync19, openSync as openSync15, readdirSync as readdirSync11, readFileSync as readFileSync27, readSync as readSync8, renameSync as renameSync10, statSync as statSync17, unlinkSync as unlinkSync7, writeFileSync as writeFileSync13 } from "node:fs";
76260
+ import { closeSync as closeSync15, existsSync as existsSync19, fstatSync as fstatSync3, mkdirSync as mkdirSync21, openSync as openSync16, readdirSync as readdirSync12, readFileSync as readFileSync29, readSync as readSync8, renameSync as renameSync10, statSync as statSync18, unlinkSync as unlinkSync7, writeFileSync as writeFileSync15 } from "node:fs";
75840
76261
  import { createHash as createHash15 } from "node:crypto";
75841
76262
  import { StringDecoder as StringDecoder6 } from "node:string_decoder";
75842
- import { join as join39 } from "node:path";
76263
+ import { join as join42 } from "node:path";
75843
76264
  import { homedir as homedir16 } from "node:os";
75844
76265
  function formatTokens(n) {
75845
76266
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
@@ -76443,18 +76864,18 @@ function looksLikeImage(buf, ext) {
76443
76864
  }
76444
76865
  function pruneScreenshotCache() {
76445
76866
  try {
76446
- const entries2 = readdirSync11(SCREENSHOT_CACHE_DIR).filter((n) => !n.startsWith("."));
76867
+ const entries2 = readdirSync12(SCREENSHOT_CACHE_DIR).filter((n) => !n.startsWith("."));
76447
76868
  if (entries2.length <= SCREENSHOT_CACHE_MAX) return;
76448
76869
  const byMtime = entries2.map((n) => {
76449
76870
  try {
76450
- return { n, m: statSync17(join39(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
76871
+ return { n, m: statSync18(join42(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
76451
76872
  } catch {
76452
76873
  return { n, m: 0 };
76453
76874
  }
76454
76875
  }).sort((a, b) => b.m - a.m);
76455
76876
  for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
76456
76877
  try {
76457
- unlinkSync7(join39(SCREENSHOT_CACHE_DIR, n));
76878
+ unlinkSync7(join42(SCREENSHOT_CACHE_DIR, n));
76458
76879
  } catch {
76459
76880
  }
76460
76881
  }
@@ -76484,15 +76905,15 @@ function persistBase64Image(mediaType, data, idKey) {
76484
76905
  const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
76485
76906
  if (!ext || !data) return void 0;
76486
76907
  const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
76487
- const path3 = join39(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
76908
+ const path3 = join42(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
76488
76909
  try {
76489
- if (existsSync17(path3)) return path3;
76910
+ if (existsSync19(path3)) return path3;
76490
76911
  if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
76491
76912
  const buf = Buffer.from(data, "base64");
76492
76913
  if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
76493
- mkdirSync19(SCREENSHOT_CACHE_DIR, { recursive: true });
76494
- const tmp = join39(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
76495
- writeFileSync13(tmp, buf);
76914
+ mkdirSync21(SCREENSHOT_CACHE_DIR, { recursive: true });
76915
+ const tmp = join42(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
76916
+ writeFileSync15(tmp, buf);
76496
76917
  renameSync10(tmp, path3);
76497
76918
  pruneScreenshotCache();
76498
76919
  return path3;
@@ -76506,15 +76927,15 @@ function persistSentFile(srcPath, idKey) {
76506
76927
  const outExt = ext === "jpeg" ? "jpg" : ext;
76507
76928
  try {
76508
76929
  const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
76509
- const dest = join39(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
76510
- if (existsSync17(dest)) return dest;
76511
- const size = statSync17(srcPath).size;
76930
+ const dest = join42(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
76931
+ if (existsSync19(dest)) return dest;
76932
+ const size = statSync18(srcPath).size;
76512
76933
  if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
76513
- const buf = readFileSync27(srcPath);
76934
+ const buf = readFileSync29(srcPath);
76514
76935
  if (!looksLikeImage(buf, outExt)) return void 0;
76515
- mkdirSync19(SCREENSHOT_CACHE_DIR, { recursive: true });
76516
- const tmp = join39(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
76517
- writeFileSync13(tmp, buf);
76936
+ mkdirSync21(SCREENSHOT_CACHE_DIR, { recursive: true });
76937
+ const tmp = join42(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
76938
+ writeFileSync15(tmp, buf);
76518
76939
  renameSync10(tmp, dest);
76519
76940
  pruneScreenshotCache();
76520
76941
  return dest;
@@ -76932,7 +77353,7 @@ function readTranscript(project, sessionId) {
76932
77353
  const identityPrefix = `claude:${sessionId}`;
76933
77354
  let fd2;
76934
77355
  try {
76935
- fd2 = openSync15(path3, "r");
77356
+ fd2 = openSync16(path3, "r");
76936
77357
  const st2 = fstatSync3(fd2);
76937
77358
  const size = st2.size;
76938
77359
  const fileId = `${st2.dev}:${st2.ino}:${Math.trunc(st2.birthtimeMs)}`;
@@ -76946,12 +77367,12 @@ function readTranscript(project, sessionId) {
76946
77367
  } catch {
76947
77368
  return [];
76948
77369
  } finally {
76949
- if (fd2 !== void 0) closeSync14(fd2);
77370
+ if (fd2 !== void 0) closeSync15(fd2);
76950
77371
  }
76951
77372
  }
76952
77373
  function verifyIncrementalParse(path3, identityPrefix, incremental) {
76953
77374
  try {
76954
- const fresh = parseTranscript(readFileSync27(path3, "utf8"), identityPrefix);
77375
+ const fresh = parseTranscript(readFileSync29(path3, "utf8"), identityPrefix);
76955
77376
  const a = JSON.stringify(incremental);
76956
77377
  const b = JSON.stringify(fresh);
76957
77378
  if (a !== b) {
@@ -76971,16 +77392,16 @@ function verifyIncrementalParse(path3, identityPrefix, incremental) {
76971
77392
  }
76972
77393
  }
76973
77394
  function logDirOf(project) {
76974
- return join39(homedir16(), ".claude", "projects", project.cwdSlug);
77395
+ return join42(homedir16(), ".claude", "projects", project.cwdSlug);
76975
77396
  }
76976
77397
  function resolveTranscriptPath(project, sessionId) {
76977
- const path3 = join39(logDirOf(project), `${sessionId}.jsonl`);
77398
+ const path3 = join42(logDirOf(project), `${sessionId}.jsonl`);
76978
77399
  try {
76979
- if (statSync17(path3).size > 0) return path3;
77400
+ if (statSync18(path3).size > 0) return path3;
76980
77401
  } catch {
76981
77402
  }
76982
77403
  const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
76983
- return stranded ? join39(stranded, `${sessionId}.jsonl`) : path3;
77404
+ return stranded ? join42(stranded, `${sessionId}.jsonl`) : path3;
76984
77405
  }
76985
77406
  function projectCodexTranscript(raw2, identityPrefix = "codex") {
76986
77407
  const out = [];
@@ -78048,7 +78469,7 @@ function sourceForThread(project, storage, slug, backendFor) {
78048
78469
  }
78049
78470
  if (!FOREIGN_SESSION_ID_RE.test(slug)) return void 0;
78050
78471
  const claudePath = resolveTranscriptPath(project, slug);
78051
- if (existsSync17(claudePath)) {
78472
+ if (existsSync19(claudePath)) {
78052
78473
  return { slug, sessionId: slug, nativeId: slug, backend: "claude", runtimeGeneration: 0, path: claudePath };
78053
78474
  }
78054
78475
  const rollout = (backendFor?.("codex") ?? defaultCodexBackend()).transcriptPath(slug);
@@ -78084,7 +78505,7 @@ function discoveredClaudeSource(project, storage, slug, expectedNativeId) {
78084
78505
  function fixedSnapshot(source) {
78085
78506
  let fd2;
78086
78507
  try {
78087
- fd2 = openSync15(source.path, "r");
78508
+ fd2 = openSync16(source.path, "r");
78088
78509
  const before = fstatSync3(fd2);
78089
78510
  if (!Number.isSafeInteger(before.size) || before.size < 0) throw new Error("transcript is too large to page safely");
78090
78511
  const after = fstatSync3(fd2);
@@ -78094,7 +78515,7 @@ function fixedSnapshot(source) {
78094
78515
  const size = before.size;
78095
78516
  const path3 = source.path;
78096
78517
  const readRange = (from, length) => {
78097
- const rfd = openSync15(path3, "r");
78518
+ const rfd = openSync16(path3, "r");
78098
78519
  try {
78099
78520
  const st2 = fstatSync3(rfd);
78100
78521
  if (st2.dev !== before.dev || st2.ino !== before.ino || st2.size < size) {
@@ -78110,7 +78531,7 @@ function fixedSnapshot(source) {
78110
78531
  }
78111
78532
  return filled === want ? buf : buf.subarray(0, filled);
78112
78533
  } finally {
78113
- closeSync14(rfd);
78534
+ closeSync15(rfd);
78114
78535
  }
78115
78536
  };
78116
78537
  let allBytes;
@@ -78136,7 +78557,7 @@ function fixedSnapshot(source) {
78136
78557
  if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return void 0;
78137
78558
  throw error;
78138
78559
  } finally {
78139
- if (fd2 !== void 0) closeSync14(fd2);
78560
+ if (fd2 !== void 0) closeSync15(fd2);
78140
78561
  }
78141
78562
  }
78142
78563
  function projectSnapshot(snapshot) {
@@ -78320,7 +78741,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
78320
78741
  }
78321
78742
  function readCodexTranscriptFile(absPath, nativeId = absPath) {
78322
78743
  try {
78323
- return parseCodexTranscript(readFileSync27(absPath, "utf8"), `codex:${nativeId}`);
78744
+ return parseCodexTranscript(readFileSync29(absPath, "utf8"), `codex:${nativeId}`);
78324
78745
  } catch {
78325
78746
  return [];
78326
78747
  }
@@ -78388,7 +78809,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
78388
78809
  function readTranscriptFile(absPath) {
78389
78810
  try {
78390
78811
  const pathKey = createHash15("sha256").update(absPath).digest("base64url").slice(0, 16);
78391
- return parseTranscript(readFileSync27(absPath, "utf8"), `claude-file:${pathKey}`);
78812
+ return parseTranscript(readFileSync29(absPath, "utf8"), `claude-file:${pathKey}`);
78392
78813
  } catch {
78393
78814
  return [];
78394
78815
  }
@@ -78852,11 +79273,11 @@ var init_external_terminal = __esm({
78852
79273
  });
78853
79274
 
78854
79275
  // packages/server/src/background-shell-output.ts
78855
- import { closeSync as closeSync15, fstatSync as fstatSync4, openSync as openSync16, readSync as readSync9 } from "node:fs";
79276
+ import { closeSync as closeSync16, fstatSync as fstatSync4, openSync as openSync17, readSync as readSync9 } from "node:fs";
78856
79277
  function readBackgroundShellOutput(path3, maxBytes = OUTPUT_TAIL_BYTES) {
78857
79278
  let fd2;
78858
79279
  try {
78859
- fd2 = openSync16(path3, "r");
79280
+ fd2 = openSync17(path3, "r");
78860
79281
  const size = fstatSync4(fd2).size;
78861
79282
  const length = Math.min(size, maxBytes);
78862
79283
  const offset = Math.max(0, size - length);
@@ -78872,7 +79293,7 @@ function readBackgroundShellOutput(path3, maxBytes = OUTPUT_TAIL_BYTES) {
78872
79293
  } catch {
78873
79294
  return { output: "", truncated: false };
78874
79295
  } finally {
78875
- if (fd2 !== void 0) closeSync15(fd2);
79296
+ if (fd2 !== void 0) closeSync16(fd2);
78876
79297
  }
78877
79298
  }
78878
79299
  function readHead2(fd2, length) {
@@ -78889,7 +79310,7 @@ function readHead2(fd2, length) {
78889
79310
  function backgroundShellLineCount(path3) {
78890
79311
  let fd2;
78891
79312
  try {
78892
- fd2 = openSync16(path3, "r");
79313
+ fd2 = openSync17(path3, "r");
78893
79314
  const stat2 = fstatSync4(fd2);
78894
79315
  const size = stat2.size;
78895
79316
  let state = scans.get(path3);
@@ -78940,7 +79361,7 @@ function backgroundShellLineCount(path3) {
78940
79361
  } catch {
78941
79362
  return void 0;
78942
79363
  } finally {
78943
- if (fd2 !== void 0) closeSync15(fd2);
79364
+ if (fd2 !== void 0) closeSync16(fd2);
78944
79365
  }
78945
79366
  }
78946
79367
  var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, FINGERPRINT_BYTES, ANSI_ESCAPE_RE, scans;
@@ -78957,16 +79378,65 @@ var init_background_shell_output = __esm({
78957
79378
  }
78958
79379
  });
78959
79380
 
79381
+ // packages/server/src/frizz-md.ts
79382
+ import { execFileSync as execFileSync6 } from "node:child_process";
79383
+ import { existsSync as existsSync20, writeFileSync as writeFileSync16 } from "node:fs";
79384
+ import { join as join43 } from "node:path";
79385
+ function frizzMdPath(projectDir) {
79386
+ return join43(projectDir, "FRIZZ.md");
79387
+ }
79388
+ function git2(args, cwd) {
79389
+ try {
79390
+ return execFileSync6("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim() || null;
79391
+ } catch {
79392
+ return null;
79393
+ }
79394
+ }
79395
+ function defaultBranch(projectDir) {
79396
+ const remote = git2(["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"], projectDir);
79397
+ if (remote?.startsWith("origin/")) return remote.slice("origin/".length);
79398
+ const current = git2(["symbolic-ref", "--quiet", "--short", "HEAD"], projectDir);
79399
+ return current ?? "main";
79400
+ }
79401
+ function frizzMdStatus(projectDir, storage) {
79402
+ return {
79403
+ exists: existsSync20(frizzMdPath(projectDir)),
79404
+ skipped: storage.getSetting(SKIP_SETTING) !== void 0,
79405
+ defaultBranch: defaultBranch(projectDir)
79406
+ };
79407
+ }
79408
+ function createFrizzMd(projectDir, answers) {
79409
+ const path3 = frizzMdPath(projectDir);
79410
+ try {
79411
+ writeFileSync16(path3, composeFrizzMd(answers, defaultBranch(projectDir)), { encoding: "utf8", flag: "wx" });
79412
+ } catch (error) {
79413
+ if (error.code === "EEXIST") throw new Error("This project already has a FRIZZ.md.");
79414
+ throw error;
79415
+ }
79416
+ return { path: path3 };
79417
+ }
79418
+ function skipFrizzMd(storage, now = /* @__PURE__ */ new Date()) {
79419
+ storage.setSetting(SKIP_SETTING, { at: now.toISOString() });
79420
+ }
79421
+ var SKIP_SETTING;
79422
+ var init_frizz_md2 = __esm({
79423
+ "packages/server/src/frizz-md.ts"() {
79424
+ "use strict";
79425
+ init_src();
79426
+ SKIP_SETTING = "frizzMd.onboarding.skipped.v1";
79427
+ }
79428
+ });
79429
+
78960
79430
  // packages/server/src/image-header.ts
78961
- import { closeSync as closeSync16, openSync as openSync17, readSync as readSync10, statSync as statSync18 } from "node:fs";
78962
- import { extname } from "node:path";
79431
+ import { closeSync as closeSync17, openSync as openSync18, readSync as readSync10, statSync as statSync19 } from "node:fs";
79432
+ import { extname as extname2 } from "node:path";
78963
79433
  function readHead3(path3, budget) {
78964
79434
  let fd2;
78965
79435
  try {
78966
- const size = statSync18(path3).size;
79436
+ const size = statSync19(path3).size;
78967
79437
  if (size === 0) return void 0;
78968
79438
  const buffer = Buffer.alloc(Math.min(size, budget));
78969
- fd2 = openSync17(path3, "r");
79439
+ fd2 = openSync18(path3, "r");
78970
79440
  const read = readSync10(fd2, buffer, 0, buffer.length, 0);
78971
79441
  return read === buffer.length ? buffer : buffer.subarray(0, read);
78972
79442
  } catch {
@@ -78974,7 +79444,7 @@ function readHead3(path3, budget) {
78974
79444
  } finally {
78975
79445
  if (fd2 !== void 0) {
78976
79446
  try {
78977
- closeSync16(fd2);
79447
+ closeSync17(fd2);
78978
79448
  } catch {
78979
79449
  }
78980
79450
  }
@@ -79067,7 +79537,7 @@ function svg(head) {
79067
79537
  return void 0;
79068
79538
  }
79069
79539
  function svgDeclaresColour(path3) {
79070
- if (extname(path3).toLowerCase() !== ".svg") return void 0;
79540
+ if (extname2(path3).toLowerCase() !== ".svg") return void 0;
79071
79541
  const head = readHead3(path3, 512 * 1024);
79072
79542
  if (!head) return void 0;
79073
79543
  const source = head.toString("utf8");
@@ -79079,7 +79549,7 @@ function svgDeclaresColour(path3) {
79079
79549
  return false;
79080
79550
  }
79081
79551
  function imageDimensions(path3) {
79082
- const extension2 = extname(path3).toLowerCase();
79552
+ const extension2 = extname2(path3).toLowerCase();
79083
79553
  const budget = extension2 === ".jpg" || extension2 === ".jpeg" ? JPEG_SCAN_BYTES : HEAD_BYTES2;
79084
79554
  const head = readHead3(path3, budget);
79085
79555
  if (!head) return void 0;
@@ -79341,11 +79811,11 @@ function run(argv) {
79341
79811
  });
79342
79812
 
79343
79813
  // packages/server/src/router.ts
79344
- import { readFileSync as readFileSync28, statSync as statSync19 } from "node:fs";
79345
- import { join as join40, resolve as resolve10 } from "node:path";
79814
+ import { readFileSync as readFileSync30, statSync as statSync20 } from "node:fs";
79815
+ import { join as join44, resolve as resolve10 } from "node:path";
79346
79816
  import { randomUUID as randomUUID17 } from "node:crypto";
79347
- import { basename as basename9, dirname as dirname18 } from "node:path";
79348
- import { existsSync as existsSync18, mkdirSync as mkdirSync20, rmSync as rmSync11, writeFileSync as writeFileSync14 } from "node:fs";
79817
+ import { basename as basename9, dirname as dirname20 } from "node:path";
79818
+ import { existsSync as existsSync21, mkdirSync as mkdirSync22, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
79349
79819
  import { homedir as homedir17 } from "node:os";
79350
79820
  function validateGithubDispatchProfile(input, codexModels) {
79351
79821
  if (input.backend === "acp") return;
@@ -79519,11 +79989,11 @@ function projectCard(entry, stale) {
79519
79989
  function addProjectAtPath(input, home = homedir17()) {
79520
79990
  const typed = input.trim();
79521
79991
  if (!typed) throw new Error("Enter a folder path.");
79522
- const expanded = typed === "~" || typed.startsWith("~/") ? join40(home, typed.slice(1)) : typed;
79992
+ const expanded = typed === "~" || typed.startsWith("~/") ? join44(home, typed.slice(1)) : typed;
79523
79993
  const absolute = resolve10(expanded);
79524
79994
  let stats;
79525
79995
  try {
79526
- stats = statSync19(absolute);
79996
+ stats = statSync20(absolute);
79527
79997
  } catch {
79528
79998
  throw new Error(`No folder at ${absolute}`);
79529
79999
  }
@@ -79548,15 +80018,15 @@ function storeProjectIcon(id2, name, bytes) {
79548
80018
  if (!entry) throw new Error("No such project.");
79549
80019
  if (bytes.length === 0) throw new Error("That file is empty.");
79550
80020
  const path3 = customIconPath(id2, `.${extension2}`);
79551
- mkdirSync20(dirname18(path3), { recursive: true });
79552
- writeFileSync14(path3, bytes);
80021
+ mkdirSync22(dirname20(path3), { recursive: true });
80022
+ writeFileSync17(path3, bytes);
79553
80023
  if (!imageDimensions(path3)) {
79554
- rmSync11(path3, { force: true });
80024
+ rmSync12(path3, { force: true });
79555
80025
  throw new Error("That file does not look like an image Frizz can draw.");
79556
80026
  }
79557
80027
  for (const stale of PROJECT_ICON_EXTENSIONS) {
79558
80028
  const other = customIconPath(id2, `.${stale}`);
79559
- if (other !== path3) rmSync11(other, { force: true });
80029
+ if (other !== path3) rmSync12(other, { force: true });
79560
80030
  }
79561
80031
  const updated = setProjectIcon(id2, path3);
79562
80032
  if (!updated) throw new Error("No such project.");
@@ -79570,7 +80040,7 @@ function iconPicker(id2) {
79570
80040
  function setProjectIconFromFile(id2, file) {
79571
80041
  let bytes;
79572
80042
  try {
79573
- bytes = readFileSync28(file);
80043
+ bytes = readFileSync30(file);
79574
80044
  } catch {
79575
80045
  throw new Error("That file could not be read.");
79576
80046
  }
@@ -79603,7 +80073,7 @@ function mergeSubAgentSteers(messages, steers) {
79603
80073
  return merged;
79604
80074
  }
79605
80075
  function createRouter(ctx) {
79606
- const frizzDir = join40(ctx.project.dir, ".frizz");
80076
+ const frizzDir = join44(ctx.project.dir, ".frizz");
79607
80077
  const openRoots = openableFileRoots(ctx.project);
79608
80078
  function isAutoTitledSession(slug) {
79609
80079
  return ctx.storage.getSession(slug)?.title_auto === 1;
@@ -79711,15 +80181,24 @@ function createRouter(ctx) {
79711
80181
  for (const q2 of ctx.storage.listThreadQuestions(slug, { openOnly: true })) {
79712
80182
  const spec = parseQuestionSpec(q2.spec);
79713
80183
  if (!spec) continue;
79714
- out.push({ id: q2.id, spec, askedAt: new Date(q2.asked_at).toISOString() });
80184
+ out.push(questionView(slug, q2.id, spec, q2.asked_at));
79715
80185
  }
79716
80186
  return out;
79717
80187
  }
80188
+ function questionView(slug, id2, spec, askedAtMs) {
80189
+ return {
80190
+ id: id2,
80191
+ spec,
80192
+ askedAt: new Date(askedAtMs).toISOString(),
80193
+ ...spec.secret ? { secretPath: secretFilePath(ctx.project.stateDir, slug, id2) } : {}
80194
+ };
80195
+ }
79718
80196
  function cancelQuestionsForAutonomy(slug) {
79719
80197
  const now = Date.now();
79720
80198
  let cancelled = 0;
79721
80199
  for (const q2 of ctx.storage.listThreadQuestions(slug, { openOnly: true })) {
79722
- if (parseQuestionSpec(q2.spec)?.danger) continue;
80200
+ const spec = parseQuestionSpec(q2.spec);
80201
+ if (spec?.danger || spec?.secret) continue;
79723
80202
  if (ctx.storage.dismissThreadQuestion(q2.id, now)) cancelled++;
79724
80203
  }
79725
80204
  return cancelled;
@@ -80057,14 +80536,14 @@ function createRouter(ctx) {
80057
80536
  ctx.storage.listSubAgentSteers(input.slug, input.id)
80058
80537
  );
80059
80538
  const steer = subAgentSteerable(input.slug, input.id);
80060
- const stop = subAgentStoppable(input.slug, input.id);
80539
+ const stop2 = subAgentStoppable(input.slug, input.id);
80061
80540
  return {
80062
80541
  messages,
80063
80542
  state: info.state,
80064
80543
  steerable: steer.sessionId !== null,
80065
80544
  steerNote: steer.sessionId === null ? steer.note : null,
80066
- stoppable: stop.sessionId !== null,
80067
- stopNote: stop.sessionId === null ? stop.note : null
80545
+ stoppable: stop2.sessionId !== null,
80546
+ stopNote: stop2.sessionId === null ? stop2.note : null
80068
80547
  };
80069
80548
  }
80070
80549
  }),
@@ -80142,13 +80621,13 @@ function createRouter(ctx) {
80142
80621
  const info = ctx.tailer.backgroundShell?.(input.slug, input.id);
80143
80622
  if (!info) return { command: null, output: "", truncated: false, state: "gone", stoppable: false, stopNote: null };
80144
80623
  const content = info.outputFile ? readBackgroundShellOutput(info.outputFile) : { output: "", truncated: false };
80145
- const stop = subAgentStoppable(input.slug, input.id);
80624
+ const stop2 = subAgentStoppable(input.slug, input.id);
80146
80625
  return {
80147
80626
  command: info.command ?? null,
80148
80627
  ...content,
80149
80628
  state: info.state,
80150
- stoppable: stop.sessionId !== null,
80151
- stopNote: stop.sessionId === null ? stop.note : null
80629
+ stoppable: stop2.sessionId !== null,
80630
+ stopNote: stop2.sessionId === null ? stop2.note : null
80152
80631
  };
80153
80632
  }
80154
80633
  }),
@@ -81182,7 +81661,7 @@ ${gapNote}` : input.message;
81182
81661
  throw new Error("Reopen this thread before asking a question on it");
81183
81662
  }
81184
81663
  const goal = autonomousGoal(row);
81185
- if (goal) {
81664
+ if (goal && !input.questions.every((q2) => q2.secret)) {
81186
81665
  throw new Error(
81187
81666
  `This thread is running autonomously \u2014 decide it yourself and proceed. Its standing instruction is:
81188
81667
 
@@ -81198,7 +81677,7 @@ Say which way you went and why in your write-up, so the human can course-correct
81198
81677
  const id2 = `qst_${randomUUID17().replace(/-/g, "").slice(0, 12)}`;
81199
81678
  ctx.storage.clearThreadDone(input.slug);
81200
81679
  ctx.storage.askThreadQuestion({ id: id2, slug: input.slug, spec: JSON.stringify(spec), askedAtMs: now });
81201
- return { id: id2, spec, askedAt: new Date(now).toISOString() };
81680
+ return questionView(input.slug, id2, spec, now);
81202
81681
  });
81203
81682
  ctx.board.refresh();
81204
81683
  return { registered, open: openQuestionViews(input.slug) };
@@ -81223,7 +81702,14 @@ Say which way you went and why in your write-up, so the human can course-correct
81223
81702
  for (const answer of input.answers) {
81224
81703
  const q2 = ctx.storage.getThreadQuestion(answer.questionId);
81225
81704
  if (!q2 || q2.thread_slug !== input.slug || q2.state !== "open") continue;
81226
- if (ctx.storage.answerThreadQuestion(answer.questionId, JSON.stringify(answer), now)) answered.push(answer.questionId);
81705
+ let stored = answer;
81706
+ if (parseQuestionSpec(q2.spec)?.secret) {
81707
+ const value = answer.text?.trim() ?? "";
81708
+ if (!value) continue;
81709
+ const path3 = serveSecret(ctx.project.stateDir, input.slug, q2.id, value);
81710
+ stored = { questionId: answer.questionId, question: answer.question, chosen: [], text: secretAnswerText(path3) };
81711
+ }
81712
+ if (ctx.storage.answerThreadQuestion(answer.questionId, JSON.stringify(stored), now)) answered.push(answer.questionId);
81227
81713
  }
81228
81714
  if (answered.length > 0) {
81229
81715
  ctx.board.refresh();
@@ -81817,11 +82303,11 @@ Say which way you went and why in your write-up, so the human can course-correct
81817
82303
  output: ProjectCard,
81818
82304
  handler: async ({ input }) => {
81819
82305
  for (const extension2 of PROJECT_ICON_EXTENSIONS) {
81820
- rmSync11(customIconPath(input.id, `.${extension2}`), { force: true });
82306
+ rmSync12(customIconPath(input.id, `.${extension2}`), { force: true });
81821
82307
  }
81822
82308
  const updated = clearProjectIcon(input.id);
81823
82309
  if (!updated) throw new Error("No such project.");
81824
- return projectCard(updated, !existsSync18(updated.path));
82310
+ return projectCard(updated, !existsSync21(updated.path));
81825
82311
  }
81826
82312
  }),
81827
82313
  /**
@@ -81862,7 +82348,7 @@ Say which way you went and why in your write-up, so the human can course-correct
81862
82348
  }
81863
82349
  const updated = renameProject(entry.id, { name: name === basename9(path3) ? null : name, slug: name });
81864
82350
  if (!updated) throw new Error("No such project.");
81865
- return projectCard(updated, !existsSync18(updated.path));
82351
+ return projectCard(updated, !existsSync21(updated.path));
81866
82352
  }
81867
82353
  }),
81868
82354
  /**
@@ -81948,6 +82434,26 @@ Say which way you went and why in your write-up, so the human can course-correct
81948
82434
  output: Settings,
81949
82435
  handler: async () => ctx.resetSettings()
81950
82436
  }),
82437
+ // The first-run questionnaire (shared/frizz-md.ts): a project with no threads and no FRIZZ.md asks
82438
+ // how its workers should land work and how independently they should act, and writes the answers
82439
+ // as FRIZZ.md — which only Frizz workers ever read. Skipping is remembered per project.
82440
+ frizzMdStatus: query({
82441
+ output: FrizzMdStatus,
82442
+ handler: async () => frizzMdStatus(ctx.project.dir, ctx.storage)
82443
+ }),
82444
+ frizzMdCreate: mutation({
82445
+ input: FrizzMdAnswers,
82446
+ output: external_exports.object({ path: external_exports.string() }),
82447
+ handler: async ({ input }) => createFrizzMd(ctx.project.dir, input)
82448
+ }),
82449
+ frizzMdSkip: mutation({
82450
+ input: external_exports.object({}).strict(),
82451
+ output: external_exports.object({ skipped: external_exports.literal(true) }),
82452
+ handler: async () => {
82453
+ skipFrizzMd(ctx.storage);
82454
+ return { skipped: true };
82455
+ }
82456
+ }),
81951
82457
  dispatchPreferencesGet: query({
81952
82458
  output: DispatchPreferences,
81953
82459
  handler: async () => ctx.getDispatchPreferences(readCodexModels(void 0, ctx.codexVersion))
@@ -82046,6 +82552,7 @@ var init_router5 = __esm({
82046
82552
  init_server();
82047
82553
  init_src();
82048
82554
  init_context();
82555
+ init_secret_files();
82049
82556
  init_acp_agents();
82050
82557
  init_storage();
82051
82558
  init_usage_limit();
@@ -82080,6 +82587,7 @@ var init_router5 = __esm({
82080
82587
  init_transcript();
82081
82588
  init_project_registry();
82082
82589
  init_src();
82590
+ init_frizz_md2();
82083
82591
  init_image_header();
82084
82592
  init_project_root();
82085
82593
  init_project_identity();
@@ -82101,144 +82609,8 @@ var init_router5 = __esm({
82101
82609
  }
82102
82610
  });
82103
82611
 
82104
- // packages/server/src/local-origin.ts
82105
- import { isIP } from "node:net";
82106
- function publicAuthority(policy) {
82107
- const raw2 = policy?.publicOrigin;
82108
- if (!raw2) return null;
82109
- let url;
82110
- try {
82111
- url = new URL(raw2);
82112
- } catch {
82113
- return null;
82114
- }
82115
- if (url.origin !== raw2) return null;
82116
- return {
82117
- hostname: normalizedHostname(url.hostname),
82118
- port: explicitPort(url),
82119
- authority: url.host.toLowerCase(),
82120
- scheme: url.protocol === "https:" ? "https" : "http"
82121
- };
82122
- }
82123
- function acceptsHostname(hostname, policy) {
82124
- if (LOCAL_HOSTNAMES.has(hostname)) return true;
82125
- if (!policy?.exposed) return false;
82126
- if (isIP(hostname) !== 0) return true;
82127
- return (policy.allowedHosts ?? []).some((allowed) => allowed === "*" || allowed.toLowerCase() === hostname);
82128
- }
82129
- function oneHeader(value) {
82130
- return typeof value === "string" && value.length > 0 ? value : void 0;
82131
- }
82132
- function normalizedHostname(hostname) {
82133
- const lower = hostname.toLowerCase();
82134
- return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
82135
- }
82136
- function explicitPort(url) {
82137
- if (url.port) return Number(url.port);
82138
- return url.protocol === "https:" ? 443 : 80;
82139
- }
82140
- function validExpectedPort(port2) {
82141
- return Number.isInteger(port2) && port2 >= 1 && port2 <= 65535;
82142
- }
82143
- function parseLocalHttpOrigin(value, expectedPort, policy) {
82144
- const raw2 = oneHeader(value);
82145
- if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim()) return null;
82146
- const declared = publicAuthority(policy);
82147
- if (declared && raw2 === policy?.publicOrigin) return declared;
82148
- let url;
82149
- try {
82150
- url = new URL(raw2);
82151
- } catch {
82152
- return null;
82153
- }
82154
- if (url.protocol !== "http:" || url.origin !== raw2) return null;
82155
- const hostname = normalizedHostname(url.hostname);
82156
- if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
82157
- return { hostname, port: expectedPort, authority: url.host, scheme: "http" };
82158
- }
82159
- function parseLocalHost(value, expectedPort, policy) {
82160
- const raw2 = oneHeader(value);
82161
- if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim() || raw2.includes(",")) return null;
82162
- let url;
82163
- try {
82164
- url = new URL(`http://${raw2}`);
82165
- } catch {
82166
- return null;
82167
- }
82168
- if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) return null;
82169
- if (url.host.toLowerCase() !== raw2.toLowerCase()) return null;
82170
- const hostname = normalizedHostname(url.hostname);
82171
- const declared = publicAuthority(policy);
82172
- if (declared && hostname === declared.hostname) {
82173
- return url.port === "" || Number(url.port) === declared.port ? declared : null;
82174
- }
82175
- if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
82176
- return { hostname, port: expectedPort, authority: url.host.toLowerCase(), scheme: "http" };
82177
- }
82178
- function hasForwardedAuthority(headers) {
82179
- return FORWARDED_HEADERS.some((name) => headers[name] !== void 0);
82180
- }
82181
- function forwardedAuthorityAllowed(headers, host, policy) {
82182
- if (!hasForwardedAuthority(headers)) return true;
82183
- const declared = publicAuthority(policy);
82184
- return !!declared && declared.hostname === host.hostname;
82185
- }
82186
- function isTrustedLocalHttpRequest(headers, expectedPort, allowMissingOrigin = false, policy) {
82187
- const host = parseLocalHost(headers.host, expectedPort, policy);
82188
- if (!host) return false;
82189
- if (!forwardedAuthorityAllowed(headers, host, policy)) return false;
82190
- if (headers.origin === void 0) return allowMissingOrigin;
82191
- const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
82192
- return !!origin && host.hostname === origin.hostname && host.port === origin.port;
82193
- }
82194
- function allowedLocalCorsOrigin(origin, expectedPort, policy) {
82195
- return parseLocalHttpOrigin(origin, expectedPort, policy) ? origin : void 0;
82196
- }
82197
- function isTrustedLocalWebSocketRequest(req, expectedPort = req.socket.localPort, policy) {
82198
- if (!validExpectedPort(expectedPort)) return false;
82199
- const headers = req.headers;
82200
- const host = parseLocalHost(headers.host, expectedPort, policy);
82201
- if (!host || !forwardedAuthorityAllowed(headers, host, policy)) return false;
82202
- const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
82203
- return !!origin && host.hostname === origin.hostname && host.port === origin.port;
82204
- }
82205
- function rejectWebSocketUpgrade(socket, status = 403, reason = "Forbidden") {
82206
- const body = `${reason}
82207
- `;
82208
- const response = [
82209
- `HTTP/1.1 ${status} ${reason}`,
82210
- "Connection: close",
82211
- "Content-Type: text/plain; charset=utf-8",
82212
- `Content-Length: ${Buffer.byteLength(body)}`,
82213
- "",
82214
- body
82215
- ].join("\r\n");
82216
- try {
82217
- socket.end(response);
82218
- } catch {
82219
- try {
82220
- socket.destroy();
82221
- } catch {
82222
- }
82223
- }
82224
- }
82225
- var LOCAL_HOSTNAMES, FORWARDED_HEADERS;
82226
- var init_local_origin = __esm({
82227
- "packages/server/src/local-origin.ts"() {
82228
- "use strict";
82229
- LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
82230
- FORWARDED_HEADERS = [
82231
- "forwarded",
82232
- "x-forwarded-for",
82233
- "x-forwarded-host",
82234
- "x-forwarded-port",
82235
- "x-forwarded-proto"
82236
- ];
82237
- }
82238
- });
82239
-
82240
82612
  // packages/server/src/compression.ts
82241
- import { brotliCompressSync, gzipSync, constants as constants4 } from "node:zlib";
82613
+ import { brotliCompressSync, gzipSync, constants as constants5 } from "node:zlib";
82242
82614
  function negotiateEncoding(acceptEncoding) {
82243
82615
  if (!acceptEncoding) return null;
82244
82616
  const offers = /* @__PURE__ */ new Map();
@@ -82261,9 +82633,9 @@ function negotiateEncoding(acceptEncoding) {
82261
82633
  function compress(body, encoding) {
82262
82634
  const out = encoding === "br" ? brotliCompressSync(body, {
82263
82635
  params: {
82264
- [constants4.BROTLI_PARAM_QUALITY]: 4,
82636
+ [constants5.BROTLI_PARAM_QUALITY]: 4,
82265
82637
  // Telling brotli the input size lets it size its window instead of guessing.
82266
- [constants4.BROTLI_PARAM_SIZE_HINT]: body.byteLength
82638
+ [constants5.BROTLI_PARAM_SIZE_HINT]: body.byteLength
82267
82639
  }
82268
82640
  }) : gzipSync(body, { level: 6 });
82269
82641
  return Uint8Array.from(out);
@@ -82283,87 +82655,10 @@ var init_compression = __esm({
82283
82655
  }
82284
82656
  });
82285
82657
 
82286
- // packages/server/src/local-image.ts
82287
- import { createReadStream, realpathSync as realpathSync12, statSync as statSync20 } from "node:fs";
82288
- import { extname as extname2, isAbsolute as isAbsolute9 } from "node:path";
82289
- function resolveLocalImage(rawPath, range) {
82290
- if (rawPath) rawPath = normalizeLocalPath(rawPath);
82291
- if (!rawPath || !isAbsolute9(rawPath)) return { status: 400 };
82292
- const contentType = CONTENT_TYPE[extname2(rawPath).toLowerCase()];
82293
- if (!contentType) return { status: 400 };
82294
- let real;
82295
- try {
82296
- real = realpathSync12(rawPath);
82297
- } catch {
82298
- return { status: 404 };
82299
- }
82300
- let size;
82301
- try {
82302
- const stat2 = statSync20(real);
82303
- if (!stat2.isFile()) return { status: 404 };
82304
- size = stat2.size;
82305
- } catch {
82306
- return { status: 404 };
82307
- }
82308
- const span = range ? byteRange(range, size) : null;
82309
- if (span === "unsatisfiable") return { status: 416, size };
82310
- if (span) return { status: 206, contentType, file: real, size, start: span.start, end: span.end };
82311
- return { status: 200, contentType, file: real, size, start: 0, end: size - 1 };
82312
- }
82313
- function byteRange(header, size) {
82314
- const match2 = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
82315
- if (!match2) return null;
82316
- const [, first, last] = match2;
82317
- if (first === "" && last === "") return null;
82318
- if (first === "") {
82319
- const suffix = Number(last);
82320
- if (suffix === 0 || size === 0) return "unsatisfiable";
82321
- return { start: Math.max(size - suffix, 0), end: size - 1 };
82322
- }
82323
- const start = Number(first);
82324
- if (last !== "" && Number(last) < start) return null;
82325
- if (start >= size) return "unsatisfiable";
82326
- return { start, end: last === "" ? size - 1 : Math.min(Number(last), size - 1) };
82327
- }
82328
- function localImageHeaders(result) {
82329
- return {
82330
- "content-type": result.contentType,
82331
- "content-length": String(result.end - result.start + 1),
82332
- "accept-ranges": "bytes",
82333
- "cache-control": "private, max-age=60",
82334
- ...result.status === 206 ? { "content-range": `bytes ${result.start}-${result.end}/${result.size}` } : {}
82335
- };
82336
- }
82337
- function localImageStream(result) {
82338
- if (result.end < result.start) return null;
82339
- return createReadStream(result.file, { start: result.start, end: result.end });
82340
- }
82341
- var IMAGE_CONTENT_TYPE, VIDEO_CONTENT_TYPE, CONTENT_TYPE;
82342
- var init_local_image = __esm({
82343
- "packages/server/src/local-image.ts"() {
82344
- "use strict";
82345
- init_local_path();
82346
- IMAGE_CONTENT_TYPE = {
82347
- ".png": "image/png",
82348
- ".jpg": "image/jpeg",
82349
- ".jpeg": "image/jpeg",
82350
- ".gif": "image/gif",
82351
- ".webp": "image/webp"
82352
- };
82353
- VIDEO_CONTENT_TYPE = {
82354
- ".mp4": "video/mp4",
82355
- ".m4v": "video/mp4",
82356
- ".webm": "video/webm",
82357
- ".mov": "video/quicktime"
82358
- };
82359
- CONTENT_TYPE = { ...IMAGE_CONTENT_TYPE, ...VIDEO_CONTENT_TYPE };
82360
- }
82361
- });
82362
-
82363
82658
  // packages/server/src/project-icon.ts
82364
- import { readFileSync as readFileSync29, readdirSync as readdirSync12, realpathSync as realpathSync13, statSync as statSync21 } from "node:fs";
82659
+ import { readFileSync as readFileSync31, readdirSync as readdirSync13, realpathSync as realpathSync13, statSync as statSync21 } from "node:fs";
82365
82660
  import { homedir as homedir18 } from "node:os";
82366
- import { basename as basename10, dirname as dirname19, extname as extname3, join as join41, relative as relative2, sep as sep4 } from "node:path";
82661
+ import { basename as basename10, dirname as dirname21, extname as extname3, join as join45, relative as relative2, sep as sep4 } from "node:path";
82367
82662
  function normalizeStem(stem) {
82368
82663
  const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
82369
82664
  const normalized = sized.replace(VARIANT_SUFFIX, "");
@@ -82381,11 +82676,11 @@ function sizeScore(dimensions) {
82381
82676
  return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
82382
82677
  }
82383
82678
  function under(root, relativeDirectory) {
82384
- return relativeDirectory ? join41(root, relativeDirectory) : root;
82679
+ return relativeDirectory ? join45(root, relativeDirectory) : root;
82385
82680
  }
82386
82681
  function listFiles(directory) {
82387
82682
  try {
82388
- return readdirSync12(directory, { withFileTypes: true }).filter((entry) => entry.isFile() || entry.isSymbolicLink()).map((entry) => entry.name);
82683
+ return readdirSync13(directory, { withFileTypes: true }).filter((entry) => entry.isFile() || entry.isSymbolicLink()).map((entry) => entry.name);
82389
82684
  } catch {
82390
82685
  return [];
82391
82686
  }
@@ -82394,7 +82689,7 @@ function iconDirectories(root) {
82394
82689
  let children2;
82395
82690
  try {
82396
82691
  children2 = new Set(
82397
- readdirSync12(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name)
82692
+ readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name)
82398
82693
  );
82399
82694
  } catch {
82400
82695
  return [root];
@@ -82403,19 +82698,19 @@ function iconDirectories(root) {
82403
82698
  for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
82404
82699
  for (const host of HOST_DIRECTORIES) {
82405
82700
  if (!children2.has(host)) continue;
82406
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join41(root, host), asset));
82701
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join45(root, host), asset));
82407
82702
  }
82408
82703
  for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
82409
82704
  for (const container of WORKSPACE_CONTAINERS) {
82410
82705
  if (!children2.has(container)) continue;
82411
82706
  let members;
82412
82707
  try {
82413
- members = readdirSync12(join41(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
82708
+ members = readdirSync13(join45(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
82414
82709
  } catch {
82415
82710
  continue;
82416
82711
  }
82417
82712
  for (const member of members) {
82418
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join41(root, container, member), asset));
82713
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join45(root, container, member), asset));
82419
82714
  }
82420
82715
  }
82421
82716
  return [...new Set(directories)];
@@ -82423,13 +82718,13 @@ function iconDirectories(root) {
82423
82718
  function manifestIcons(manifestPath) {
82424
82719
  let parsed;
82425
82720
  try {
82426
- parsed = JSON.parse(readFileSync29(manifestPath, "utf8"));
82721
+ parsed = JSON.parse(readFileSync31(manifestPath, "utf8"));
82427
82722
  } catch {
82428
82723
  return [];
82429
82724
  }
82430
82725
  if (!Array.isArray(parsed?.icons)) return [];
82431
- const directory = dirname19(manifestPath);
82432
- 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) => join41(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
82726
+ const directory = dirname21(manifestPath);
82727
+ 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) => join45(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
82433
82728
  }
82434
82729
  function projectIconCandidates(root) {
82435
82730
  const projectStem = normalizeStem(basename10(root)).normalized;
@@ -82448,10 +82743,10 @@ function projectIconCandidates(root) {
82448
82743
  for (const name of listFiles(directory)) {
82449
82744
  const extension2 = extname3(name).toLowerCase();
82450
82745
  if (MANIFEST_NAMES.includes(name.toLowerCase())) {
82451
- for (const icon of manifestIcons(join41(directory, name))) {
82746
+ for (const icon of manifestIcons(join45(directory, name))) {
82452
82747
  if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
82453
82748
  fromManifest.add(icon);
82454
- files.push({ path: icon, directory: dirname19(icon) });
82749
+ files.push({ path: icon, directory: dirname21(icon) });
82455
82750
  }
82456
82751
  }
82457
82752
  continue;
@@ -82459,7 +82754,7 @@ function projectIconCandidates(root) {
82459
82754
  if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
82460
82755
  const stem = name.slice(0, name.length - extension2.length);
82461
82756
  if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
82462
- files.push({ path: join41(directory, name), directory });
82757
+ files.push({ path: join45(directory, name), directory });
82463
82758
  if (files.length >= MAX_CANDIDATES) break;
82464
82759
  }
82465
82760
  }
@@ -82524,7 +82819,7 @@ function resolveProjectIconResponse(id2, options = {}) {
82524
82819
  });
82525
82820
  if (!roots.some((root) => real === root || real.startsWith(root + sep4))) return { status: 404 };
82526
82821
  try {
82527
- return { status: 200, contentType, body: readFileSync29(real) };
82822
+ return { status: 200, contentType, body: readFileSync31(real) };
82528
82823
  } catch {
82529
82824
  return { status: 404 };
82530
82825
  }
@@ -82636,11 +82931,11 @@ var init_project_icon = __esm({
82636
82931
  });
82637
82932
 
82638
82933
  // packages/server/src/local-visualization.ts
82639
- import { readdirSync as readdirSync13, readFileSync as readFileSync30, realpathSync as realpathSync14, statSync as statSync22 } from "node:fs";
82640
- import { join as join42, sep as sep5 } from "node:path";
82934
+ import { readdirSync as readdirSync14, readFileSync as readFileSync32, realpathSync as realpathSync14, statSync as statSync22 } from "node:fs";
82935
+ import { join as join46, sep as sep5 } from "node:path";
82641
82936
  function children(path3, pattern) {
82642
82937
  try {
82643
- return readdirSync13(path3, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
82938
+ return readdirSync14(path3, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
82644
82939
  } catch {
82645
82940
  return [];
82646
82941
  }
@@ -82649,7 +82944,7 @@ function isUnder2(path3, root) {
82649
82944
  return path3 === root || path3.startsWith(root.endsWith(sep5) ? root : root + sep5);
82650
82945
  }
82651
82946
  function resolveFragment(projectDir, sessionId, file) {
82652
- const base = join42(projectDir, ".codex", "visualizations");
82947
+ const base = join46(projectDir, ".codex", "visualizations");
82653
82948
  let projectReal;
82654
82949
  let baseReal;
82655
82950
  try {
@@ -82660,12 +82955,12 @@ function resolveFragment(projectDir, sessionId, file) {
82660
82955
  }
82661
82956
  if (!isUnder2(baseReal, projectReal)) return null;
82662
82957
  for (const year of children(base, YEAR_PART)) {
82663
- const yearDir = join42(base, year);
82958
+ const yearDir = join46(base, year);
82664
82959
  for (const month of children(yearDir, DATE_PART)) {
82665
- const monthDir = join42(yearDir, month);
82960
+ const monthDir = join46(yearDir, month);
82666
82961
  for (const day of children(monthDir, DATE_PART)) {
82667
- const sessionRoot = join42(baseReal, year, month, day, sessionId);
82668
- const candidate = join42(monthDir, day, sessionId, file);
82962
+ const sessionRoot = join46(baseReal, year, month, day, sessionId);
82963
+ const candidate = join46(monthDir, day, sessionId, file);
82669
82964
  try {
82670
82965
  const real = realpathSync14(candidate);
82671
82966
  if (isUnder2(real, sessionRoot) && statSync22(real).isFile()) return real;
@@ -82755,7 +83050,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
82755
83050
  try {
82756
83051
  const size = statSync22(path3).size;
82757
83052
  if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
82758
- fragment = readFileSync30(path3, "utf8");
83053
+ fragment = readFileSync32(path3, "utf8");
82759
83054
  } catch {
82760
83055
  return { status: 404 };
82761
83056
  }
@@ -82797,9 +83092,9 @@ var init_local_visualization = __esm({
82797
83092
  });
82798
83093
 
82799
83094
  // packages/server/src/app.ts
82800
- import { mkdirSync as mkdirSync21, writeFileSync as writeFileSync15 } from "node:fs";
83095
+ import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync18 } from "node:fs";
82801
83096
  import { Readable } from "node:stream";
82802
- import { join as join43 } from "node:path";
83097
+ import { join as join47 } from "node:path";
82803
83098
  import { randomUUID as randomUUID18 } from "node:crypto";
82804
83099
  function createApp(ctx, options = {}) {
82805
83100
  const app = new Hono2();
@@ -82860,8 +83155,8 @@ function createApp(ctx, options = {}) {
82860
83155
  const supplied = c.req.header("x-frizz-launch-token");
82861
83156
  if (!options.controlToken || !supplied || supplied !== options.controlToken) return c.text("Forbidden", 403);
82862
83157
  if (!options.requestOwnerStop) return c.text("Owner control unavailable", 503);
82863
- const stop = setTimeout(options.requestOwnerStop, 25);
82864
- stop.unref();
83158
+ const stop2 = setTimeout(options.requestOwnerStop, 25);
83159
+ stop2.unref();
82865
83160
  return c.json({ accepted: true }, 202);
82866
83161
  });
82867
83162
  app.get(frizzRoute("/local-image"), (c) => {
@@ -82906,11 +83201,11 @@ function createApp(ctx, options = {}) {
82906
83201
  if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
82907
83202
  const ext = `.${attachmentExtension(name)}`;
82908
83203
  const buf = Buffer.from(body.data, "base64");
82909
- const dir = join43(ctx.project.stateDir, "attachments");
82910
- mkdirSync21(dir, { recursive: true });
83204
+ const dir = join47(ctx.project.stateDir, "attachments");
83205
+ mkdirSync23(dir, { recursive: true });
82911
83206
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
82912
- const path3 = join43(dir, `${Date.now()}-${randomUUID18().slice(0, 8)}-${base}${ext}`);
82913
- writeFileSync15(path3, buf);
83207
+ const path3 = join47(dir, `${Date.now()}-${randomUUID18().slice(0, 8)}-${base}${ext}`);
83208
+ writeFileSync18(path3, buf);
82914
83209
  return c.json({ path: path3 });
82915
83210
  });
82916
83211
  app.get(
@@ -83830,7 +84125,7 @@ var init_app_socket = __esm({
83830
84125
 
83831
84126
  // packages/server/src/local-file-watch.ts
83832
84127
  import { statSync as statSync23, watch } from "node:fs";
83833
- import { basename as basename11, dirname as dirname20 } from "node:path";
84128
+ import { basename as basename11, dirname as dirname22 } from "node:path";
83834
84129
  function stampOf(path3) {
83835
84130
  try {
83836
84131
  const s = statSync23(path3, { bigint: true });
@@ -83853,7 +84148,7 @@ function watchLocalFile(path3, onChange) {
83853
84148
  let entry = entries.get(path3);
83854
84149
  if (!entry) {
83855
84150
  const name = basename11(path3);
83856
- const watcher2 = watch(dirname20(path3), { persistent: false }, (_event, changed) => {
84151
+ const watcher2 = watch(dirname22(path3), { persistent: false }, (_event, changed) => {
83857
84152
  if (changed !== null && changed !== void 0 && changed.toString() !== name) return;
83858
84153
  const current = entries.get(path3);
83859
84154
  if (!current) return;
@@ -83889,10 +84184,10 @@ var init_local_file_watch = __esm({
83889
84184
  });
83890
84185
 
83891
84186
  // packages/server/src/boot-progress.ts
83892
- import { mkdirSync as mkdirSync22, readFileSync as readFileSync31, renameSync as renameSync11, rmSync as rmSync12, writeFileSync as writeFileSync16 } from "node:fs";
83893
- import { basename as basename12, dirname as dirname21, join as join44 } from "node:path";
84187
+ import { mkdirSync as mkdirSync24, readFileSync as readFileSync33, renameSync as renameSync11, rmSync as rmSync13, writeFileSync as writeFileSync19 } from "node:fs";
84188
+ import { basename as basename12, dirname as dirname23, join as join48 } from "node:path";
83894
84189
  function bootProgressPath(stateDir) {
83895
- return join44(stateDir, BOOT_PROGRESS_NAME);
84190
+ return join48(stateDir, BOOT_PROGRESS_NAME);
83896
84191
  }
83897
84192
  function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
83898
84193
  if (!stateDir) {
@@ -83912,9 +84207,9 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
83912
84207
  lastAt = now;
83913
84208
  step++;
83914
84209
  try {
83915
- mkdirSync22(dirname21(path3), { recursive: true, mode: 448 });
83916
- const temp = join44(dirname21(path3), `.${basename12(path3)}.${process.pid}.tmp`);
83917
- writeFileSync16(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
84210
+ mkdirSync24(dirname23(path3), { recursive: true, mode: 448 });
84211
+ const temp = join48(dirname23(path3), `.${basename12(path3)}.${process.pid}.tmp`);
84212
+ writeFileSync19(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
83918
84213
  `, "utf8");
83919
84214
  renameSync11(temp, path3);
83920
84215
  } catch {
@@ -83923,7 +84218,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
83923
84218
  return Object.assign(write, {
83924
84219
  done: () => {
83925
84220
  try {
83926
- rmSync12(path3, { force: true });
84221
+ rmSync13(path3, { force: true });
83927
84222
  } catch {
83928
84223
  }
83929
84224
  }
@@ -83939,13 +84234,13 @@ var init_boot_progress = __esm({
83939
84234
  });
83940
84235
 
83941
84236
  // packages/server/src/runtime-lease.ts
83942
- import { existsSync as existsSync19, mkdirSync as mkdirSync23, readdirSync as readdirSync14, readFileSync as readFileSync32, unlinkSync as unlinkSync8, writeFileSync as writeFileSync17 } from "node:fs";
83943
- import { dirname as dirname22, join as join45 } from "node:path";
84237
+ import { existsSync as existsSync22, mkdirSync as mkdirSync25, readdirSync as readdirSync15, readFileSync as readFileSync34, unlinkSync as unlinkSync8, writeFileSync as writeFileSync20 } from "node:fs";
84238
+ import { dirname as dirname24, join as join49 } from "node:path";
83944
84239
  function runtimeVersionDir(bin) {
83945
- let dir = dirname22(bin);
84240
+ let dir = dirname24(bin);
83946
84241
  for (let step = 0; step < MAX_ASCENT; step++) {
83947
- if (existsSync19(join45(dir, PROVISIONED_MARKER))) return dir;
83948
- const parent = dirname22(dir);
84242
+ if (existsSync22(join49(dir, PROVISIONED_MARKER))) return dir;
84243
+ const parent = dirname24(dir);
83949
84244
  if (parent === dir) return void 0;
83950
84245
  dir = parent;
83951
84246
  }
@@ -83963,11 +84258,11 @@ function leaseRuntime(bin, role) {
83963
84258
  const versionDir = runtimeVersionDir(bin);
83964
84259
  if (!versionDir) return () => {
83965
84260
  };
83966
- const path3 = join45(versionDir, LEASES_DIR, `${process.pid}.json`);
84261
+ const path3 = join49(versionDir, LEASES_DIR, `${process.pid}.json`);
83967
84262
  try {
83968
- mkdirSync23(dirname22(path3), { recursive: true });
84263
+ mkdirSync25(dirname24(path3), { recursive: true });
83969
84264
  const lease = { pid: process.pid, role, bin, at: (/* @__PURE__ */ new Date()).toISOString() };
83970
- writeFileSync17(path3, JSON.stringify(lease));
84265
+ writeFileSync20(path3, JSON.stringify(lease));
83971
84266
  } catch {
83972
84267
  return () => {
83973
84268
  };
@@ -83980,20 +84275,20 @@ function leaseRuntime(bin, role) {
83980
84275
  };
83981
84276
  }
83982
84277
  function liveRuntimeLeases(versionDir) {
83983
- const dir = join45(versionDir, LEASES_DIR);
84278
+ const dir = join49(versionDir, LEASES_DIR);
83984
84279
  let names;
83985
84280
  try {
83986
- names = readdirSync14(dir);
84281
+ names = readdirSync15(dir);
83987
84282
  } catch {
83988
84283
  return [];
83989
84284
  }
83990
84285
  const live = [];
83991
84286
  for (const name of names) {
83992
84287
  if (!name.endsWith(".json")) continue;
83993
- const path3 = join45(dir, name);
84288
+ const path3 = join49(dir, name);
83994
84289
  let lease;
83995
84290
  try {
83996
- lease = JSON.parse(readFileSync32(path3, "utf8"));
84291
+ lease = JSON.parse(readFileSync34(path3, "utf8"));
83997
84292
  } catch {
83998
84293
  continue;
83999
84294
  }
@@ -84022,27 +84317,27 @@ var init_runtime_lease = __esm({
84022
84317
  // packages/server/src/runtimes.ts
84023
84318
  import { createHash as createHash17 } from "node:crypto";
84024
84319
  import {
84025
- chmodSync as chmodSync2,
84026
- closeSync as closeSync17,
84027
- existsSync as existsSync20,
84028
- mkdirSync as mkdirSync24,
84029
- openSync as openSync18,
84030
- readFileSync as readFileSync33,
84031
- readdirSync as readdirSync15,
84320
+ chmodSync as chmodSync4,
84321
+ closeSync as closeSync18,
84322
+ existsSync as existsSync23,
84323
+ mkdirSync as mkdirSync26,
84324
+ openSync as openSync19,
84325
+ readFileSync as readFileSync35,
84326
+ readdirSync as readdirSync16,
84032
84327
  renameSync as renameSync12,
84033
- rmSync as rmSync13,
84328
+ rmSync as rmSync14,
84034
84329
  statSync as statSync24,
84035
- writeFileSync as writeFileSync18,
84036
- writeSync as writeSync2
84330
+ writeFileSync as writeFileSync21,
84331
+ writeSync as writeSync3
84037
84332
  } from "node:fs";
84038
- import { dirname as dirname23, isAbsolute as isAbsolute10, join as join46, normalize, relative as relative3, sep as sep6 } from "node:path";
84333
+ import { dirname as dirname25, isAbsolute as isAbsolute10, join as join50, normalize, relative as relative3, sep as sep6 } from "node:path";
84039
84334
  import { Readable as Readable2, Transform, Writable as Writable4 } from "node:stream";
84040
84335
  import { pipeline } from "node:stream/promises";
84041
84336
  import { createGunzip } from "node:zlib";
84042
84337
  function runtimesRoot(env = process.env) {
84043
84338
  const override = env[RUNTIMES_DIR_ENV];
84044
84339
  if (override && isAbsolute10(override)) return override;
84045
- return join46(frizzRoots().cache, "runtimes");
84340
+ return join50(frizzRoots().cache, "runtimes");
84046
84341
  }
84047
84342
  function isMusl() {
84048
84343
  if (process.platform !== "linux") return false;
@@ -84059,16 +84354,16 @@ function runtimeCoordinates(backend, platform3 = process.platform, arch = proces
84059
84354
  return { pkg: "@openai/codex", packageVersion: `${CODEX_VERSION}-${platform3}-${arch}`, label: CODEX_VERSION, binary: `codex${exe2}` };
84060
84355
  }
84061
84356
  function provisionedBinary(backend, root, label) {
84062
- const dir = join46(root, backend, label);
84357
+ const dir = join50(root, backend, label);
84063
84358
  let marker;
84064
84359
  try {
84065
- marker = JSON.parse(readFileSync33(join46(dir, MARKER), "utf8"));
84360
+ marker = JSON.parse(readFileSync35(join50(dir, MARKER), "utf8"));
84066
84361
  } catch {
84067
84362
  return void 0;
84068
84363
  }
84069
84364
  if (typeof marker.binary !== "string" || marker.label !== label) return void 0;
84070
- const bin = join46(dir, marker.binary);
84071
- return existsSync20(bin) ? bin : void 0;
84365
+ const bin = join50(dir, marker.binary);
84366
+ return existsSync23(bin) ? bin : void 0;
84072
84367
  }
84073
84368
  function octal(buffer, offset, length) {
84074
84369
  const text2 = buffer.toString("latin1", offset, offset + length).replace(/\0.*$/su, "").trim();
@@ -84082,26 +84377,26 @@ function safeEntryPath(dest, name) {
84082
84377
  if (parts.length < 2) return void 0;
84083
84378
  const rel = normalize(parts.slice(1).join(sep6));
84084
84379
  if (isAbsolute10(rel) || rel === ".." || rel.startsWith(`..${sep6}`)) return void 0;
84085
- const full = join46(dest, rel);
84380
+ const full = join50(dest, rel);
84086
84381
  const back = relative3(dest, full);
84087
84382
  if (back.startsWith("..") || isAbsolute10(back)) return void 0;
84088
84383
  return full;
84089
84384
  }
84090
84385
  function locateBinary(dir, backend, binary) {
84091
84386
  if (backend === "claude") {
84092
- const direct = join46(dir, binary);
84093
- return existsSync20(direct) ? direct : void 0;
84387
+ const direct = join50(dir, binary);
84388
+ return existsSync23(direct) ? direct : void 0;
84094
84389
  }
84095
- const vendor = join46(dir, "vendor");
84390
+ const vendor = join50(dir, "vendor");
84096
84391
  let triples;
84097
84392
  try {
84098
- triples = readdirSync15(vendor);
84393
+ triples = readdirSync16(vendor);
84099
84394
  } catch {
84100
84395
  return void 0;
84101
84396
  }
84102
84397
  for (const triple of triples) {
84103
- const candidate = join46(vendor, triple, "bin", binary);
84104
- if (existsSync20(candidate)) return candidate;
84398
+ const candidate = join50(vendor, triple, "bin", binary);
84399
+ if (existsSync23(candidate)) return candidate;
84105
84400
  }
84106
84401
  return void 0;
84107
84402
  }
@@ -84116,12 +84411,12 @@ async function provisionRuntime(backend, options) {
84116
84411
  const registry = options.registry ?? REGISTRY;
84117
84412
  const progress = options.onProgress ?? (() => {
84118
84413
  });
84119
- const backendDir = join46(root, backend);
84120
- const finalDir = join46(backendDir, coordinates.label);
84121
- const partial = join46(backendDir, `.partial-${coordinates.label}-${process.pid}`);
84122
- mkdirSync24(backendDir, { recursive: true });
84123
- rmSync13(partial, { recursive: true, force: true });
84124
- mkdirSync24(partial);
84414
+ const backendDir = join50(root, backend);
84415
+ const finalDir = join50(backendDir, coordinates.label);
84416
+ const partial = join50(backendDir, `.partial-${coordinates.label}-${process.pid}`);
84417
+ mkdirSync26(backendDir, { recursive: true });
84418
+ rmSync14(partial, { recursive: true, force: true });
84419
+ mkdirSync26(partial);
84125
84420
  try {
84126
84421
  const manifestUrl = `${registry}/${coordinates.pkg.replace("/", "%2F")}/${coordinates.packageVersion}`;
84127
84422
  progress(`resolving ${coordinates.pkg}@${coordinates.packageVersion}`);
@@ -84155,7 +84450,7 @@ async function provisionRuntime(backend, options) {
84155
84450
  if (digest !== integrity) throw new Error(`integrity mismatch for ${tarball}: expected ${integrity}, got ${digest}`);
84156
84451
  const bin = locateBinary(partial, backend, coordinates.binary);
84157
84452
  if (!bin) throw new Error(`${coordinates.pkg}@${coordinates.packageVersion} unpacked without a ${coordinates.binary} binary`);
84158
- if (process.platform !== "win32") chmodSync2(bin, 493);
84453
+ if (process.platform !== "win32") chmodSync4(bin, 493);
84159
84454
  const marker = {
84160
84455
  backend,
84161
84456
  label: coordinates.label,
@@ -84165,7 +84460,7 @@ async function provisionRuntime(backend, options) {
84165
84460
  binary: relative3(partial, bin),
84166
84461
  at: (/* @__PURE__ */ new Date()).toISOString()
84167
84462
  };
84168
- writeFileSync18(join46(partial, MARKER), `${JSON.stringify(marker, null, 2)}
84463
+ writeFileSync21(join50(partial, MARKER), `${JSON.stringify(marker, null, 2)}
84169
84464
  `, "utf8");
84170
84465
  const rename2 = options.rename ?? renameSync12;
84171
84466
  try {
@@ -84174,36 +84469,36 @@ async function provisionRuntime(backend, options) {
84174
84469
  rename2(partial, finalDir);
84175
84470
  break;
84176
84471
  } catch (err) {
84177
- if (attempt >= RENAME_ATTEMPTS || !TRANSIENT_HANDLE_CODES.has(errorCode4(err) ?? "") || existsSync20(finalDir)) throw err;
84472
+ if (attempt >= RENAME_ATTEMPTS || !TRANSIENT_HANDLE_CODES.has(errorCode4(err) ?? "") || existsSync23(finalDir)) throw err;
84178
84473
  await new Promise((resolve13) => setTimeout(resolve13, options.retryDelayMs ?? RENAME_RETRY_DELAY_MS));
84179
84474
  }
84180
84475
  }
84181
84476
  } catch (err) {
84182
84477
  const theirs = provisionedBinary(backend, root, coordinates.label);
84183
84478
  if (!theirs) throw err;
84184
- rmSync13(partial, { recursive: true, force: true });
84479
+ rmSync14(partial, { recursive: true, force: true });
84185
84480
  return { bin: theirs, label: coordinates.label, fetched: false };
84186
84481
  }
84187
84482
  progress("ready");
84188
- return { bin: join46(finalDir, marker.binary), label: coordinates.label, fetched: true };
84483
+ return { bin: join50(finalDir, marker.binary), label: coordinates.label, fetched: true };
84189
84484
  } catch (err) {
84190
- rmSync13(partial, { recursive: true, force: true });
84485
+ rmSync14(partial, { recursive: true, force: true });
84191
84486
  throw err;
84192
84487
  }
84193
84488
  }
84194
84489
  function sweepRuntimes(backend, root, keepLabel, now = Date.now(), deps = {}) {
84195
84490
  const rm2 = deps.rm ?? defaultSweepRm;
84196
- const backendDir = join46(root, backend);
84491
+ const backendDir = join50(root, backend);
84197
84492
  let entries2;
84198
84493
  try {
84199
- entries2 = readdirSync15(backendDir);
84494
+ entries2 = readdirSync16(backendDir);
84200
84495
  } catch {
84201
84496
  return { removed: [], kept: [] };
84202
84497
  }
84203
84498
  const sweep = { removed: [], kept: [] };
84204
84499
  for (const entry of entries2) {
84205
84500
  if (entry === keepLabel) continue;
84206
- const full = join46(backendDir, entry);
84501
+ const full = join50(backendDir, entry);
84207
84502
  if (entry.startsWith(".partial-")) {
84208
84503
  try {
84209
84504
  if (now - statSync24(full).mtimeMs < 24 * 60 * 60 * 1e3) continue;
@@ -84329,7 +84624,7 @@ var init_runtimes = __esm({
84329
84624
  }
84330
84625
  }
84331
84626
  _final(callback) {
84332
- if (this.fd !== void 0) closeSync17(this.fd);
84627
+ if (this.fd !== void 0) closeSync18(this.fd);
84333
84628
  this.fd = void 0;
84334
84629
  callback(this.remaining > 0 ? new Error("tarball ended inside a file entry") : null);
84335
84630
  }
@@ -84386,7 +84681,7 @@ var init_runtimes = __esm({
84386
84681
  return;
84387
84682
  case "5": {
84388
84683
  const dir = safeEntryPath(this.dest, name);
84389
- if (dir) mkdirSync24(dir, { recursive: true });
84684
+ if (dir) mkdirSync26(dir, { recursive: true });
84390
84685
  return;
84391
84686
  }
84392
84687
  case "0":
@@ -84394,8 +84689,8 @@ var init_runtimes = __esm({
84394
84689
  case "7": {
84395
84690
  const file = safeEntryPath(this.dest, name);
84396
84691
  if (!file) return;
84397
- mkdirSync24(dirname23(file), { recursive: true });
84398
- this.fd = openSync18(file, "w", octal(header, 100, 8) & 511 || 420);
84692
+ mkdirSync26(dirname25(file), { recursive: true });
84693
+ this.fd = openSync19(file, "w", octal(header, 100, 8) & 511 || 420);
84399
84694
  this.written.push(file);
84400
84695
  return;
84401
84696
  }
@@ -84404,13 +84699,13 @@ var init_runtimes = __esm({
84404
84699
  }
84405
84700
  }
84406
84701
  sink(bytes) {
84407
- if (this.fd !== void 0) writeSync2(this.fd, bytes);
84702
+ if (this.fd !== void 0) writeSync3(this.fd, bytes);
84408
84703
  else if (this.nameBuffer) this.nameBuffer.push(Buffer.from(bytes));
84409
84704
  else if (this.paxBuffer) this.paxBuffer.push(Buffer.from(bytes));
84410
84705
  }
84411
84706
  finishEntry() {
84412
84707
  if (this.fd !== void 0) {
84413
- closeSync17(this.fd);
84708
+ closeSync18(this.fd);
84414
84709
  this.fd = void 0;
84415
84710
  }
84416
84711
  if (this.nameBuffer) {
@@ -84438,7 +84733,7 @@ var init_runtimes = __esm({
84438
84733
  RENAME_RETRY_DELAY_MS = 200;
84439
84734
  TRANSIENT_HANDLE_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
84440
84735
  errorCode4 = (err) => err?.code;
84441
- defaultSweepRm = (path3) => rmSync13(path3, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
84736
+ defaultSweepRm = (path3) => rmSync14(path3, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
84442
84737
  }
84443
84738
  });
84444
84739
 
@@ -84974,18 +85269,18 @@ var init_legacy_project_db = __esm({
84974
85269
  });
84975
85270
 
84976
85271
  // packages/server/src/frizz-db.ts
84977
- import { existsSync as existsSync21, mkdirSync as mkdirSync25, readdirSync as readdirSync16, renameSync as renameSync13, statSync as statSync25 } from "node:fs";
84978
- import { basename as basename13, dirname as dirname24, join as join47 } from "node:path";
85272
+ import { existsSync as existsSync24, mkdirSync as mkdirSync27, readdirSync as readdirSync17, renameSync as renameSync13, statSync as statSync25 } from "node:fs";
85273
+ import { basename as basename13, dirname as dirname26, join as join51 } from "node:path";
84979
85274
  function frizzDatabaseLocation(options) {
84980
85275
  if (options.stateDir !== void 0) {
84981
- const projectsDir = dirname24(options.stateDir);
85276
+ const projectsDir = dirname26(options.stateDir);
84982
85277
  if (basename13(projectsDir) === "projects") {
84983
- return { path: options.path ?? join47(dirname24(projectsDir), "ui.db"), projectsDir };
85278
+ return { path: options.path ?? join51(dirname26(projectsDir), "ui.db"), projectsDir };
84984
85279
  }
84985
- return { path: options.path ?? join47(options.stateDir, "ui.db"), projectsDir: void 0 };
85280
+ return { path: options.path ?? join51(options.stateDir, "ui.db"), projectsDir: void 0 };
84986
85281
  }
84987
85282
  const data = options.home ? frizzPaths({ home: options.home }).data : frizzRoots().data;
84988
- return { path: options.path ?? join47(data, "ui.db"), projectsDir: join47(data, "projects") };
85283
+ return { path: options.path ?? join51(data, "ui.db"), projectsDir: join51(data, "projects") };
84989
85284
  }
84990
85285
  function ensureFrizzSchema(db2) {
84991
85286
  db2.exec(`
@@ -85004,7 +85299,7 @@ function ensureFrizzSchema(db2) {
85004
85299
  }
85005
85300
  function openFrizzDatabase(options = {}) {
85006
85301
  const { path: path3, projectsDir } = frizzDatabaseLocation(options);
85007
- mkdirSync25(dirname24(path3), { recursive: true });
85302
+ mkdirSync27(dirname26(path3), { recursive: true });
85008
85303
  const db2 = new sqlite_default(path3);
85009
85304
  db2.pragma("busy_timeout = 5000");
85010
85305
  db2.pragma("journal_mode = WAL");
@@ -85016,10 +85311,10 @@ function openFrizzDatabase(options = {}) {
85016
85311
  );
85017
85312
  for (const projectId of retiredLegacyProjectIds(projectsDir)) {
85018
85313
  if (alreadyImported.has(projectId)) continue;
85019
- const dir = join47(projectsDir, projectId);
85314
+ const dir = join51(projectsDir, projectId);
85020
85315
  try {
85021
- renameSync13(join47(dir, "ui.db.imported"), join47(dir, "ui.db"));
85022
- db2.prepare("INSERT INTO imported_project (project_id, source, rows, imported_at) VALUES (?, ?, 0, ?)").run(projectId, join47(dir, "ui.db"), (/* @__PURE__ */ new Date()).toISOString());
85316
+ renameSync13(join51(dir, "ui.db.imported"), join51(dir, "ui.db"));
85317
+ db2.prepare("INSERT INTO imported_project (project_id, source, rows, imported_at) VALUES (?, ?, 0, ?)").run(projectId, join51(dir, "ui.db"), (/* @__PURE__ */ new Date()).toISOString());
85023
85318
  alreadyImported.add(projectId);
85024
85319
  log.info("frizz-db", `${projectId}: restored ui.db.imported to ui.db and recorded it as imported`);
85025
85320
  } catch (error) {
@@ -85029,7 +85324,7 @@ function openFrizzDatabase(options = {}) {
85029
85324
  }
85030
85325
  for (const projectId of legacyProjectIds(projectsDir)) {
85031
85326
  if (alreadyImported.has(projectId)) continue;
85032
- const legacyPath = join47(projectsDir, projectId, "ui.db");
85327
+ const legacyPath = join51(projectsDir, projectId, "ui.db");
85033
85328
  try {
85034
85329
  const rows = importLegacyProject(db2, projectId, legacyPath);
85035
85330
  imported.push({ projectId, rows });
@@ -85059,10 +85354,10 @@ function openFrizzDatabase(options = {}) {
85059
85354
  };
85060
85355
  }
85061
85356
  function projectIdsWithFile(projectsDir, file) {
85062
- if (!existsSync21(projectsDir)) return [];
85063
- return readdirSync16(projectsDir).filter((name) => {
85357
+ if (!existsSync24(projectsDir)) return [];
85358
+ return readdirSync17(projectsDir).filter((name) => {
85064
85359
  try {
85065
- return statSync25(join47(projectsDir, name, file)).isFile();
85360
+ return statSync25(join51(projectsDir, name, file)).isFile();
85066
85361
  } catch {
85067
85362
  return false;
85068
85363
  }
@@ -85072,7 +85367,7 @@ function legacyProjectIds(projectsDir) {
85072
85367
  return projectIdsWithFile(projectsDir, "ui.db");
85073
85368
  }
85074
85369
  function retiredLegacyProjectIds(projectsDir) {
85075
- return projectIdsWithFile(projectsDir, "ui.db.imported").filter((id2) => !existsSync21(join47(projectsDir, id2, "ui.db")));
85370
+ return projectIdsWithFile(projectsDir, "ui.db.imported").filter((id2) => !existsSync24(join51(projectsDir, id2, "ui.db")));
85076
85371
  }
85077
85372
  function tableColumns(db2, schema, table) {
85078
85373
  return db2.prepare(`PRAGMA ${schema}.table_info(${table})`).all().map((c) => c.name);
@@ -85226,9 +85521,9 @@ var init_tenant_prime = __esm({
85226
85521
  });
85227
85522
 
85228
85523
  // packages/server/src/project-teardown.ts
85229
- import { rmSync as rmSync14 } from "node:fs";
85524
+ import { rmSync as rmSync15 } from "node:fs";
85230
85525
  import { homedir as homedir19 } from "node:os";
85231
- import { dirname as dirname25, resolve as resolve11 } from "node:path";
85526
+ import { dirname as dirname27, resolve as resolve11 } from "node:path";
85232
85527
  async function stopProjectWorkers(ctx) {
85233
85528
  let stopped = 0;
85234
85529
  for (const row of ctx.storage.allSessions()) {
@@ -85248,10 +85543,10 @@ function deleteProjectState(projectId, home = homedir19()) {
85248
85543
  if (!/^[\w.-]+$/u.test(projectId) || projectId === "." || projectId === "..") {
85249
85544
  throw new Error(`Refusing to delete state for a malformed project id: ${projectId}`);
85250
85545
  }
85251
- if (dirname25(resolve11(target)) !== resolve11(dirname25(projectStateDir("x", home)))) {
85546
+ if (dirname27(resolve11(target)) !== resolve11(dirname27(projectStateDir("x", home)))) {
85252
85547
  throw new Error(`Refusing to delete ${target} \u2014 it is not a project state directory`);
85253
85548
  }
85254
- rmSync14(target, { recursive: true, force: true });
85549
+ rmSync15(target, { recursive: true, force: true });
85255
85550
  }
85256
85551
  var init_project_teardown = __esm({
85257
85552
  "packages/server/src/project-teardown.ts"() {
@@ -85277,11 +85572,11 @@ __export(index_exports, {
85277
85572
  unknownProjectPage: () => unknownProjectPage
85278
85573
  });
85279
85574
  import { createServer } from "node:http";
85280
- import { readFileSync as readFileSync34, existsSync as existsSync22, statSync as statSync26 } from "node:fs";
85281
- import { dirname as dirname26, join as join48, resolve as resolve12, extname as extname4, posix as posix2, sep as sep7 } from "node:path";
85575
+ import { readFileSync as readFileSync36, existsSync as existsSync25, statSync as statSync26 } from "node:fs";
85576
+ import { dirname as dirname28, join as join52, resolve as resolve12, extname as extname4, posix as posix2, sep as sep7 } from "node:path";
85282
85577
  function readServerAddressHolder(path3) {
85283
85578
  try {
85284
- const value = JSON.parse(readFileSync34(path3, "utf8"));
85579
+ const value = JSON.parse(readFileSync36(path3, "utf8"));
85285
85580
  if (typeof value?.pid !== "number") return void 0;
85286
85581
  return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
85287
85582
  } catch {
@@ -85406,12 +85701,12 @@ function staticIsFresh(req, etag, mtimeMs) {
85406
85701
  }
85407
85702
  function serveStatic(distDir, req, res) {
85408
85703
  const rel = posix2.normalize((req.url ?? "/").split("?")[0].replace(/\\/g, "/")).replace(/^(\.\.[/\\])+/, "");
85409
- let file = join48(distDir, rel === "/" ? "index.html" : rel);
85410
- if (!file.startsWith(distDir + sep7)) file = join48(distDir, "index.html");
85411
- if (!existsSync22(file)) file = join48(distDir, "index.html");
85704
+ let file = join52(distDir, rel === "/" ? "index.html" : rel);
85705
+ if (!file.startsWith(distDir + sep7)) file = join52(distDir, "index.html");
85706
+ if (!existsSync25(file)) file = join52(distDir, "index.html");
85412
85707
  try {
85413
85708
  const stats = statSync26(file);
85414
- const cacheControl = file.startsWith(join48(distDir, "assets") + sep7) ? STATIC_CACHE_IMMUTABLE : STATIC_CACHE_REVALIDATE;
85709
+ const cacheControl = file.startsWith(join52(distDir, "assets") + sep7) ? STATIC_CACHE_IMMUTABLE : STATIC_CACHE_REVALIDATE;
85415
85710
  const etag = `"${stats.size.toString(16)}-${Math.trunc(stats.mtimeMs).toString(16)}"`;
85416
85711
  const headers = {
85417
85712
  "content-type": MIME[extname4(file)] ?? "application/octet-stream",
@@ -85427,7 +85722,7 @@ function serveStatic(distDir, req, res) {
85427
85722
  res.end();
85428
85723
  return;
85429
85724
  }
85430
- let body = readFileSync34(file);
85725
+ let body = readFileSync36(file);
85431
85726
  const accept = req.headers["accept-encoding"];
85432
85727
  const encoding = negotiateEncoding(Array.isArray(accept) ? accept.join(",") : accept);
85433
85728
  if (encoding && shouldCompress(new Headers({ "content-type": headers["content-type"] }), body.byteLength)) {
@@ -85684,7 +85979,7 @@ async function startServer(opts = {}) {
85684
85979
  if (statusPath && statusIdentity) runtime.removeStatus(statusPath, statusIdentity);
85685
85980
  if (statusPath && statusIdentity) {
85686
85981
  try {
85687
- runtime.removeStatus(serverAddressPathForStateDir(dirname26(statusPath)), statusIdentity);
85982
+ runtime.removeStatus(serverAddressPathForStateDir(dirname28(statusPath)), statusIdentity);
85688
85983
  } catch {
85689
85984
  }
85690
85985
  }
@@ -85816,7 +86111,7 @@ async function startServer(opts = {}) {
85816
86111
  }
85817
86112
  statusPath = serverLockPathFor(ctx.project);
85818
86113
  const webRoot = resolve12(import.meta.dirname, "..", "..", "web");
85819
- const distDir = opts.webDistDir ? resolve12(opts.webDistDir) : join48(webRoot, "dist");
86114
+ const distDir = opts.webDistDir ? resolve12(opts.webDistDir) : join52(webRoot, "dist");
85820
86115
  startupPhase = "Vite";
85821
86116
  if (opts.dev) {
85822
86117
  try {
@@ -85894,7 +86189,7 @@ async function startServer(opts = {}) {
85894
86189
  if (vite) {
85895
86190
  vite.middlewares(req, res, () => {
85896
86191
  try {
85897
- const html = readFileSync34(join48(webRoot, "index.html"), "utf8");
86192
+ const html = readFileSync36(join52(webRoot, "index.html"), "utf8");
85898
86193
  void vite.transformIndexHtml(url, html).then((out) => {
85899
86194
  res.writeHead(200, { "content-type": "text/html" });
85900
86195
  res.end(out);
@@ -85906,7 +86201,7 @@ async function startServer(opts = {}) {
85906
86201
  });
85907
86202
  return;
85908
86203
  }
85909
- if (existsSync22(distDir)) {
86204
+ if (existsSync25(distDir)) {
85910
86205
  serveStatic(distDir, req, res);
85911
86206
  return;
85912
86207
  }
@@ -86100,7 +86395,7 @@ var init_index = __esm({
86100
86395
  }
86101
86396
  };
86102
86397
  isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
86103
- serverLockPathFor = (project) => join48(project.stateDir, "server.lock");
86398
+ serverLockPathFor = (project) => join52(project.stateDir, "server.lock");
86104
86399
  MIME = {
86105
86400
  ".html": "text/html",
86106
86401
  ".js": "text/javascript",
@@ -86123,8 +86418,316 @@ init_project();
86123
86418
  init_project_launch();
86124
86419
  init_shutdown();
86125
86420
  init_logging();
86126
- import { existsSync as existsSync23 } from "node:fs";
86127
- import { join as join49 } from "node:path";
86421
+ import { existsSync as existsSync26 } from "node:fs";
86422
+ import { join as join53 } from "node:path";
86423
+
86424
+ // packages/server/src/access-codes.ts
86425
+ import { randomBytes, timingSafeEqual, createHmac } from "node:crypto";
86426
+ import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
86427
+ import { dirname as dirname6, join as join9 } from "node:path";
86428
+ var DEFAULT_CODE_TTL_MS = 5 * 6e4;
86429
+ var DEFAULT_SESSION_TTL_MS = 30 * 24 * 60 * 6e4;
86430
+ var SESSION_EPOCH = 1;
86431
+ var SESSION_KEY_FILE = "session-key";
86432
+ var SESSION_EPOCH_FILE = "session-epoch";
86433
+ function writeSessionKey(path3, key) {
86434
+ mkdirSync7(dirname6(path3), { recursive: true });
86435
+ writeFileSync6(path3, key, { mode: 384 });
86436
+ try {
86437
+ chmodSync(path3, 384);
86438
+ } catch {
86439
+ }
86440
+ }
86441
+ function rotateSessionKey(stateDir) {
86442
+ const key = randomBytes(32);
86443
+ writeSessionKey(join9(stateDir, SESSION_KEY_FILE), key);
86444
+ return key;
86445
+ }
86446
+ function readSessionEpoch(stateDir) {
86447
+ try {
86448
+ const parsed = JSON.parse(readFileSync6(join9(stateDir, SESSION_EPOCH_FILE), "utf8"));
86449
+ return Number.isInteger(parsed?.epoch) && parsed.epoch >= 0 ? parsed.epoch : 0;
86450
+ } catch {
86451
+ return 0;
86452
+ }
86453
+ }
86454
+ function advanceSessionEpoch(stateDir, epoch = SESSION_EPOCH) {
86455
+ const from = readSessionEpoch(stateDir);
86456
+ if (from >= epoch) return { advanced: false, epoch: from };
86457
+ const keyPath = join9(stateDir, SESSION_KEY_FILE);
86458
+ const rotatedKey = existsSync4(keyPath);
86459
+ if (rotatedKey) rotateSessionKey(stateDir);
86460
+ mkdirSync7(stateDir, { recursive: true });
86461
+ writeFileSync6(
86462
+ join9(stateDir, SESSION_EPOCH_FILE),
86463
+ JSON.stringify({ epoch, advancedAt: (/* @__PURE__ */ new Date()).toISOString() }),
86464
+ { mode: 384 }
86465
+ );
86466
+ return { advanced: true, from, to: epoch, rotatedKey };
86467
+ }
86468
+ function sessionEpochLogLine(advance, signedOut) {
86469
+ if (!advance.advanced || !advance.rotatedKey) return null;
86470
+ const count = signedOut === null ? "an unknown number of" : String(signedOut);
86471
+ return `session epoch ${advance.from} -> ${advance.to}: rotated the session key and signed out ${count} recorded remote device(s); every older remote session is refused`;
86472
+ }
86473
+
86474
+ // packages/server/src/session-epoch-child.ts
86475
+ import { readFileSync as readFileSync7 } from "node:fs";
86476
+ import { join as join10 } from "node:path";
86477
+
86478
+ // packages/server/src/restart-supervisor.ts
86479
+ init_local_origin();
86480
+ init_local_image();
86481
+
86482
+ // packages/server/src/supervisor-pages.ts
86483
+ var BASE_STYLE = `
86484
+ *,*::before,*::after{box-sizing:border-box}
86485
+ :root{
86486
+ color-scheme:dark;
86487
+ --bg:#0d0e10;--panel:#131519;--panel-2:#181b20;
86488
+ --border:#26282d;--border-strong:#33363c;--control-border:#26282d;--control-strong:#33363c;
86489
+ --fg:#e6e7e9;--muted:#8b8f96;--accent:#e8b923;--danger:#fca5a5;
86490
+ --focus-border:color-mix(in srgb,var(--accent) 55%,transparent);--focus-ring:color-mix(in srgb,var(--accent) 22%,transparent);
86491
+ --sans:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
86492
+ --mono:ui-monospace,"JetBrains Mono","SF Mono","Cascadia Mono",Menlo,Consolas,monospace;
86493
+ --ease:cubic-bezier(0,0,.2,1);
86494
+ }
86495
+ :root[data-theme=light]{
86496
+ color-scheme:light;
86497
+ --bg:#f7f7f7;--panel:#fff;--panel-2:#fafafa;
86498
+ --border:#dedede;--border-strong:#cecece;--control-border:#858585;--control-strong:#7d7d7d;
86499
+ --fg:#292929;--muted:#606060;--accent:#416896;--danger:#cf222e;
86500
+ --focus-border:#416896;--focus-ring:#416896;
86501
+ }
86502
+ @media(prefers-color-scheme:light){
86503
+ :root:not([data-theme]){
86504
+ color-scheme:light;
86505
+ --bg:#f7f7f7;--panel:#fff;--panel-2:#fafafa;
86506
+ --border:#dedede;--border-strong:#cecece;--control-border:#858585;--control-strong:#7d7d7d;
86507
+ --fg:#292929;--muted:#606060;--accent:#416896;--danger:#cf222e;
86508
+ --focus-border:#416896;--focus-ring:#416896;
86509
+ }
86510
+ }
86511
+ html,body{background:var(--bg)}
86512
+ body{
86513
+ margin:0;min-height:100vh;min-height:100dvh;
86514
+ display:flex;align-items:center;justify-content:center;padding:24px;
86515
+ color:var(--fg);font-family:var(--sans);font-size:12.5px;line-height:1.55;
86516
+ -webkit-font-smoothing:antialiased;
86517
+ }
86518
+ main{width:100%;max-width:28rem;padding:18px;border:1px solid var(--border-strong);border-radius:12px;background:var(--panel-2)}
86519
+ h1{margin:0;display:flex;align-items:baseline;gap:7px;font-size:14px;font-weight:600;letter-spacing:-.01em;line-height:1.4}
86520
+ p{margin:0;text-wrap:pretty}
86521
+ .detail{margin-top:7px;color:color-mix(in srgb,var(--fg) 88%,transparent)}
86522
+ .note{margin-top:12px;padding-top:11px;border-top:1px solid var(--border);color:var(--muted);font-size:11.5px;line-height:1.6}
86523
+ code{font-family:var(--mono);font-size:.92em;padding:.1em .35em;border-radius:4px;background:var(--panel);border:1px solid var(--border);white-space:nowrap}
86524
+ [hidden]{display:none!important}
86525
+ `.trim();
86526
+ var RECOVERY_STYLE = `
86527
+ .actions{margin-top:14px;display:flex;flex-wrap:wrap;gap:8px}
86528
+ /* ErrorBoundary's ACTION_CLASS, one size up for a page that is alone in a viewport. */
86529
+ .btn{
86530
+ appearance:none;display:inline-flex;align-items:center;
86531
+ border:1px solid var(--control-border);border-radius:6px;background:transparent;
86532
+ padding:5px 10px;font:inherit;font-size:11.5px;color:color-mix(in srgb,var(--fg) 90%,transparent);
86533
+ cursor:pointer;text-decoration:none;
86534
+ transition:background-color 120ms var(--ease),border-color 120ms var(--ease),color 120ms var(--ease);
86535
+ }
86536
+ .btn:hover{background:var(--panel);border-color:var(--control-strong);color:var(--fg)}
86537
+ .btn:focus-visible{outline:none;border-color:var(--focus-border);box-shadow:0 0 0 2px var(--focus-ring)}
86538
+ .btn:disabled{opacity:.5;pointer-events:none}
86539
+ /* min-height holds the slot open while it is LIVE, so a changing status line never nudges the card;
86540
+ :empty collapses it when there is nothing live to say, so a halted card has no trailing gutter. */
86541
+ .probe{margin-top:12px;font-family:var(--mono);font-size:11px;line-height:1.5;color:var(--muted);min-height:1.5em}
86542
+ .probe:empty{margin-top:0;min-height:0}
86543
+ /* RestartFailureNotice's block, at this altitude: a supervisor \`message\` is raw build output, and it
86544
+ reads as what it is \u2014 a terminal excerpt \u2014 only inside a scrolling mono box. */
86545
+ .log{
86546
+ margin-top:10px;max-height:16rem;overflow:auto;white-space:pre-wrap;overflow-wrap:break-word;
86547
+ border:1px solid var(--border);border-radius:6px;background:var(--panel);padding:8px 10px;
86548
+ font-family:var(--mono);font-size:11px;line-height:1.6;color:color-mix(in srgb,var(--fg) 70%,transparent);
86549
+ }
86550
+
86551
+ /* THE LIVE DOT, and it is the app's own \`.frizz-live-dot\` \u2014 same 6px, same 28%/14% halo, same 1.25s
86552
+ cadence \u2014 because it means the same thing here that it means there: work is in flight.
86553
+
86554
+ Alignment is an INK problem. A baseline-aligned flex item with no text of its own contributes its
86555
+ BORDER-BOX BOTTOM as the baseline, so the dot's ink centre lands 3px above it while the cap band's
86556
+ centre sits 0.5cap above it. \`cap\` is the resolved font's own cap height, so the correction holds
86557
+ at any size, with nothing to re-measure when the type scale moves. The em spelling is the fallback for a browser without the unit (.35em ~= 0.5 x a
86558
+ 0.7em cap) and is overwritten wherever \`cap\` parses. */
86559
+ .dot{
86560
+ width:6px;height:6px;flex:0 0 auto;border-radius:9999px;background:var(--accent);
86561
+ box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 28%,transparent);
86562
+ animation:frizz-live-pulse 1.25s ease-in-out infinite;
86563
+ transform:translateY(calc(3px - .35em));
86564
+ transform:translateY(calc(3px - .5cap));
86565
+ }
86566
+ .dot[data-state=idle]{animation:none;background:var(--muted);box-shadow:none}
86567
+ .dot[data-state=bad]{animation:none;background:var(--danger);box-shadow:0 0 0 1px color-mix(in srgb,var(--danger) 28%,transparent)}
86568
+ @keyframes frizz-live-pulse{50%{opacity:.62;box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 14%,transparent)}}
86569
+ @media (prefers-reduced-motion:reduce){
86570
+ .dot{animation:none;background:transparent;border:2px solid var(--accent);box-shadow:none}
86571
+ .dot[data-state=idle]{border-color:var(--muted)}
86572
+ .dot[data-state=bad]{border-color:var(--danger);background:transparent}
86573
+ }
86574
+
86575
+ /* The app's \`.shimmer-text\`: a highlight sweeping muted text is how this product says "working", and
86576
+ the probe line is the only thing on the page that is. */
86577
+ .probe[data-live=yes]{
86578
+ color:transparent;
86579
+ background:linear-gradient(90deg,var(--muted) 0%,var(--muted) 35%,var(--fg) 50%,var(--muted) 65%,var(--muted) 100%) 0 0/200% 100%;
86580
+ -webkit-background-clip:text;background-clip:text;
86581
+ animation:frizz-shimmer 2.2s linear infinite;
86582
+ }
86583
+ @keyframes frizz-shimmer{from{background-position:200% 0}to{background-position:-200% 0}}
86584
+ @media (prefers-reduced-motion:reduce){
86585
+ .probe[data-live=yes]{animation:none;background:none;color:var(--muted)}
86586
+ }
86587
+ `.trim();
86588
+ var RECOVERY_SCRIPT = `
86589
+ (function(){
86590
+ var target=document.body.dataset.target||"/"
86591
+ var heading=document.getElementById("heading")
86592
+ var detail=document.getElementById("detail")
86593
+ var probe=document.getElementById("probe")
86594
+ var log=document.getElementById("log")
86595
+ var dot=document.getElementById("dot")
86596
+ var restart=document.getElementById("restart")
86597
+ var BUDGET=120000,MIN=600,MAX=4000,GROWTH=1.4
86598
+ var delay=MIN,deadline=Date.now()+BUDGET,timer=0,stopped=false,busy=false,told=""
86599
+
86600
+ function say(text,live){probe.textContent=text;probe.setAttribute("data-live",live?"yes":"no")}
86601
+ function halt(text,bad){stopped=true;clearTimeout(timer);dot.setAttribute("data-state",bad?"bad":"idle");say(text,false)}
86602
+ function showLog(message){if(message){log.textContent=message;log.hidden=false}else{log.hidden=true}}
86603
+ function resume(){stopped=false;busy=false;delay=MIN;deadline=Date.now()+BUDGET;dot.removeAttribute("data-state");clearTimeout(timer);timer=setTimeout(tick,0)}
86604
+
86605
+ // 503 is this proxy's own "no child". Every other answer \u2014 200, 404, even a 500 from the app \u2014 means
86606
+ // something is listening again, and the reader's own URL is the right thing to ask.
86607
+ function alive(){
86608
+ return fetch(target,{method:"HEAD",cache:"no-store",credentials:"same-origin"})
86609
+ .then(function(r){return r.status!==503}).catch(function(){return false})
86610
+ }
86611
+ function readStatus(){
86612
+ return fetch("/_frizz/control/status",{cache:"no-store",headers:{"cache-control":"no-store"}})
86613
+ .then(function(r){return r.ok?r.json():null})
86614
+ .then(function(b){return b&&b.protocol===1?b:null}).catch(function(){return null})
86615
+ }
86616
+
86617
+ // An unreachable launcher leaves the server-rendered copy alone: it is already right for the case
86618
+ // that rendered it, and guessing over it would be worse than saying nothing.
86619
+ function narrate(status){
86620
+ if(!status||status.state===told)return
86621
+ told=status.state
86622
+ if(status.state==="failed"){
86623
+ heading.textContent="Frizz did not restart"
86624
+ // Not a second copy of the note below it \u2014 a lead-in to the log, which is the next thing down.
86625
+ detail.textContent="The launcher could not bring the application server back, and reported this:"
86626
+ showLog(status.message||"The launcher gave no reason.")
86627
+ halt("",true)
86628
+ return
86629
+ }
86630
+ showLog("")
86631
+ if(status.state==="restarting"){
86632
+ heading.textContent="Frizz is restarting"
86633
+ detail.textContent="The application server is coming back up."
86634
+ }
86635
+ }
86636
+
86637
+ function tick(){
86638
+ if(stopped||busy)return
86639
+ // A hidden tab neither polls nor spends its budget; visibilitychange starts the loop again.
86640
+ if(document.hidden)return
86641
+ alive().then(function(up){
86642
+ if(up){say("Frizz is back. Reloading.",true);location.replace(target);return}
86643
+ return readStatus().then(function(status){
86644
+ narrate(status)
86645
+ if(stopped)return
86646
+ if(Date.now()>deadline){halt("No answer after 2m. This page stopped checking.",false);return}
86647
+ delay=Math.min(MAX,delay*GROWTH)
86648
+ say("Waiting for Frizz",true)
86649
+ timer=setTimeout(tick,delay)
86650
+ })
86651
+ })
86652
+ }
86653
+
86654
+ document.addEventListener("visibilitychange",function(){
86655
+ if(document.hidden||stopped||busy)return
86656
+ resume()
86657
+ })
86658
+
86659
+ restart.addEventListener("click",function(){
86660
+ if(busy)return
86661
+ busy=true;stopped=false;told="";clearTimeout(timer)
86662
+ restart.disabled=true;restart.textContent="Restarting"
86663
+ dot.removeAttribute("data-state");showLog("");say("Restarting Frizz",true)
86664
+ fetch("/_frizz/control/restart",{method:"POST",headers:{"cache-control":"no-store"}})
86665
+ .then(function(r){return r.json().catch(function(){return null}).then(function(b){return{ok:r.ok,status:r.status,body:b}})})
86666
+ .catch(function(){return{ok:false,status:0,body:null}})
86667
+ .then(function(r){
86668
+ restart.disabled=false;restart.textContent="Restart Frizz";busy=false
86669
+ if(!r.ok){
86670
+ heading.textContent="Frizz did not restart"
86671
+ detail.textContent="The launcher could not bring the application server back, and reported this:"
86672
+ showLog((r.body&&r.body.message)||("The launcher refused the restart ("+(r.status||"no response")+")."))
86673
+ halt("",true)
86674
+ return
86675
+ }
86676
+ // Accepted. The probe, not this response, decides whether the child is actually back.
86677
+ resume()
86678
+ })
86679
+ })
86680
+
86681
+ say("Waiting for Frizz",true)
86682
+ tick()
86683
+ })()
86684
+ `.trim();
86685
+
86686
+ // packages/server/src/restart-supervisor.ts
86687
+ init_src();
86688
+ var SUPERVISOR_CONTROL_PREFIX = "/_frizz/control";
86689
+ var SUPERVISOR_RESTART_PATH = `${SUPERVISOR_CONTROL_PREFIX}/restart`;
86690
+ var SUPERVISOR_UPDATE_RESTART_PATH = `${SUPERVISOR_CONTROL_PREFIX}/update-restart`;
86691
+ var SUPERVISOR_STATUS_PATH = `${SUPERVISOR_CONTROL_PREFIX}/status`;
86692
+ var SUPERVISOR_ACCESS_CODE_PATH = `${SUPERVISOR_CONTROL_PREFIX}/access-code`;
86693
+ var SUPERVISOR_SESSIONS_PATH = `${SUPERVISOR_CONTROL_PREFIX}/sessions`;
86694
+ var SUPERVISOR_SIGN_OUT_PATH = `${SUPERVISOR_CONTROL_PREFIX}/sign-out`;
86695
+ var LOCAL_IMAGE_PATH = new RegExp(`^${FRIZZ_ROUTE_PREFIX}(?:/[^/]+)?/local-image$`);
86696
+
86697
+ // packages/server/src/session-epoch-child.ts
86698
+ async function signOutOlderSessionEpoch(options) {
86699
+ const advance = advanceSessionEpoch(options.stateDir, options.epoch ?? SESSION_EPOCH);
86700
+ if (!advance.advanced || !advance.rotatedKey) return { advance, signedOut: 0 };
86701
+ const port2 = supervisorPort(options.stateDir, options.supervisorPid);
86702
+ if (port2 === void 0) return { advance, signedOut: null };
86703
+ try {
86704
+ const response = await (options.fetcher ?? fetch)(`http://127.0.0.1:${port2}${SUPERVISOR_SESSIONS_PATH}`, {
86705
+ method: "POST",
86706
+ // Node's fetch sends no Origin, and the control plane wants one on a POST: name the loopback
86707
+ // authority, as `frizz --sign-out` does.
86708
+ headers: { origin: `http://127.0.0.1:${port2}`, "content-type": "application/json" },
86709
+ body: JSON.stringify({ all: true }),
86710
+ signal: AbortSignal.timeout(5e3)
86711
+ });
86712
+ if (response.status === 409) return { advance, signedOut: 0 };
86713
+ if (!response.ok) return { advance, signedOut: null };
86714
+ const body = await response.json().catch(() => void 0);
86715
+ return { advance, signedOut: typeof body?.signedOut === "number" ? body.signedOut : null };
86716
+ } catch {
86717
+ return { advance, signedOut: null };
86718
+ }
86719
+ }
86720
+ function supervisorPort(stateDir, supervisorPid) {
86721
+ try {
86722
+ const status = JSON.parse(readFileSync7(join10(stateDir, "dev-supervisor.lock"), "utf8"));
86723
+ if (status.pid !== supervisorPid) return void 0;
86724
+ return Number.isInteger(status.port) && status.port > 0 && status.port <= 65535 ? status.port : void 0;
86725
+ } catch {
86726
+ return void 0;
86727
+ }
86728
+ }
86729
+
86730
+ // packages/server/src/dev-child.ts
86128
86731
  process.on("uncaughtException", (error) => {
86129
86732
  log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
86130
86733
  process.exit(1);
@@ -86179,9 +86782,9 @@ try {
86179
86782
  ["FRIZZ_SCRIPTS_DIR", process.env.FRIZZ_SCRIPTS_DIR, "index.mjs"],
86180
86783
  ["FRIZZ_WORKER_PLUGIN_DIR", process.env.FRIZZ_WORKER_PLUGIN_DIR, ".claude-plugin/plugin.json"]
86181
86784
  ];
86182
- if (!existsSync23(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
86785
+ if (!existsSync26(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
86183
86786
  for (const [name, directory, requiredFile] of required) {
86184
- if (!directory || !existsSync23(join49(directory, requiredFile)))
86787
+ if (!directory || !existsSync26(join53(directory, requiredFile)))
86185
86788
  throw new Error(`stable artifact launch is missing verified ${name}`);
86186
86789
  }
86187
86790
  }
@@ -86201,8 +86804,14 @@ try {
86201
86804
  port: server.port,
86202
86805
  bootId: server.ctx.bootId
86203
86806
  });
86807
+ if (process.connected) {
86808
+ void signOutOlderSessionEpoch({ stateDir: target.stateDir, supervisorPid: process.ppid }).then(({ advance, signedOut }) => {
86809
+ const line = sessionEpochLogLine(advance, signedOut);
86810
+ if (line) log.warn("dev-child", `${line} (a launcher older than this release refuses the rest from its next start)`);
86811
+ }).catch((error) => log.warn("dev-child", `session epoch: ${error instanceof Error ? error.message : error}`));
86812
+ }
86204
86813
  let shuttingDown = false;
86205
- const stop = async () => {
86814
+ const stop2 = async () => {
86206
86815
  if (shuttingDown) return;
86207
86816
  shuttingDown = true;
86208
86817
  const force = setTimeout(() => process.exit(1), 15e3);
@@ -86225,9 +86834,9 @@ try {
86225
86834
  process.exit(1);
86226
86835
  }
86227
86836
  };
86228
- shutdown = stop;
86229
- process.on("SIGINT", () => void stop());
86230
- process.on("SIGTERM", () => void stop());
86837
+ shutdown = stop2;
86838
+ process.on("SIGINT", () => void stop2());
86839
+ process.on("SIGTERM", () => void stop2());
86231
86840
  } catch (err) {
86232
86841
  log.error("dev-child", `failed to start: ${err instanceof Error ? err.stack ?? err.message : err}`);
86233
86842
  process.exit(1);