frizz 0.7.8 → 0.8.0

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 (124) hide show
  1. package/README.md +5 -0
  2. package/dist/claude-agent-broker.js +7 -4
  3. package/dist/dev-child.js +225 -214
  4. package/dist/frizz.js +92 -7
  5. package/package.json +1 -1
  6. package/runtime/cc-worker/.claude-plugin/plugin.json +1 -1
  7. package/runtime/cc-worker/DECISIONS.md +29 -1
  8. package/runtime/cc-worker/agents/high.md +7 -0
  9. package/runtime/cc-worker/agents/low.md +7 -0
  10. package/runtime/cc-worker/agents/max.md +7 -0
  11. package/runtime/cc-worker/agents/medium.md +7 -0
  12. package/runtime/cc-worker/agents/xhigh.md +7 -0
  13. package/runtime/cc-worker/hooks/agent-dispatch.mjs +7 -6
  14. package/runtime/cc-worker/hooks/hooks.json +0 -2
  15. package/runtime/cc-worker/hooks/scratchpad.mjs +5 -3
  16. package/runtime/cc-worker/hooks/session-seed.mjs +17 -17
  17. package/runtime/cc-worker/skills/gh/SKILL.md +5 -19
  18. package/web-dist/assets/{TerminalPane-ubcEP7X3.js → TerminalPane-BIBHC61j.js} +1 -1
  19. package/web-dist/assets/{abnfDiagram-VRR7QNED-0brfnieb.js → abnfDiagram-VRR7QNED-CcFQGFPf.js} +1 -1
  20. package/web-dist/assets/architecture-TIHT7OUA-BZEZt7jZ.js +1 -0
  21. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-Dji-XBdF.js → architectureDiagram-ZJ3FMSHR-DErIQOIs.js} +1 -1
  22. package/web-dist/assets/{blockDiagram-677ZJIJ3-BQMyz3Q9.js → blockDiagram-677ZJIJ3-CpsUqur1.js} +1 -1
  23. package/web-dist/assets/{c4Diagram-LMCZKHZV-BMNws0Oi.js → c4Diagram-LMCZKHZV-D2dHmCEJ.js} +1 -1
  24. package/web-dist/assets/channel-DdFRPviT.js +1 -0
  25. package/web-dist/assets/{chunk-32BRIVSS-CVv1ae7n.js → chunk-32BRIVSS-aOCEfxRW.js} +1 -1
  26. package/web-dist/assets/{chunk-52WLFC77-BYhPlKCT.js → chunk-52WLFC77-2iw4nJPC.js} +1 -1
  27. package/web-dist/assets/{chunk-C7G6YPKG-Cn4HhNwb.js → chunk-C7G6YPKG-BPD3iHVE.js} +1 -1
  28. package/web-dist/assets/{chunk-EX3LRPZG-P3ZYFC1W.js → chunk-EX3LRPZG-DrefHift.js} +1 -1
  29. package/web-dist/assets/{chunk-FWX5IMBZ-Ba3NpEQa.js → chunk-FWX5IMBZ-By940EHT.js} +2 -2
  30. package/web-dist/assets/{chunk-HOUHSVGY-BCWyMhwJ.js → chunk-HOUHSVGY-B1Cqvz7e.js} +1 -1
  31. package/web-dist/assets/{chunk-ICXQ74PX-DWAAqHL7.js → chunk-ICXQ74PX-1LkVpWuI.js} +1 -1
  32. package/web-dist/assets/{chunk-MOJQB5TN-pc5VJ4Nq.js → chunk-MOJQB5TN-Ip1cy64r.js} +1 -1
  33. package/web-dist/assets/{chunk-OGEWGWER-DUxmbiuX.js → chunk-OGEWGWER-CNjVyu8F.js} +1 -1
  34. package/web-dist/assets/{chunk-PUDLZKDR-DRdZWzxX.js → chunk-PUDLZKDR-9HZR6DAU.js} +1 -1
  35. package/web-dist/assets/{chunk-Q4XR5HBZ-Bafzu7s-.js → chunk-Q4XR5HBZ-vtWwOCuQ.js} +1 -1
  36. package/web-dist/assets/{chunk-V7JOEXUC-Bj0A8ftW.js → chunk-V7JOEXUC-DC6YaHG0.js} +1 -1
  37. package/web-dist/assets/{chunk-VAUOI2AC-DBgVQKIO.js → chunk-VAUOI2AC-CP-xe7SD.js} +1 -1
  38. package/web-dist/assets/{chunk-VR4S4FIN-DU-1KtuM.js → chunk-VR4S4FIN-wbxDFptH.js} +1 -1
  39. package/web-dist/assets/{chunk-WYO6CB5R-DzVb3-Rj.js → chunk-WYO6CB5R-dibXmwpK.js} +1 -1
  40. package/web-dist/assets/{chunk-ZGVPDNZ5-BPKQvduj.js → chunk-ZGVPDNZ5-_y_itJHG.js} +1 -1
  41. package/web-dist/assets/classDiagram-OUVF2IWQ-Bf3duLb8.js +1 -0
  42. package/web-dist/assets/classDiagram-v2-EOCWNBFH-Bf3duLb8.js +1 -0
  43. package/web-dist/assets/{cynefin-VYW2F7L2-lo8PqVCk.js → cynefin-VYW2F7L2-D1RYokZP.js} +1 -1
  44. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-BtQLaDV0.js → cynefinDiagram-TSTJHNR4-qofqoy3T.js} +1 -1
  45. package/web-dist/assets/{dagre-VKFMJZFB-BJ2-f-A0.js → dagre-VKFMJZFB-CgHLoGFk.js} +1 -1
  46. package/web-dist/assets/{diagram-FQU43EPY-CLM-8r74.js → diagram-FQU43EPY-JEAs4LOb.js} +1 -1
  47. package/web-dist/assets/{diagram-G47NLZAW-CfuoJGpN.js → diagram-G47NLZAW--tLd4Lf7.js} +1 -1
  48. package/web-dist/assets/{diagram-NH7WQ7WH-DfxxRwH8.js → diagram-NH7WQ7WH-DPbw9CJU.js} +1 -1
  49. package/web-dist/assets/{diagram-OA4YK3LP-D7knxZee.js → diagram-OA4YK3LP-CDrb7nWs.js} +1 -1
  50. package/web-dist/assets/{diagram-WEI45ONY-C2WfMXWl.js → diagram-WEI45ONY-DJswZe3f.js} +1 -1
  51. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-DRSZ24tF.js → ebnfDiagram-CCIWWBDH-BP8-PZMF.js} +1 -1
  52. package/web-dist/assets/{erDiagram-Q63AITRT-DXe0OrbY.js → erDiagram-Q63AITRT-BQXuebf5.js} +1 -1
  53. package/web-dist/assets/eventmodeling-45OFAUF4-DOLxRQQ5.js +1 -0
  54. package/web-dist/assets/flowDiagram-23GEKE2U-DoK1yb0H.js +1 -0
  55. package/web-dist/assets/{ganttDiagram-NO4QXBWP-wGqOgjvs.js → ganttDiagram-NO4QXBWP-DotMb935.js} +1 -1
  56. package/web-dist/assets/{gitGraph-TEB2WS4Q-BygokG6y.js → gitGraph-TEB2WS4Q-B1vbYyKQ.js} +1 -1
  57. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-CV1933_M.js → gitGraphDiagram-IHSO6WYX-BjDXKk4m.js} +1 -1
  58. package/web-dist/assets/{index-DB1d3eMJ.js → index-Cs0TDGMu.js} +124 -124
  59. package/web-dist/assets/{info-DKCQHKI2-DLavbzui.js → info-DKCQHKI2-xLTLqQju.js} +1 -1
  60. package/web-dist/assets/{infoDiagram-FWYZ7A6U-Biouxd9G.js → infoDiagram-FWYZ7A6U-BFfYUsrC.js} +1 -1
  61. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DJxwwS3R.js → ishikawaDiagram-FXEZZL3T-45a7VMwm.js} +1 -1
  62. package/web-dist/assets/{journeyDiagram-5HDEW3XC-Clx_WkdW.js → journeyDiagram-5HDEW3XC-CEBUpu59.js} +1 -1
  63. package/web-dist/assets/{kanban-definition-HUTT4EX6-Bf7bX_96.js → kanban-definition-HUTT4EX6-RwKtDFzG.js} +1 -1
  64. package/web-dist/assets/{line-CV2v49IN.js → line-DStcMIry.js} +1 -1
  65. package/web-dist/assets/{mermaid-parser.core-BPsFhEi6.js → mermaid-parser.core-B0ekgQMA.js} +3 -3
  66. package/web-dist/assets/{mermaid.core-0EWDNL_R.js → mermaid.core-w1hcQaPy.js} +3 -3
  67. package/web-dist/assets/{mindmap-definition-LN4V7U3C-C1y4yy3Z.js → mindmap-definition-LN4V7U3C-D_n38Imb.js} +1 -1
  68. package/web-dist/assets/{packet-7NZHBO7P-CpcpxruB.js → packet-7NZHBO7P-CstGeBOX.js} +1 -1
  69. package/web-dist/assets/{pegDiagram-2B236MQR-CVlVP4cH.js → pegDiagram-2B236MQR-DvowVyTO.js} +1 -1
  70. package/web-dist/assets/{pie-RZYD4A2V-BcVPOhTZ.js → pie-RZYD4A2V-BOP2j_HH.js} +1 -1
  71. package/web-dist/assets/{pieDiagram-ENE6RG2P-DZv4Tfae.js → pieDiagram-ENE6RG2P-CKRqu_2f.js} +1 -1
  72. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DOzS_U_a.js → quadrantDiagram-ABIIQ3AL-zSArSS8R.js} +1 -1
  73. package/web-dist/assets/{radar-I7S5WNFK-8YADxkdT.js → radar-I7S5WNFK-BqRdNIBw.js} +1 -1
  74. package/web-dist/assets/{railroad-3IZDKUUU-DzndPrRy.js → railroad-3IZDKUUU-BaKcl_LU.js} +1 -1
  75. package/web-dist/assets/railroad-abnf-AHOZXSZD-itqDLg1p.js +1 -0
  76. package/web-dist/assets/railroad-ebnf-EBAXGLYW-ze7rLVCi.js +1 -0
  77. package/web-dist/assets/railroad-peg-LSFZ7HO6-DKsYkEuG.js +1 -0
  78. package/web-dist/assets/{railroadDiagram-RFXS5EU6-CPJAH-r7.js → railroadDiagram-RFXS5EU6-BrXTQge9.js} +1 -1
  79. package/web-dist/assets/{requirementDiagram-TGXJPOKE-BVFJZfwl.js → requirementDiagram-TGXJPOKE-DBBNi_SS.js} +1 -1
  80. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-CUhvFPmE.js → sankeyDiagram-HTMAVEWB-BwFi7xFy.js} +1 -1
  81. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-Cy9CGhNq.js → sequenceDiagram-DBY2YBRQ-CeivqMeT.js} +1 -1
  82. package/web-dist/assets/{stateDiagram-2N3HPSRC-CqOnmPLp.js → stateDiagram-2N3HPSRC-C6NZsnFm.js} +1 -1
  83. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-B3YRnI4W.js +1 -0
  84. package/web-dist/assets/{swimlanes-5IMT3BWC-c_zBqkb9.js → swimlanes-5IMT3BWC-C0MubXTG.js} +1 -1
  85. package/web-dist/assets/swimlanesDiagram-G3AALYLV-CXva4Ic9.js +8 -0
  86. package/web-dist/assets/{timeline-definition-FHXFAJF6-y_QM62SK.js → timeline-definition-FHXFAJF6-CtxwSvFu.js} +1 -1
  87. package/web-dist/assets/{treeView-QDETBFTQ-T3y_1KXV.js → treeView-QDETBFTQ-CXcwSjey.js} +1 -1
  88. package/web-dist/assets/{treemap-6X3UGDF4-CzvqucqY.js → treemap-6X3UGDF4-Uspgr-d1.js} +1 -1
  89. package/web-dist/assets/{vennDiagram-L72KCM5P-6-HNOpN0.js → vennDiagram-L72KCM5P-tZamQQAQ.js} +1 -1
  90. package/web-dist/assets/{wardley-OPB4EBWU-BrsaqsLL.js → wardley-OPB4EBWU-0_79c19P.js} +1 -1
  91. package/web-dist/assets/{wardleyDiagram-EHGQE667-Cr_rCzwd.js → wardleyDiagram-EHGQE667-uYmUsP66.js} +1 -1
  92. package/web-dist/assets/{xychartDiagram-FW5EYKEG-BnX6ccx4.js → xychartDiagram-FW5EYKEG-BsOU7Wf7.js} +1 -1
  93. package/web-dist/index.html +1 -1
  94. package/runtime/cc-worker/agents/fable-high.md +0 -8
  95. package/runtime/cc-worker/agents/fable-low.md +0 -8
  96. package/runtime/cc-worker/agents/fable-max.md +0 -8
  97. package/runtime/cc-worker/agents/fable-medium.md +0 -8
  98. package/runtime/cc-worker/agents/fable-xhigh.md +0 -8
  99. package/runtime/cc-worker/agents/haiku.md +0 -7
  100. package/runtime/cc-worker/agents/opus-high.md +0 -8
  101. package/runtime/cc-worker/agents/opus-low.md +0 -8
  102. package/runtime/cc-worker/agents/opus-max.md +0 -8
  103. package/runtime/cc-worker/agents/opus-medium.md +0 -8
  104. package/runtime/cc-worker/agents/opus-xhigh.md +0 -8
  105. package/runtime/cc-worker/agents/sonnet-high.md +0 -8
  106. package/runtime/cc-worker/agents/sonnet-low.md +0 -8
  107. package/runtime/cc-worker/agents/sonnet-max.md +0 -8
  108. package/runtime/cc-worker/agents/sonnet-medium.md +0 -8
  109. package/runtime/cc-worker/agents/sonnet-xhigh.md +0 -8
  110. package/runtime/cc-worker/bin/browser-mcp-tools.json +0 -1192
  111. package/runtime/cc-worker/bin/browser-mcp.mjs +0 -730
  112. package/runtime/cc-worker/hooks/precompact-instructions.mjs +0 -133
  113. package/runtime/cc-worker/skills/waits/SKILL.md +0 -84
  114. package/web-dist/assets/architecture-TIHT7OUA-DksosNDW.js +0 -1
  115. package/web-dist/assets/channel-DqoPvfQz.js +0 -1
  116. package/web-dist/assets/classDiagram-OUVF2IWQ-DwUs74RB.js +0 -1
  117. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DwUs74RB.js +0 -1
  118. package/web-dist/assets/eventmodeling-45OFAUF4-CUIjQ7kE.js +0 -1
  119. package/web-dist/assets/flowDiagram-23GEKE2U-Dka-3F3n.js +0 -1
  120. package/web-dist/assets/railroad-abnf-AHOZXSZD-CCnWa6K9.js +0 -1
  121. package/web-dist/assets/railroad-ebnf-EBAXGLYW-jtVdzv7e.js +0 -1
  122. package/web-dist/assets/railroad-peg-LSFZ7HO6-B8D6TyEe.js +0 -1
  123. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DWKW-4qu.js +0 -1
  124. package/web-dist/assets/swimlanesDiagram-G3AALYLV-DZKoB7ae.js +0 -8
package/dist/dev-child.js CHANGED
@@ -12938,6 +12938,13 @@ function retiredAwaitingKindsIn(body) {
12938
12938
  }
12939
12939
  return found;
12940
12940
  }
12941
+ function trimAwaitingTitle(raw2) {
12942
+ const flat = raw2.replace(/\s+/g, " ").trim();
12943
+ if (flat.length <= AWAITING_TITLE_MAX) return flat;
12944
+ const cut = flat.slice(0, AWAITING_TITLE_MAX);
12945
+ const space = cut.lastIndexOf(" ");
12946
+ return `${(space > AWAITING_TITLE_MAX / 2 ? cut.slice(0, space) : cut).replace(/[.,;:–—-]$/, "").trimEnd()}\u2026`;
12947
+ }
12941
12948
  function splitAwaitingFrontmatter(raw2) {
12942
12949
  const lines = raw2.split("\n").map((l) => l.replace(/\r$/, ""));
12943
12950
  const delimiter2 = lines.findIndex((l) => /^\s*---+\s*$/.test(l));
@@ -12981,6 +12988,8 @@ function parseAwaitingYaml(text) {
12981
12988
  for (const entry of Array.isArray(raw2) ? raw2 : [raw2]) push(itemKind, entry);
12982
12989
  } else if (key === "for") {
12983
12990
  push("for", raw2);
12991
+ } else if (key === "title") {
12992
+ if (typeof raw2 === "string" || typeof raw2 === "number") push("title", trimAwaitingTitle(String(raw2)));
12984
12993
  }
12985
12994
  }
12986
12995
  return { ok: true, hints };
@@ -13263,7 +13272,7 @@ function parseGithubWakeSteer(text) {
13263
13272
  function frizzRoute(path) {
13264
13273
  return `${FRIZZ_ROUTE_PREFIX}${path.startsWith("/") ? path : `/${path}`}`;
13265
13274
  }
13266
- var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, 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_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, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, ThreadWatchView, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, SetThreadSnoozeInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, 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_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketClientMsg, ProjectCard, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
13275
+ var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, 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_TITLE_MAX, 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, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, ThreadWatchView, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, SetThreadSnoozeInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, 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_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketClientMsg, ProjectCard, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
13267
13276
  var init_src = __esm({
13268
13277
  "packages/shared/src/index.ts"() {
13269
13278
  "use strict";
@@ -13519,7 +13528,7 @@ var init_src = __esm({
13519
13528
  questions: external_exports.array(AskQuestion)
13520
13529
  });
13521
13530
  AwaitingHint = external_exports.object({
13522
- kind: external_exports.enum(["shell", "agent", "timer", "pr", "for"]),
13531
+ kind: external_exports.enum(["shell", "agent", "timer", "pr", "for", "title"]),
13523
13532
  value: external_exports.string()
13524
13533
  });
13525
13534
  RETIRED_AWAITING_KINDS = ["watch", "pr-watch", "human", "ci", "session", "shell", "agent", "timer", "pr", "reason"];
@@ -13541,7 +13550,7 @@ var init_src = __esm({
13541
13550
  "reason": "put it below the `---` as ordinary Markdown \u2014 the frontmatter is YAML now and takes no prose"
13542
13551
  };
13543
13552
  AWAITING_KEY_RE = /^([a-z][a-z-]*):\s*(\S.*)?$/i;
13544
- AWAITING_YAML_KEYS = /* @__PURE__ */ new Set(["shells", "agents", "timers", "prs", "for"]);
13553
+ AWAITING_YAML_KEYS = /* @__PURE__ */ new Set(["shells", "agents", "timers", "prs", "for", "title"]);
13545
13554
  AWAITING_SEQUENCE_KEYS = {
13546
13555
  shells: "shell",
13547
13556
  agents: "agent",
@@ -13550,6 +13559,7 @@ var init_src = __esm({
13550
13559
  };
13551
13560
  AWAITING_HINT_MAX = 8;
13552
13561
  AWAITING_HINT_VALUE_MAX = 200;
13562
+ AWAITING_TITLE_MAX = 40;
13553
13563
  AWAITING_ITEM_KINDS = ["shell", "agent", "timer", "pr"];
13554
13564
  AWAITING_DURATION_RE = /^(\d{1,5})(s|m|h|d)$/;
13555
13565
  DURATION_UNIT_MS = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
@@ -14133,6 +14143,14 @@ var init_src = __esm({
14133
14143
  // Default action for a vetted non-image local path in agent markdown. Image clicks always use the
14134
14144
  // OS default viewer so screenshots retain their expected behavior.
14135
14145
  localFileOpener: LocalFileOpener.optional(),
14146
+ // The token count at which a NEW Claude worker auto-compacts its conversation. Frizz requests the
14147
+ // 1M context window on every dispatch (resolveClaudeLaunchModel), so without this a worker grows
14148
+ // toward 1M before it ever compacts — and every turn past 200K re-sends up to 5x the conversation a
14149
+ // 200K TUI session would, which is the single largest reason a Frizz thread spends quota faster than
14150
+ // the TUI (measured 2026-08-26). Reaches the worker as CLAUDE_CODE_AUTO_COMPACT_WINDOW, which Claude
14151
+ // Code caps to the model's real window. Optional so an old blob parses; defaultSettings pins 500_000
14152
+ // (maintainer 2026-08-26: "a default compaction window of 500k by default").
14153
+ autoCompactWindow: external_exports.number().int().positive().optional(),
14136
14154
  // The GitHub batch-dispatch prompt template (the picker's per-item worker prompt). Optional: when
14137
14155
  // unset OR blank the server falls back to its exported DEFAULT_GITHUB_PROMPT. Substitution tokens
14138
14156
  // the server fills: {repo} {n} {title} {url} {labels} {body}. The leading `THREAD: <slug>` tag is
@@ -19652,6 +19670,9 @@ var init_settings = __esm({
19652
19670
  notifications: true,
19653
19671
  font: "sans",
19654
19672
  localFileOpener: "system",
19673
+ // 500K tokens: half the 1M window every Claude worker is dispatched with. See the schema for why a
19674
+ // worker left to compact at 1M is the biggest single reason a Frizz thread out-spends the TUI.
19675
+ autoCompactWindow: 5e5,
19655
19676
  // Hidden until asked for — see the schema for why.
19656
19677
  projectRail: false
19657
19678
  });
@@ -28586,32 +28607,7 @@ var init_wrapper = __esm({
28586
28607
  }
28587
28608
  });
28588
28609
 
28589
- // packages/server/src/worker-plugin-dir.ts
28590
- import { existsSync as existsSync6 } from "node:fs";
28591
- import { dirname as dirname9, join as join20 } from "node:path";
28592
- import { fileURLToPath as fileURLToPath2 } from "node:url";
28593
- function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
28594
- const override = env.FRIZZ_WORKER_PLUGIN_DIR;
28595
- if (override && existsSync6(join20(override, ".claude-plugin", "plugin.json")))
28596
- return override;
28597
- let current = dirname9(fileURLToPath2(moduleUrl));
28598
- for (; ; ) {
28599
- const candidate = join20(current, "cc-worker");
28600
- if (existsSync6(join20(candidate, ".claude-plugin", "plugin.json"))) return candidate;
28601
- const parent = dirname9(current);
28602
- if (parent === current) return void 0;
28603
- current = parent;
28604
- }
28605
- }
28606
- var init_worker_plugin_dir = __esm({
28607
- "packages/server/src/worker-plugin-dir.ts"() {
28608
- "use strict";
28609
- }
28610
- });
28611
-
28612
28610
  // packages/server/src/backend/types.ts
28613
- import { existsSync as existsSync7 } from "node:fs";
28614
- import { join as join21 } from "node:path";
28615
28611
  function frizzMcpEnv(mcp) {
28616
28612
  return {
28617
28613
  FRIZZ_STATE_DIR: mcp.stateDir,
@@ -28620,24 +28616,6 @@ function frizzMcpEnv(mcp) {
28620
28616
  ...mcp.slug ? { FRIZZ_THREAD_SLUG: mcp.slug } : {}
28621
28617
  };
28622
28618
  }
28623
- function chromeDevtoolsMcpSpec(scriptPath, nodeBin) {
28624
- const args = [...CHROME_DEVTOOLS_MCP.args];
28625
- if (!scriptPath) return { command: "npx", args: ["-y", `${CHROME_DEVTOOLS_MCP.package}@${CHROME_DEVTOOLS_MCP.version}`, ...args] };
28626
- return {
28627
- command: nodeBin,
28628
- args: [scriptPath, ...args],
28629
- env: { FRIZZ_BROWSER_MCP_PACKAGE: `${CHROME_DEVTOOLS_MCP.package}@${CHROME_DEVTOOLS_MCP.version}` }
28630
- };
28631
- }
28632
- function chromeDevtoolsMcpMount() {
28633
- return chromeDevtoolsMcpSpec(resolveBrowserMcpScript(), process.execPath);
28634
- }
28635
- function resolveBrowserMcpScript(moduleUrl = import.meta.url, env = process.env) {
28636
- const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
28637
- if (!pluginDir) return void 0;
28638
- const scriptPath = join21(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
28639
- return existsSync7(scriptPath) ? scriptPath : void 0;
28640
- }
28641
28619
  function workerCap(name, lifted, env) {
28642
28620
  const override = env[name];
28643
28621
  if (override !== void 0 && /^[1-9][0-9]*$/.test(override)) return override;
@@ -28651,29 +28629,20 @@ function claudeWorkerEnv(env = process.env) {
28651
28629
  CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS: workerCap("CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS", WORKER_MAX_CONCURRENT_SUBAGENTS, env)
28652
28630
  };
28653
28631
  }
28654
- var FRIZZ_MCP, CHROME_DEVTOOLS_MCP, WORKER_MAX_WEB_SEARCHES, WORKER_MAX_SUBAGENTS, WORKER_MAX_CONCURRENT_SUBAGENTS, CLAUDE_WORKER_ENV, WORKER_DISALLOWED_TOOLS;
28632
+ function claudeCompactionEnv(settings) {
28633
+ const window = settings?.autoCompactWindow;
28634
+ if (window === void 0 || !Number.isInteger(window) || window <= 0) return {};
28635
+ return { CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(window) };
28636
+ }
28637
+ var FRIZZ_MCP, WORKER_MAX_WEB_SEARCHES, WORKER_MAX_SUBAGENTS, WORKER_MAX_CONCURRENT_SUBAGENTS, CLAUDE_WORKER_ENV, WORKER_DISALLOWED_TOOLS;
28655
28638
  var init_types2 = __esm({
28656
28639
  "packages/server/src/backend/types.ts"() {
28657
28640
  "use strict";
28658
- init_worker_plugin_dir();
28659
28641
  FRIZZ_MCP = {
28660
28642
  name: "frizz",
28661
28643
  script: "frizz-mcp.mjs"
28662
28644
  // resolved under <worker plugin dir>/bin/
28663
28645
  };
28664
- CHROME_DEVTOOLS_MCP = {
28665
- name: "chrome-devtools",
28666
- // Resolved under <worker plugin dir>/bin/, exactly like FRIZZ_MCP.script.
28667
- script: "browser-mcp.mjs",
28668
- package: "chrome-devtools-mcp",
28669
- version: "1.7.0",
28670
- args: [
28671
- "--experimentalPageIdRouting",
28672
- "--headless",
28673
- "--isolated",
28674
- "--no-usage-statistics"
28675
- ]
28676
- };
28677
28646
  WORKER_MAX_WEB_SEARCHES = 1e4;
28678
28647
  WORKER_MAX_SUBAGENTS = 1e4;
28679
28648
  WORKER_MAX_CONCURRENT_SUBAGENTS = 100;
@@ -28703,12 +28672,8 @@ function serverTable(command, args, env) {
28703
28672
  }
28704
28673
  return inlineTable(entries);
28705
28674
  }
28706
- function codexMcpConfigArgs(frizzMcp, nodeBin = process.execPath, browserMcpScript) {
28707
- const chrome = chromeDevtoolsMcpSpec(browserMcpScript ?? resolveBrowserMcpScript(), nodeBin);
28708
- const args = [
28709
- "-c",
28710
- `mcp_servers.${CHROME_DEVTOOLS_MCP.name}=${serverTable(chrome.command, chrome.args, chrome.env)}`
28711
- ];
28675
+ function codexMcpConfigArgs(frizzMcp, nodeBin = process.execPath) {
28676
+ const args = [];
28712
28677
  if (frizzMcp) {
28713
28678
  args.push(
28714
28679
  "-c",
@@ -28733,15 +28698,15 @@ import { spawn as spawn2 } from "node:child_process";
28733
28698
  import { connect } from "node:net";
28734
28699
  import { Agent as HttpAgent } from "node:http";
28735
28700
  import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
28736
- import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
28737
- import { join as join22 } from "node:path";
28701
+ import { existsSync as existsSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
28702
+ import { join as join20 } from "node:path";
28738
28703
  import { PassThrough, Writable } from "node:stream";
28739
28704
  import { StringDecoder } from "node:string_decoder";
28740
28705
  function nativeDir(stateDir) {
28741
- return join22(stateDir, "codex-app-server-native");
28706
+ return join20(stateDir, "codex-app-server-native");
28742
28707
  }
28743
28708
  function nativeRecordPath(stateDir, projectId) {
28744
- return join22(nativeDir(stateDir), `${projectId}.json`);
28709
+ return join20(nativeDir(stateDir), `${projectId}.json`);
28745
28710
  }
28746
28711
  function nativeListenSocketPath(stateDir, projectId) {
28747
28712
  const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
@@ -28773,7 +28738,7 @@ function readNativeRecord(stateDir, projectId) {
28773
28738
  function liveNativeRecord(stateDir, projectId) {
28774
28739
  const record = readNativeRecord(stateDir, projectId);
28775
28740
  if (!record) return null;
28776
- if (pidAlive2(record.listenerPid) && existsSync8(record.socketPath)) return record;
28741
+ if (pidAlive2(record.listenerPid) && existsSync6(record.socketPath)) return record;
28777
28742
  try {
28778
28743
  unlinkSync2(nativeRecordPath(stateDir, projectId));
28779
28744
  } catch {
@@ -28915,7 +28880,7 @@ async function startListener(options) {
28915
28880
  const { stateDir, projectId } = options;
28916
28881
  mkdirSync11(nativeDir(stateDir), { recursive: true });
28917
28882
  const socketPath = nativeListenSocketPath(stateDir, projectId);
28918
- if (existsSync8(socketPath) && !await socketAccepting(socketPath)) {
28883
+ if (existsSync6(socketPath) && !await socketAccepting(socketPath)) {
28919
28884
  try {
28920
28885
  unlinkSync2(socketPath);
28921
28886
  } catch {
@@ -28939,7 +28904,7 @@ async function startListener(options) {
28939
28904
  writeFileSync9(nativeRecordPath(stateDir, projectId), JSON.stringify(record));
28940
28905
  const deadline = Date.now() + (options.timeoutMs ?? 3e4);
28941
28906
  for (; ; ) {
28942
- if (existsSync8(socketPath) && await socketAccepting(socketPath)) return record;
28907
+ if (existsSync6(socketPath) && await socketAccepting(socketPath)) return record;
28943
28908
  if (!pidAlive2(record.listenerPid)) throw new Error("codex app-server listener exited before it became ready");
28944
28909
  if (Date.now() > deadline) throw new Error("codex app-server listener did not become ready");
28945
28910
  await new Promise((resolve10) => setTimeout(resolve10, 50));
@@ -29005,15 +28970,15 @@ var init_codex_app_server_native = __esm({
29005
28970
  import { spawn as spawn3, spawnSync } from "node:child_process";
29006
28971
  import { createConnection } from "node:net";
29007
28972
  import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
29008
- import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync3 } from "node:fs";
29009
- import { join as join23 } from "node:path";
28973
+ import { existsSync as existsSync7, mkdirSync as mkdirSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync3 } from "node:fs";
28974
+ import { join as join21 } from "node:path";
29010
28975
  import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
29011
28976
  import { StringDecoder as StringDecoder2 } from "node:string_decoder";
29012
28977
  function daemonDir(stateDir) {
29013
- return join23(stateDir, "codex-app-server");
28978
+ return join21(stateDir, "codex-app-server");
29014
28979
  }
29015
28980
  function recordPath(stateDir, projectId) {
29016
- return join23(daemonDir(stateDir), `${projectId}.json`);
28981
+ return join21(daemonDir(stateDir), `${projectId}.json`);
29017
28982
  }
29018
28983
  function codexAppServerSocketPath(stateDir, projectId) {
29019
28984
  const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
@@ -29295,7 +29260,7 @@ var init_codex_app_server_host = __esm({
29295
29260
  }
29296
29261
  if (process.platform !== "win32") {
29297
29262
  const stale = codexAppServerSocketPath(options.stateDir, options.projectId);
29298
- if (existsSync9(stale) && !liveDaemonRecord(options.stateDir, options.projectId)) {
29263
+ if (existsSync7(stale) && !liveDaemonRecord(options.stateDir, options.projectId)) {
29299
29264
  try {
29300
29265
  unlinkSync3(stale);
29301
29266
  } catch {
@@ -32241,11 +32206,11 @@ var init_codex_app_server = __esm({
32241
32206
  });
32242
32207
 
32243
32208
  // packages/server/src/backend/codex-quota.ts
32244
- import { join as join24 } from "node:path";
32209
+ import { join as join22 } from "node:path";
32245
32210
  import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
32246
32211
  import { spawn as spawn4 } from "node:child_process";
32247
32212
  function sessionsDir2(codexHome) {
32248
- return join24(codexHome, "sessions");
32213
+ return join22(codexHome, "sessions");
32249
32214
  }
32250
32215
  function newestRollouts(dir, out, budget) {
32251
32216
  if (budget.n <= 0) return;
@@ -32259,11 +32224,11 @@ function newestRollouts(dir, out, budget) {
32259
32224
  const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
32260
32225
  for (const d of dirs) {
32261
32226
  if (budget.n <= 0) return;
32262
- newestRollouts(join24(dir, d), out, budget);
32227
+ newestRollouts(join22(dir, d), out, budget);
32263
32228
  }
32264
32229
  for (const f of files) {
32265
32230
  if (budget.n <= 0) return;
32266
- out.push(join24(dir, f));
32231
+ out.push(join22(dir, f));
32267
32232
  budget.n--;
32268
32233
  }
32269
32234
  }
@@ -32463,7 +32428,7 @@ var init_codex_quota = __esm({
32463
32428
  });
32464
32429
 
32465
32430
  // packages/server/src/backend/claude-quota.ts
32466
- import { join as join25 } from "node:path";
32431
+ import { join as join23 } from "node:path";
32467
32432
  import { homedir as homedir9, platform } from "node:os";
32468
32433
  import { createHash as createHash10 } from "node:crypto";
32469
32434
  import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
@@ -32471,7 +32436,7 @@ import { execFile as execFile2 } from "node:child_process";
32471
32436
  import { promisify as promisify2 } from "node:util";
32472
32437
  function claudeConfigDir() {
32473
32438
  const override = process.env.CLAUDE_CONFIG_DIR;
32474
- return override && override.trim() ? override : join25(homedir9(), ".claude");
32439
+ return override && override.trim() ? override : join23(homedir9(), ".claude");
32475
32440
  }
32476
32441
  function tokenFromCredentialsJson(raw2) {
32477
32442
  let doc;
@@ -32500,7 +32465,7 @@ async function readKeychainToken() {
32500
32465
  }
32501
32466
  async function readAccessToken(configDir) {
32502
32467
  try {
32503
- const fromFile = tokenFromCredentialsJson(await readFile(join25(configDir, ".credentials.json"), "utf8"));
32468
+ const fromFile = tokenFromCredentialsJson(await readFile(join23(configDir, ".credentials.json"), "utf8"));
32504
32469
  if (fromFile) return fromFile;
32505
32470
  } catch {
32506
32471
  }
@@ -32569,8 +32534,8 @@ function parseClaudeUsage(body, planType) {
32569
32534
  function cachePaths(cacheDir, configDir) {
32570
32535
  const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
32571
32536
  return {
32572
- data: join25(cacheDir, `claude-${profile}.json`),
32573
- lock: join25(cacheDir, `claude-${profile}.lock`)
32537
+ data: join23(cacheDir, `claude-${profile}.json`),
32538
+ lock: join23(cacheDir, `claude-${profile}.lock`)
32574
32539
  };
32575
32540
  }
32576
32541
  async function readShared(path) {
@@ -32766,7 +32731,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
32766
32731
  async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32767
32732
  const now = (deps.now ?? Date.now)();
32768
32733
  const configDir = claudeConfigDir();
32769
- const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
32734
+ const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32770
32735
  try {
32771
32736
  await mkdir(cacheDir, { recursive: true, mode: 448 });
32772
32737
  } catch {
@@ -32777,7 +32742,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
32777
32742
  async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
32778
32743
  const now = (deps.now ?? Date.now)();
32779
32744
  const configDir = claudeConfigDir();
32780
- const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
32745
+ const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
32781
32746
  const paths = cachePaths(cacheDir, configDir);
32782
32747
  try {
32783
32748
  await mkdir(cacheDir, { recursive: true, mode: 448 });
@@ -32937,7 +32902,7 @@ var init_quota = __esm({
32937
32902
  // packages/server/src/frizz.ts
32938
32903
  import { execFile as execFile3 } from "node:child_process";
32939
32904
  import { lstatSync as lstatSync2, realpathSync as realpathSync6 } from "node:fs";
32940
- import { basename as basename5, dirname as dirname10, join as join26, resolve as resolve4 } from "node:path";
32905
+ import { basename as basename5, dirname as dirname9, join as join24, resolve as resolve4 } from "node:path";
32941
32906
  import { promisify as promisify3 } from "node:util";
32942
32907
  function frizzScriptsDir() {
32943
32908
  if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
@@ -32946,11 +32911,11 @@ function frizzScriptsDir() {
32946
32911
  function directFrizzRoot(projectDir) {
32947
32912
  try {
32948
32913
  const projectRoot = realpathSync6(projectDir);
32949
- const path = join26(projectRoot, ".frizz");
32914
+ const path = join24(projectRoot, ".frizz");
32950
32915
  const stat2 = lstatSync2(path);
32951
32916
  if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
32952
32917
  const real = realpathSync6(path);
32953
- return dirname10(real) === projectRoot && basename5(real) === ".frizz" ? real : null;
32918
+ return dirname9(real) === projectRoot && basename5(real) === ".frizz" ? real : null;
32954
32919
  } catch {
32955
32920
  return null;
32956
32921
  }
@@ -32960,7 +32925,7 @@ function frizzDirExists(projectDir) {
32960
32925
  }
32961
32926
  async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32962
32927
  if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
32963
- const { stdout } = await execFileP("node", [join26(scriptsDir, "index.mjs"), "--json"], {
32928
+ const { stdout } = await execFileP("node", [join24(scriptsDir, "index.mjs"), "--json"], {
32964
32929
  cwd: projectDir,
32965
32930
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
32966
32931
  maxBuffer: 32 * 1024 * 1024
@@ -32985,7 +32950,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
32985
32950
  };
32986
32951
  }
32987
32952
  async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
32988
- await execFileP("node", [join26(scriptsDir, "thread-update.mjs"), slug, ...args], {
32953
+ await execFileP("node", [join24(scriptsDir, "thread-update.mjs"), slug, ...args], {
32989
32954
  cwd: projectDir,
32990
32955
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
32991
32956
  });
@@ -33021,7 +32986,12 @@ function readAwaitingPark(hints) {
33021
32986
  return { items, forMs };
33022
32987
  }
33023
32988
  function unaccountedItems(items, live) {
33024
- return items.filter((i) => !live[LIVE_SET[i.kind]].has(i.value));
32989
+ return items.filter((i) => !live[LIVE_SET[i.kind]].has(liveKey(i)));
32990
+ }
32991
+ function liveKey(i) {
32992
+ if (i.kind !== "pr") return i.value;
32993
+ const ref = parsePrRef(i.value);
32994
+ return ref ? githubStatusKey(ref) : i.value;
33025
32995
  }
33026
32996
  function parkIsHonoured(park, live) {
33027
32997
  if (park.items.length === 0) return false;
@@ -33060,6 +33030,29 @@ var init_awaiting = __esm({
33060
33030
  }
33061
33031
  });
33062
33032
 
33033
+ // packages/server/src/worker-plugin-dir.ts
33034
+ import { existsSync as existsSync8 } from "node:fs";
33035
+ import { dirname as dirname10, join as join25 } from "node:path";
33036
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
33037
+ function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
33038
+ const override = env.FRIZZ_WORKER_PLUGIN_DIR;
33039
+ if (override && existsSync8(join25(override, ".claude-plugin", "plugin.json")))
33040
+ return override;
33041
+ let current = dirname10(fileURLToPath2(moduleUrl));
33042
+ for (; ; ) {
33043
+ const candidate = join25(current, "cc-worker");
33044
+ if (existsSync8(join25(candidate, ".claude-plugin", "plugin.json"))) return candidate;
33045
+ const parent = dirname10(current);
33046
+ if (parent === current) return void 0;
33047
+ current = parent;
33048
+ }
33049
+ }
33050
+ var init_worker_plugin_dir = __esm({
33051
+ "packages/server/src/worker-plugin-dir.ts"() {
33052
+ "use strict";
33053
+ }
33054
+ });
33055
+
33063
33056
  // packages/server/src/workerPrompt.ts
33064
33057
  function buildWorkerPrompt(kind = "claude", opts = {}) {
33065
33058
  const lean = kind === "claude";
@@ -33264,6 +33257,7 @@ a second read for nothing, and it is the commonest thing wrong with an otherwise
33264
33257
  timers: [tmr_a1b2c3d4e5f6]
33265
33258
  prs: [acme/app#391]
33266
33259
  for: 2h
33260
+ title: Three-platform CI run
33267
33261
  ---
33268
33262
  Waiting on the three-platform run before porting the v2 drivers.
33269
33263
 
@@ -33272,9 +33266,9 @@ a second read for nothing, and it is the commonest thing wrong with an otherwise
33272
33266
  \`\`\`
33273
33267
 
33274
33268
  **THE FRONTMATTER IS YAML. THE BODY IS MARKDOWN.** Everything above the \`---\` is a real YAML mapping \u2014
33275
- four PLURAL keys taking LISTS, plus \`for:\`. Everything after the \`---\` is ordinary Markdown, as much as
33276
- you want, with paragraphs, lists and links. That prose is what the human reads on your resting card, so
33277
- write it as a handoff, not as a label.
33269
+ four PLURAL keys taking LISTS, plus the scalars \`for:\` and \`title:\`. Everything after the \`---\` is
33270
+ ordinary Markdown, as much as you want, with paragraphs, lists and links. That prose is what the human
33271
+ reads on your resting card, so write it as a handoff, not as a label.
33278
33272
 
33279
33273
  **NO PROSE ABOVE THE \`---\`, EVER.** A sentence in the frontmatter is what makes it stop being YAML: a
33280
33274
  colon inside it, or a \` #\` before an issue ref, and the parse either fails or silently eats half the
@@ -33303,6 +33297,11 @@ a second read for nothing, and it is the commonest thing wrong with an otherwise
33303
33297
  and on every later review, approval or comment, human or bot, for as long as the PR lives.
33304
33298
  - \`for:\` \u2014 **REQUIRED**, and a DURATION: \`30s\`, \`15m\`, \`2h\`, \`3d\`. Never an instant. When it runs
33305
33299
  out frizz brings you back to re-check everything; re-parking is fine and uncapped.
33300
+ - \`title:\` \u2014 OPTIONAL, and the one place your own words reach the top of the resting card. Without it
33301
+ the card is headed "Awaiting", which is true of every park on the board and specific to none. Write a
33302
+ HEADING, not a sentence: **40 characters or fewer**, sentence case, naming THIS wait \u2014 "Three-platform
33303
+ CI run", "Fork-CI approval", "Nightly bench, arm 3 of 3". Anything longer is trimmed on a word
33304
+ boundary, and the detail belongs below the \`---\` where there is room for it.
33306
33305
 
33307
33306
  **THE SINGULAR KEYS ARE GONE** \u2014 \`shell:\`, \`agent:\`, \`timer:\`, \`pr:\` and \`reason:\`, one per line, were
33308
33307
  the grammar until 2026-08-24. YAML cannot express a repeated key, so they became the lists above. Write
@@ -33630,13 +33629,10 @@ see your conversation, so handing over context is always your job. The absence o
33630
33629
  a blocker to report \u2014 write what the child needs into the prompt or a scratch file you name, or do
33631
33630
  the work inline.
33632
33631
 
33633
- Pass \`subagent_type\` as the namespaced string \`frizz:<model>-<effort>\` (a bare \`opus-high\` will not
33634
- resolve); the profile descriptions carry the routing guidance. Tier by JUDGMENT required, not task
33635
- type: \`frizz:haiku\` for fully-scripted mechanical harvest only; \`frizz:sonnet-medium\` for
33636
- observable-fact probes, scaffolding, and doc/CI work; \`frizz:opus-high\`/\`-xhigh\` for the fix that
33637
- lands, diagnosis, architecture, and any probe whose deliverable is a load-bearing verdict. Effort runs
33638
- low\u2192medium\u2192high\u2192xhigh\u2192max. Bias toward Opus and buy extra rigor with EFFORT; re-verify any cheap-tier
33639
- load-bearing claim yourself.
33632
+ Two knobs, one each: the model rides the Agent tool's own \`model\` parameter (omit it and the child
33633
+ inherits yours), and the effort rides \`subagent_type\` as the namespaced string \`frizz:<effort>\` \u2014
33634
+ \`frizz:low\`, \`frizz:medium\`, \`frizz:high\`, \`frizz:xhigh\` or \`frizz:max\` (a bare \`high\` will not
33635
+ resolve). Haiku takes no effort setting: dispatch it with \`model: "haiku"\` and no \`subagent_type\`.
33640
33636
 
33641
33637
  Fan out one sub-agent per prong when work genuinely decomposes and the scale warrants it \u2014 authorized,
33642
33638
  never required, and never a substitute for running the thing yourself.
@@ -34595,6 +34591,9 @@ function createClaudeAgentBrokerBridge(deps) {
34595
34591
  // claudeWorkerEnv). Spread here rather than inherited, which is what gives these per-thread
34596
34592
  // values priority over anything in the environment frizz itself was launched with.
34597
34593
  ...claudeWorkerEnv(),
34594
+ // The auto-compact ceiling, from Settings (500K by default). Without it a `[1m]` worker compacts
34595
+ // only near 1M, re-sending up to 5x a TUI session's conversation on every turn past 200K.
34596
+ ...claudeCompactionEnv(deps.getSettings?.()),
34598
34597
  ...we?.permDir ? { FRIZZ_PERM_DIR: we.permDir } : {},
34599
34598
  // The cc-worker plugin's PreToolUse hook DENIES AskUserQuestion, because without frizz in the
34600
34599
  // loop a blocking question freezes a headless worker where nobody can answer it. On the broker path
@@ -34870,19 +34869,19 @@ var init_claude_agent_broker_bridge = __esm({
34870
34869
  });
34871
34870
 
34872
34871
  // packages/server/src/backend/auth-status.ts
34873
- import { join as join27 } from "node:path";
34872
+ import { join as join26 } from "node:path";
34874
34873
  import { homedir as homedir11, platform as platform2 } from "node:os";
34875
34874
  import { readFileSync as readFileSync16, statSync as statSync11 } from "node:fs";
34876
34875
  import { execFile as execFile4 } from "node:child_process";
34877
34876
  import { promisify as promisify4 } from "node:util";
34878
34877
  function claudeConfigDir2() {
34879
34878
  const override = process.env.CLAUDE_CONFIG_DIR;
34880
- return override && override.trim() ? override : join27(homedir11(), ".claude");
34879
+ return override && override.trim() ? override : join26(homedir11(), ".claude");
34881
34880
  }
34882
34881
  function claudeFileState(configDir) {
34883
34882
  let raw2;
34884
34883
  try {
34885
- raw2 = readFileSync16(join27(configDir, ".credentials.json"), "utf8");
34884
+ raw2 = readFileSync16(join26(configDir, ".credentials.json"), "utf8");
34886
34885
  } catch (err) {
34887
34886
  return err.code === "ENOENT" ? "absent" : "error";
34888
34887
  }
@@ -34915,7 +34914,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
34915
34914
  if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
34916
34915
  let raw2;
34917
34916
  try {
34918
- raw2 = readFileSync16(join27(codexHome, "auth.json"), "utf8");
34917
+ raw2 = readFileSync16(join26(codexHome, "auth.json"), "utf8");
34919
34918
  } catch (err) {
34920
34919
  return err.code === "ENOENT" ? "signed-out" : "unknown";
34921
34920
  }
@@ -34980,7 +34979,7 @@ function asEmail(value) {
34980
34979
  }
34981
34980
  function claudeAccountFile() {
34982
34981
  const override = process.env.CLAUDE_CONFIG_DIR;
34983
- return override && override.trim() ? join27(override, ".claude.json") : join27(homedir11(), ".claude.json");
34982
+ return override && override.trim() ? join26(override, ".claude.json") : join26(homedir11(), ".claude.json");
34984
34983
  }
34985
34984
  function readClaudeAccountEmail(path = claudeAccountFile()) {
34986
34985
  let stat2;
@@ -35004,7 +35003,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
35004
35003
  function readCodexAccountEmail(codexHome = defaultCodexHome()) {
35005
35004
  let doc;
35006
35005
  try {
35007
- doc = JSON.parse(readFileSync16(join27(codexHome, "auth.json"), "utf8"));
35006
+ doc = JSON.parse(readFileSync16(join26(codexHome, "auth.json"), "utf8"));
35008
35007
  } catch {
35009
35008
  return void 0;
35010
35009
  }
@@ -35072,8 +35071,8 @@ var init_auth_status = __esm({
35072
35071
  });
35073
35072
 
35074
35073
  // packages/server/src/dispatch.ts
35075
- import { closeSync as closeSync12, constants, existsSync as existsSync10, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync17, realpathSync as realpathSync7, statSync as statSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync9 } from "node:fs";
35076
- import { basename as basename6, join as join28, dirname as dirname11 } from "node:path";
35074
+ import { closeSync as closeSync12, constants, existsSync as existsSync9, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync17, realpathSync as realpathSync7, statSync as statSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync9 } from "node:fs";
35075
+ import { basename as basename6, join as join27, dirname as dirname11 } from "node:path";
35077
35076
  import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
35078
35077
  function fallbackTitle(prompt) {
35079
35078
  const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
@@ -35092,7 +35091,7 @@ function fallbackTitle(prompt) {
35092
35091
  }
35093
35092
  function resolveSlug(frizzDir, base, taken) {
35094
35093
  base = ThreadSlug.parse(base);
35095
- const isTaken = (slug) => existsSync10(join28(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
35094
+ const isTaken = (slug) => existsSync9(join27(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
35096
35095
  if (!isTaken(base)) return base;
35097
35096
  for (let n = 2; ; n++) {
35098
35097
  const suffix = `-${n}`;
@@ -35109,12 +35108,12 @@ function resolveLegacyThreadFile(projectDir, value) {
35109
35108
  if (!parsed.success) return null;
35110
35109
  try {
35111
35110
  const projectRoot = realpathSync7(projectDir);
35112
- const frizzPath = join28(projectRoot, ".frizz");
35111
+ const frizzPath = join27(projectRoot, ".frizz");
35113
35112
  const frizzStat = lstatSync3(frizzPath);
35114
35113
  if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
35115
35114
  const realFrizz = realpathSync7(frizzPath);
35116
35115
  if (dirname11(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
35117
- const path = join28(realFrizz, `${parsed.data}.md`);
35116
+ const path = join27(realFrizz, `${parsed.data}.md`);
35118
35117
  const before = lstatSync3(path);
35119
35118
  if (!before.isFile() || before.isSymbolicLink()) return null;
35120
35119
  const realPath = realpathSync7(path);
@@ -35158,7 +35157,7 @@ function boardAuthorizesAdoption(board, slug) {
35158
35157
  return !board.errorItems.some((item) => item.file === `${slug}.md`);
35159
35158
  }
35160
35159
  function ensureSafeDirectDirectory(parent, name) {
35161
- const path = join28(parent, name);
35160
+ const path = join27(parent, name);
35162
35161
  try {
35163
35162
  mkdirSync13(path);
35164
35163
  } catch (error) {
@@ -35188,8 +35187,8 @@ function loadWorkerPrompt(kind = "claude") {
35188
35187
  function monitorScriptsDir() {
35189
35188
  const plugin = workerPluginDir();
35190
35189
  if (!plugin) return void 0;
35191
- const dir = join28(plugin, "skills", "gh", "scripts");
35192
- return existsSync10(join28(dir, "ci-watch.mjs")) ? dir : void 0;
35190
+ const dir = join27(plugin, "skills", "gh", "scripts");
35191
+ return existsSync9(join27(dir, "ci-watch.mjs")) ? dir : void 0;
35193
35192
  }
35194
35193
  function codexScratchpadHookConfig(hookScript, sessionId) {
35195
35194
  if (!hookScript || !sessionId) return {};
@@ -35201,7 +35200,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
35201
35200
  }
35202
35201
  ]
35203
35202
  });
35204
- const bashBackgroundHook = join28(dirname11(hookScript), "bash-background.mjs");
35203
+ const bashBackgroundHook = join27(dirname11(hookScript), "bash-background.mjs");
35205
35204
  return {
35206
35205
  bypass_hook_trust: true,
35207
35206
  hooks: {
@@ -35227,7 +35226,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
35227
35226
  }
35228
35227
  function scratchpadHookScript() {
35229
35228
  const plugin = workerPluginDir();
35230
- return plugin ? join28(plugin, "hooks", "scratchpad.mjs") : void 0;
35229
+ return plugin ? join27(plugin, "hooks", "scratchpad.mjs") : void 0;
35231
35230
  }
35232
35231
  function composePrompt(sessionId, prompt, kind = "claude") {
35233
35232
  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.";
@@ -35243,7 +35242,7 @@ function scratchpadOrientation(sessionId, kind = "claude") {
35243
35242
  return `SCRATCH DIRECTORY: .frizz/threads/${sessionId}/ \u2014 yours, free-form, as many files as you like, and nothing is expected in it. A single direct task usually needs none; writing notes is never a substitute for doing the work. On a long effort write the doc you would want if you lost your context (${children2}), then arm mcp__frizz__recurring_prompt with post_compaction: true and a prompt LINKING that file \u2014 frizz hands the link back when your context is compacted. Nothing in this directory is read automatically.`;
35244
35243
  }
35245
35244
  function frizzConfigBlock(projectDir) {
35246
- const path = join28(projectDir, "FRIZZ.md");
35245
+ const path = join27(projectDir, "FRIZZ.md");
35247
35246
  let body;
35248
35247
  try {
35249
35248
  const st = statSync12(path);
@@ -35283,8 +35282,8 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
35283
35282
  const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
35284
35283
  const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
35285
35284
  if (!pluginDir) return void 0;
35286
- const scriptPath = join28(pluginDir, "bin", FRIZZ_MCP.script);
35287
- if (!existsSync10(scriptPath)) return void 0;
35285
+ const scriptPath = join27(pluginDir, "bin", FRIZZ_MCP.script);
35286
+ if (!existsSync9(scriptPath)) return void 0;
35288
35287
  return {
35289
35288
  scriptPath,
35290
35289
  stateDir,
@@ -35294,12 +35293,8 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
35294
35293
  };
35295
35294
  }
35296
35295
  function claudeMcpConfig(mcp) {
35297
- const mcpServers = {
35298
- // chromeDevtoolsMcpMount(), never the fields: it is the ONE builder both backends render, and it
35299
- // is what mounts frizz's lazy proxy instead of the real server (backend/types.ts).
35300
- [CHROME_DEVTOOLS_MCP.name]: chromeDevtoolsMcpMount()
35301
- };
35302
- const allowedTools = [`mcp__${CHROME_DEVTOOLS_MCP.name}`];
35296
+ const mcpServers = {};
35297
+ const allowedTools = [];
35303
35298
  if (mcp) {
35304
35299
  const env = frizzMcpEnv(mcp);
35305
35300
  mcpServers[FRIZZ_MCP.name] = { command: process.execPath, args: [mcp.scriptPath], env };
@@ -35309,6 +35304,7 @@ function claudeMcpConfig(mcp) {
35309
35304
  }
35310
35305
  function claudeMcpFlags(mcp) {
35311
35306
  const { mcpServers, allowedTools } = claudeMcpConfig(mcp);
35307
+ if (Object.keys(mcpServers).length === 0) return [];
35312
35308
  const config = JSON.stringify({ mcpServers });
35313
35309
  return ["--mcp-config", config, `--allowedTools=${allowedTools.join(",")}`];
35314
35310
  }
@@ -35366,7 +35362,7 @@ function buildClaudeResumeCommand(opts) {
35366
35362
  }
35367
35363
  function createDispatcher(deps) {
35368
35364
  const readBoardSource = deps.readBoard ?? readBoard;
35369
- const frizzDir = join28(deps.project.dir, ".frizz");
35365
+ const frizzDir = join27(deps.project.dir, ".frizz");
35370
35366
  const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
35371
35367
  function cleanupPrewrites(built) {
35372
35368
  for (const path of new Set(built.prewrite.map((file) => file.path))) {
@@ -35379,7 +35375,7 @@ function createDispatcher(deps) {
35379
35375
  function cleanupDispatchFiles(scratchRel, built, sessionId) {
35380
35376
  cleanupPrewrites(built);
35381
35377
  try {
35382
- rmSync9(join28(deps.project.dir, scratchRel), { force: true, recursive: true });
35378
+ rmSync9(join27(deps.project.dir, scratchRel), { force: true, recursive: true });
35383
35379
  } catch {
35384
35380
  }
35385
35381
  cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
@@ -35812,7 +35808,7 @@ import {
35812
35808
  watch as fsWatch
35813
35809
  } from "node:fs";
35814
35810
  import { homedir as homedir12 } from "node:os";
35815
- import { join as join29 } from "node:path";
35811
+ import { join as join28 } from "node:path";
35816
35812
  import watcher from "@parcel/watcher";
35817
35813
  function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
35818
35814
  if (!liveness) return false;
@@ -35910,9 +35906,9 @@ function hasParkedTimerWatch(tele, armedTimerIds) {
35910
35906
  if (tele?.lastFence?.kind !== "awaiting") return false;
35911
35907
  return tele.lastFence.hints.some((hint) => hint.kind === "timer" && armedTimerIds.has(hint.value.trim()));
35912
35908
  }
35913
- function hasDeclaredWait(tele, nowMs, armedTimerIds = /* @__PURE__ */ new Set()) {
35909
+ function hasDeclaredWait(tele, nowMs, armedTimerIds = /* @__PURE__ */ new Set(), registeredPrWatches = /* @__PURE__ */ new Set()) {
35914
35910
  if (hasDeclaredBackgroundPark(tele, nowMs)) return true;
35915
- if (tele?.lastFence?.kind === "awaiting" && hasParkedPrWatch(tele)) return true;
35911
+ if (tele?.lastFence?.kind === "awaiting" && hasParkedPrWatch(tele, registeredPrWatches)) return true;
35916
35912
  if (hasParkedTimerWatch(tele, armedTimerIds)) return true;
35917
35913
  return (tele?.subAgents ?? []).some((a) => isDirectSubAgent(a) && a.state === "running");
35918
35914
  }
@@ -35930,7 +35926,7 @@ function heldByRunningChecks(tele, github, registered) {
35930
35926
  return status?.checks === "running" && status.state === "open";
35931
35927
  });
35932
35928
  }
35933
- function hasLiveOwnWork(tele) {
35929
+ function hasLiveOwnWork(tele, registeredPrWatches) {
35934
35930
  return Boolean(
35935
35931
  tele?.subAgents?.some((agent) => isDirectSubAgent(agent) && agent.state === "running") || tele?.bgShells?.some((shell) => shell.state === "running") || // A PARKED PR WATCHER COUNTS (2026-08-13). It is the same shape of thing as a detached shell: the
35936
35932
  // worker left it running, it will re-invoke the thread on its own, and until it does there is
@@ -35938,12 +35934,16 @@ function hasLiveOwnWork(tele) {
35938
35934
  // counting it — for that card's event-snooze, which is now the ONE control for hiding a parked
35939
35935
  // watcher (maintainer: "the user can just use the generic snooze card… now GitHub watchers can be
35940
35936
  // included in the ranks of those").
35941
- hasParkedPrWatch(tele)
35937
+ hasParkedPrWatch(tele, registeredPrWatches)
35942
35938
  );
35943
35939
  }
35944
- function hasParkedPrWatch(tele) {
35940
+ function hasParkedPrWatch(tele, registered) {
35945
35941
  if (tele?.lastFence?.kind !== "awaiting") return false;
35946
- return tele.lastFence.hints.some((hint) => hint.kind === "pr" && parsePrRef(hint.value) !== void 0);
35942
+ return tele.lastFence.hints.some((hint) => {
35943
+ if (hint.kind !== "pr") return false;
35944
+ const ref = parsePrRef(hint.value);
35945
+ return ref !== void 0 && registered.has(githubStatusKey(ref));
35946
+ });
35947
35947
  }
35948
35948
  function bgSnoozeArmed(row) {
35949
35949
  return row.bg_snooze_rested_at != null && row.rested_at != null && row.bg_snooze_rested_at === row.rested_at;
@@ -35985,7 +35985,7 @@ function fenceWatchViews(slug, tele, fenceAt, github = {}, registered = [], arme
35985
35985
  if (tele?.lastFence?.kind !== "awaiting") return out;
35986
35986
  const createdAt = fenceAt ?? tele.lastAssistantAt ?? (/* @__PURE__ */ new Date()).toISOString();
35987
35987
  for (const hint of tele.lastFence.hints) {
35988
- if (hint.kind !== "shell" && hint.kind !== "agent") continue;
35988
+ if (hint.kind !== "shell") continue;
35989
35989
  const target = hint.value.trim();
35990
35990
  if (!target || seen.has(`shell:${target}`) || !liveWaitHandles(tele).has(target)) continue;
35991
35991
  seen.add(`shell:${target}`);
@@ -36012,15 +36012,15 @@ function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, no
36012
36012
  if (excuseLiveOwnWork && runtime !== "exited" && hasLiveBackgroundWork(tele) && !tele?.lastFence) return false;
36013
36013
  if (excuseLiveOwnWork && runtime !== "exited" && hasDeclaredBackgroundPark(tele, nowMs)) return false;
36014
36014
  if (excuseLiveOwnWork && runtime !== "exited" && heldByRunningChecks(tele, github, registeredPrWatches)) return false;
36015
- if (runtime !== "exited" && (hasLiveOwnWork(tele) || hasParkedTimerWatch(tele, armedTimerIds)) && tele?.lastFence?.kind !== "done") return !bgSnoozeArmed(row);
36015
+ if (runtime !== "exited" && (hasLiveOwnWork(tele, registeredPrWatches) || hasParkedTimerWatch(tele, armedTimerIds)) && tele?.lastFence?.kind !== "done") return !bgSnoozeArmed(row);
36016
36016
  if (tele?.lastFence?.kind === "done") return true;
36017
36017
  return true;
36018
36018
  }
36019
36019
  function deriveAwaitingBackground(row, tele, runtime, hasActionableInteraction = false, nowMs = Date.now(), limitPause = void 0, deliveryProcessGone = false, github = {}, registeredPrWatches = /* @__PURE__ */ new Set(), armedTimerIds = /* @__PURE__ */ new Set()) {
36020
- if (runtime !== "turn-idle" || !hasDeclaredWait(tele, nowMs, armedTimerIds)) return false;
36020
+ if (runtime !== "turn-idle" || !hasDeclaredWait(tele, nowMs, armedTimerIds, registeredPrWatches)) return false;
36021
36021
  if (hasActionableInteraction || tele?.pendingAsk || tele?.pendingQuestion) return false;
36022
36022
  if (tele?.lastFence?.kind === "done") return false;
36023
- if (tele?.lastFence?.kind === "awaiting" && !hasParkedPrWatch(tele) && !hasDeclaredBackgroundPark(tele, nowMs) && // A TIMER PARK IS THE SAME EXCEPTION AGAIN (2026-08-24): its fence has no park action either, so
36023
+ if (tele?.lastFence?.kind === "awaiting" && !hasParkedPrWatch(tele, registeredPrWatches) && !hasDeclaredBackgroundPark(tele, nowMs) && // A TIMER PARK IS THE SAME EXCEPTION AGAIN (2026-08-24): its fence has no park action either, so
36024
36024
  // suppressing this card left the wait stated nowhere but the fence's own machinery footer.
36025
36025
  !hasParkedTimerWatch(tele, armedTimerIds)) return false;
36026
36026
  return deriveNeedsYou({ ...row, bg_snooze_rested_at: null }, tele, runtime, hasActionableInteraction, nowMs, limitPause, false, deliveryProcessGone, {}, /* @__PURE__ */ new Set(), armedTimerIds);
@@ -36497,7 +36497,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
36497
36497
  if (parcelSub || stopped) return Promise.resolve();
36498
36498
  if (watchSetup) return watchSetup;
36499
36499
  const setup = (async () => {
36500
- const next = await subscribe(join29(project.dir, ".frizz"), () => scheduleRebuild());
36500
+ const next = await subscribe(join28(project.dir, ".frizz"), () => scheduleRebuild());
36501
36501
  if (stopped) {
36502
36502
  await next.unsubscribe();
36503
36503
  return;
@@ -37724,10 +37724,17 @@ ${wakeTimeHeader(now(), spokeAt)}`;
37724
37724
  for (const sh of tele.retiredShells ?? []) {
37725
37725
  for (const h of [sh.taskId, sh.id, sh.label]) if (h) finishedHandles.add(h);
37726
37726
  }
37727
- const finishedItem = (i) => finishedHandles.has(i.value);
37727
+ for (const a of tele.subAgents ?? []) {
37728
+ if (a.state !== "rested") continue;
37729
+ for (const h of [a.id, a.label]) if (h) finishedHandles.add(h);
37730
+ }
37731
+ const firedTimers = new Set(
37732
+ deps.storage.listThreadTimers(row.slug).filter((t) => t.state === "fired").map((t) => t.id)
37733
+ );
37734
+ const finishedItem = (i) => finishedHandles.has(i.value) || i.kind === "timer" && firedTimers.has(i.value);
37728
37735
  const status = park.items.map((i) => {
37729
37736
  const gone = dead.some((d) => d.kind === i.kind && d.value === i.value);
37730
- const note = !gone ? "still running" : finishedItem(i) ? "FINISHED \u2014 its result is waiting for you" : i.kind === "pr" ? "NOT REGISTERED \u2014 register it with `mcp__frizz__watch_pr` first, then name it here" : "NOT RUNNING (nothing by that name)";
37737
+ const note = !gone ? "still running" : i.kind === "timer" && firedTimers.has(i.value) ? "already FIRED \u2014 its wake was delivered; there is nothing left to wait on" : finishedItem(i) ? "FINISHED \u2014 its result is waiting for you" : i.kind === "pr" ? "NOT REGISTERED \u2014 register it with `mcp__frizz__watch_pr` first, then name it here" : "NOT RUNNING (nothing by that name)";
37731
37738
  return `- \`${AWAITING_KEY_OF[i.kind]}: [${i.value}]\` \u2014 ${note}`;
37732
37739
  });
37733
37740
  const allFinished = dead.length > 0 && dead.every(finishedItem);
@@ -38523,7 +38530,7 @@ var init_resume = __esm({
38523
38530
  });
38524
38531
 
38525
38532
  // packages/server/src/backend/claude.ts
38526
- import { join as join30 } from "node:path";
38533
+ import { join as join29 } from "node:path";
38527
38534
  function toolResultText2(content) {
38528
38535
  if (typeof content === "string") return content;
38529
38536
  if (!Array.isArray(content)) return "";
@@ -38612,7 +38619,7 @@ function createClaudeBackend(opts) {
38612
38619
  return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
38613
38620
  },
38614
38621
  transcriptPath(sessionId) {
38615
- return join30(opts.logDir, `${sessionId}.jsonl`);
38622
+ return join29(opts.logDir, `${sessionId}.jsonl`);
38616
38623
  },
38617
38624
  parseLine(line) {
38618
38625
  return parseClaudeLine(line);
@@ -38782,12 +38789,12 @@ var init_login_utility = __esm({
38782
38789
 
38783
38790
  // packages/server/src/backend/codex-app-server-diagnostics.ts
38784
38791
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync14, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
38785
- import { join as join31 } from "node:path";
38792
+ import { join as join30 } from "node:path";
38786
38793
  function codexDiagnosticLogPath(stateDir, projectId) {
38787
- return join31(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38794
+ return join30(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
38788
38795
  }
38789
38796
  function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
38790
- const dir = join31(stateDir, "codex-app-server");
38797
+ const dir = join30(stateDir, "codex-app-server");
38791
38798
  const path = codexDiagnosticLogPath(stateDir, projectId);
38792
38799
  let ensured = false;
38793
38800
  return (event) => {
@@ -38819,7 +38826,7 @@ var init_codex_app_server_diagnostics = __esm({
38819
38826
  import { execFile as execFile7 } from "node:child_process";
38820
38827
  import { readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
38821
38828
  import { connect as connectSocket } from "node:net";
38822
- import { join as join32 } from "node:path";
38829
+ import { join as join31 } from "node:path";
38823
38830
  function parseLsofSocketNames(stdout) {
38824
38831
  const referenced = /* @__PURE__ */ new Set();
38825
38832
  for (const line of stdout.split("\n")) {
@@ -38836,7 +38843,7 @@ function sweepStaleSockets(options, deps = {}) {
38836
38843
  const keep = new Set(options.keep ?? []);
38837
38844
  let candidates;
38838
38845
  try {
38839
- candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join32(options.dir, name)).filter((path) => !keep.has(path));
38846
+ candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join31(options.dir, name)).filter((path) => !keep.has(path));
38840
38847
  } catch {
38841
38848
  return;
38842
38849
  }
@@ -39300,7 +39307,7 @@ var init_thread_hibernation = __esm({
39300
39307
  });
39301
39308
 
39302
39309
  // packages/server/src/context.ts
39303
- import { join as join33 } from "node:path";
39310
+ import { join as join32 } from "node:path";
39304
39311
  import { randomUUID as randomUUID15 } from "node:crypto";
39305
39312
  import { homedir as homedir13 } from "node:os";
39306
39313
  function reconcileSessions(storage) {
@@ -39458,7 +39465,7 @@ async function createContext(opts = {}) {
39458
39465
  function createContextUnchecked(opts, resources) {
39459
39466
  const home = opts.home ?? homedir13();
39460
39467
  const project = opts.project ?? resolveProject();
39461
- const dbPath = join33(project.stateDir, "ui.db");
39468
+ const dbPath = join32(project.stateDir, "ui.db");
39462
39469
  const storage = createStorage(dbPath);
39463
39470
  resources.storage = storage;
39464
39471
  const bus = new Bus();
@@ -39603,12 +39610,16 @@ function createContextUnchecked(opts, resources) {
39603
39610
  projectId: project.id,
39604
39611
  // The frizz worker environment — the SDK equivalent of the CLI argv's --plugin-dir / --mcp-config.
39605
39612
  // Computed ONCE here (constant per project) and applied on every broker fork so a broker worker
39606
- // gets the frizz sub-agent profiles, the frizz + chrome-devtools MCP, and the cc-worker hooks.
39613
+ // gets the frizz sub-agent profiles, the frizz MCP server (the only one frizz mounts), and the
39614
+ // cc-worker hooks. A project's own `.mcp.json` servers load on top of these, not through them.
39607
39615
  workerEnv: {
39608
39616
  pluginDir: workerPluginDir(),
39609
39617
  ...claudeMcpConfig(resolveFrizzMcp(frizzMcpTarget)),
39610
39618
  permDir: permRequestDir(project)
39611
39619
  },
39620
+ // Read at every fork, not captured once: the compaction window is a Settings value the drawer
39621
+ // can change while the server runs, and the next dispatch or cold resume should carry it.
39622
+ getSettings: () => getSettings(storage, home),
39612
39623
  // Which broker threads warmUp() may reattach at boot. Same predicate codex's shouldAutoResume
39613
39624
  // applies: never wake a thread the human has already put away — a boot reattach is only for a
39614
39625
  // thread that is still open and still theirs to come back to. Broker-backed rows only; a
@@ -42499,7 +42510,7 @@ var init_server = __esm({
42499
42510
  });
42500
42511
 
42501
42512
  // packages/server/src/repair.ts
42502
- import { existsSync as existsSync12, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "node:fs";
42513
+ import { existsSync as existsSync11, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "node:fs";
42503
42514
  import { basename as basename7, dirname as dirname13, resolve as resolve6 } from "node:path";
42504
42515
  function quoteValue(v) {
42505
42516
  if (/^[\w./#:+-]+$/.test(v)) return v;
@@ -42514,7 +42525,7 @@ function repairThreadFile(frizzDir, file) {
42514
42525
  const abs = resolve6(root, file);
42515
42526
  if (dirname13(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
42516
42527
  if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
42517
- if (!existsSync12(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
42528
+ if (!existsSync11(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
42518
42529
  const content = readFileSync19(abs, "utf8");
42519
42530
  const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
42520
42531
  if (firstLine2?.trim() === "---") {
@@ -42706,10 +42717,10 @@ var init_bash_background = __esm({
42706
42717
  });
42707
42718
 
42708
42719
  // packages/server/src/transcript.ts
42709
- import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync21, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
42720
+ import { closeSync as closeSync13, existsSync as existsSync12, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync21, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
42710
42721
  import { createHash as createHash13 } from "node:crypto";
42711
42722
  import { StringDecoder as StringDecoder4 } from "node:string_decoder";
42712
- import { join as join34 } from "node:path";
42723
+ import { join as join33 } from "node:path";
42713
42724
  import { homedir as homedir14 } from "node:os";
42714
42725
  function formatTokens(n) {
42715
42726
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
@@ -43259,14 +43270,14 @@ function pruneScreenshotCache() {
43259
43270
  if (entries.length <= SCREENSHOT_CACHE_MAX) return;
43260
43271
  const byMtime = entries.map((n) => {
43261
43272
  try {
43262
- return { n, m: statSync14(join34(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
43273
+ return { n, m: statSync14(join33(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
43263
43274
  } catch {
43264
43275
  return { n, m: 0 };
43265
43276
  }
43266
43277
  }).sort((a, b) => b.m - a.m);
43267
43278
  for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
43268
43279
  try {
43269
- unlinkSync5(join34(SCREENSHOT_CACHE_DIR, n));
43280
+ unlinkSync5(join33(SCREENSHOT_CACHE_DIR, n));
43270
43281
  } catch {
43271
43282
  }
43272
43283
  }
@@ -43296,14 +43307,14 @@ function persistBase64Image(mediaType, data, idKey) {
43296
43307
  const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
43297
43308
  if (!ext || !data) return void 0;
43298
43309
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
43299
- const path = join34(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
43310
+ const path = join33(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
43300
43311
  try {
43301
- if (existsSync13(path)) return path;
43312
+ if (existsSync12(path)) return path;
43302
43313
  if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
43303
43314
  const buf = Buffer.from(data, "base64");
43304
43315
  if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
43305
43316
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
43306
- const tmp = join34(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43317
+ const tmp = join33(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43307
43318
  writeFileSync12(tmp, buf);
43308
43319
  renameSync9(tmp, path);
43309
43320
  pruneScreenshotCache();
@@ -43318,14 +43329,14 @@ function persistSentFile(srcPath, idKey) {
43318
43329
  const outExt = ext === "jpeg" ? "jpg" : ext;
43319
43330
  try {
43320
43331
  const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
43321
- const dest = join34(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
43322
- if (existsSync13(dest)) return dest;
43332
+ const dest = join33(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
43333
+ if (existsSync12(dest)) return dest;
43323
43334
  const size = statSync14(srcPath).size;
43324
43335
  if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
43325
43336
  const buf = readFileSync21(srcPath);
43326
43337
  if (!looksLikeImage(buf, outExt)) return void 0;
43327
43338
  mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
43328
- const tmp = join34(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43339
+ const tmp = join33(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
43329
43340
  writeFileSync12(tmp, buf);
43330
43341
  renameSync9(tmp, dest);
43331
43342
  pruneScreenshotCache();
@@ -43762,16 +43773,16 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
43762
43773
  }
43763
43774
  }
43764
43775
  function logDirOf(project) {
43765
- return join34(homedir14(), ".claude", "projects", project.cwdSlug);
43776
+ return join33(homedir14(), ".claude", "projects", project.cwdSlug);
43766
43777
  }
43767
43778
  function resolveTranscriptPath(project, sessionId) {
43768
- const path = join34(logDirOf(project), `${sessionId}.jsonl`);
43779
+ const path = join33(logDirOf(project), `${sessionId}.jsonl`);
43769
43780
  try {
43770
43781
  if (statSync14(path).size > 0) return path;
43771
43782
  } catch {
43772
43783
  }
43773
43784
  const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
43774
- return stranded ? join34(stranded, `${sessionId}.jsonl`) : path;
43785
+ return stranded ? join33(stranded, `${sessionId}.jsonl`) : path;
43775
43786
  }
43776
43787
  function projectCodexTranscript(raw2, identityPrefix = "codex") {
43777
43788
  const out = [];
@@ -44715,7 +44726,7 @@ function sourceForThread(project, storage, slug, backendFor) {
44715
44726
  }
44716
44727
  if (!FOREIGN_SESSION_ID_RE.test(slug)) return void 0;
44717
44728
  const claudePath = resolveTranscriptPath(project, slug);
44718
- if (existsSync13(claudePath)) {
44729
+ if (existsSync12(claudePath)) {
44719
44730
  return { slug, sessionId: slug, nativeId: slug, backend: "claude", runtimeGeneration: 0, path: claudePath };
44720
44731
  }
44721
44732
  const rollout = (backendFor?.("codex") ?? defaultCodexBackend()).transcriptPath(slug);
@@ -45171,7 +45182,7 @@ var init_open_external = __esm({
45171
45182
  import { spawn as spawn6 } from "node:child_process";
45172
45183
  import { readFileSync as readFileSync22, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
45173
45184
  import { homedir as homedir15 } from "node:os";
45174
- import { isAbsolute as isAbsolute3, join as join35, resolve as resolve7, sep } from "node:path";
45185
+ import { isAbsolute as isAbsolute3, join as join34, resolve as resolve7, sep } from "node:path";
45175
45186
  function isUnder(real, root) {
45176
45187
  let rootReal;
45177
45188
  try {
@@ -45201,7 +45212,7 @@ function resolveLocalFile(rawPath, roots) {
45201
45212
  function resolveOpenableFile(raw2, projectDir, roots, home = homedir15()) {
45202
45213
  const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
45203
45214
  if (!trimmed) return null;
45204
- const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join35(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
45215
+ const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join34(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
45205
45216
  try {
45206
45217
  return resolveLocalFile(abs, roots);
45207
45218
  } catch {
@@ -45912,10 +45923,10 @@ var init_directory_picker = __esm({
45912
45923
 
45913
45924
  // packages/server/src/router.ts
45914
45925
  import { readFileSync as readFileSync23, statSync as statSync17 } from "node:fs";
45915
- import { join as join36, resolve as resolve8 } from "node:path";
45926
+ import { join as join35, resolve as resolve8 } from "node:path";
45916
45927
  import { randomUUID as randomUUID16 } from "node:crypto";
45917
45928
  import { basename as basename9, dirname as dirname14 } from "node:path";
45918
- import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "node:fs";
45929
+ import { existsSync as existsSync13, mkdirSync as mkdirSync16, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "node:fs";
45919
45930
  import { homedir as homedir16 } from "node:os";
45920
45931
  function validateGithubDispatchProfile(input) {
45921
45932
  validateThreadProfile(input.backend, input.model, input.effort);
@@ -46075,7 +46086,7 @@ function projectCard(entry, stale) {
46075
46086
  function addProjectAtPath(input) {
46076
46087
  const typed = input.trim();
46077
46088
  if (!typed) throw new Error("Enter a folder path.");
46078
- const expanded = typed === "~" || typed.startsWith("~/") ? join36(homedir16(), typed.slice(1)) : typed;
46089
+ const expanded = typed === "~" || typed.startsWith("~/") ? join35(homedir16(), typed.slice(1)) : typed;
46079
46090
  const absolute = resolve8(expanded);
46080
46091
  let stats;
46081
46092
  try {
@@ -46128,7 +46139,7 @@ function setProjectIconFromFile(id, file) {
46128
46139
  return storeProjectIcon(id, file, bytes);
46129
46140
  }
46130
46141
  function createRouter(ctx) {
46131
- const frizzDir = join36(ctx.project.dir, ".frizz");
46142
+ const frizzDir = join35(ctx.project.dir, ".frizz");
46132
46143
  const openRoots = openableFileRoots(ctx.project);
46133
46144
  function isAutoTitledSession(slug) {
46134
46145
  return ctx.storage.getSession(slug)?.title_auto === 1;
@@ -47739,7 +47750,7 @@ ${gapNote}` : input.message;
47739
47750
  }
47740
47751
  const updated = clearProjectIcon(input.id);
47741
47752
  if (!updated) throw new Error("No such project.");
47742
- return projectCard(updated, !existsSync14(updated.path));
47753
+ return projectCard(updated, !existsSync13(updated.path));
47743
47754
  }
47744
47755
  }),
47745
47756
  /**
@@ -47789,7 +47800,7 @@ ${gapNote}` : input.message;
47789
47800
  for (const entry of listProjects()) {
47790
47801
  if (entry.stale) continue;
47791
47802
  try {
47792
- const db = new sqlite_default(join36(projectStateDir(entry.id), "ui.db"), { readonly: true });
47803
+ const db = new sqlite_default(join35(projectStateDir(entry.id), "ui.db"), { readonly: true });
47793
47804
  try {
47794
47805
  const hit = db.prepare("SELECT 1 FROM session WHERE slug = ? LIMIT 1").get(input.slug);
47795
47806
  if (hit) found.push({ projectSlug: entry.slug, projectName: entry.name ?? entry.slug });
@@ -48181,7 +48192,7 @@ var init_local_image = __esm({
48181
48192
  // packages/server/src/project-icon.ts
48182
48193
  import { readFileSync as readFileSync25, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
48183
48194
  import { homedir as homedir17 } from "node:os";
48184
- import { basename as basename10, dirname as dirname15, extname as extname3, join as join37, relative, sep as sep2 } from "node:path";
48195
+ import { basename as basename10, dirname as dirname15, extname as extname3, join as join36, relative, sep as sep2 } from "node:path";
48185
48196
  function normalizeStem(stem) {
48186
48197
  const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
48187
48198
  const normalized = sized.replace(VARIANT_SUFFIX, "");
@@ -48199,7 +48210,7 @@ function sizeScore(dimensions) {
48199
48210
  return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
48200
48211
  }
48201
48212
  function under(root, relativeDirectory) {
48202
- return relativeDirectory ? join37(root, relativeDirectory) : root;
48213
+ return relativeDirectory ? join36(root, relativeDirectory) : root;
48203
48214
  }
48204
48215
  function listFiles(directory) {
48205
48216
  try {
@@ -48221,19 +48232,19 @@ function iconDirectories(root) {
48221
48232
  for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
48222
48233
  for (const host of HOST_DIRECTORIES) {
48223
48234
  if (!children2.has(host)) continue;
48224
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join37(root, host), asset));
48235
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join36(root, host), asset));
48225
48236
  }
48226
48237
  for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
48227
48238
  for (const container of WORKSPACE_CONTAINERS) {
48228
48239
  if (!children2.has(container)) continue;
48229
48240
  let members;
48230
48241
  try {
48231
- members = readdirSync10(join37(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
48242
+ members = readdirSync10(join36(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
48232
48243
  } catch {
48233
48244
  continue;
48234
48245
  }
48235
48246
  for (const member of members) {
48236
- for (const asset of ASSET_DIRECTORIES) directories.push(under(join37(root, container, member), asset));
48247
+ for (const asset of ASSET_DIRECTORIES) directories.push(under(join36(root, container, member), asset));
48237
48248
  }
48238
48249
  }
48239
48250
  return [...new Set(directories)];
@@ -48247,7 +48258,7 @@ function manifestIcons(manifestPath) {
48247
48258
  }
48248
48259
  if (!Array.isArray(parsed?.icons)) return [];
48249
48260
  const directory = dirname15(manifestPath);
48250
- return parsed.icons.map((icon) => typeof icon?.src === "string" ? icon.src : void 0).filter((src) => !!src && !/^(https?:)?\/\//u.test(src) && !src.startsWith("data:")).map((src) => join37(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
48261
+ 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) => join36(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
48251
48262
  }
48252
48263
  function projectIconCandidates(root) {
48253
48264
  const projectStem = normalizeStem(basename10(root)).normalized;
@@ -48266,7 +48277,7 @@ function projectIconCandidates(root) {
48266
48277
  for (const name of listFiles(directory)) {
48267
48278
  const extension2 = extname3(name).toLowerCase();
48268
48279
  if (MANIFEST_NAMES.includes(name.toLowerCase())) {
48269
- for (const icon of manifestIcons(join37(directory, name))) {
48280
+ for (const icon of manifestIcons(join36(directory, name))) {
48270
48281
  if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
48271
48282
  fromManifest.add(icon);
48272
48283
  files.push({ path: icon, directory: dirname15(icon) });
@@ -48277,7 +48288,7 @@ function projectIconCandidates(root) {
48277
48288
  if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
48278
48289
  const stem = name.slice(0, name.length - extension2.length);
48279
48290
  if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
48280
- files.push({ path: join37(directory, name), directory });
48291
+ files.push({ path: join36(directory, name), directory });
48281
48292
  if (files.length >= MAX_CANDIDATES) break;
48282
48293
  }
48283
48294
  }
@@ -48455,7 +48466,7 @@ var init_project_icon = __esm({
48455
48466
 
48456
48467
  // packages/server/src/local-visualization.ts
48457
48468
  import { readdirSync as readdirSync11, readFileSync as readFileSync26, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
48458
- import { join as join38, sep as sep3 } from "node:path";
48469
+ import { join as join37, sep as sep3 } from "node:path";
48459
48470
  function children(path, pattern) {
48460
48471
  try {
48461
48472
  return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
@@ -48467,7 +48478,7 @@ function isUnder2(path, root) {
48467
48478
  return path === root || path.startsWith(root.endsWith(sep3) ? root : root + sep3);
48468
48479
  }
48469
48480
  function resolveFragment(projectDir, sessionId, file) {
48470
- const base = join38(projectDir, ".codex", "visualizations");
48481
+ const base = join37(projectDir, ".codex", "visualizations");
48471
48482
  let projectReal;
48472
48483
  let baseReal;
48473
48484
  try {
@@ -48478,12 +48489,12 @@ function resolveFragment(projectDir, sessionId, file) {
48478
48489
  }
48479
48490
  if (!isUnder2(baseReal, projectReal)) return null;
48480
48491
  for (const year of children(base, YEAR_PART)) {
48481
- const yearDir = join38(base, year);
48492
+ const yearDir = join37(base, year);
48482
48493
  for (const month of children(yearDir, DATE_PART)) {
48483
- const monthDir = join38(yearDir, month);
48494
+ const monthDir = join37(yearDir, month);
48484
48495
  for (const day of children(monthDir, DATE_PART)) {
48485
- const sessionRoot = join38(baseReal, year, month, day, sessionId);
48486
- const candidate = join38(monthDir, day, sessionId, file);
48496
+ const sessionRoot = join37(baseReal, year, month, day, sessionId);
48497
+ const candidate = join37(monthDir, day, sessionId, file);
48487
48498
  try {
48488
48499
  const real = realpathSync11(candidate);
48489
48500
  if (isUnder2(real, sessionRoot) && statSync20(real).isFile()) return real;
@@ -48612,7 +48623,7 @@ var init_local_visualization = __esm({
48612
48623
 
48613
48624
  // packages/server/src/app.ts
48614
48625
  import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync14 } from "node:fs";
48615
- import { join as join39 } from "node:path";
48626
+ import { join as join38 } from "node:path";
48616
48627
  import { randomUUID as randomUUID17 } from "node:crypto";
48617
48628
  function createApp(ctx, options = {}) {
48618
48629
  const app = new Hono2();
@@ -48716,10 +48727,10 @@ function createApp(ctx, options = {}) {
48716
48727
  if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
48717
48728
  const ext = `.${attachmentExtension(name)}`;
48718
48729
  const buf = Buffer.from(body.data, "base64");
48719
- const dir = join39(ctx.project.stateDir, "attachments");
48730
+ const dir = join38(ctx.project.stateDir, "attachments");
48720
48731
  mkdirSync17(dir, { recursive: true });
48721
48732
  const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
48722
- const path = join39(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
48733
+ const path = join38(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
48723
48734
  writeFileSync14(path, buf);
48724
48735
  return c.json({ path });
48725
48736
  });
@@ -49959,9 +49970,9 @@ var init_app_socket = __esm({
49959
49970
 
49960
49971
  // packages/server/src/boot-progress.ts
49961
49972
  import { mkdirSync as mkdirSync18, readFileSync as readFileSync27, renameSync as renameSync10, rmSync as rmSync11, writeFileSync as writeFileSync15 } from "node:fs";
49962
- import { basename as basename11, dirname as dirname16, join as join40 } from "node:path";
49973
+ import { basename as basename11, dirname as dirname16, join as join39 } from "node:path";
49963
49974
  function bootProgressPath(stateDir) {
49964
- return join40(stateDir, BOOT_PROGRESS_NAME);
49975
+ return join39(stateDir, BOOT_PROGRESS_NAME);
49965
49976
  }
49966
49977
  function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49967
49978
  if (!stateDir) {
@@ -49982,7 +49993,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
49982
49993
  step++;
49983
49994
  try {
49984
49995
  mkdirSync18(dirname16(path), { recursive: true, mode: 448 });
49985
- const temp = join40(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49996
+ const temp = join39(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
49986
49997
  writeFileSync15(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
49987
49998
  `, "utf8");
49988
49999
  renameSync10(temp, path);
@@ -50099,8 +50110,8 @@ __export(index_exports, {
50099
50110
  unknownProjectPage: () => unknownProjectPage
50100
50111
  });
50101
50112
  import { createServer } from "node:http";
50102
- import { readFileSync as readFileSync28, existsSync as existsSync15 } from "node:fs";
50103
- import { dirname as dirname17, join as join41, resolve as resolve9, extname as extname4, normalize } from "node:path";
50113
+ import { readFileSync as readFileSync28, existsSync as existsSync14 } from "node:fs";
50114
+ import { dirname as dirname17, join as join40, resolve as resolve9, extname as extname4, normalize } from "node:path";
50104
50115
  function readServerAddressHolder(path) {
50105
50116
  try {
50106
50117
  const value = JSON.parse(readFileSync28(path, "utf8"));
@@ -50203,9 +50214,9 @@ function createShutdownSignalHandler(options) {
50203
50214
  }
50204
50215
  function serveStatic(distDir, req, res) {
50205
50216
  const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
50206
- let file = join41(distDir, rel === "/" ? "index.html" : rel);
50207
- if (!file.startsWith(distDir)) file = join41(distDir, "index.html");
50208
- if (!existsSync15(file)) file = join41(distDir, "index.html");
50217
+ let file = join40(distDir, rel === "/" ? "index.html" : rel);
50218
+ if (!file.startsWith(distDir)) file = join40(distDir, "index.html");
50219
+ if (!existsSync14(file)) file = join40(distDir, "index.html");
50209
50220
  try {
50210
50221
  const body = readFileSync28(file);
50211
50222
  res.writeHead(200, { "content-type": MIME[extname4(file)] ?? "application/octet-stream" });
@@ -50556,7 +50567,7 @@ async function startServer(opts = {}) {
50556
50567
  }
50557
50568
  statusPath = serverLockPathFor(ctx.project);
50558
50569
  const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
50559
- const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join41(webRoot, "dist");
50570
+ const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join40(webRoot, "dist");
50560
50571
  startupPhase = "Vite";
50561
50572
  if (opts.dev) {
50562
50573
  try {
@@ -50632,7 +50643,7 @@ async function startServer(opts = {}) {
50632
50643
  if (vite) {
50633
50644
  vite.middlewares(req, res, () => {
50634
50645
  try {
50635
- const html = readFileSync28(join41(webRoot, "index.html"), "utf8");
50646
+ const html = readFileSync28(join40(webRoot, "index.html"), "utf8");
50636
50647
  void vite.transformIndexHtml(url, html).then((out) => {
50637
50648
  res.writeHead(200, { "content-type": "text/html" });
50638
50649
  res.end(out);
@@ -50644,7 +50655,7 @@ async function startServer(opts = {}) {
50644
50655
  });
50645
50656
  return;
50646
50657
  }
50647
- if (existsSync15(distDir)) {
50658
+ if (existsSync14(distDir)) {
50648
50659
  serveStatic(distDir, req, res);
50649
50660
  return;
50650
50661
  }
@@ -50824,7 +50835,7 @@ var init_index = __esm({
50824
50835
  }
50825
50836
  };
50826
50837
  isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
50827
- serverLockPathFor = (project) => join41(project.stateDir, "server.lock");
50838
+ serverLockPathFor = (project) => join40(project.stateDir, "server.lock");
50828
50839
  MIME = {
50829
50840
  ".html": "text/html",
50830
50841
  ".js": "text/javascript",
@@ -50842,8 +50853,8 @@ init_project();
50842
50853
  init_project_launch();
50843
50854
  init_shutdown();
50844
50855
  init_logging();
50845
- import { existsSync as existsSync16 } from "node:fs";
50846
- import { join as join42 } from "node:path";
50856
+ import { existsSync as existsSync15 } from "node:fs";
50857
+ import { join as join41 } from "node:path";
50847
50858
  process.on("uncaughtException", (error) => {
50848
50859
  log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
50849
50860
  process.exit(1);
@@ -50881,9 +50892,9 @@ try {
50881
50892
  ["FRIZZ_SCRIPTS_DIR", process.env.FRIZZ_SCRIPTS_DIR, "index.mjs"],
50882
50893
  ["FRIZZ_WORKER_PLUGIN_DIR", process.env.FRIZZ_WORKER_PLUGIN_DIR, ".claude-plugin/plugin.json"]
50883
50894
  ];
50884
- if (!existsSync16(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
50895
+ if (!existsSync15(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
50885
50896
  for (const [name, directory, requiredFile] of required) {
50886
- if (!directory || !existsSync16(join42(directory, requiredFile)))
50897
+ if (!directory || !existsSync15(join41(directory, requiredFile)))
50887
50898
  throw new Error(`stable artifact launch is missing verified ${name}`);
50888
50899
  }
50889
50900
  }