frizz-server 0.15.16 → 0.15.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-child.js +1254 -779
- package/package.json +1 -1
- package/runtime/cc-worker/bin/frizz-mcp.mjs +66 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-DjpPWj1n.js → abnfDiagram-VRR7QNED-BCWz80uN.js} +1 -1
- package/web-dist/assets/{arc-GGQPeqIn.js → arc-DDtkTWyk.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-BSM-tgTt.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-i9N18wLs.js → architectureDiagram-ZJ3FMSHR-BpRbm_s5.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-CIc5kmW3.js → blockDiagram-677ZJIJ3-_kGtJSW2.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-DjUgY_rv.js → c4Diagram-LMCZKHZV-D8XwDoiY.js} +1 -1
- package/web-dist/assets/channel-BwwaRyUv.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-DdVPbS2L.js → chunk-32BRIVSS-BUGbBNz_.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-k-avutEL.js → chunk-52WLFC77-Dc0eyYJe.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-jMdA6WRB.js → chunk-C7G6YPKG-CNP8apQ_.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-DPQFUeFc.js → chunk-EX3LRPZG-m5klG9uB.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-CnOUb3RH.js → chunk-FWX5IMBZ-CHO58JFl.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-YdnK1w2S.js → chunk-HOUHSVGY-DjH-r82r.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-hdfmNc2d.js → chunk-ICXQ74PX-DkYjEd46.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-CsGFUAEU.js → chunk-MOJQB5TN-D89rLIxX.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-CzQY8gM0.js → chunk-OGEWGWER-Db2MBETv.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-CquKZy9Z.js → chunk-PUDLZKDR-Dtdx_z8j.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-C_1V073n.js → chunk-Q4XR5HBZ-XYvD_xYq.js} +1 -1
- package/web-dist/assets/{chunk-RYQCIY6F-B2Y6QBP5.js → chunk-RYQCIY6F-CZ7RTprX.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-_NMzZcnP.js → chunk-V7JOEXUC-CoAVJiNJ.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-D8ojVgWd.js → chunk-VAUOI2AC-DbjEHErZ.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-CgTzyBot.js → chunk-VR4S4FIN-4BB6eLCK.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-D0qL-eZe.js → chunk-WYO6CB5R-Cuvm_fLi.js} +1 -1
- package/web-dist/assets/{chunk-XXDRQBXY-CqoZQ1Er.js → chunk-XXDRQBXY-CvLzx99l.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-CY3MtA1p.js → chunk-ZGVPDNZ5-BccJcRbi.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DTgWbehh.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DTgWbehh.js +1 -0
- package/web-dist/assets/{cose-bilkent-JH36ORCC-CdwbTfJj.js → cose-bilkent-JH36ORCC-BfwT-16i.js} +1 -1
- package/web-dist/assets/{cynefin-VYW2F7L2-CpVXg7NY.js → cynefin-VYW2F7L2-DbZ1V36t.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Bq8xdMaL.js → cynefinDiagram-TSTJHNR4-mFI_mDt-.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-3LmR7haE.js → dagre-VKFMJZFB-BldEgHyl.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-Bl3VhSKJ.js → diagram-FQU43EPY-CWSdOHjN.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-Dx8wicI9.js → diagram-G47NLZAW-CohHPpmC.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-D-ac7oKf.js → diagram-NH7WQ7WH-CY9SIr04.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-C3n9muDh.js → diagram-OA4YK3LP-D1ChaJcq.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-zhWZ_XKT.js → diagram-WEI45ONY-Bng85j-O.js} +1 -1
- package/web-dist/assets/{dist-C2WuhXSR.js → dist-Dn2m7SMF.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-BYXQgDLw.js → ebnfDiagram-CCIWWBDH-CcHfTwsR.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-DSTBG9Mp.js → erDiagram-Q63AITRT-D9XptUTi.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-vqzohKbi.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-CYPLykok.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-C9RStO67.js → ganttDiagram-NO4QXBWP-CpDcHWNC.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-JFtHkb0B.js → gitGraph-TEB2WS4Q-dskxWshP.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-uVA8Zt2w.js → gitGraphDiagram-IHSO6WYX-Gm-g6rXY.js} +1 -1
- package/web-dist/assets/index-Bi4vNYho.css +2 -0
- package/web-dist/assets/index-C5sCt0eh.js +334 -0
- package/web-dist/assets/{info-DKCQHKI2-hrkiQZrg.js → info-DKCQHKI2-DfBWPig9.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-BhdOdJlu.js → infoDiagram-FWYZ7A6U-RA1gm_5G.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-zdLsCb3B.js → ishikawaDiagram-FXEZZL3T-DMO4tlB7.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-C_2hQwBD.js → journeyDiagram-5HDEW3XC-CGn0Vfft.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-o0jEXUku.js → kanban-definition-HUTT4EX6-qRxs3pxC.js} +1 -1
- package/web-dist/assets/{line-BI9UTuIR.js → line-BihkNjKV.js} +1 -1
- package/web-dist/assets/{linear-Rr0EbNoq.js → linear-CbcYjraG.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-yhmLALkv.js → mermaid-parser.core-CstJtBOd.js} +3 -3
- package/web-dist/assets/{mermaid.core-BRyxVBzn.js → mermaid.core-CAoFTj5o.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-BA9ji-1w.js → mindmap-definition-LN4V7U3C-Dobyf2TY.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-DBhL0KIK.js → packet-7NZHBO7P-BV-_zRVl.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-CPxXVeZH.js → pegDiagram-2B236MQR-CoWfyvfk.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-ByCiaDbD.js → pie-RZYD4A2V-ptQFpYwJ.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-Bw8GvNiv.js → pieDiagram-ENE6RG2P-DCYSn0kJ.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-CwL8u1x5.js → quadrantDiagram-ABIIQ3AL-D-IhKJdt.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-Ds0-Pw3X.js → radar-I7S5WNFK-CqtSeYcU.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-xwnxXT5n.js → railroad-3IZDKUUU-CejeX1m0.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-D858Ks1V.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-CnKN0qs5.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-CG_oVFtv.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-B1rEgDrn.js → railroadDiagram-RFXS5EU6-CLMVsbkb.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-CdLF-_L5.js → requirementDiagram-TGXJPOKE-J6ovU2nZ.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-DTmdqI7H.js → sankeyDiagram-HTMAVEWB-BN1Wcnxg.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-CKtz0A1H.js → sequenceDiagram-DBY2YBRQ-CnDSUjeE.js} +1 -1
- package/web-dist/assets/{src-BqbE4HyW.js → src-ie67lQl7.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-GYGYAkK2.js → stateDiagram-2N3HPSRC-CDvDw5S6.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-CWmRITC6.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-DAi3tBaQ.js → swimlanes-5IMT3BWC-BmljTUhI.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BTxJqUkH.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-O4KNojxn.js → timeline-definition-FHXFAJF6-CjA-qR6O.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-BbAhfX9e.js → treeView-QDETBFTQ-CHKGsZbS.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-D3XVXTNg.js → treemap-6X3UGDF4-CqU-nL1w.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-BjsVc4st.js → vennDiagram-L72KCM5P-BwQcxcel.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-CcWQmwG4.js → wardley-OPB4EBWU-Bo8e8N-h.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-Cz-aojN7.js → wardleyDiagram-EHGQE667-ByioZC4m.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-CASxN8z7.js → xychartDiagram-FW5EYKEG-B48Vy_EL.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-qF4uSd6w.js +0 -1
- package/web-dist/assets/channel-KKo0nJfj.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-B4WEPxqA.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-B4WEPxqA.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-Dfi1SiqN.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-DrZ_4EiE.js +0 -1
- package/web-dist/assets/index-DdA4AFB7.js +0 -334
- package/web-dist/assets/index-J1N8yjnp.css +0 -2
- package/web-dist/assets/railroad-abnf-AHOZXSZD-BMLoaNxy.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-BRk3kvdr.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-h9Wo00HF.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BmiBzOjo.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BvIghLXt.js +0 -8
package/dist/dev-child.js
CHANGED
|
@@ -760,10 +760,10 @@ function discoverProjectRoot(cwd = process.cwd(), home = homedir3()) {
|
|
|
760
760
|
} catch {
|
|
761
761
|
return resolve3(cwd);
|
|
762
762
|
}
|
|
763
|
-
const
|
|
763
|
+
const stop2 = resolve3(home);
|
|
764
764
|
const filesystemRoot = parse(dir).root;
|
|
765
765
|
for (let at2 = dir; ; at2 = dirname3(at2)) {
|
|
766
|
-
if (at2 ===
|
|
766
|
+
if (at2 === stop2 || at2 === filesystemRoot) break;
|
|
767
767
|
if (existsSync2(projectIdPath(at2))) return at2;
|
|
768
768
|
if (hasAny(at2, REPO_MARKERS)) return at2;
|
|
769
769
|
if (hasAny(at2, PROJECT_MARKERS)) return at2;
|
|
@@ -13731,9 +13731,10 @@ function signoffNudgeText(needsInput) {
|
|
|
13731
13731
|
" `mcp__frizz__timer`; `mcp__frizz__activity` reads back everything you have running, with its id.",
|
|
13732
13732
|
"- `` ```awaiting `` with `steps:` \u2014 the human must PERFORM something you cannot: sign in, approve,",
|
|
13733
13733
|
" merge, press a button you may not. List each step as a `- ` line under `steps:`, written to be",
|
|
13734
|
-
" followed cold
|
|
13735
|
-
"
|
|
13736
|
-
"
|
|
13734
|
+
" followed cold: a real Markdown link to every page and file it names, every command in a code span,",
|
|
13735
|
+
" every value the act needs written in. Frizz reads them verbatim. Steps name the HUMAN as the wait,",
|
|
13736
|
+
" so the fence needs no other name and no `for:`, and the thread goes into their queue. Their Done",
|
|
13737
|
+
" comes back to you as their reply; anything else they need to say comes as a message of their own.",
|
|
13737
13738
|
"- `` ```awaiting `` with `questions:` \u2014 a question you registered at an EARLIER rest is still open and",
|
|
13738
13739
|
" you still need its answer. Name every such question (`questions: [qst_\u2026]`) and withdraw the rest with",
|
|
13739
13740
|
" `mcp__frizz__unask`: a fence that leaves an open question out is refused. A named card is drawn at",
|
|
@@ -13854,6 +13855,8 @@ function askedQuestionFaults(q2) {
|
|
|
13854
13855
|
const faults = [];
|
|
13855
13856
|
const walk = (node, path3) => {
|
|
13856
13857
|
const options = node.options ?? [];
|
|
13858
|
+
if (node.secret && options.length > 0) faults.push(`${path3}: a secret request takes no options \u2014 it is one masked box`);
|
|
13859
|
+
if (node.secret && path3 !== "question") faults.push(`${path3}: a secret request cannot be a follow-up \u2014 register it on its own`);
|
|
13857
13860
|
if (node.kind === "multi" && options.length === 0) faults.push(`${path3}: \`kind: "multi"\` needs options \u2014 a question with none is free text`);
|
|
13858
13861
|
if (options.filter((o) => o.recommended).length > 1) faults.push(`${path3}: only ONE option may be \`recommended\` \u2014 a recommendation on two of three choices says nothing`);
|
|
13859
13862
|
for (const [i, option] of options.entries()) {
|
|
@@ -13870,6 +13873,12 @@ function askedQuestionFaults(q2) {
|
|
|
13870
13873
|
}
|
|
13871
13874
|
return faults;
|
|
13872
13875
|
}
|
|
13876
|
+
function secretAnswerText(path3) {
|
|
13877
|
+
return `(secret ready at ${quotePath(path3)} \u2014 it can be read ONCE, within ${SECRET_TTL_MS / 6e4}m; never print it)`;
|
|
13878
|
+
}
|
|
13879
|
+
function quotePath(value) {
|
|
13880
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
13881
|
+
}
|
|
13873
13882
|
function questionAnswerMessage(answers, dismissed = []) {
|
|
13874
13883
|
if (answers.length === 0) return questionsCancelledWakeMessage(dismissed.length);
|
|
13875
13884
|
const rows = [];
|
|
@@ -14118,7 +14127,7 @@ function parseGithubWakeSteer(text2) {
|
|
|
14118
14127
|
function frizzRoute(path3) {
|
|
14119
14128
|
return `${FRIZZ_ROUTE_PREFIX}${path3.startsWith("/") ? path3 : `/${path3}`}`;
|
|
14120
14129
|
}
|
|
14121
|
-
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, CODEX_MODELS_FALLBACK, AcpAgent, ACP_MODEL_PREFIX, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, RETIRED_AWAITING_REPLACEMENT, AWAITING_KEY_RE, AWAITING_YAML_KEYS, AWAITING_SEQUENCE_KEYS, AWAITING_HINT_MAX, AWAITING_HINT_VALUE_MAX, AWAITING_SCALAR_KINDS, AWAITING_STEPS_MAX, AWAITING_STEP_VALUE_MAX, AWAITING_QUESTIONS_MAX, AWAITING_TITLE_MAX, AWAITING_STATUSES, AWAITING_ITEM_KINDS, AWAITING_DURATION_RE, DURATION_UNIT_MS, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, INTERRUPT_MARKERS, ALLDONE_SENTINEL, OPT_OUT_NOTE, OVER_QUESTION_NOTE, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TIMER_MAX_ARMED, TimerPromptText, PR_WATCH_SPENT_TRAILER, PR_WATCH_ARMED_TRAILER, SHELL_DONE_TRAILER, ISSUE_WATCH_SPENT_TRAILER, ISSUE_WATCH_ARMED_TRAILER, INTERRUPT_ENDED_LEAD, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, PARK_CORRECTION_NEEDS_INPUT_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, OWN_WATCH_MAX_ARMED, QUESTION_FENCE_RETIRED_AT, NEEDS_INPUT_REQUIRED_AT, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, WAKE_TIME_HEADER_TAIL, WAKE_TRAILERS, HUMAN_GAP_FLOOR_MS, HUMAN_GAP_NOTE_TAIL, WAKE_DELIVERY_TOKEN_TAIL, WAKE_DELIVERY_TOKEN_LINE, NOISE_PREFIXES, AGENT_MESSAGE_WRAPPER, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REVIEW_LEAD, WAKE_BACKLOG_TAIL, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, WAKE_ITEM, WAKE_MORE, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
|
|
14130
|
+
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ClaudeModel, CODEX_MODELS_FALLBACK, AcpAgent, ACP_MODEL_PREFIX, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, RETIRED_AWAITING_REPLACEMENT, AWAITING_KEY_RE, AWAITING_YAML_KEYS, AWAITING_SEQUENCE_KEYS, AWAITING_HINT_MAX, AWAITING_HINT_VALUE_MAX, AWAITING_SCALAR_KINDS, AWAITING_STEPS_MAX, AWAITING_STEP_VALUE_MAX, AWAITING_QUESTIONS_MAX, AWAITING_TITLE_MAX, AWAITING_STATUSES, AWAITING_ITEM_KINDS, AWAITING_DURATION_RE, DURATION_UNIT_MS, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, INTERRUPT_MARKERS, ALLDONE_SENTINEL, OPT_OUT_NOTE, OVER_QUESTION_NOTE, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TIMER_MAX_ARMED, TimerPromptText, PR_WATCH_SPENT_TRAILER, PR_WATCH_ARMED_TRAILER, SHELL_DONE_TRAILER, ISSUE_WATCH_SPENT_TRAILER, ISSUE_WATCH_ARMED_TRAILER, INTERRUPT_ENDED_LEAD, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, SIGNOFF_NUDGE_MESSAGE_NEEDS_INPUT, PARK_CORRECTION_NAMES_LEAD, PARK_CORRECTION_RETIRED_LEAD, PARK_CORRECTION_QUESTION_LEAD, PARK_CORRECTION_NEEDS_INPUT_LEAD, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PR_WATCH_MAX_ARMED, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, OWN_WATCH_MAX_ARMED, QUESTION_FENCE_RETIRED_AT, NEEDS_INPUT_REQUIRED_AT, AskQuestionKind, ASK_MAX_DEPTH, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, SECRET_TTL_MS, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, DISMISSED_ANSWER, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, LiveTool, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, DismissFailedFollowUpInput, DismissFailedFollowUpResult, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, CompactThreadInput, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, UpgradeThreadModelInput, UpgradeThreadModelResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, GITHUB_DISPATCH_UI_BOUNDARY, WAKE_TIME_HEADER_TAIL, WAKE_TRAILERS, HUMAN_GAP_FLOOR_MS, HUMAN_GAP_NOTE_TAIL, WAKE_DELIVERY_TOKEN_TAIL, WAKE_DELIVERY_TOKEN_LINE, NOISE_PREFIXES, AGENT_MESSAGE_WRAPPER, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REVIEW_LEAD, WAKE_BACKLOG_TAIL, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, WAKE_ITEM, WAKE_MORE, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, ProjectRailCounts, PROJECT_ICON_EXTENSIONS, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT, threadIdentityName;
|
|
14122
14131
|
var init_src = __esm({
|
|
14123
14132
|
"packages/shared/src/index.ts"() {
|
|
14124
14133
|
"use strict";
|
|
@@ -14794,6 +14803,7 @@ var init_src = __esm({
|
|
|
14794
14803
|
header: external_exports.string().trim().max(24).optional(),
|
|
14795
14804
|
kind: AskQuestionKind,
|
|
14796
14805
|
danger: external_exports.boolean().optional(),
|
|
14806
|
+
secret: external_exports.boolean().optional(),
|
|
14797
14807
|
// UNBOUNDED, deliberately. This carried `.max(8)` from launch until 2026-09-03, when the maintainer
|
|
14798
14808
|
// asked for the cap to go ("allow arbitrary numbers of options"): a `multi` over a long list — which
|
|
14799
14809
|
// gates to run, which of twenty findings to act on — is a real shape, and the card numbers past 9
|
|
@@ -14811,8 +14821,12 @@ var init_src = __esm({
|
|
|
14811
14821
|
* an id alone cannot be correlated back to what was asked. */
|
|
14812
14822
|
id: external_exports.string(),
|
|
14813
14823
|
spec: AskedQuestionSchema,
|
|
14814
|
-
askedAt: external_exports.string()
|
|
14824
|
+
askedAt: external_exports.string(),
|
|
14825
|
+
/** A `secret` question only: the path its value will be served at. Known at registration, so the
|
|
14826
|
+
* worker can prepare the command that reads it before the human has answered. */
|
|
14827
|
+
secretPath: external_exports.string().optional()
|
|
14815
14828
|
}).strict();
|
|
14829
|
+
SECRET_TTL_MS = 15 * 6e4;
|
|
14816
14830
|
AskResult = external_exports.object({
|
|
14817
14831
|
registered: external_exports.array(RegisteredQuestionView),
|
|
14818
14832
|
/** Everything still open on this thread afterwards, so a worker never needs a second call. */
|
|
@@ -18087,6 +18101,229 @@ var init_logging = __esm({
|
|
|
18087
18101
|
}
|
|
18088
18102
|
});
|
|
18089
18103
|
|
|
18104
|
+
// packages/server/src/local-origin.ts
|
|
18105
|
+
import { isIP } from "node:net";
|
|
18106
|
+
function publicAuthority(policy) {
|
|
18107
|
+
const raw2 = policy?.publicOrigin;
|
|
18108
|
+
if (!raw2) return null;
|
|
18109
|
+
let url;
|
|
18110
|
+
try {
|
|
18111
|
+
url = new URL(raw2);
|
|
18112
|
+
} catch {
|
|
18113
|
+
return null;
|
|
18114
|
+
}
|
|
18115
|
+
if (url.origin !== raw2) return null;
|
|
18116
|
+
return {
|
|
18117
|
+
hostname: normalizedHostname(url.hostname),
|
|
18118
|
+
port: explicitPort(url),
|
|
18119
|
+
authority: url.host.toLowerCase(),
|
|
18120
|
+
scheme: url.protocol === "https:" ? "https" : "http"
|
|
18121
|
+
};
|
|
18122
|
+
}
|
|
18123
|
+
function acceptsHostname(hostname, policy) {
|
|
18124
|
+
if (LOCAL_HOSTNAMES.has(hostname)) return true;
|
|
18125
|
+
if (!policy?.exposed) return false;
|
|
18126
|
+
if (isIP(hostname) !== 0) return true;
|
|
18127
|
+
return (policy.allowedHosts ?? []).some((allowed) => allowed === "*" || allowed.toLowerCase() === hostname);
|
|
18128
|
+
}
|
|
18129
|
+
function oneHeader(value) {
|
|
18130
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
18131
|
+
}
|
|
18132
|
+
function normalizedHostname(hostname) {
|
|
18133
|
+
const lower = hostname.toLowerCase();
|
|
18134
|
+
return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
|
|
18135
|
+
}
|
|
18136
|
+
function explicitPort(url) {
|
|
18137
|
+
if (url.port) return Number(url.port);
|
|
18138
|
+
return url.protocol === "https:" ? 443 : 80;
|
|
18139
|
+
}
|
|
18140
|
+
function validExpectedPort(port2) {
|
|
18141
|
+
return Number.isInteger(port2) && port2 >= 1 && port2 <= 65535;
|
|
18142
|
+
}
|
|
18143
|
+
function parseLocalHttpOrigin(value, expectedPort, policy) {
|
|
18144
|
+
const raw2 = oneHeader(value);
|
|
18145
|
+
if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim()) return null;
|
|
18146
|
+
const declared = publicAuthority(policy);
|
|
18147
|
+
if (declared && raw2 === policy?.publicOrigin) return declared;
|
|
18148
|
+
let url;
|
|
18149
|
+
try {
|
|
18150
|
+
url = new URL(raw2);
|
|
18151
|
+
} catch {
|
|
18152
|
+
return null;
|
|
18153
|
+
}
|
|
18154
|
+
if (url.protocol !== "http:" || url.origin !== raw2) return null;
|
|
18155
|
+
const hostname = normalizedHostname(url.hostname);
|
|
18156
|
+
if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
|
|
18157
|
+
return { hostname, port: expectedPort, authority: url.host, scheme: "http" };
|
|
18158
|
+
}
|
|
18159
|
+
function parseLocalHost(value, expectedPort, policy) {
|
|
18160
|
+
const raw2 = oneHeader(value);
|
|
18161
|
+
if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim() || raw2.includes(",")) return null;
|
|
18162
|
+
let url;
|
|
18163
|
+
try {
|
|
18164
|
+
url = new URL(`http://${raw2}`);
|
|
18165
|
+
} catch {
|
|
18166
|
+
return null;
|
|
18167
|
+
}
|
|
18168
|
+
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) return null;
|
|
18169
|
+
if (url.host.toLowerCase() !== raw2.toLowerCase()) return null;
|
|
18170
|
+
const hostname = normalizedHostname(url.hostname);
|
|
18171
|
+
const declared = publicAuthority(policy);
|
|
18172
|
+
if (declared && hostname === declared.hostname) {
|
|
18173
|
+
return url.port === "" || Number(url.port) === declared.port ? declared : null;
|
|
18174
|
+
}
|
|
18175
|
+
if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
|
|
18176
|
+
return { hostname, port: expectedPort, authority: url.host.toLowerCase(), scheme: "http" };
|
|
18177
|
+
}
|
|
18178
|
+
function hasForwardedAuthority(headers) {
|
|
18179
|
+
return FORWARDED_HEADERS.some((name) => headers[name] !== void 0);
|
|
18180
|
+
}
|
|
18181
|
+
function forwardedAuthorityAllowed(headers, host, policy) {
|
|
18182
|
+
if (!hasForwardedAuthority(headers)) return true;
|
|
18183
|
+
const declared = publicAuthority(policy);
|
|
18184
|
+
return !!declared && declared.hostname === host.hostname;
|
|
18185
|
+
}
|
|
18186
|
+
function isTrustedLocalHttpRequest(headers, expectedPort, allowMissingOrigin = false, policy) {
|
|
18187
|
+
const host = parseLocalHost(headers.host, expectedPort, policy);
|
|
18188
|
+
if (!host) return false;
|
|
18189
|
+
if (!forwardedAuthorityAllowed(headers, host, policy)) return false;
|
|
18190
|
+
if (headers.origin === void 0) return allowMissingOrigin;
|
|
18191
|
+
const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
|
|
18192
|
+
return !!origin && host.hostname === origin.hostname && host.port === origin.port;
|
|
18193
|
+
}
|
|
18194
|
+
function allowedLocalCorsOrigin(origin, expectedPort, policy) {
|
|
18195
|
+
return parseLocalHttpOrigin(origin, expectedPort, policy) ? origin : void 0;
|
|
18196
|
+
}
|
|
18197
|
+
function isTrustedLocalWebSocketRequest(req, expectedPort = req.socket.localPort, policy) {
|
|
18198
|
+
if (!validExpectedPort(expectedPort)) return false;
|
|
18199
|
+
const headers = req.headers;
|
|
18200
|
+
const host = parseLocalHost(headers.host, expectedPort, policy);
|
|
18201
|
+
if (!host || !forwardedAuthorityAllowed(headers, host, policy)) return false;
|
|
18202
|
+
const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
|
|
18203
|
+
return !!origin && host.hostname === origin.hostname && host.port === origin.port;
|
|
18204
|
+
}
|
|
18205
|
+
function rejectWebSocketUpgrade(socket, status = 403, reason = "Forbidden") {
|
|
18206
|
+
const body = `${reason}
|
|
18207
|
+
`;
|
|
18208
|
+
const response = [
|
|
18209
|
+
`HTTP/1.1 ${status} ${reason}`,
|
|
18210
|
+
"Connection: close",
|
|
18211
|
+
"Content-Type: text/plain; charset=utf-8",
|
|
18212
|
+
`Content-Length: ${Buffer.byteLength(body)}`,
|
|
18213
|
+
"",
|
|
18214
|
+
body
|
|
18215
|
+
].join("\r\n");
|
|
18216
|
+
try {
|
|
18217
|
+
socket.end(response);
|
|
18218
|
+
} catch {
|
|
18219
|
+
try {
|
|
18220
|
+
socket.destroy();
|
|
18221
|
+
} catch {
|
|
18222
|
+
}
|
|
18223
|
+
}
|
|
18224
|
+
}
|
|
18225
|
+
var LOCAL_HOSTNAMES, FORWARDED_HEADERS;
|
|
18226
|
+
var init_local_origin = __esm({
|
|
18227
|
+
"packages/server/src/local-origin.ts"() {
|
|
18228
|
+
"use strict";
|
|
18229
|
+
LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
18230
|
+
FORWARDED_HEADERS = [
|
|
18231
|
+
"forwarded",
|
|
18232
|
+
"x-forwarded-for",
|
|
18233
|
+
"x-forwarded-host",
|
|
18234
|
+
"x-forwarded-port",
|
|
18235
|
+
"x-forwarded-proto"
|
|
18236
|
+
];
|
|
18237
|
+
}
|
|
18238
|
+
});
|
|
18239
|
+
|
|
18240
|
+
// packages/server/src/local-path.ts
|
|
18241
|
+
function normalizeLocalPath(path3, platform3 = process.platform) {
|
|
18242
|
+
return platform3 === "win32" ? path3.replace(/^\/([a-zA-Z]:[\\/])/, "$1") : path3;
|
|
18243
|
+
}
|
|
18244
|
+
var init_local_path = __esm({
|
|
18245
|
+
"packages/server/src/local-path.ts"() {
|
|
18246
|
+
"use strict";
|
|
18247
|
+
}
|
|
18248
|
+
});
|
|
18249
|
+
|
|
18250
|
+
// packages/server/src/local-image.ts
|
|
18251
|
+
import { createReadStream, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
|
|
18252
|
+
import { extname, isAbsolute as isAbsolute3 } from "node:path";
|
|
18253
|
+
function resolveLocalImage(rawPath, range) {
|
|
18254
|
+
if (rawPath) rawPath = normalizeLocalPath(rawPath);
|
|
18255
|
+
if (!rawPath || !isAbsolute3(rawPath)) return { status: 400 };
|
|
18256
|
+
const contentType = CONTENT_TYPE[extname(rawPath).toLowerCase()];
|
|
18257
|
+
if (!contentType) return { status: 400 };
|
|
18258
|
+
let real;
|
|
18259
|
+
try {
|
|
18260
|
+
real = realpathSync5(rawPath);
|
|
18261
|
+
} catch {
|
|
18262
|
+
return { status: 404 };
|
|
18263
|
+
}
|
|
18264
|
+
let size;
|
|
18265
|
+
try {
|
|
18266
|
+
const stat2 = statSync4(real);
|
|
18267
|
+
if (!stat2.isFile()) return { status: 404 };
|
|
18268
|
+
size = stat2.size;
|
|
18269
|
+
} catch {
|
|
18270
|
+
return { status: 404 };
|
|
18271
|
+
}
|
|
18272
|
+
const span = range ? byteRange(range, size) : null;
|
|
18273
|
+
if (span === "unsatisfiable") return { status: 416, size };
|
|
18274
|
+
if (span) return { status: 206, contentType, file: real, size, start: span.start, end: span.end };
|
|
18275
|
+
return { status: 200, contentType, file: real, size, start: 0, end: size - 1 };
|
|
18276
|
+
}
|
|
18277
|
+
function byteRange(header, size) {
|
|
18278
|
+
const match2 = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
|
|
18279
|
+
if (!match2) return null;
|
|
18280
|
+
const [, first, last] = match2;
|
|
18281
|
+
if (first === "" && last === "") return null;
|
|
18282
|
+
if (first === "") {
|
|
18283
|
+
const suffix = Number(last);
|
|
18284
|
+
if (suffix === 0 || size === 0) return "unsatisfiable";
|
|
18285
|
+
return { start: Math.max(size - suffix, 0), end: size - 1 };
|
|
18286
|
+
}
|
|
18287
|
+
const start = Number(first);
|
|
18288
|
+
if (last !== "" && Number(last) < start) return null;
|
|
18289
|
+
if (start >= size) return "unsatisfiable";
|
|
18290
|
+
return { start, end: last === "" ? size - 1 : Math.min(Number(last), size - 1) };
|
|
18291
|
+
}
|
|
18292
|
+
function localImageHeaders(result) {
|
|
18293
|
+
return {
|
|
18294
|
+
"content-type": result.contentType,
|
|
18295
|
+
"content-length": String(result.end - result.start + 1),
|
|
18296
|
+
"accept-ranges": "bytes",
|
|
18297
|
+
"cache-control": "private, max-age=60",
|
|
18298
|
+
...result.status === 206 ? { "content-range": `bytes ${result.start}-${result.end}/${result.size}` } : {}
|
|
18299
|
+
};
|
|
18300
|
+
}
|
|
18301
|
+
function localImageStream(result) {
|
|
18302
|
+
if (result.end < result.start) return null;
|
|
18303
|
+
return createReadStream(result.file, { start: result.start, end: result.end });
|
|
18304
|
+
}
|
|
18305
|
+
var IMAGE_CONTENT_TYPE, VIDEO_CONTENT_TYPE, CONTENT_TYPE;
|
|
18306
|
+
var init_local_image = __esm({
|
|
18307
|
+
"packages/server/src/local-image.ts"() {
|
|
18308
|
+
"use strict";
|
|
18309
|
+
init_local_path();
|
|
18310
|
+
IMAGE_CONTENT_TYPE = {
|
|
18311
|
+
".png": "image/png",
|
|
18312
|
+
".jpg": "image/jpeg",
|
|
18313
|
+
".jpeg": "image/jpeg",
|
|
18314
|
+
".gif": "image/gif",
|
|
18315
|
+
".webp": "image/webp"
|
|
18316
|
+
};
|
|
18317
|
+
VIDEO_CONTENT_TYPE = {
|
|
18318
|
+
".mp4": "video/mp4",
|
|
18319
|
+
".m4v": "video/mp4",
|
|
18320
|
+
".webm": "video/webm",
|
|
18321
|
+
".mov": "video/quicktime"
|
|
18322
|
+
};
|
|
18323
|
+
CONTENT_TYPE = { ...IMAGE_CONTENT_TYPE, ...VIDEO_CONTENT_TYPE };
|
|
18324
|
+
}
|
|
18325
|
+
});
|
|
18326
|
+
|
|
18090
18327
|
// packages/server/src/bus.ts
|
|
18091
18328
|
var Bus, Emitter;
|
|
18092
18329
|
var init_bus = __esm({
|
|
@@ -21229,16 +21466,122 @@ var init_storage = __esm({
|
|
|
21229
21466
|
}
|
|
21230
21467
|
});
|
|
21231
21468
|
|
|
21469
|
+
// packages/server/src/secret-files.ts
|
|
21470
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
21471
|
+
import { chmodSync as chmodSync2, closeSync as closeSync5, constants, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync8, openSync as openSync6, readdirSync as readdirSync3, rmdirSync, rmSync as rmSync6, writeFileSync as writeFileSync7, writeSync as writeSync2 } from "node:fs";
|
|
21472
|
+
import { dirname as dirname7, join as join11 } from "node:path";
|
|
21473
|
+
function secretsRoot(stateDir) {
|
|
21474
|
+
return join11(stateDir, "secrets");
|
|
21475
|
+
}
|
|
21476
|
+
function secretFilePath(stateDir, slug, questionId) {
|
|
21477
|
+
return join11(secretsRoot(stateDir), slug, questionId);
|
|
21478
|
+
}
|
|
21479
|
+
function stop(path3) {
|
|
21480
|
+
const entry = served.get(path3);
|
|
21481
|
+
if (entry) clearInterval(entry.timer);
|
|
21482
|
+
served.delete(path3);
|
|
21483
|
+
rmSync6(path3, { force: true });
|
|
21484
|
+
try {
|
|
21485
|
+
rmdirSync(dirname7(path3));
|
|
21486
|
+
} catch {
|
|
21487
|
+
}
|
|
21488
|
+
}
|
|
21489
|
+
function serveSecret(stateDir, slug, questionId, value, opts = {}) {
|
|
21490
|
+
const now = opts.now ?? Date.now;
|
|
21491
|
+
const expiresAt = now() + (opts.ttlMs ?? SECRET_TTL_MS);
|
|
21492
|
+
const root = secretsRoot(stateDir);
|
|
21493
|
+
const dir = join11(root, slug);
|
|
21494
|
+
const path3 = secretFilePath(stateDir, slug, questionId);
|
|
21495
|
+
stop(path3);
|
|
21496
|
+
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
21497
|
+
chmodSync2(root, 448);
|
|
21498
|
+
chmodSync2(dir, 448);
|
|
21499
|
+
if ((opts.platform ?? process.platform) === "win32") {
|
|
21500
|
+
writeFileSync7(path3, value, { mode: 384 });
|
|
21501
|
+
const timer2 = setInterval(() => {
|
|
21502
|
+
if (now() >= expiresAt || !existsSync5(path3)) stop(path3);
|
|
21503
|
+
}, 1e3);
|
|
21504
|
+
timer2.unref();
|
|
21505
|
+
served.set(path3, { timer: timer2 });
|
|
21506
|
+
return path3;
|
|
21507
|
+
}
|
|
21508
|
+
execFileSync4("mkfifo", ["-m", "600", path3]);
|
|
21509
|
+
const bytes = Buffer.from(value, "utf8");
|
|
21510
|
+
const timer = setInterval(() => {
|
|
21511
|
+
if (now() >= expiresAt || !existsSync5(path3)) return stop(path3);
|
|
21512
|
+
let fd2;
|
|
21513
|
+
try {
|
|
21514
|
+
fd2 = openSync6(path3, constants.O_WRONLY | constants.O_NONBLOCK);
|
|
21515
|
+
} catch {
|
|
21516
|
+
return;
|
|
21517
|
+
}
|
|
21518
|
+
let delivered = false;
|
|
21519
|
+
try {
|
|
21520
|
+
delivered = writeSync2(fd2, bytes) === bytes.length;
|
|
21521
|
+
} catch {
|
|
21522
|
+
} finally {
|
|
21523
|
+
closeSync5(fd2);
|
|
21524
|
+
}
|
|
21525
|
+
if (delivered) stop(path3);
|
|
21526
|
+
}, POLL_MS2);
|
|
21527
|
+
timer.unref();
|
|
21528
|
+
served.set(path3, { timer });
|
|
21529
|
+
return path3;
|
|
21530
|
+
}
|
|
21531
|
+
function clearSecrets(stateDir) {
|
|
21532
|
+
const root = secretsRoot(stateDir);
|
|
21533
|
+
let removed = 0;
|
|
21534
|
+
let threads;
|
|
21535
|
+
try {
|
|
21536
|
+
threads = readdirSync3(root);
|
|
21537
|
+
} catch {
|
|
21538
|
+
return 0;
|
|
21539
|
+
}
|
|
21540
|
+
for (const thread of threads) {
|
|
21541
|
+
const dir = join11(root, thread);
|
|
21542
|
+
let entries2;
|
|
21543
|
+
try {
|
|
21544
|
+
if (!lstatSync(dir).isDirectory()) {
|
|
21545
|
+
rmSync6(dir, { force: true });
|
|
21546
|
+
continue;
|
|
21547
|
+
}
|
|
21548
|
+
entries2 = readdirSync3(dir);
|
|
21549
|
+
} catch {
|
|
21550
|
+
continue;
|
|
21551
|
+
}
|
|
21552
|
+
for (const entry of entries2) {
|
|
21553
|
+
const path3 = join11(dir, entry);
|
|
21554
|
+
if (served.has(path3)) continue;
|
|
21555
|
+
rmSync6(path3, { force: true });
|
|
21556
|
+
removed++;
|
|
21557
|
+
}
|
|
21558
|
+
try {
|
|
21559
|
+
if (readdirSync3(dir).length === 0) rmSync6(dir, { recursive: true, force: true });
|
|
21560
|
+
} catch {
|
|
21561
|
+
}
|
|
21562
|
+
}
|
|
21563
|
+
return removed;
|
|
21564
|
+
}
|
|
21565
|
+
var POLL_MS2, served;
|
|
21566
|
+
var init_secret_files = __esm({
|
|
21567
|
+
"packages/server/src/secret-files.ts"() {
|
|
21568
|
+
"use strict";
|
|
21569
|
+
init_src();
|
|
21570
|
+
POLL_MS2 = 100;
|
|
21571
|
+
served = /* @__PURE__ */ new Map();
|
|
21572
|
+
}
|
|
21573
|
+
});
|
|
21574
|
+
|
|
21232
21575
|
// packages/server/src/machine-config.ts
|
|
21233
|
-
import { closeSync as
|
|
21234
|
-
import { dirname as
|
|
21576
|
+
import { closeSync as closeSync6, fsyncSync as fsyncSync5, mkdirSync as mkdirSync9, openSync as openSync7, readFileSync as readFileSync8, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
21577
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
21235
21578
|
function machineConfigPath(home) {
|
|
21236
|
-
return
|
|
21579
|
+
return join12(frizzPaths({ home }).data, "config.json");
|
|
21237
21580
|
}
|
|
21238
21581
|
function readAll(home) {
|
|
21239
21582
|
let raw2;
|
|
21240
21583
|
try {
|
|
21241
|
-
raw2 = JSON.parse(
|
|
21584
|
+
raw2 = JSON.parse(readFileSync8(machineConfigPath(home), "utf8"));
|
|
21242
21585
|
} catch {
|
|
21243
21586
|
return {};
|
|
21244
21587
|
}
|
|
@@ -21246,24 +21589,24 @@ function readAll(home) {
|
|
|
21246
21589
|
}
|
|
21247
21590
|
function writeAll(home, all) {
|
|
21248
21591
|
const path3 = machineConfigPath(home);
|
|
21249
|
-
|
|
21592
|
+
mkdirSync9(dirname8(path3), { recursive: true });
|
|
21250
21593
|
const temp = `${path3}.${process.pid}.tmp`;
|
|
21251
21594
|
let fd2;
|
|
21252
21595
|
try {
|
|
21253
|
-
fd2 =
|
|
21254
|
-
|
|
21596
|
+
fd2 = openSync7(temp, "w", 384);
|
|
21597
|
+
writeFileSync8(fd2, `${JSON.stringify(all, null, 2)}
|
|
21255
21598
|
`, "utf8");
|
|
21256
21599
|
fsyncSync5(fd2);
|
|
21257
|
-
|
|
21600
|
+
closeSync6(fd2);
|
|
21258
21601
|
fd2 = void 0;
|
|
21259
21602
|
renameSync5(temp, path3);
|
|
21260
21603
|
} catch {
|
|
21261
21604
|
if (fd2 !== void 0) try {
|
|
21262
|
-
|
|
21605
|
+
closeSync6(fd2);
|
|
21263
21606
|
} catch {
|
|
21264
21607
|
}
|
|
21265
21608
|
try {
|
|
21266
|
-
|
|
21609
|
+
rmSync7(temp, { force: true });
|
|
21267
21610
|
} catch {
|
|
21268
21611
|
}
|
|
21269
21612
|
}
|
|
@@ -21291,10 +21634,10 @@ var init_machine_config = __esm({
|
|
|
21291
21634
|
});
|
|
21292
21635
|
|
|
21293
21636
|
// packages/server/src/settings.ts
|
|
21294
|
-
import { readFileSync as
|
|
21295
|
-
import { join as
|
|
21637
|
+
import { readFileSync as readFileSync9, rmSync as rmSync8 } from "node:fs";
|
|
21638
|
+
import { join as join13 } from "node:path";
|
|
21296
21639
|
function legacyMachineSettingsPath(home) {
|
|
21297
|
-
return
|
|
21640
|
+
return join13(frizzPaths({ home }).data, "settings.json");
|
|
21298
21641
|
}
|
|
21299
21642
|
function pickMachine(settings) {
|
|
21300
21643
|
return Object.fromEntries(MACHINE_KEYS.map((key) => [key, settings[key]]));
|
|
@@ -21304,7 +21647,7 @@ function readMachineSettings(home) {
|
|
|
21304
21647
|
if (stored) return pickPresent(stored);
|
|
21305
21648
|
let raw2;
|
|
21306
21649
|
try {
|
|
21307
|
-
raw2 = JSON.parse(
|
|
21650
|
+
raw2 = JSON.parse(readFileSync9(legacyMachineSettingsPath(home), "utf8"));
|
|
21308
21651
|
} catch {
|
|
21309
21652
|
return {};
|
|
21310
21653
|
}
|
|
@@ -21335,7 +21678,7 @@ function resetSettings(storage, home) {
|
|
|
21335
21678
|
storage.deleteSetting(SETTINGS_KEY);
|
|
21336
21679
|
deleteMachineConfig(home, SETTINGS_KEY);
|
|
21337
21680
|
try {
|
|
21338
|
-
|
|
21681
|
+
rmSync8(legacyMachineSettingsPath(home), { force: true });
|
|
21339
21682
|
} catch {
|
|
21340
21683
|
}
|
|
21341
21684
|
return defaultSettings();
|
|
@@ -21635,15 +21978,15 @@ var init_codex_error = __esm({
|
|
|
21635
21978
|
});
|
|
21636
21979
|
|
|
21637
21980
|
// packages/server/src/discover.ts
|
|
21638
|
-
import { readdirSync as
|
|
21639
|
-
import { dirname as
|
|
21981
|
+
import { readdirSync as readdirSync4, statSync as statSync5, openSync as openSync8, readSync, closeSync as closeSync7 } from "node:fs";
|
|
21982
|
+
import { dirname as dirname9, join as join14 } from "node:path";
|
|
21640
21983
|
function sentinelFor(sessionId) {
|
|
21641
21984
|
return `threads/${sessionId}/`;
|
|
21642
21985
|
}
|
|
21643
21986
|
function readHead(path3) {
|
|
21644
21987
|
let fd2;
|
|
21645
21988
|
try {
|
|
21646
|
-
fd2 =
|
|
21989
|
+
fd2 = openSync8(path3, "r");
|
|
21647
21990
|
const buf = Buffer.allocUnsafe(HEAD_BYTES);
|
|
21648
21991
|
const n = readSync(fd2, buf, 0, HEAD_BYTES, 0);
|
|
21649
21992
|
return buf.toString("utf8", 0, n);
|
|
@@ -21652,7 +21995,7 @@ function readHead(path3) {
|
|
|
21652
21995
|
} finally {
|
|
21653
21996
|
if (fd2 !== void 0) {
|
|
21654
21997
|
try {
|
|
21655
|
-
|
|
21998
|
+
closeSync7(fd2);
|
|
21656
21999
|
} catch {
|
|
21657
22000
|
}
|
|
21658
22001
|
}
|
|
@@ -21664,7 +22007,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
21664
22007
|
const sentinel = sentinelFor(sessionId);
|
|
21665
22008
|
let names;
|
|
21666
22009
|
try {
|
|
21667
|
-
names =
|
|
22010
|
+
names = readdirSync4(logDir);
|
|
21668
22011
|
} catch {
|
|
21669
22012
|
return void 0;
|
|
21670
22013
|
}
|
|
@@ -21673,10 +22016,10 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
21673
22016
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
21674
22017
|
const id2 = name.slice(0, -".jsonl".length);
|
|
21675
22018
|
if (!id2 || id2 === sessionId || exclude?.has(id2)) continue;
|
|
21676
|
-
const path3 =
|
|
22019
|
+
const path3 = join14(logDir, name);
|
|
21677
22020
|
let mtime;
|
|
21678
22021
|
try {
|
|
21679
|
-
mtime =
|
|
22022
|
+
mtime = statSync5(path3).mtimeMs;
|
|
21680
22023
|
} catch {
|
|
21681
22024
|
continue;
|
|
21682
22025
|
}
|
|
@@ -21691,7 +22034,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
21691
22034
|
}
|
|
21692
22035
|
function mtimeOfNonEmpty(path3) {
|
|
21693
22036
|
try {
|
|
21694
|
-
const st2 =
|
|
22037
|
+
const st2 = statSync5(path3, { throwIfNoEntry: false });
|
|
21695
22038
|
return st2 && st2.size > 0 ? st2.mtimeMs : void 0;
|
|
21696
22039
|
} catch {
|
|
21697
22040
|
return void 0;
|
|
@@ -21701,7 +22044,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
|
|
|
21701
22044
|
const name = `${sessionId}.jsonl`;
|
|
21702
22045
|
const better = (best2, dir) => {
|
|
21703
22046
|
if (dir === logDir) return best2;
|
|
21704
|
-
const at2 = mtimeOfNonEmpty(
|
|
22047
|
+
const at2 = mtimeOfNonEmpty(join14(dir, name));
|
|
21705
22048
|
if (at2 === void 0) return best2;
|
|
21706
22049
|
return !best2 || at2 > best2.mtimeMs ? { dir, mtimeMs: at2 } : best2;
|
|
21707
22050
|
};
|
|
@@ -21710,11 +22053,11 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
|
|
|
21710
22053
|
if (best) return best.dir;
|
|
21711
22054
|
let entries2;
|
|
21712
22055
|
try {
|
|
21713
|
-
entries2 =
|
|
22056
|
+
entries2 = readdirSync4(dirname9(logDir), { withFileTypes: true }).filter((e14) => e14.isDirectory()).map((e14) => e14.name);
|
|
21714
22057
|
} catch {
|
|
21715
22058
|
return void 0;
|
|
21716
22059
|
}
|
|
21717
|
-
for (const entry of entries2) best = better(best,
|
|
22060
|
+
for (const entry of entries2) best = better(best, join14(dirname9(logDir), entry));
|
|
21718
22061
|
if (!best) return void 0;
|
|
21719
22062
|
memo3.add(best.dir);
|
|
21720
22063
|
return best.dir;
|
|
@@ -21800,27 +22143,27 @@ var init_types2 = __esm({
|
|
|
21800
22143
|
});
|
|
21801
22144
|
|
|
21802
22145
|
// packages/server/src/session-files.ts
|
|
21803
|
-
import { chmodSync, lstatSync, mkdirSync as
|
|
21804
|
-
import { join as
|
|
22146
|
+
import { chmodSync as chmodSync3, lstatSync as lstatSync2, mkdirSync as mkdirSync10, rmSync as rmSync9, writeFileSync as writeFileSync9 } from "node:fs";
|
|
22147
|
+
import { join as join15 } from "node:path";
|
|
21805
22148
|
function systemPromptPath(sessionId) {
|
|
21806
22149
|
if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
|
|
21807
|
-
return
|
|
22150
|
+
return join15(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
|
|
21808
22151
|
}
|
|
21809
22152
|
function mcpConfigPath(sessionId) {
|
|
21810
22153
|
if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
|
|
21811
|
-
return
|
|
22154
|
+
return join15(MCP_CONFIG_DIR, `${sessionId}.json`);
|
|
21812
22155
|
}
|
|
21813
22156
|
function writeMcpConfigFile(sessionId, mcpServers) {
|
|
21814
22157
|
const path3 = mcpConfigPath(sessionId);
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
|
|
22158
|
+
mkdirSync10(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
|
|
22159
|
+
chmodSync3(MCP_CONFIG_DIR, 448);
|
|
22160
|
+
writeFileSync9(path3, JSON.stringify({ mcpServers }), { mode: 384 });
|
|
22161
|
+
chmodSync3(path3, 384);
|
|
21819
22162
|
return path3;
|
|
21820
22163
|
}
|
|
21821
22164
|
function isDirectDirectory(path3) {
|
|
21822
22165
|
try {
|
|
21823
|
-
const stat2 =
|
|
22166
|
+
const stat2 = lstatSync2(path3);
|
|
21824
22167
|
return stat2.isDirectory() && !stat2.isSymbolicLink();
|
|
21825
22168
|
} catch {
|
|
21826
22169
|
return false;
|
|
@@ -21828,7 +22171,7 @@ function isDirectDirectory(path3) {
|
|
|
21828
22171
|
}
|
|
21829
22172
|
function pathAbsent(path3) {
|
|
21830
22173
|
try {
|
|
21831
|
-
|
|
22174
|
+
lstatSync2(path3);
|
|
21832
22175
|
return false;
|
|
21833
22176
|
} catch (error) {
|
|
21834
22177
|
return error.code === "ENOENT";
|
|
@@ -21836,9 +22179,9 @@ function pathAbsent(path3) {
|
|
|
21836
22179
|
}
|
|
21837
22180
|
function unlinkDirectChild(parent, filename) {
|
|
21838
22181
|
if (!isDirectDirectory(parent)) return pathAbsent(parent);
|
|
21839
|
-
const child =
|
|
22182
|
+
const child = join15(parent, filename);
|
|
21840
22183
|
try {
|
|
21841
|
-
|
|
22184
|
+
rmSync9(child, { force: true });
|
|
21842
22185
|
} catch {
|
|
21843
22186
|
return false;
|
|
21844
22187
|
}
|
|
@@ -21846,14 +22189,14 @@ function unlinkDirectChild(parent, filename) {
|
|
|
21846
22189
|
}
|
|
21847
22190
|
function cleanupAdoptionSessionFiles(projectDir, sessionId) {
|
|
21848
22191
|
if (!SESSION_ID_RE.test(sessionId)) return false;
|
|
21849
|
-
const frizzDir =
|
|
22192
|
+
const frizzDir = join15(projectDir, ".frizz");
|
|
21850
22193
|
let clean = true;
|
|
21851
22194
|
if (isDirectDirectory(frizzDir)) {
|
|
21852
|
-
const threads =
|
|
22195
|
+
const threads = join15(frizzDir, "threads");
|
|
21853
22196
|
if (isDirectDirectory(threads)) {
|
|
21854
|
-
const child =
|
|
22197
|
+
const child = join15(threads, sessionId);
|
|
21855
22198
|
try {
|
|
21856
|
-
|
|
22199
|
+
rmSync9(child, { recursive: true, force: true });
|
|
21857
22200
|
} catch {
|
|
21858
22201
|
clean = false;
|
|
21859
22202
|
}
|
|
@@ -22105,10 +22448,10 @@ var init_adoption_recovery = __esm({
|
|
|
22105
22448
|
});
|
|
22106
22449
|
|
|
22107
22450
|
// packages/server/src/backend/codex-models.ts
|
|
22108
|
-
import { join as
|
|
22109
|
-
import { readFileSync as
|
|
22451
|
+
import { join as join16 } from "node:path";
|
|
22452
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
22110
22453
|
function cachePath(codexHome) {
|
|
22111
|
-
return
|
|
22454
|
+
return join16(codexHome, "models_cache.json");
|
|
22112
22455
|
}
|
|
22113
22456
|
function toCodexModel(raw2) {
|
|
22114
22457
|
if (!raw2 || typeof raw2 !== "object") return void 0;
|
|
@@ -22162,7 +22505,7 @@ function readCodexModels(codexHome = defaultCodexHome(), expectedClientVersion,
|
|
|
22162
22505
|
if (hit && nowMs - hit.at < TTL_MS) return hit.models;
|
|
22163
22506
|
let models;
|
|
22164
22507
|
try {
|
|
22165
|
-
const raw2 =
|
|
22508
|
+
const raw2 = readFileSync10(path3, "utf8");
|
|
22166
22509
|
models = parseCodexModelsCache(raw2, expectedClientVersion, trusted.get(key));
|
|
22167
22510
|
let writer;
|
|
22168
22511
|
try {
|
|
@@ -22839,10 +23182,10 @@ var init_claude_agent_sdk_protocol = __esm({
|
|
|
22839
23182
|
});
|
|
22840
23183
|
|
|
22841
23184
|
// packages/server/src/backend/claude-broker-diagnostics.ts
|
|
22842
|
-
import { appendFileSync as appendFileSync2, mkdirSync as
|
|
22843
|
-
import { join as
|
|
23185
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync11, readFileSync as readFileSync11, renameSync as renameSync6, statSync as statSync6 } from "node:fs";
|
|
23186
|
+
import { join as join17 } from "node:path";
|
|
22844
23187
|
function claudeBrokerDiagnosticLogPath(stateDir, sessionId) {
|
|
22845
|
-
return
|
|
23188
|
+
return join17(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
|
|
22846
23189
|
}
|
|
22847
23190
|
function readClaudeBrokerExit(stateDir, sessionId, generation) {
|
|
22848
23191
|
if (!generation) return null;
|
|
@@ -22850,7 +23193,7 @@ function readClaudeBrokerExit(stateDir, sessionId, generation) {
|
|
|
22850
23193
|
for (const path3 of [`${claudeBrokerDiagnosticLogPath(stateDir, sessionId)}.1`, claudeBrokerDiagnosticLogPath(stateDir, sessionId)]) {
|
|
22851
23194
|
let text2;
|
|
22852
23195
|
try {
|
|
22853
|
-
text2 =
|
|
23196
|
+
text2 = readFileSync11(path3, "utf8");
|
|
22854
23197
|
} catch {
|
|
22855
23198
|
continue;
|
|
22856
23199
|
}
|
|
@@ -22903,11 +23246,11 @@ var init_claude_broker_diagnostics = __esm({
|
|
|
22903
23246
|
});
|
|
22904
23247
|
|
|
22905
23248
|
// packages/server/src/detached-daemons.ts
|
|
22906
|
-
import { existsSync as
|
|
23249
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
22907
23250
|
import { fileURLToPath } from "node:url";
|
|
22908
23251
|
function resolveDetachedDaemonEntry(moduleUrl, basename14) {
|
|
22909
23252
|
const candidates = [`./${basename14}.js`, `./${basename14}.ts`].map((rel) => fileURLToPath(new URL(rel, moduleUrl)));
|
|
22910
|
-
const found = candidates.find((path3) =>
|
|
23253
|
+
const found = candidates.find((path3) => existsSync6(path3));
|
|
22911
23254
|
if (!found) throw new Error(`frizz is missing the ${basename14} entry \u2014 looked for ${candidates.join(" and ")}`);
|
|
22912
23255
|
return found;
|
|
22913
23256
|
}
|
|
@@ -22947,10 +23290,10 @@ var init_daemon_tree = __esm({
|
|
|
22947
23290
|
});
|
|
22948
23291
|
|
|
22949
23292
|
// packages/server/src/backend/ipc-path.ts
|
|
22950
|
-
import { join as
|
|
23293
|
+
import { join as join18 } from "node:path";
|
|
22951
23294
|
function frizzIpcPath(name) {
|
|
22952
23295
|
if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
|
|
22953
|
-
return
|
|
23296
|
+
return join18(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
|
|
22954
23297
|
}
|
|
22955
23298
|
var init_ipc_path = __esm({
|
|
22956
23299
|
"packages/server/src/backend/ipc-path.ts"() {
|
|
@@ -22961,18 +23304,18 @@ var init_ipc_path = __esm({
|
|
|
22961
23304
|
// packages/server/src/backend/claude-broker-host.ts
|
|
22962
23305
|
import { spawn } from "node:child_process";
|
|
22963
23306
|
import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
|
|
22964
|
-
import { accessSync, constants as fsConstants, mkdirSync as
|
|
22965
|
-
import { delimiter, dirname as
|
|
23307
|
+
import { accessSync, constants as fsConstants, mkdirSync as mkdirSync12, readFileSync as readFileSync12, readdirSync as readdirSync5, unlinkSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
23308
|
+
import { delimiter, dirname as dirname10, isAbsolute as isAbsolute4, join as join19 } from "node:path";
|
|
22966
23309
|
function windowsShimTarget(shimPath) {
|
|
22967
23310
|
let body;
|
|
22968
23311
|
try {
|
|
22969
|
-
body =
|
|
23312
|
+
body = readFileSync12(shimPath, "utf8");
|
|
22970
23313
|
} catch {
|
|
22971
23314
|
return void 0;
|
|
22972
23315
|
}
|
|
22973
23316
|
const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
|
|
22974
23317
|
if (!target) return void 0;
|
|
22975
|
-
const full =
|
|
23318
|
+
const full = join19(dirname10(shimPath), target);
|
|
22976
23319
|
try {
|
|
22977
23320
|
accessSync(full, fsConstants.F_OK);
|
|
22978
23321
|
return full;
|
|
@@ -22988,22 +23331,22 @@ function searchPath(env) {
|
|
|
22988
23331
|
}
|
|
22989
23332
|
function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
22990
23333
|
const candidate = bin && bin.length > 0 ? bin : "claude";
|
|
22991
|
-
if (
|
|
23334
|
+
if (isAbsolute4(candidate)) return candidate;
|
|
22992
23335
|
const windows = process.platform === "win32";
|
|
22993
23336
|
for (const dir of searchPath(env).split(delimiter)) {
|
|
22994
23337
|
if (!dir) continue;
|
|
22995
23338
|
if (windows) {
|
|
22996
|
-
const exe2 =
|
|
23339
|
+
const exe2 = join19(dir, `${candidate}.exe`);
|
|
22997
23340
|
try {
|
|
22998
23341
|
accessSync(exe2, fsConstants.F_OK);
|
|
22999
23342
|
return exe2;
|
|
23000
23343
|
} catch {
|
|
23001
23344
|
}
|
|
23002
|
-
const viaShim = windowsShimTarget(
|
|
23345
|
+
const viaShim = windowsShimTarget(join19(dir, `${candidate}.cmd`));
|
|
23003
23346
|
if (viaShim) return viaShim;
|
|
23004
23347
|
continue;
|
|
23005
23348
|
}
|
|
23006
|
-
const full =
|
|
23349
|
+
const full = join19(dir, candidate);
|
|
23007
23350
|
try {
|
|
23008
23351
|
accessSync(full, fsConstants.X_OK);
|
|
23009
23352
|
return full;
|
|
@@ -23018,18 +23361,18 @@ function claudeBrokerSocketPath(stateDir, sessionId) {
|
|
|
23018
23361
|
}
|
|
23019
23362
|
function claudeBrokerRecordPath(stateDir, sessionId) {
|
|
23020
23363
|
const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
23021
|
-
return
|
|
23364
|
+
return join19(stateDir, "claude-broker", `${key}.json`);
|
|
23022
23365
|
}
|
|
23023
23366
|
function claudeBrokerRetirementPath(stateDir, sessionId) {
|
|
23024
23367
|
const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
23025
|
-
return
|
|
23368
|
+
return join19(stateDir, "claude-broker", `${key}.retired`);
|
|
23026
23369
|
}
|
|
23027
23370
|
function markBrokerRetired(stateDir, sessionId, reason, generation) {
|
|
23028
23371
|
const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
|
|
23029
23372
|
try {
|
|
23030
23373
|
const path3 = claudeBrokerRetirementPath(stateDir, sessionId);
|
|
23031
|
-
|
|
23032
|
-
|
|
23374
|
+
mkdirSync12(dirname10(path3), { recursive: true });
|
|
23375
|
+
writeFileSync10(path3, JSON.stringify(mark));
|
|
23033
23376
|
} catch {
|
|
23034
23377
|
}
|
|
23035
23378
|
}
|
|
@@ -23037,7 +23380,7 @@ function takeBrokerRetirement(stateDir, sessionId) {
|
|
|
23037
23380
|
const path3 = claudeBrokerRetirementPath(stateDir, sessionId);
|
|
23038
23381
|
let mark = null;
|
|
23039
23382
|
try {
|
|
23040
|
-
const parsed = JSON.parse(
|
|
23383
|
+
const parsed = JSON.parse(readFileSync12(path3, "utf8"));
|
|
23041
23384
|
if (typeof parsed?.at === "string" && typeof parsed.generation === "string" && typeof parsed.reason === "string") {
|
|
23042
23385
|
mark = { at: parsed.at, generation: parsed.generation, reason: parsed.reason };
|
|
23043
23386
|
}
|
|
@@ -23059,7 +23402,7 @@ function pidAlive(pid) {
|
|
|
23059
23402
|
}
|
|
23060
23403
|
function readBrokerRecord(recordPath2) {
|
|
23061
23404
|
try {
|
|
23062
|
-
return JSON.parse(
|
|
23405
|
+
return JSON.parse(readFileSync12(recordPath2, "utf8"));
|
|
23063
23406
|
} catch {
|
|
23064
23407
|
return null;
|
|
23065
23408
|
}
|
|
@@ -23072,7 +23415,7 @@ function lastKnownBrokerDaemon(stateDir, sessionId) {
|
|
|
23072
23415
|
}
|
|
23073
23416
|
function rememberBrokerIdentity(recordPath2, record) {
|
|
23074
23417
|
try {
|
|
23075
|
-
|
|
23418
|
+
writeFileSync10(brokerLastKnownPath(recordPath2), JSON.stringify(record));
|
|
23076
23419
|
} catch {
|
|
23077
23420
|
}
|
|
23078
23421
|
}
|
|
@@ -23089,17 +23432,17 @@ function liveBrokerRecord(recordPath2) {
|
|
|
23089
23432
|
return null;
|
|
23090
23433
|
}
|
|
23091
23434
|
function liveBrokerRecords(stateDir) {
|
|
23092
|
-
const dir =
|
|
23435
|
+
const dir = join19(stateDir, "claude-broker");
|
|
23093
23436
|
let names;
|
|
23094
23437
|
try {
|
|
23095
|
-
names =
|
|
23438
|
+
names = readdirSync5(dir);
|
|
23096
23439
|
} catch {
|
|
23097
23440
|
return [];
|
|
23098
23441
|
}
|
|
23099
23442
|
const out = [];
|
|
23100
23443
|
for (const name of names) {
|
|
23101
23444
|
if (!name.endsWith(".json")) continue;
|
|
23102
|
-
const record = liveBrokerRecord(
|
|
23445
|
+
const record = liveBrokerRecord(join19(dir, name));
|
|
23103
23446
|
if (record) out.push(record);
|
|
23104
23447
|
}
|
|
23105
23448
|
return out;
|
|
@@ -23107,7 +23450,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
23107
23450
|
function forkBroker(options) {
|
|
23108
23451
|
const socketPath = claudeBrokerSocketPath(options.stateDir, options.sessionId);
|
|
23109
23452
|
const recordPath2 = claudeBrokerRecordPath(options.stateDir, options.sessionId);
|
|
23110
|
-
|
|
23453
|
+
mkdirSync12(dirname10(recordPath2), { recursive: true });
|
|
23111
23454
|
const generation = randomUUID8();
|
|
23112
23455
|
const config = {
|
|
23113
23456
|
socketPath,
|
|
@@ -23717,7 +24060,7 @@ var init_delivery_ledger = __esm({
|
|
|
23717
24060
|
});
|
|
23718
24061
|
|
|
23719
24062
|
// packages/server/src/codex-subagents.ts
|
|
23720
|
-
import { closeSync as
|
|
24063
|
+
import { closeSync as closeSync8, openSync as openSync9, readSync as readSync2, statSync as statSync7 } from "node:fs";
|
|
23721
24064
|
function createCodexSubAgentTracker(deps) {
|
|
23722
24065
|
const findRollouts = deps.findRollouts ?? ((ids) => findRolloutsByIds(ids, deps.codexHome));
|
|
23723
24066
|
const readAppended = deps.readAppended ?? defaultReadAppended;
|
|
@@ -23909,7 +24252,7 @@ function agentLabel(path3) {
|
|
|
23909
24252
|
function defaultReadAppended(path3, offset) {
|
|
23910
24253
|
let size;
|
|
23911
24254
|
try {
|
|
23912
|
-
size =
|
|
24255
|
+
size = statSync7(path3).size;
|
|
23913
24256
|
} catch {
|
|
23914
24257
|
return void 0;
|
|
23915
24258
|
}
|
|
@@ -23917,7 +24260,7 @@ function defaultReadAppended(path3, offset) {
|
|
|
23917
24260
|
const from = restarted ? 0 : offset;
|
|
23918
24261
|
if (size <= from) return { text: "", offset: from, restarted };
|
|
23919
24262
|
try {
|
|
23920
|
-
const fd2 =
|
|
24263
|
+
const fd2 = openSync9(path3, "r");
|
|
23921
24264
|
try {
|
|
23922
24265
|
const want = Math.min(ROLLOUT_READ_WINDOW, size - from);
|
|
23923
24266
|
const buf = Buffer.allocUnsafe(want);
|
|
@@ -23926,7 +24269,7 @@ function defaultReadAppended(path3, offset) {
|
|
|
23926
24269
|
const end = read < size - from && lastNl >= 0 ? lastNl + 1 : read;
|
|
23927
24270
|
return { text: buf.toString("utf8", 0, end), offset: from + end, restarted };
|
|
23928
24271
|
} finally {
|
|
23929
|
-
|
|
24272
|
+
closeSync8(fd2);
|
|
23930
24273
|
}
|
|
23931
24274
|
} catch {
|
|
23932
24275
|
return void 0;
|
|
@@ -24051,15 +24394,15 @@ var init_completion_relay = __esm({
|
|
|
24051
24394
|
|
|
24052
24395
|
// packages/server/src/tail-cache.ts
|
|
24053
24396
|
import { createHash as createHash6 } from "node:crypto";
|
|
24054
|
-
import { closeSync as
|
|
24055
|
-
import { join as
|
|
24397
|
+
import { closeSync as closeSync9, openSync as openSync10, readFileSync as readFileSync13, readSync as readSync3, statSync as statSync8 } from "node:fs";
|
|
24398
|
+
import { join as join20 } from "node:path";
|
|
24056
24399
|
function foldSchemaDigest(dir = import.meta.dirname) {
|
|
24057
24400
|
if (foldSchemaMemo) return foldSchemaMemo;
|
|
24058
24401
|
const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
|
|
24059
24402
|
let read = 0;
|
|
24060
24403
|
for (const name of FOLD_SOURCES) {
|
|
24061
24404
|
try {
|
|
24062
|
-
hash.update(name).update("\0").update(
|
|
24405
|
+
hash.update(name).update("\0").update(readFileSync13(join20(dir, name)));
|
|
24063
24406
|
read++;
|
|
24064
24407
|
} catch {
|
|
24065
24408
|
hash.update(name).update("\0missing\0");
|
|
@@ -24089,9 +24432,9 @@ function measureFence(path3, offset) {
|
|
|
24089
24432
|
if (!Number.isSafeInteger(offset) || offset <= 0) return null;
|
|
24090
24433
|
let fd2;
|
|
24091
24434
|
try {
|
|
24092
|
-
const stat2 =
|
|
24435
|
+
const stat2 = statSync8(path3);
|
|
24093
24436
|
if (stat2.size < offset) return null;
|
|
24094
|
-
fd2 =
|
|
24437
|
+
fd2 = openSync10(path3, "r");
|
|
24095
24438
|
const window = Math.min(SAMPLE_BYTES, offset);
|
|
24096
24439
|
const head = Buffer.allocUnsafe(window);
|
|
24097
24440
|
const headRead = readSync3(fd2, head, 0, window, 0);
|
|
@@ -24111,7 +24454,7 @@ function measureFence(path3, offset) {
|
|
|
24111
24454
|
} finally {
|
|
24112
24455
|
if (fd2 !== void 0) {
|
|
24113
24456
|
try {
|
|
24114
|
-
|
|
24457
|
+
closeSync9(fd2);
|
|
24115
24458
|
} catch {
|
|
24116
24459
|
}
|
|
24117
24460
|
}
|
|
@@ -24262,11 +24605,11 @@ var init_tail_cache = __esm({
|
|
|
24262
24605
|
});
|
|
24263
24606
|
|
|
24264
24607
|
// packages/server/src/tailer.ts
|
|
24265
|
-
import { statSync as
|
|
24608
|
+
import { statSync as statSync9, openSync as openSync11, readSync as readSync4, closeSync as closeSync10, readdirSync as readdirSync6, realpathSync as realpathSync6, mkdirSync as mkdirSync13, writeFileSync as writeFileSync11, readFileSync as readFileSync14, existsSync as existsSync7 } from "node:fs";
|
|
24266
24609
|
import { execFile as execFile2 } from "node:child_process";
|
|
24267
24610
|
import { createHash as createHash7 } from "node:crypto";
|
|
24268
24611
|
import { promisify as promisify2 } from "node:util";
|
|
24269
|
-
import { basename as basename4, join as
|
|
24612
|
+
import { basename as basename4, join as join21, win32 } from "node:path";
|
|
24270
24613
|
import { homedir as homedir7 } from "node:os";
|
|
24271
24614
|
function pendingCallDeadline(tail) {
|
|
24272
24615
|
const resolved2 = /* @__PURE__ */ new Set();
|
|
@@ -24313,7 +24656,7 @@ function readTranscriptTail(path3, size, window) {
|
|
|
24313
24656
|
const length = Math.min(size, window);
|
|
24314
24657
|
let fd2;
|
|
24315
24658
|
try {
|
|
24316
|
-
fd2 =
|
|
24659
|
+
fd2 = openSync11(path3, "r");
|
|
24317
24660
|
const buffer = Buffer.alloc(length);
|
|
24318
24661
|
const read = readSync4(fd2, buffer, 0, length, size - length);
|
|
24319
24662
|
const text2 = buffer.toString("utf8", 0, read);
|
|
@@ -24323,7 +24666,7 @@ function readTranscriptTail(path3, size, window) {
|
|
|
24323
24666
|
} finally {
|
|
24324
24667
|
if (fd2 !== void 0) {
|
|
24325
24668
|
try {
|
|
24326
|
-
|
|
24669
|
+
closeSync10(fd2);
|
|
24327
24670
|
} catch {
|
|
24328
24671
|
}
|
|
24329
24672
|
}
|
|
@@ -24337,7 +24680,7 @@ async function probeShellsAlive(shells, opts = {}) {
|
|
|
24337
24680
|
const verdicts = /* @__PURE__ */ new Map();
|
|
24338
24681
|
if (platform3 === "win32") {
|
|
24339
24682
|
const present = outputFiles.filter((file) => {
|
|
24340
|
-
if (
|
|
24683
|
+
if (existsSync7(file)) return true;
|
|
24341
24684
|
verdicts.set(file, void 0);
|
|
24342
24685
|
return false;
|
|
24343
24686
|
});
|
|
@@ -24355,12 +24698,12 @@ async function probeShellsAlive(shells, opts = {}) {
|
|
|
24355
24698
|
}
|
|
24356
24699
|
const live = [];
|
|
24357
24700
|
for (const file of outputFiles) {
|
|
24358
|
-
if (!
|
|
24701
|
+
if (!existsSync7(file)) {
|
|
24359
24702
|
verdicts.set(file, void 0);
|
|
24360
24703
|
continue;
|
|
24361
24704
|
}
|
|
24362
24705
|
try {
|
|
24363
|
-
live.push({ requested: file, real:
|
|
24706
|
+
live.push({ requested: file, real: realpathSync6(file) });
|
|
24364
24707
|
} catch {
|
|
24365
24708
|
verdicts.set(file, void 0);
|
|
24366
24709
|
}
|
|
@@ -24793,7 +25136,7 @@ function launchTaskId(text2) {
|
|
|
24793
25136
|
function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
24794
25137
|
let names;
|
|
24795
25138
|
try {
|
|
24796
|
-
names =
|
|
25139
|
+
names = readdirSync6(join21(sessionDir, "subagents"));
|
|
24797
25140
|
} catch {
|
|
24798
25141
|
return [];
|
|
24799
25142
|
}
|
|
@@ -24804,7 +25147,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
24804
25147
|
if (!agentId) continue;
|
|
24805
25148
|
let parsed;
|
|
24806
25149
|
try {
|
|
24807
|
-
parsed = JSON.parse(
|
|
25150
|
+
parsed = JSON.parse(readFileSync14(join21(sessionDir, "subagents", name), "utf8"));
|
|
24808
25151
|
} catch {
|
|
24809
25152
|
continue;
|
|
24810
25153
|
}
|
|
@@ -24818,7 +25161,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
24818
25161
|
agentType: text2(meta.agentType),
|
|
24819
25162
|
parentAgentId: text2(meta.parentAgentId),
|
|
24820
25163
|
spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
|
|
24821
|
-
spawnedAtMs: mtimeMs(
|
|
25164
|
+
spawnedAtMs: mtimeMs(join21(sessionDir, "subagents", name))
|
|
24822
25165
|
});
|
|
24823
25166
|
}
|
|
24824
25167
|
return out;
|
|
@@ -25307,19 +25650,19 @@ function isPermMarker(v) {
|
|
|
25307
25650
|
}
|
|
25308
25651
|
function defaultMtimeMs(path3) {
|
|
25309
25652
|
try {
|
|
25310
|
-
return
|
|
25653
|
+
return statSync9(path3).mtimeMs;
|
|
25311
25654
|
} catch {
|
|
25312
25655
|
return void 0;
|
|
25313
25656
|
}
|
|
25314
25657
|
}
|
|
25315
25658
|
function defaultLogDir(project) {
|
|
25316
|
-
return
|
|
25659
|
+
return join21(homedir7(), ".claude", "projects", project.cwdSlug);
|
|
25317
25660
|
}
|
|
25318
25661
|
function defaultReadPermMarker(project) {
|
|
25319
25662
|
if (!project.stateDir) return () => void 0;
|
|
25320
25663
|
return (slug) => {
|
|
25321
25664
|
try {
|
|
25322
|
-
const parsed = JSON.parse(
|
|
25665
|
+
const parsed = JSON.parse(readFileSync14(permMarkerPath(project, slug), "utf8"));
|
|
25323
25666
|
return isPermMarker(parsed) ? parsed : void 0;
|
|
25324
25667
|
} catch {
|
|
25325
25668
|
return void 0;
|
|
@@ -25337,7 +25680,7 @@ function defaultBrokerDaemonAlive(project, now) {
|
|
|
25337
25680
|
try {
|
|
25338
25681
|
const path3 = claudeBrokerRecordPath(project.stateDir, sessionId);
|
|
25339
25682
|
const record = readBrokerRecord(path3);
|
|
25340
|
-
if (!record) alive =
|
|
25683
|
+
if (!record) alive = existsSync7(path3);
|
|
25341
25684
|
else if (typeof record.daemonPid !== "number") alive = true;
|
|
25342
25685
|
else {
|
|
25343
25686
|
try {
|
|
@@ -25445,7 +25788,7 @@ function createTailer(deps) {
|
|
|
25445
25788
|
return paneDead(row.slug);
|
|
25446
25789
|
}
|
|
25447
25790
|
const defaultBackend = {
|
|
25448
|
-
transcriptPath: (sessionId) =>
|
|
25791
|
+
transcriptPath: (sessionId) => join21(logDir, `${sessionId}.jsonl`),
|
|
25449
25792
|
foldLine: (state, line) => {
|
|
25450
25793
|
const rec = parseLine(line);
|
|
25451
25794
|
if (rec) applyRecord(state, rec);
|
|
@@ -25487,7 +25830,7 @@ function createTailer(deps) {
|
|
|
25487
25830
|
function blockedUntil(path3, m) {
|
|
25488
25831
|
let size;
|
|
25489
25832
|
try {
|
|
25490
|
-
size =
|
|
25833
|
+
size = statSync9(path3).size;
|
|
25491
25834
|
} catch {
|
|
25492
25835
|
return void 0;
|
|
25493
25836
|
}
|
|
@@ -25613,7 +25956,7 @@ ${ask}`;
|
|
|
25613
25956
|
return state.path.replace(/\.jsonl$/, "");
|
|
25614
25957
|
}
|
|
25615
25958
|
function descendantSidecars(state) {
|
|
25616
|
-
const at2 = mtimeMs(
|
|
25959
|
+
const at2 = mtimeMs(join21(sessionDirOf(state), "subagents"));
|
|
25617
25960
|
const cached2 = descendantIndex.get(state.slug);
|
|
25618
25961
|
if (cached2 && cached2.at === at2) return cached2.all;
|
|
25619
25962
|
const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
|
|
@@ -25627,7 +25970,7 @@ ${ask}`;
|
|
|
25627
25970
|
return descendantIndex.get(state.slug)?.byToolUse.get(id2);
|
|
25628
25971
|
}
|
|
25629
25972
|
function descendantTranscript(state, meta) {
|
|
25630
|
-
return
|
|
25973
|
+
return join21(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
|
|
25631
25974
|
}
|
|
25632
25975
|
function subAgentDescendantTasks(slug, id2) {
|
|
25633
25976
|
const state = states.get(slug);
|
|
@@ -25947,7 +26290,7 @@ ${ask}`;
|
|
|
25947
26290
|
if (!deps.project.dir) return [];
|
|
25948
26291
|
const cwds = /* @__PURE__ */ new Set([deps.project.dir]);
|
|
25949
26292
|
try {
|
|
25950
|
-
cwds.add(
|
|
26293
|
+
cwds.add(realpathSync6(deps.project.dir));
|
|
25951
26294
|
} catch {
|
|
25952
26295
|
}
|
|
25953
26296
|
try {
|
|
@@ -25965,7 +26308,7 @@ ${ask}`;
|
|
|
25965
26308
|
function scanForeign(nowMs) {
|
|
25966
26309
|
let names;
|
|
25967
26310
|
try {
|
|
25968
|
-
names =
|
|
26311
|
+
names = readdirSync6(logDir);
|
|
25969
26312
|
} catch {
|
|
25970
26313
|
return [];
|
|
25971
26314
|
}
|
|
@@ -25975,10 +26318,10 @@ ${ask}`;
|
|
|
25975
26318
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
25976
26319
|
const id2 = name.slice(0, -".jsonl".length);
|
|
25977
26320
|
if (!id2 || registered.has(id2)) continue;
|
|
25978
|
-
const path3 =
|
|
26321
|
+
const path3 = join21(logDir, name);
|
|
25979
26322
|
let mtime;
|
|
25980
26323
|
try {
|
|
25981
|
-
mtime =
|
|
26324
|
+
mtime = statSync9(path3).mtimeMs;
|
|
25982
26325
|
} catch {
|
|
25983
26326
|
continue;
|
|
25984
26327
|
}
|
|
@@ -26131,7 +26474,7 @@ ${ask}`;
|
|
|
26131
26474
|
if (entry.path !== state.path) {
|
|
26132
26475
|
let derivedSize = 0;
|
|
26133
26476
|
try {
|
|
26134
|
-
derivedSize =
|
|
26477
|
+
derivedSize = statSync9(state.path).size;
|
|
26135
26478
|
} catch {
|
|
26136
26479
|
derivedSize = 0;
|
|
26137
26480
|
}
|
|
@@ -26188,7 +26531,7 @@ ${ask}`;
|
|
|
26188
26531
|
function consume(state, backend, onLine) {
|
|
26189
26532
|
let size;
|
|
26190
26533
|
try {
|
|
26191
|
-
size =
|
|
26534
|
+
size = statSync9(state.path).size;
|
|
26192
26535
|
} catch {
|
|
26193
26536
|
return;
|
|
26194
26537
|
}
|
|
@@ -26199,7 +26542,7 @@ ${ask}`;
|
|
|
26199
26542
|
if (size <= state.offset) return;
|
|
26200
26543
|
let carry = state.partial ? Buffer.from(state.partial, "utf8") : EMPTY_BUFFER;
|
|
26201
26544
|
try {
|
|
26202
|
-
const fd2 =
|
|
26545
|
+
const fd2 = openSync11(state.path, "r");
|
|
26203
26546
|
try {
|
|
26204
26547
|
const buf = Buffer.allocUnsafe(Math.min(TRANSCRIPT_READ_WINDOW, size - state.offset));
|
|
26205
26548
|
while (state.offset < size) {
|
|
@@ -26219,7 +26562,7 @@ ${ask}`;
|
|
|
26219
26562
|
carry = start < view.length ? Buffer.from(view.subarray(start)) : EMPTY_BUFFER;
|
|
26220
26563
|
}
|
|
26221
26564
|
} finally {
|
|
26222
|
-
|
|
26565
|
+
closeSync10(fd2);
|
|
26223
26566
|
}
|
|
26224
26567
|
} catch {
|
|
26225
26568
|
state.partial = carry.toString("utf8");
|
|
@@ -26246,8 +26589,8 @@ ${ask}`;
|
|
|
26246
26589
|
`thread ${row.slug} (session ${row.session_id}): no transcript ${DISCOVERY_GRACE_MS / 1e3}s after dispatch \u2014 likely a boot failure. ${detail2.slice(0, 4e3)}`
|
|
26247
26590
|
);
|
|
26248
26591
|
try {
|
|
26249
|
-
|
|
26250
|
-
|
|
26592
|
+
mkdirSync13(stallLogDir, { recursive: true });
|
|
26593
|
+
writeFileSync11(join21(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
|
|
26251
26594
|
captured_at: ${new Date(now()).toISOString()}
|
|
26252
26595
|
|
|
26253
26596
|
${detail2}
|
|
@@ -26257,10 +26600,10 @@ ${detail2}
|
|
|
26257
26600
|
}
|
|
26258
26601
|
function relocatedTranscript(state) {
|
|
26259
26602
|
const name = `${state.nativeSessionId}.jsonl`;
|
|
26260
|
-
const home =
|
|
26603
|
+
const home = join21(logDir, name);
|
|
26261
26604
|
const homeAt = home === state.path ? void 0 : mtimeOfNonEmpty(home);
|
|
26262
26605
|
const dir = discoverTranscriptDir(logDir, state.nativeSessionId);
|
|
26263
|
-
const sibling = dir ?
|
|
26606
|
+
const sibling = dir ? join21(dir, name) : void 0;
|
|
26264
26607
|
const siblingAt = sibling && sibling !== state.path ? mtimeOfNonEmpty(sibling) : void 0;
|
|
26265
26608
|
if (homeAt === void 0) return siblingAt === void 0 ? void 0 : sibling;
|
|
26266
26609
|
if (siblingAt === void 0) return home;
|
|
@@ -26268,7 +26611,7 @@ ${detail2}
|
|
|
26268
26611
|
}
|
|
26269
26612
|
function resolveTranscript(state, row, nowMs) {
|
|
26270
26613
|
if (state.offset > 0) {
|
|
26271
|
-
if (
|
|
26614
|
+
if (existsSync7(state.path)) {
|
|
26272
26615
|
state.discoverMisses = 0;
|
|
26273
26616
|
state.nextDiscoverMs = 0;
|
|
26274
26617
|
return true;
|
|
@@ -26295,7 +26638,7 @@ ${detail2}
|
|
|
26295
26638
|
}
|
|
26296
26639
|
let size = 0;
|
|
26297
26640
|
try {
|
|
26298
|
-
size =
|
|
26641
|
+
size = statSync9(state.path).size;
|
|
26299
26642
|
} catch {
|
|
26300
26643
|
size = 0;
|
|
26301
26644
|
}
|
|
@@ -26312,7 +26655,7 @@ ${detail2}
|
|
|
26312
26655
|
state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
|
|
26313
26656
|
const strandedDir = discoverTranscriptDir(logDir, row.session_id);
|
|
26314
26657
|
if (strandedDir) {
|
|
26315
|
-
state.path =
|
|
26658
|
+
state.path = join21(strandedDir, `${row.session_id}.jsonl`);
|
|
26316
26659
|
state.offset = 0;
|
|
26317
26660
|
state.partial = "";
|
|
26318
26661
|
state.primed = false;
|
|
@@ -26336,7 +26679,7 @@ ${detail2}
|
|
|
26336
26679
|
committed = false;
|
|
26337
26680
|
}
|
|
26338
26681
|
if (!committed) return false;
|
|
26339
|
-
state.path =
|
|
26682
|
+
state.path = join21(logDir, `${found}.jsonl`);
|
|
26340
26683
|
state.offset = 0;
|
|
26341
26684
|
state.partial = "";
|
|
26342
26685
|
state.primed = false;
|
|
@@ -26396,7 +26739,7 @@ ${detail2}
|
|
|
26396
26739
|
continue;
|
|
26397
26740
|
}
|
|
26398
26741
|
if (!state) {
|
|
26399
|
-
const path3 = backend.transcriptPath(nativeId) ??
|
|
26742
|
+
const path3 = backend.transcriptPath(nativeId) ?? join21(logDir, `${nativeId}.jsonl`);
|
|
26400
26743
|
state = newTailState(row.slug, row.session_id, path3, false, nativeId, runtimeGeneration);
|
|
26401
26744
|
state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
|
|
26402
26745
|
hydrateFromCache(state, row, nativeId);
|
|
@@ -26631,12 +26974,12 @@ ${detail2}
|
|
|
26631
26974
|
const elapsed = monotonicNow() - started;
|
|
26632
26975
|
lastTickMs = elapsed;
|
|
26633
26976
|
lastTickEndedAtMs = now();
|
|
26634
|
-
if (elapsed >
|
|
26977
|
+
if (elapsed > POLL_MS3) {
|
|
26635
26978
|
overBudgetTicks++;
|
|
26636
26979
|
if (overBudgetTicks === 1 || overBudgetTicks % 30 === 0) {
|
|
26637
26980
|
log.warn(
|
|
26638
26981
|
"tailer",
|
|
26639
|
-
`tick took ${Math.round(elapsed)}ms (poll ${
|
|
26982
|
+
`tick took ${Math.round(elapsed)}ms (poll ${POLL_MS3}ms, ${states.size} sessions) \u2014 the event loop is blocked for that long, so RPCs and board pushes are delayed (occurrence ${overBudgetTicks})`
|
|
26640
26983
|
);
|
|
26641
26984
|
}
|
|
26642
26985
|
}
|
|
@@ -26650,7 +26993,7 @@ ${detail2}
|
|
|
26650
26993
|
}
|
|
26651
26994
|
}
|
|
26652
26995
|
function scheduleTick() {
|
|
26653
|
-
const delay2 = primeIncomplete ? 1 : Math.min(MAX_POLL_MS, Math.max(
|
|
26996
|
+
const delay2 = primeIncomplete ? 1 : Math.min(MAX_POLL_MS, Math.max(POLL_MS3, Math.round(lastTickMs)));
|
|
26654
26997
|
timer = setTimeout(() => {
|
|
26655
26998
|
timer = null;
|
|
26656
26999
|
try {
|
|
@@ -26754,7 +27097,7 @@ function landsAfterRead(eventAt, lastReadAt) {
|
|
|
26754
27097
|
if (!Number.isFinite(e14) || !Number.isFinite(r)) return true;
|
|
26755
27098
|
return e14 > r;
|
|
26756
27099
|
}
|
|
26757
|
-
var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX,
|
|
27100
|
+
var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS3, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, BASH_TIMEOUT_CEILING_MS, PENDING_CALL_TAIL_BYTES, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, LIVE_TOOLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, ASSISTANT_LINE_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, FOLDED_TERMINALS_MAX, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
|
|
26758
27101
|
var init_tailer = __esm({
|
|
26759
27102
|
"packages/server/src/tailer.ts"() {
|
|
26760
27103
|
"use strict";
|
|
@@ -26780,7 +27123,7 @@ var init_tailer = __esm({
|
|
|
26780
27123
|
init_credential_redaction();
|
|
26781
27124
|
IDLE_BACKSTOP_MS = 5e3;
|
|
26782
27125
|
RUNTIME_CHASE_MAX = 20;
|
|
26783
|
-
|
|
27126
|
+
POLL_MS3 = 1e3;
|
|
26784
27127
|
MAX_PRIME_ROWS_PER_TICK = 25;
|
|
26785
27128
|
PRIME_BUDGET_MS = 200;
|
|
26786
27129
|
TRANSCRIPT_READ_WINDOW = 16 * 1024 * 1024;
|
|
@@ -26864,14 +27207,14 @@ var init_tailer = __esm({
|
|
|
26864
27207
|
});
|
|
26865
27208
|
|
|
26866
27209
|
// packages/server/src/backend/codex.ts
|
|
26867
|
-
import { join as
|
|
27210
|
+
import { join as join22 } from "node:path";
|
|
26868
27211
|
import { homedir as homedir8 } from "node:os";
|
|
26869
|
-
import { readdirSync as
|
|
27212
|
+
import { readdirSync as readdirSync7, statSync as statSync10, readFileSync as readFileSync15, openSync as openSync12, readSync as readSync5, closeSync as closeSync11 } from "node:fs";
|
|
26870
27213
|
function defaultCodexHome() {
|
|
26871
|
-
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME :
|
|
27214
|
+
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join22(homedir8(), ".codex");
|
|
26872
27215
|
}
|
|
26873
27216
|
function sessionsDir(codexHome) {
|
|
26874
|
-
return
|
|
27217
|
+
return join22(codexHome, "sessions");
|
|
26875
27218
|
}
|
|
26876
27219
|
function codexSandbox(mode) {
|
|
26877
27220
|
switch (mode) {
|
|
@@ -27317,23 +27660,23 @@ function collectRollouts(dir, out, budget) {
|
|
|
27317
27660
|
const files = entries2.filter((e14) => e14.isFile() && e14.name.startsWith("rollout-") && e14.name.endsWith(".jsonl")).sort(descByName);
|
|
27318
27661
|
for (const d of dirs) {
|
|
27319
27662
|
if (budget.n <= 0) return;
|
|
27320
|
-
collectRollouts(
|
|
27663
|
+
collectRollouts(join22(dir, d.name), out, budget);
|
|
27321
27664
|
}
|
|
27322
27665
|
for (const f of files) {
|
|
27323
27666
|
if (budget.n <= 0) return;
|
|
27324
27667
|
let mtimeMs;
|
|
27325
27668
|
try {
|
|
27326
|
-
mtimeMs =
|
|
27669
|
+
mtimeMs = statSync10(join22(dir, f.name)).mtimeMs;
|
|
27327
27670
|
} catch {
|
|
27328
27671
|
continue;
|
|
27329
27672
|
}
|
|
27330
|
-
out.push({ path:
|
|
27673
|
+
out.push({ path: join22(dir, f.name), mtimeMs });
|
|
27331
27674
|
budget.n--;
|
|
27332
27675
|
}
|
|
27333
27676
|
}
|
|
27334
27677
|
function safeReaddir(dir) {
|
|
27335
27678
|
try {
|
|
27336
|
-
return
|
|
27679
|
+
return readdirSync7(dir, { withFileTypes: true });
|
|
27337
27680
|
} catch {
|
|
27338
27681
|
return [];
|
|
27339
27682
|
}
|
|
@@ -27371,9 +27714,9 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
|
|
|
27371
27714
|
const out = /* @__PURE__ */ new Map();
|
|
27372
27715
|
let raw2;
|
|
27373
27716
|
try {
|
|
27374
|
-
const path3 =
|
|
27375
|
-
if (
|
|
27376
|
-
raw2 =
|
|
27717
|
+
const path3 = join22(codexHome, "session_index.jsonl");
|
|
27718
|
+
if (statSync10(path3).size > SESSION_INDEX_MAX_BYTES) return out;
|
|
27719
|
+
raw2 = readFileSync15(path3, "utf8");
|
|
27377
27720
|
} catch {
|
|
27378
27721
|
return out;
|
|
27379
27722
|
}
|
|
@@ -27413,7 +27756,7 @@ function rolloutIdOf(path3) {
|
|
|
27413
27756
|
function readSessionMeta(path3) {
|
|
27414
27757
|
let fd2;
|
|
27415
27758
|
try {
|
|
27416
|
-
fd2 =
|
|
27759
|
+
fd2 = openSync12(path3, "r");
|
|
27417
27760
|
const buf = Buffer.allocUnsafe(FOREIGN_ROLLOUT_HEAD_BYTES);
|
|
27418
27761
|
const n = readSync5(fd2, buf, 0, FOREIGN_ROLLOUT_HEAD_BYTES, 0);
|
|
27419
27762
|
const line = buf.toString("utf8", 0, n).split("\n", 1)[0];
|
|
@@ -27430,7 +27773,7 @@ function readSessionMeta(path3) {
|
|
|
27430
27773
|
} finally {
|
|
27431
27774
|
if (fd2 !== void 0) {
|
|
27432
27775
|
try {
|
|
27433
|
-
|
|
27776
|
+
closeSync11(fd2);
|
|
27434
27777
|
} catch {
|
|
27435
27778
|
}
|
|
27436
27779
|
}
|
|
@@ -27549,7 +27892,7 @@ var init_codex = __esm({
|
|
|
27549
27892
|
});
|
|
27550
27893
|
|
|
27551
27894
|
// packages/server/src/backend/codex-executable.ts
|
|
27552
|
-
import { accessSync as accessSync2, constants as fsConstants2, readFileSync as
|
|
27895
|
+
import { accessSync as accessSync2, constants as fsConstants2, readFileSync as readFileSync16 } from "node:fs";
|
|
27553
27896
|
import { posix, win32 as win322 } from "node:path";
|
|
27554
27897
|
function defaultAccess(path3, mode) {
|
|
27555
27898
|
try {
|
|
@@ -27561,7 +27904,7 @@ function defaultAccess(path3, mode) {
|
|
|
27561
27904
|
}
|
|
27562
27905
|
function defaultReadFile(path3) {
|
|
27563
27906
|
try {
|
|
27564
|
-
return
|
|
27907
|
+
return readFileSync16(path3, "utf8");
|
|
27565
27908
|
} catch {
|
|
27566
27909
|
return void 0;
|
|
27567
27910
|
}
|
|
@@ -27575,19 +27918,19 @@ function searchPath2(env) {
|
|
|
27575
27918
|
function vendoredNativeBeside(launcherJs, arch, access) {
|
|
27576
27919
|
const triple = WINDOWS_TRIPLE[arch];
|
|
27577
27920
|
if (!triple) return void 0;
|
|
27578
|
-
const { dirname:
|
|
27579
|
-
const pkgRoot =
|
|
27921
|
+
const { dirname: dirname29, join: join54 } = win322;
|
|
27922
|
+
const pkgRoot = dirname29(dirname29(launcherJs));
|
|
27580
27923
|
const platformPkg = `codex-win32-${arch}`;
|
|
27581
27924
|
const vendorRoots = [
|
|
27582
|
-
|
|
27925
|
+
join54(pkgRoot, "node_modules", "@openai", platformPkg, "vendor"),
|
|
27583
27926
|
// nested under the package
|
|
27584
|
-
|
|
27927
|
+
join54(dirname29(pkgRoot), platformPkg, "vendor"),
|
|
27585
27928
|
// hoisted beside it: <prefix>\node_modules\@openai\<pkg>
|
|
27586
|
-
|
|
27929
|
+
join54(pkgRoot, "vendor")
|
|
27587
27930
|
// the pre-platform-package layout, binaries inside @openai/codex itself
|
|
27588
27931
|
];
|
|
27589
27932
|
for (const root of vendorRoots) {
|
|
27590
|
-
const exe2 =
|
|
27933
|
+
const exe2 = join54(root, triple, "bin", "codex.exe");
|
|
27591
27934
|
if (access(exe2, "exists")) return exe2;
|
|
27592
27935
|
}
|
|
27593
27936
|
return void 0;
|
|
@@ -29911,7 +30254,7 @@ var require_websocket = __commonJS({
|
|
|
29911
30254
|
var http = __require("http");
|
|
29912
30255
|
var net2 = __require("net");
|
|
29913
30256
|
var tls = __require("tls");
|
|
29914
|
-
var { randomBytes, createHash: createHash18 } = __require("crypto");
|
|
30257
|
+
var { randomBytes: randomBytes2, createHash: createHash18 } = __require("crypto");
|
|
29915
30258
|
var { Duplex, Readable: Readable3 } = __require("stream");
|
|
29916
30259
|
var { URL: URL2 } = __require("url");
|
|
29917
30260
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -30449,7 +30792,7 @@ var require_websocket = __commonJS({
|
|
|
30449
30792
|
}
|
|
30450
30793
|
}
|
|
30451
30794
|
const defaultPort = isSecure ? 443 : 80;
|
|
30452
|
-
const key =
|
|
30795
|
+
const key = randomBytes2(16).toString("base64");
|
|
30453
30796
|
const request = isSecure ? https.request : http.request;
|
|
30454
30797
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
30455
30798
|
let perMessageDeflate;
|
|
@@ -31419,15 +31762,15 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
31419
31762
|
import { connect } from "node:net";
|
|
31420
31763
|
import { Agent as HttpAgent } from "node:http";
|
|
31421
31764
|
import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
|
|
31422
|
-
import { existsSync as
|
|
31423
|
-
import { join as
|
|
31765
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync14, readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync12 } from "node:fs";
|
|
31766
|
+
import { join as join23 } from "node:path";
|
|
31424
31767
|
import { PassThrough, Writable } from "node:stream";
|
|
31425
31768
|
import { StringDecoder } from "node:string_decoder";
|
|
31426
31769
|
function nativeDir(stateDir) {
|
|
31427
|
-
return
|
|
31770
|
+
return join23(stateDir, "codex-app-server-native");
|
|
31428
31771
|
}
|
|
31429
31772
|
function nativeRecordPath(stateDir, projectId) {
|
|
31430
|
-
return
|
|
31773
|
+
return join23(nativeDir(stateDir), `${projectId}.json`);
|
|
31431
31774
|
}
|
|
31432
31775
|
function nativeListenSocketPath(stateDir, projectId) {
|
|
31433
31776
|
const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
@@ -31443,7 +31786,7 @@ function pidAlive2(pid) {
|
|
|
31443
31786
|
}
|
|
31444
31787
|
function readNativeRecord(stateDir, projectId) {
|
|
31445
31788
|
try {
|
|
31446
|
-
const value = JSON.parse(
|
|
31789
|
+
const value = JSON.parse(readFileSync17(nativeRecordPath(stateDir, projectId), "utf8"));
|
|
31447
31790
|
if (typeof value.listenerPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
31448
31791
|
return {
|
|
31449
31792
|
projectId,
|
|
@@ -31460,7 +31803,7 @@ function readNativeRecord(stateDir, projectId) {
|
|
|
31460
31803
|
function liveNativeRecord(stateDir, projectId) {
|
|
31461
31804
|
const record = readNativeRecord(stateDir, projectId);
|
|
31462
31805
|
if (!record) return null;
|
|
31463
|
-
if (pidAlive2(record.listenerPid) &&
|
|
31806
|
+
if (pidAlive2(record.listenerPid) && existsSync8(record.socketPath)) return record;
|
|
31464
31807
|
try {
|
|
31465
31808
|
unlinkSync2(nativeRecordPath(stateDir, projectId));
|
|
31466
31809
|
} catch {
|
|
@@ -31600,9 +31943,9 @@ function attach(record, timeoutMs) {
|
|
|
31600
31943
|
}
|
|
31601
31944
|
async function startListener(options) {
|
|
31602
31945
|
const { stateDir, projectId } = options;
|
|
31603
|
-
|
|
31946
|
+
mkdirSync14(nativeDir(stateDir), { recursive: true });
|
|
31604
31947
|
const socketPath = nativeListenSocketPath(stateDir, projectId);
|
|
31605
|
-
if (
|
|
31948
|
+
if (existsSync8(socketPath) && !await socketAccepting(socketPath)) {
|
|
31606
31949
|
try {
|
|
31607
31950
|
unlinkSync2(socketPath);
|
|
31608
31951
|
} catch {
|
|
@@ -31627,10 +31970,10 @@ async function startListener(options) {
|
|
|
31627
31970
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
31628
31971
|
...options.authAccountId ? { authAccountId: options.authAccountId } : {}
|
|
31629
31972
|
};
|
|
31630
|
-
|
|
31973
|
+
writeFileSync12(nativeRecordPath(stateDir, projectId), JSON.stringify(record));
|
|
31631
31974
|
const deadline = Date.now() + (options.timeoutMs ?? 3e4);
|
|
31632
31975
|
for (; ; ) {
|
|
31633
|
-
if (
|
|
31976
|
+
if (existsSync8(socketPath) && await socketAccepting(socketPath)) return record;
|
|
31634
31977
|
if (!pidAlive2(record.listenerPid)) throw new Error("codex app-server listener exited before it became ready");
|
|
31635
31978
|
if (Date.now() > deadline) throw new Error("codex app-server listener did not become ready");
|
|
31636
31979
|
await new Promise((resolve13) => setTimeout(resolve13, 50));
|
|
@@ -31699,15 +32042,15 @@ var init_codex_app_server_native = __esm({
|
|
|
31699
32042
|
import { spawn as spawn3 } from "node:child_process";
|
|
31700
32043
|
import { createConnection } from "node:net";
|
|
31701
32044
|
import { createHash as createHash9, randomUUID as randomUUID10 } from "node:crypto";
|
|
31702
|
-
import { existsSync as
|
|
31703
|
-
import { join as
|
|
32045
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync15, readFileSync as readFileSync18, unlinkSync as unlinkSync3 } from "node:fs";
|
|
32046
|
+
import { join as join24 } from "node:path";
|
|
31704
32047
|
import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
|
|
31705
32048
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
31706
32049
|
function daemonDir(stateDir) {
|
|
31707
|
-
return
|
|
32050
|
+
return join24(stateDir, "codex-app-server");
|
|
31708
32051
|
}
|
|
31709
32052
|
function recordPath(stateDir, projectId) {
|
|
31710
|
-
return
|
|
32053
|
+
return join24(daemonDir(stateDir), `${projectId}.json`);
|
|
31711
32054
|
}
|
|
31712
32055
|
function codexAppServerSocketPath(stateDir, projectId) {
|
|
31713
32056
|
const key = createHash9("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
@@ -31723,7 +32066,7 @@ function pidAlive3(pid) {
|
|
|
31723
32066
|
}
|
|
31724
32067
|
function readDaemonRecord(stateDir, projectId) {
|
|
31725
32068
|
try {
|
|
31726
|
-
const value = JSON.parse(
|
|
32069
|
+
const value = JSON.parse(readFileSync18(recordPath(stateDir, projectId), "utf8"));
|
|
31727
32070
|
if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
31728
32071
|
return {
|
|
31729
32072
|
projectId,
|
|
@@ -31740,7 +32083,7 @@ function readDaemonRecord(stateDir, projectId) {
|
|
|
31740
32083
|
}
|
|
31741
32084
|
function readDaemonExitBreadcrumb(stateDir, projectId) {
|
|
31742
32085
|
try {
|
|
31743
|
-
const value = JSON.parse(
|
|
32086
|
+
const value = JSON.parse(readFileSync18(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
|
|
31744
32087
|
if (typeof value.generation !== "string" || typeof value.reason !== "string") return null;
|
|
31745
32088
|
return {
|
|
31746
32089
|
generation: value.generation,
|
|
@@ -31790,7 +32133,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
31790
32133
|
}
|
|
31791
32134
|
function forkDaemon(options) {
|
|
31792
32135
|
const { stateDir, projectId } = options;
|
|
31793
|
-
|
|
32136
|
+
mkdirSync15(daemonDir(stateDir), { recursive: true });
|
|
31794
32137
|
const record = recordPath(stateDir, projectId);
|
|
31795
32138
|
try {
|
|
31796
32139
|
unlinkSync3(record);
|
|
@@ -31985,7 +32328,7 @@ var init_codex_app_server_host = __esm({
|
|
|
31985
32328
|
}
|
|
31986
32329
|
if (process.platform !== "win32") {
|
|
31987
32330
|
const stale = codexAppServerSocketPath(options.stateDir, options.projectId);
|
|
31988
|
-
if (
|
|
32331
|
+
if (existsSync9(stale) && !liveDaemonRecord(options.stateDir, options.projectId)) {
|
|
31989
32332
|
try {
|
|
31990
32333
|
unlinkSync3(stale);
|
|
31991
32334
|
} catch {
|
|
@@ -32005,7 +32348,7 @@ var init_codex_app_server_host = __esm({
|
|
|
32005
32348
|
});
|
|
32006
32349
|
|
|
32007
32350
|
// packages/server/src/backend/claude-quota.ts
|
|
32008
|
-
import { join as
|
|
32351
|
+
import { join as join25 } from "node:path";
|
|
32009
32352
|
import { homedir as homedir9, platform } from "node:os";
|
|
32010
32353
|
import { createHash as createHash10 } from "node:crypto";
|
|
32011
32354
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -32013,7 +32356,7 @@ import { execFile as execFile3 } from "node:child_process";
|
|
|
32013
32356
|
import { promisify as promisify3 } from "node:util";
|
|
32014
32357
|
function claudeConfigDir() {
|
|
32015
32358
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32016
|
-
return override && override.trim() ? override :
|
|
32359
|
+
return override && override.trim() ? override : join25(homedir9(), ".claude");
|
|
32017
32360
|
}
|
|
32018
32361
|
function tokenFromCredentialsJson(raw2) {
|
|
32019
32362
|
let doc;
|
|
@@ -32042,7 +32385,7 @@ async function readKeychainToken() {
|
|
|
32042
32385
|
}
|
|
32043
32386
|
async function readAccessToken(configDir) {
|
|
32044
32387
|
try {
|
|
32045
|
-
const fromFile = tokenFromCredentialsJson(await readFile(
|
|
32388
|
+
const fromFile = tokenFromCredentialsJson(await readFile(join25(configDir, ".credentials.json"), "utf8"));
|
|
32046
32389
|
if (fromFile) return fromFile;
|
|
32047
32390
|
} catch {
|
|
32048
32391
|
}
|
|
@@ -32116,8 +32459,8 @@ function retryAtFrom(res, now) {
|
|
|
32116
32459
|
function cachePaths(cacheDir, configDir) {
|
|
32117
32460
|
const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
|
|
32118
32461
|
return {
|
|
32119
|
-
data:
|
|
32120
|
-
lock:
|
|
32462
|
+
data: join25(cacheDir, `claude-${profile}.json`),
|
|
32463
|
+
lock: join25(cacheDir, `claude-${profile}.lock`)
|
|
32121
32464
|
};
|
|
32122
32465
|
}
|
|
32123
32466
|
async function readShared(path3) {
|
|
@@ -32329,7 +32672,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
|
|
|
32329
32672
|
async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
32330
32673
|
const now = (deps.now ?? Date.now)();
|
|
32331
32674
|
const configDir = claudeConfigDir();
|
|
32332
|
-
const cacheDir = deps.cacheDir ??
|
|
32675
|
+
const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
|
|
32333
32676
|
try {
|
|
32334
32677
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
32335
32678
|
} catch {
|
|
@@ -32343,7 +32686,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
|
32343
32686
|
async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
|
|
32344
32687
|
const now = (deps.now ?? Date.now)();
|
|
32345
32688
|
const configDir = claudeConfigDir();
|
|
32346
|
-
const cacheDir = deps.cacheDir ??
|
|
32689
|
+
const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
|
|
32347
32690
|
const paths = cachePaths(cacheDir, configDir);
|
|
32348
32691
|
try {
|
|
32349
32692
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
@@ -32450,19 +32793,19 @@ var init_claude_quota = __esm({
|
|
|
32450
32793
|
});
|
|
32451
32794
|
|
|
32452
32795
|
// packages/server/src/backend/auth-status.ts
|
|
32453
|
-
import { join as
|
|
32796
|
+
import { join as join26 } from "node:path";
|
|
32454
32797
|
import { homedir as homedir10, platform as platform2 } from "node:os";
|
|
32455
|
-
import { readFileSync as
|
|
32798
|
+
import { readFileSync as readFileSync19, statSync as statSync11 } from "node:fs";
|
|
32456
32799
|
import { execFile as execFile4 } from "node:child_process";
|
|
32457
32800
|
import { promisify as promisify4 } from "node:util";
|
|
32458
32801
|
function claudeConfigDir2() {
|
|
32459
32802
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32460
|
-
return override && override.trim() ? override :
|
|
32803
|
+
return override && override.trim() ? override : join26(homedir10(), ".claude");
|
|
32461
32804
|
}
|
|
32462
32805
|
function claudeFileState(configDir) {
|
|
32463
32806
|
let raw2;
|
|
32464
32807
|
try {
|
|
32465
|
-
raw2 =
|
|
32808
|
+
raw2 = readFileSync19(join26(configDir, ".credentials.json"), "utf8");
|
|
32466
32809
|
} catch (err) {
|
|
32467
32810
|
return err.code === "ENOENT" ? "absent" : "error";
|
|
32468
32811
|
}
|
|
@@ -32495,7 +32838,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
32495
32838
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
|
|
32496
32839
|
let raw2;
|
|
32497
32840
|
try {
|
|
32498
|
-
raw2 =
|
|
32841
|
+
raw2 = readFileSync19(join26(codexHome, "auth.json"), "utf8");
|
|
32499
32842
|
} catch (err) {
|
|
32500
32843
|
return err.code === "ENOENT" ? "signed-out" : "unknown";
|
|
32501
32844
|
}
|
|
@@ -32515,7 +32858,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
32515
32858
|
function readCodexAccountId(codexHome = defaultCodexHome()) {
|
|
32516
32859
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return void 0;
|
|
32517
32860
|
try {
|
|
32518
|
-
const doc = JSON.parse(
|
|
32861
|
+
const doc = JSON.parse(readFileSync19(join26(codexHome, "auth.json"), "utf8"));
|
|
32519
32862
|
if (!doc || typeof doc !== "object") return void 0;
|
|
32520
32863
|
const tokens = doc.tokens;
|
|
32521
32864
|
if (!tokens || typeof tokens !== "object") return void 0;
|
|
@@ -32574,12 +32917,12 @@ function asEmail(value) {
|
|
|
32574
32917
|
}
|
|
32575
32918
|
function claudeAccountFile() {
|
|
32576
32919
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32577
|
-
return override && override.trim() ?
|
|
32920
|
+
return override && override.trim() ? join26(override, ".claude.json") : join26(homedir10(), ".claude.json");
|
|
32578
32921
|
}
|
|
32579
32922
|
function readClaudeAccountEmail(path3 = claudeAccountFile()) {
|
|
32580
32923
|
let stat2;
|
|
32581
32924
|
try {
|
|
32582
|
-
stat2 =
|
|
32925
|
+
stat2 = statSync11(path3);
|
|
32583
32926
|
} catch {
|
|
32584
32927
|
return void 0;
|
|
32585
32928
|
}
|
|
@@ -32587,7 +32930,7 @@ function readClaudeAccountEmail(path3 = claudeAccountFile()) {
|
|
|
32587
32930
|
if (memo3 && memo3.path === path3 && memo3.mtimeMs === stat2.mtimeMs && memo3.size === stat2.size) return memo3.email;
|
|
32588
32931
|
let email;
|
|
32589
32932
|
try {
|
|
32590
|
-
const doc = JSON.parse(
|
|
32933
|
+
const doc = JSON.parse(readFileSync19(path3, "utf8"));
|
|
32591
32934
|
email = asEmail(doc?.oauthAccount?.emailAddress);
|
|
32592
32935
|
} catch {
|
|
32593
32936
|
email = void 0;
|
|
@@ -32598,7 +32941,7 @@ function readClaudeAccountEmail(path3 = claudeAccountFile()) {
|
|
|
32598
32941
|
function readCodexAccountEmail(codexHome = defaultCodexHome()) {
|
|
32599
32942
|
let doc;
|
|
32600
32943
|
try {
|
|
32601
|
-
doc = JSON.parse(
|
|
32944
|
+
doc = JSON.parse(readFileSync19(join26(codexHome, "auth.json"), "utf8"));
|
|
32602
32945
|
} catch {
|
|
32603
32946
|
return void 0;
|
|
32604
32947
|
}
|
|
@@ -32724,7 +33067,7 @@ var init_codex_execution_health = __esm({
|
|
|
32724
33067
|
|
|
32725
33068
|
// packages/server/src/backend/codex-app-server.ts
|
|
32726
33069
|
import { createHash as createHash11, randomUUID as randomUUID11 } from "node:crypto";
|
|
32727
|
-
import { existsSync as
|
|
33070
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
32728
33071
|
import { StringDecoder as StringDecoder3 } from "node:string_decoder";
|
|
32729
33072
|
function selectCodexHostKind(flagValue, platform3, hasSpawn) {
|
|
32730
33073
|
if (hasSpawn) return "direct";
|
|
@@ -35174,7 +35517,7 @@ var init_codex_app_server = __esm({
|
|
|
35174
35517
|
* external rollout may legitimately live somewhere else.
|
|
35175
35518
|
*/
|
|
35176
35519
|
resumeCwdOverride(row) {
|
|
35177
|
-
if (
|
|
35520
|
+
if (existsSync10(row.cwd)) return {};
|
|
35178
35521
|
return { cwd: this.options.projectDir };
|
|
35179
35522
|
}
|
|
35180
35523
|
recordResumedCwd(row, override) {
|
|
@@ -35996,17 +36339,17 @@ var init_codex_app_server = __esm({
|
|
|
35996
36339
|
});
|
|
35997
36340
|
|
|
35998
36341
|
// packages/server/src/backend/codex-quota.ts
|
|
35999
|
-
import { join as
|
|
36000
|
-
import { readdirSync as
|
|
36342
|
+
import { join as join27 } from "node:path";
|
|
36343
|
+
import { readdirSync as readdirSync8, statSync as statSync12, openSync as openSync13, readSync as readSync6, fstatSync, closeSync as closeSync12 } from "node:fs";
|
|
36001
36344
|
import { spawn as spawn4 } from "node:child_process";
|
|
36002
36345
|
function sessionsDir2(codexHome) {
|
|
36003
|
-
return
|
|
36346
|
+
return join27(codexHome, "sessions");
|
|
36004
36347
|
}
|
|
36005
36348
|
function newestRollouts(dir, out, budget) {
|
|
36006
36349
|
if (budget.n <= 0) return;
|
|
36007
36350
|
let entries2;
|
|
36008
36351
|
try {
|
|
36009
|
-
entries2 =
|
|
36352
|
+
entries2 = readdirSync8(dir, { withFileTypes: true });
|
|
36010
36353
|
} catch {
|
|
36011
36354
|
return;
|
|
36012
36355
|
}
|
|
@@ -36014,18 +36357,18 @@ function newestRollouts(dir, out, budget) {
|
|
|
36014
36357
|
const files = entries2.filter((e14) => e14.isFile() && e14.name.startsWith("rollout-") && e14.name.endsWith(".jsonl")).map((e14) => e14.name).sort(descByName2);
|
|
36015
36358
|
for (const d of dirs) {
|
|
36016
36359
|
if (budget.n <= 0) return;
|
|
36017
|
-
newestRollouts(
|
|
36360
|
+
newestRollouts(join27(dir, d), out, budget);
|
|
36018
36361
|
}
|
|
36019
36362
|
for (const f of files) {
|
|
36020
36363
|
if (budget.n <= 0) return;
|
|
36021
|
-
out.push(
|
|
36364
|
+
out.push(join27(dir, f));
|
|
36022
36365
|
budget.n--;
|
|
36023
36366
|
}
|
|
36024
36367
|
}
|
|
36025
36368
|
function readTail(path3) {
|
|
36026
36369
|
let fd2;
|
|
36027
36370
|
try {
|
|
36028
|
-
fd2 =
|
|
36371
|
+
fd2 = openSync13(path3, "r");
|
|
36029
36372
|
const size = fstatSync(fd2).size;
|
|
36030
36373
|
const start = Math.max(0, size - TAIL_BYTES);
|
|
36031
36374
|
const len = size - start;
|
|
@@ -36042,7 +36385,7 @@ function readTail(path3) {
|
|
|
36042
36385
|
} finally {
|
|
36043
36386
|
if (fd2 !== void 0) {
|
|
36044
36387
|
try {
|
|
36045
|
-
|
|
36388
|
+
closeSync12(fd2);
|
|
36046
36389
|
} catch {
|
|
36047
36390
|
}
|
|
36048
36391
|
}
|
|
@@ -36090,7 +36433,7 @@ function readCodexQuotaFromRollouts(codexHome = defaultCodexHome()) {
|
|
|
36090
36433
|
newestRollouts(sessionsDir2(codexHome), rollouts, { n: 8 });
|
|
36091
36434
|
const byMtime = rollouts.map((path3) => {
|
|
36092
36435
|
try {
|
|
36093
|
-
return { path: path3, mtimeMs:
|
|
36436
|
+
return { path: path3, mtimeMs: statSync12(path3).mtimeMs };
|
|
36094
36437
|
} catch {
|
|
36095
36438
|
return void 0;
|
|
36096
36439
|
}
|
|
@@ -36289,25 +36632,15 @@ var init_quota = __esm({
|
|
|
36289
36632
|
}
|
|
36290
36633
|
});
|
|
36291
36634
|
|
|
36292
|
-
// packages/server/src/local-path.ts
|
|
36293
|
-
function normalizeLocalPath(path3, platform3 = process.platform) {
|
|
36294
|
-
return platform3 === "win32" ? path3.replace(/^\/([a-zA-Z]:[\\/])/, "$1") : path3;
|
|
36295
|
-
}
|
|
36296
|
-
var init_local_path = __esm({
|
|
36297
|
-
"packages/server/src/local-path.ts"() {
|
|
36298
|
-
"use strict";
|
|
36299
|
-
}
|
|
36300
|
-
});
|
|
36301
|
-
|
|
36302
36635
|
// packages/server/src/local-file.ts
|
|
36303
36636
|
import { spawn as spawn5 } from "node:child_process";
|
|
36304
|
-
import { existsSync as
|
|
36637
|
+
import { existsSync as existsSync11, readFileSync as readFileSync20, realpathSync as realpathSync7, statSync as statSync13 } from "node:fs";
|
|
36305
36638
|
import { homedir as homedir11 } from "node:os";
|
|
36306
|
-
import { dirname as
|
|
36639
|
+
import { dirname as dirname11, isAbsolute as isAbsolute5, join as join28, resolve as resolve5, sep as sep2 } from "node:path";
|
|
36307
36640
|
function isUnder(real, root) {
|
|
36308
36641
|
let rootReal;
|
|
36309
36642
|
try {
|
|
36310
|
-
rootReal =
|
|
36643
|
+
rootReal = realpathSync7(root);
|
|
36311
36644
|
} catch {
|
|
36312
36645
|
return false;
|
|
36313
36646
|
}
|
|
@@ -36315,12 +36648,12 @@ function isUnder(real, root) {
|
|
|
36315
36648
|
return real === rootReal || real.startsWith(rootReal.endsWith(sep2) ? rootReal : rootReal + sep2);
|
|
36316
36649
|
}
|
|
36317
36650
|
try {
|
|
36318
|
-
const trusted2 =
|
|
36651
|
+
const trusted2 = statSync13(rootReal, { bigint: true });
|
|
36319
36652
|
if (!trusted2.isDirectory() || trusted2.ino === 0n) return false;
|
|
36320
36653
|
for (let ancestor = real; ; ) {
|
|
36321
|
-
const actual =
|
|
36654
|
+
const actual = statSync13(ancestor, { bigint: true });
|
|
36322
36655
|
if (actual.dev === trusted2.dev && actual.ino === trusted2.ino) return true;
|
|
36323
|
-
const parent =
|
|
36656
|
+
const parent = dirname11(ancestor);
|
|
36324
36657
|
if (parent === ancestor) return false;
|
|
36325
36658
|
ancestor = parent;
|
|
36326
36659
|
}
|
|
@@ -36330,16 +36663,16 @@ function isUnder(real, root) {
|
|
|
36330
36663
|
}
|
|
36331
36664
|
function resolveLocalFile(rawPath, roots) {
|
|
36332
36665
|
rawPath = normalizeLocalPath(rawPath);
|
|
36333
|
-
if (!
|
|
36666
|
+
if (!isAbsolute5(rawPath)) throw new Error("Local path must be absolute");
|
|
36334
36667
|
let real;
|
|
36335
36668
|
try {
|
|
36336
|
-
real =
|
|
36669
|
+
real = realpathSync7(rawPath);
|
|
36337
36670
|
} catch {
|
|
36338
36671
|
throw new Error("Local file was not found");
|
|
36339
36672
|
}
|
|
36340
36673
|
if (!roots.some((root) => isUnder(real, root))) throw new Error("Local file is outside Frizz's trusted roots");
|
|
36341
36674
|
try {
|
|
36342
|
-
if (!
|
|
36675
|
+
if (!statSync13(real).isFile()) throw new Error("Local path is not a regular file");
|
|
36343
36676
|
} catch (error) {
|
|
36344
36677
|
if (error instanceof Error && error.message === "Local path is not a regular file") throw error;
|
|
36345
36678
|
throw new Error("Local file was not found");
|
|
@@ -36349,7 +36682,7 @@ function resolveLocalFile(rawPath, roots) {
|
|
|
36349
36682
|
function resolveOpenableFile(raw2, projectDir, roots, home = homedir11()) {
|
|
36350
36683
|
const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
|
|
36351
36684
|
if (!trimmed) return null;
|
|
36352
|
-
const abs = trimmed === "~" ? home : /^~[\/\\]/.test(trimmed) ?
|
|
36685
|
+
const abs = trimmed === "~" ? home : /^~[\/\\]/.test(trimmed) ? join28(home, trimmed.slice(2)) : isAbsolute5(trimmed) ? trimmed : resolve5(projectDir, trimmed);
|
|
36353
36686
|
try {
|
|
36354
36687
|
return resolveLocalFile(abs, roots);
|
|
36355
36688
|
} catch {
|
|
@@ -36358,7 +36691,7 @@ function resolveOpenableFile(raw2, projectDir, roots, home = homedir11()) {
|
|
|
36358
36691
|
}
|
|
36359
36692
|
function readLocalTextFile(rawPath, roots) {
|
|
36360
36693
|
const path3 = resolveLocalFile(rawPath, roots);
|
|
36361
|
-
const bytes =
|
|
36694
|
+
const bytes = readFileSync20(path3);
|
|
36362
36695
|
if (bytes.subarray(0, 8192).includes(0)) throw new Error("Local file is not a text file");
|
|
36363
36696
|
if (bytes.length <= MARKDOWN_READ_LIMIT) return { path: path3, text: bytes.toString("utf8"), truncated: false };
|
|
36364
36697
|
const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
|
|
@@ -36369,7 +36702,7 @@ function readLocalMarkdown(rawPath, roots) {
|
|
|
36369
36702
|
if (!MARKDOWN_FILE_EXT.test(rawPath.trim())) throw new Error("Local file is not a Markdown file");
|
|
36370
36703
|
const path3 = resolveLocalFile(rawPath, roots);
|
|
36371
36704
|
if (!MARKDOWN_FILE_EXT.test(path3)) throw new Error("Local file is not a Markdown file");
|
|
36372
|
-
const bytes =
|
|
36705
|
+
const bytes = readFileSync20(path3);
|
|
36373
36706
|
if (bytes.length <= MARKDOWN_READ_LIMIT) return { path: path3, markdown: bytes.toString("utf8"), truncated: false };
|
|
36374
36707
|
const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
|
|
36375
36708
|
const lastBreak = head.lastIndexOf(10);
|
|
@@ -36404,10 +36737,10 @@ function localFileOpenCommand(path3, selected, options = {}) {
|
|
|
36404
36737
|
if (selected === "finder") return { command: "explorer.exe", args: [`/select,${path3}`] };
|
|
36405
36738
|
const editor = WINDOWS_EDITOR_EXE[selected];
|
|
36406
36739
|
const env = options.env ?? process.env;
|
|
36407
|
-
const exists = options.exists ??
|
|
36740
|
+
const exists = options.exists ?? existsSync11;
|
|
36408
36741
|
const localAppData = env.LOCALAPPDATA;
|
|
36409
36742
|
if (localAppData) {
|
|
36410
|
-
const exe2 =
|
|
36743
|
+
const exe2 = join28(localAppData, ...editor.exe);
|
|
36411
36744
|
if (exists(exe2)) return { command: exe2, args: [path3] };
|
|
36412
36745
|
}
|
|
36413
36746
|
if (/["%\r\n]/u.test(path3)) throw new Error(`cannot hand ${path3} to the ${editor.shim} shim through cmd.exe`);
|
|
@@ -36445,7 +36778,7 @@ var init_local_file = __esm({
|
|
|
36445
36778
|
});
|
|
36446
36779
|
|
|
36447
36780
|
// packages/server/src/thread-links.ts
|
|
36448
|
-
import { isAbsolute as
|
|
36781
|
+
import { isAbsolute as isAbsolute6 } from "node:path";
|
|
36449
36782
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
36450
36783
|
function threadLinkView(row) {
|
|
36451
36784
|
return { id: row.id, kind: row.kind, label: row.label, target: row.target };
|
|
@@ -36461,7 +36794,7 @@ function resolveThreadLink(target, projectDir, roots) {
|
|
|
36461
36794
|
const url = new URL(target);
|
|
36462
36795
|
if (url.search || url.hash) throw new Error("File links must not contain a query or fragment");
|
|
36463
36796
|
path3 = fileURLToPath2(url);
|
|
36464
|
-
} else if (!
|
|
36797
|
+
} else if (!isAbsolute6(target) && /^[a-z][a-z\d+.-]*:/i.test(target)) {
|
|
36465
36798
|
throw new Error("Register an HTTP(S) URL or a local file");
|
|
36466
36799
|
}
|
|
36467
36800
|
const resolved2 = resolveOpenableFile(path3, projectDir, roots);
|
|
@@ -36672,8 +37005,8 @@ var init_claude_model_upgrade = __esm({
|
|
|
36672
37005
|
|
|
36673
37006
|
// packages/server/src/frizz.ts
|
|
36674
37007
|
import { execFile as execFile6 } from "node:child_process";
|
|
36675
|
-
import { lstatSync as
|
|
36676
|
-
import { basename as basename5, dirname as
|
|
37008
|
+
import { lstatSync as lstatSync3, realpathSync as realpathSync8 } from "node:fs";
|
|
37009
|
+
import { basename as basename5, dirname as dirname12, join as join29, resolve as resolve6 } from "node:path";
|
|
36677
37010
|
import { promisify as promisify5 } from "node:util";
|
|
36678
37011
|
function frizzScriptsDir() {
|
|
36679
37012
|
if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
|
|
@@ -36681,12 +37014,12 @@ function frizzScriptsDir() {
|
|
|
36681
37014
|
}
|
|
36682
37015
|
function directFrizzRoot(projectDir) {
|
|
36683
37016
|
try {
|
|
36684
|
-
const projectRoot =
|
|
36685
|
-
const path3 =
|
|
36686
|
-
const stat2 =
|
|
37017
|
+
const projectRoot = realpathSync8(projectDir);
|
|
37018
|
+
const path3 = join29(projectRoot, ".frizz");
|
|
37019
|
+
const stat2 = lstatSync3(path3);
|
|
36687
37020
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
36688
|
-
const real =
|
|
36689
|
-
return
|
|
37021
|
+
const real = realpathSync8(path3);
|
|
37022
|
+
return dirname12(real) === projectRoot && basename5(real) === ".frizz" ? real : null;
|
|
36690
37023
|
} catch {
|
|
36691
37024
|
return null;
|
|
36692
37025
|
}
|
|
@@ -36696,7 +37029,7 @@ function frizzDirExists(projectDir) {
|
|
|
36696
37029
|
}
|
|
36697
37030
|
async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
36698
37031
|
if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
|
|
36699
|
-
const { stdout } = await execFileP("node", [
|
|
37032
|
+
const { stdout } = await execFileP("node", [join29(scriptsDir, "index.mjs"), "--json"], {
|
|
36700
37033
|
cwd: projectDir,
|
|
36701
37034
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
|
|
36702
37035
|
maxBuffer: 32 * 1024 * 1024
|
|
@@ -36721,7 +37054,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
|
36721
37054
|
};
|
|
36722
37055
|
}
|
|
36723
37056
|
async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
|
|
36724
|
-
await execFileP("node", [
|
|
37057
|
+
await execFileP("node", [join29(scriptsDir, "thread-update.mjs"), slug, ...args], {
|
|
36725
37058
|
cwd: projectDir,
|
|
36726
37059
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
|
|
36727
37060
|
});
|
|
@@ -36855,12 +37188,12 @@ var init_awaiting = __esm({
|
|
|
36855
37188
|
});
|
|
36856
37189
|
|
|
36857
37190
|
// packages/server/src/backend/project-mcp-servers.ts
|
|
36858
|
-
import { readFileSync as
|
|
37191
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
36859
37192
|
import { homedir as homedir12 } from "node:os";
|
|
36860
|
-
import { join as
|
|
37193
|
+
import { join as join30 } from "node:path";
|
|
36861
37194
|
function readJsonObject(path3) {
|
|
36862
37195
|
try {
|
|
36863
|
-
const parsed = JSON.parse(
|
|
37196
|
+
const parsed = JSON.parse(readFileSync21(path3, "utf8"));
|
|
36864
37197
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
36865
37198
|
} catch {
|
|
36866
37199
|
return void 0;
|
|
@@ -36953,15 +37286,15 @@ function projectMcpServers(cwd, options = {}) {
|
|
|
36953
37286
|
const env = options.env ?? process.env;
|
|
36954
37287
|
const home = options.home ?? homedir12();
|
|
36955
37288
|
const configOverride = options.claudeConfigDir ?? (env.CLAUDE_CONFIG_DIR?.trim() ? env.CLAUDE_CONFIG_DIR.trim() : void 0);
|
|
36956
|
-
const accountFile = configOverride ?
|
|
36957
|
-
const userSettingsFile =
|
|
37289
|
+
const accountFile = configOverride ? join30(configOverride, ".claude.json") : join30(home, ".claude.json");
|
|
37290
|
+
const userSettingsFile = join30(configOverride ?? join30(home, ".claude"), "settings.json");
|
|
36958
37291
|
const account = readJsonObject(accountFile);
|
|
36959
37292
|
const out = userScopeRemoteServers(account, cwd, env);
|
|
36960
|
-
const declared = objectField(readJsonObject(
|
|
37293
|
+
const declared = objectField(readJsonObject(join30(cwd, ".mcp.json")), "mcpServers");
|
|
36961
37294
|
if (!declared) return out;
|
|
36962
37295
|
const approval = collectApproval([
|
|
36963
|
-
readJsonObject(
|
|
36964
|
-
readJsonObject(
|
|
37296
|
+
readJsonObject(join30(cwd, ".claude", "settings.json")),
|
|
37297
|
+
readJsonObject(join30(cwd, ".claude", "settings.local.json")),
|
|
36965
37298
|
readJsonObject(userSettingsFile),
|
|
36966
37299
|
objectField(objectField(account, "projects"), cwd)
|
|
36967
37300
|
]);
|
|
@@ -36985,18 +37318,18 @@ var init_project_mcp_servers = __esm({
|
|
|
36985
37318
|
});
|
|
36986
37319
|
|
|
36987
37320
|
// packages/server/src/worker-plugin-dir.ts
|
|
36988
|
-
import { existsSync as
|
|
36989
|
-
import { dirname as
|
|
37321
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
37322
|
+
import { dirname as dirname13, join as join31 } from "node:path";
|
|
36990
37323
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
36991
37324
|
function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
|
|
36992
37325
|
const override = env.FRIZZ_WORKER_PLUGIN_DIR;
|
|
36993
|
-
if (override &&
|
|
37326
|
+
if (override && existsSync12(join31(override, ".claude-plugin", "plugin.json")))
|
|
36994
37327
|
return override;
|
|
36995
|
-
let current =
|
|
37328
|
+
let current = dirname13(fileURLToPath3(moduleUrl));
|
|
36996
37329
|
for (; ; ) {
|
|
36997
|
-
const candidate =
|
|
36998
|
-
if (
|
|
36999
|
-
const parent =
|
|
37330
|
+
const candidate = join31(current, "cc-worker");
|
|
37331
|
+
if (existsSync12(join31(candidate, ".claude-plugin", "plugin.json"))) return candidate;
|
|
37332
|
+
const parent = dirname13(current);
|
|
37000
37333
|
if (parent === current) return void 0;
|
|
37001
37334
|
current = parent;
|
|
37002
37335
|
}
|
|
@@ -37144,9 +37477,9 @@ reasoning around the ask, never a copy of it (see Questions for the human).
|
|
|
37144
37477
|
**AT EVERY LATER REST, SAY WHERE EACH OLD QUESTION STANDS.** A question still open from an EARLIER rest
|
|
37145
37478
|
is not your new rest's sign-off, and frizz does NOT redraw its card under your new handoff \u2014 it stays
|
|
37146
37479
|
where you asked it. So a later rest either NAMES each one you still need under \`questions:\` in an
|
|
37147
|
-
\` \`\`\`awaiting \` fence \u2014 its card is then drawn at this rest, under your fence \u2014 or WITHDRAWS
|
|
37148
|
-
\`unask\`. A rest that does neither is bumped, and so is any \` \`\`\`awaiting \` fence that leaves
|
|
37149
|
-
question out, at whichever rest it lands.
|
|
37480
|
+
\` \`\`\`awaiting \` fence \u2014 its card is then drawn at this rest, under your fence's prose \u2014 or WITHDRAWS
|
|
37481
|
+
it with \`unask\`. A rest that does neither is bumped, and so is any \` \`\`\`awaiting \` fence that leaves
|
|
37482
|
+
an open question out, at whichever rest it lands.
|
|
37150
37483
|
|
|
37151
37484
|
Use at most ONE fenced signal block, at the very END (a question's PLACEMENT marker is not a signal
|
|
37152
37485
|
block \u2014 see Questions for the human). The fence language is the state; the body is the card the human
|
|
@@ -37267,7 +37600,7 @@ exactly ONE of them.
|
|
|
37267
37600
|
title: Sign in to npm so the release can publish
|
|
37268
37601
|
steps:
|
|
37269
37602
|
- Run \`npm login --auth-type=web\` in a terminal on this machine.
|
|
37270
|
-
- Approve the browser prompt with the maintainer account.
|
|
37603
|
+
- Approve the browser prompt with the maintainer account; if no prompt opens, sign in at [npmjs.com/login](https://www.npmjs.com/login) and run the command again.
|
|
37271
37604
|
---
|
|
37272
37605
|
The publish step runs as the maintainer, and no token for that account is available to this thread.
|
|
37273
37606
|
\`\`\`
|
|
@@ -37352,12 +37685,34 @@ exactly ONE of them.
|
|
|
37352
37685
|
\`Done\`, the same as anything they type; anything else they need to tell you \u2014 a step that failed,
|
|
37353
37686
|
the account they used \u2014 comes as a message of their own. An act is not a decision: never ask
|
|
37354
37687
|
WHETHER they will do it, and never call \`done\` while it is still owed.
|
|
37688
|
+
**EVERY STEP IS CLICKABLE AND COMPLETE \u2014 A STEP THAT MAKES THE HUMAN GO LOOKING IS A BROKEN STEP.**
|
|
37689
|
+
The steps are the most actionable thing you hand over, so write each one to be DONE, not
|
|
37690
|
+
researched: every page it names is a real Markdown link to that exact page (the settings screen,
|
|
37691
|
+
the audit log, the PR, the release run \u2014 never "in the dashboard" or "on GitHub"); every file is a
|
|
37692
|
+
real link; every command is a code span ready to paste; and every value the act needs \u2014 the account,
|
|
37693
|
+
the date range, the token or secret name, the exact button \u2014 is written into the step. Steps render
|
|
37694
|
+
as Markdown, so links click. Bad: \`Open the Cloudflare dashboard and check the audit log for the
|
|
37695
|
+
upload.\` Good: \`Open the [Frizz account audit log](https://dash.cloudflare.com/<account-id>/audit-log),
|
|
37696
|
+
filter to 2026-10-05 18:00\u201319:00 UTC, and note the actor and IP on the frizz-relay upload.\`
|
|
37697
|
+
Fill in every id you hold; when you cannot know a URL, link the nearest page you can and say what to
|
|
37698
|
+
click there. A step is cut at 500 characters, so keep each link inside that.
|
|
37699
|
+
(Maintainer 2026-10-08, after a security handoff listed seven to-dos with no link in any of them:
|
|
37700
|
+
*"Anytime you stop with a to-do block for the user, it needs to include clickable links. It needs to
|
|
37701
|
+
be as actionable as possible."*)
|
|
37702
|
+
**A VALUE ONLY THE HUMAN HOLDS IS NOT A STEP** \u2014 a 2FA code, a token, a password a command needs.
|
|
37703
|
+
Ask for it with \`mcp__frizz__secret\`: the human pastes it into a masked card, from any device, and
|
|
37704
|
+
it is served from memory through a private pipe whose path the tool returns. The path reads ONCE:
|
|
37705
|
+
use it inside the command (\`--otp "$(cat '<path>')"\`) and never print it. It is a registered
|
|
37706
|
+
question: name it under \`questions:\` at later rests.
|
|
37355
37707
|
- \`questions:\` \u2014 your registered questions you are STILL waiting on, by id: \`questions: [qst_ab12cd34]\`.
|
|
37356
37708
|
A fence beside open questions names EVERY one of them \u2014 withdraw any you no longer need with
|
|
37357
37709
|
\`mcp__frizz__unask\` first \u2014 or frizz refuses the park and lists what it left out. Each named card is
|
|
37358
37710
|
drawn at THIS rest, under your fence; to set it inside your prose instead, add its placement marker
|
|
37359
|
-
(see Questions for the human).
|
|
37360
|
-
|
|
37711
|
+
(see Questions for the human). A fence that names questions draws NO awaiting card of its own: the
|
|
37712
|
+
question cards are the rest's ending, its prose under \`---\` reads as plain handoff text, and the
|
|
37713
|
+
work it also names is listed beside the human's prompt box (a fence with \`steps:\` keeps its card).
|
|
37714
|
+
Like \`steps:\`, questions name the human as the wait: no other name and no \`for:\` needed, and the
|
|
37715
|
+
thread stays in their queue.
|
|
37361
37716
|
- **REGISTERING IS NOT PARKING, AND PARKING IS NOT REGISTERING.** Your shells, sub-agents, timers
|
|
37362
37717
|
and PR watchers are watched AUTOMATICALLY, fence or no fence \u2014 frizz wakes you when one finishes,
|
|
37363
37718
|
every time. The fence only declares that you have STOPPED, names which of them you stopped for,
|
|
@@ -38108,26 +38463,26 @@ checks. Depth scales with blast radius and yields to the project's conventions.`
|
|
|
38108
38463
|
});
|
|
38109
38464
|
|
|
38110
38465
|
// packages/server/src/backend/acp-agents.ts
|
|
38111
|
-
import { accessSync as accessSync3, constants, statSync as
|
|
38112
|
-
import { delimiter as delimiter2, isAbsolute as
|
|
38466
|
+
import { accessSync as accessSync3, constants as constants2, statSync as statSync14 } from "node:fs";
|
|
38467
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute7, join as join32 } from "node:path";
|
|
38113
38468
|
function isExecutableFile(path3) {
|
|
38114
38469
|
try {
|
|
38115
|
-
if (!
|
|
38116
|
-
if (process.platform !== "win32") accessSync3(path3,
|
|
38470
|
+
if (!statSync14(path3).isFile()) return false;
|
|
38471
|
+
if (process.platform !== "win32") accessSync3(path3, constants2.X_OK);
|
|
38117
38472
|
return true;
|
|
38118
38473
|
} catch {
|
|
38119
38474
|
return false;
|
|
38120
38475
|
}
|
|
38121
38476
|
}
|
|
38122
38477
|
function findOnPath(command, env = process.env) {
|
|
38123
|
-
if (
|
|
38478
|
+
if (isAbsolute7(command)) return isExecutableFile(command) ? command : void 0;
|
|
38124
38479
|
const dirs = (env.PATH ?? env.Path ?? "").split(delimiter2).filter(Boolean);
|
|
38125
38480
|
const exts = process.platform === "win32" ? ["", ...(env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")] : [""];
|
|
38126
38481
|
for (const dir of dirs) {
|
|
38127
38482
|
for (const ext of exts) {
|
|
38128
|
-
const candidate =
|
|
38483
|
+
const candidate = join32(dir, command + ext.toLowerCase());
|
|
38129
38484
|
if (isExecutableFile(candidate)) return candidate;
|
|
38130
|
-
if (ext && isExecutableFile(
|
|
38485
|
+
if (ext && isExecutableFile(join32(dir, command + ext))) return join32(dir, command + ext);
|
|
38131
38486
|
}
|
|
38132
38487
|
}
|
|
38133
38488
|
return void 0;
|
|
@@ -39144,8 +39499,8 @@ var init_claude_agent_broker_bridge = __esm({
|
|
|
39144
39499
|
});
|
|
39145
39500
|
|
|
39146
39501
|
// packages/server/src/dispatch.ts
|
|
39147
|
-
import { closeSync as
|
|
39148
|
-
import { basename as basename6, join as
|
|
39502
|
+
import { closeSync as closeSync13, constants as constants3, existsSync as existsSync13, fstatSync as fstatSync2, lstatSync as lstatSync4, openSync as openSync14, readFileSync as readFileSync22, realpathSync as realpathSync9, statSync as statSync15, writeFileSync as writeFileSync13, mkdirSync as mkdirSync16, rmSync as rmSync10 } from "node:fs";
|
|
39503
|
+
import { basename as basename6, join as join33, dirname as dirname14 } from "node:path";
|
|
39149
39504
|
import { createHash as createHash12, randomUUID as randomUUID13 } from "node:crypto";
|
|
39150
39505
|
function fallbackTitle(prompt) {
|
|
39151
39506
|
const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
|
|
@@ -39164,7 +39519,7 @@ function fallbackTitle(prompt) {
|
|
|
39164
39519
|
}
|
|
39165
39520
|
function resolveSlug(frizzDir, base, taken) {
|
|
39166
39521
|
base = ThreadSlug.parse(base);
|
|
39167
|
-
const isTaken = (slug) =>
|
|
39522
|
+
const isTaken = (slug) => existsSync13(join33(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
|
|
39168
39523
|
if (!isTaken(base)) return base;
|
|
39169
39524
|
for (let n = 2; ; n++) {
|
|
39170
39525
|
const suffix = `-${n}`;
|
|
@@ -39180,29 +39535,29 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
39180
39535
|
const parsed = ThreadSlug.safeParse(value);
|
|
39181
39536
|
if (!parsed.success) return null;
|
|
39182
39537
|
try {
|
|
39183
|
-
const projectRoot =
|
|
39184
|
-
const frizzPath =
|
|
39185
|
-
const frizzStat =
|
|
39538
|
+
const projectRoot = realpathSync9(projectDir);
|
|
39539
|
+
const frizzPath = join33(projectRoot, ".frizz");
|
|
39540
|
+
const frizzStat = lstatSync4(frizzPath);
|
|
39186
39541
|
if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
|
|
39187
|
-
const realFrizz =
|
|
39188
|
-
if (
|
|
39189
|
-
const path3 =
|
|
39190
|
-
const before =
|
|
39542
|
+
const realFrizz = realpathSync9(frizzPath);
|
|
39543
|
+
if (dirname14(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
|
|
39544
|
+
const path3 = join33(realFrizz, `${parsed.data}.md`);
|
|
39545
|
+
const before = lstatSync4(path3);
|
|
39191
39546
|
if (!before.isFile() || before.isSymbolicLink()) return null;
|
|
39192
|
-
const realPath =
|
|
39193
|
-
if (
|
|
39547
|
+
const realPath = realpathSync9(path3);
|
|
39548
|
+
if (dirname14(realPath) !== realFrizz || basename6(realPath) !== `${parsed.data}.md`) return null;
|
|
39194
39549
|
let contents;
|
|
39195
39550
|
let openedBefore;
|
|
39196
39551
|
let openedAfter;
|
|
39197
|
-
const fd2 =
|
|
39552
|
+
const fd2 = openSync14(path3, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
39198
39553
|
try {
|
|
39199
39554
|
openedBefore = fstatSync2(fd2);
|
|
39200
|
-
contents =
|
|
39555
|
+
contents = readFileSync22(fd2);
|
|
39201
39556
|
openedAfter = fstatSync2(fd2);
|
|
39202
39557
|
} finally {
|
|
39203
|
-
|
|
39558
|
+
closeSync13(fd2);
|
|
39204
39559
|
}
|
|
39205
|
-
const after =
|
|
39560
|
+
const after = lstatSync4(path3);
|
|
39206
39561
|
if (before.dev !== openedBefore.dev || before.ino !== openedBefore.ino || openedBefore.dev !== openedAfter.dev || openedBefore.ino !== openedAfter.ino || openedBefore.size !== openedAfter.size || openedBefore.mtimeMs !== openedAfter.mtimeMs || openedBefore.ctimeMs !== openedAfter.ctimeMs || after.dev !== openedAfter.dev || after.ino !== openedAfter.ino || after.size !== openedAfter.size || after.mtimeMs !== openedAfter.mtimeMs || after.ctimeMs !== openedAfter.ctimeMs || !openedAfter.isFile() || !after.isFile() || after.isSymbolicLink()) {
|
|
39207
39562
|
return null;
|
|
39208
39563
|
}
|
|
@@ -39230,17 +39585,17 @@ function boardAuthorizesAdoption(board, slug) {
|
|
|
39230
39585
|
return !board.errorItems.some((item) => item.file === `${slug}.md`);
|
|
39231
39586
|
}
|
|
39232
39587
|
function ensureSafeDirectDirectory(parent, name) {
|
|
39233
|
-
const path3 =
|
|
39588
|
+
const path3 = join33(parent, name);
|
|
39234
39589
|
try {
|
|
39235
|
-
|
|
39590
|
+
mkdirSync16(path3);
|
|
39236
39591
|
} catch (error) {
|
|
39237
39592
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
39238
39593
|
if (code !== "EEXIST") throw error;
|
|
39239
39594
|
}
|
|
39240
|
-
const stat2 =
|
|
39595
|
+
const stat2 = lstatSync4(path3);
|
|
39241
39596
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("unsafe project directory");
|
|
39242
|
-
const real =
|
|
39243
|
-
if (
|
|
39597
|
+
const real = realpathSync9(path3);
|
|
39598
|
+
if (dirname14(real) !== parent || basename6(real) !== name) throw new Error("unsafe project directory");
|
|
39244
39599
|
return real;
|
|
39245
39600
|
}
|
|
39246
39601
|
function scratchDirRelPath(sessionId) {
|
|
@@ -39248,7 +39603,7 @@ function scratchDirRelPath(sessionId) {
|
|
|
39248
39603
|
}
|
|
39249
39604
|
function writeScratchDir(projectDir, sessionId) {
|
|
39250
39605
|
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,199}$/.test(sessionId)) throw new Error("invalid session id");
|
|
39251
|
-
const projectRoot =
|
|
39606
|
+
const projectRoot = realpathSync9(projectDir);
|
|
39252
39607
|
const frizzDir = ensureSafeDirectDirectory(projectRoot, ".frizz");
|
|
39253
39608
|
const threadsDir = ensureSafeDirectDirectory(frizzDir, "threads");
|
|
39254
39609
|
ensureSafeDirectDirectory(threadsDir, sessionId);
|
|
@@ -39260,8 +39615,8 @@ function loadWorkerPrompt(kind = "claude") {
|
|
|
39260
39615
|
function monitorScriptsDir() {
|
|
39261
39616
|
const plugin = workerPluginDir();
|
|
39262
39617
|
if (!plugin) return void 0;
|
|
39263
|
-
const dir =
|
|
39264
|
-
return
|
|
39618
|
+
const dir = join33(plugin, "skills", "gh", "scripts");
|
|
39619
|
+
return existsSync13(join33(dir, "ci-watch.mjs")) ? dir : void 0;
|
|
39265
39620
|
}
|
|
39266
39621
|
function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
39267
39622
|
if (!hookScript || !sessionId) return {};
|
|
@@ -39273,7 +39628,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
39273
39628
|
}
|
|
39274
39629
|
]
|
|
39275
39630
|
});
|
|
39276
|
-
const bashBackgroundHook =
|
|
39631
|
+
const bashBackgroundHook = join33(dirname14(hookScript), "bash-background.mjs");
|
|
39277
39632
|
return {
|
|
39278
39633
|
bypass_hook_trust: true,
|
|
39279
39634
|
hooks: {
|
|
@@ -39299,7 +39654,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
39299
39654
|
}
|
|
39300
39655
|
function scratchpadHookScript() {
|
|
39301
39656
|
const plugin = workerPluginDir();
|
|
39302
|
-
return plugin ?
|
|
39657
|
+
return plugin ? join33(plugin, "hooks", "scratchpad.mjs") : void 0;
|
|
39303
39658
|
}
|
|
39304
39659
|
function composePrompt(sessionId, prompt, kind = "claude") {
|
|
39305
39660
|
const children2 = kind === "codex" ? "Native sub-agents share it \u2014 have each write its OWN file rather than all editing one." : "Name it in a sub-agent's prompt when you want its notes to land somewhere you can read; give each child its OWN file rather than having them all edit one.";
|
|
@@ -39315,12 +39670,12 @@ function scratchpadOrientation(sessionId, kind = "claude") {
|
|
|
39315
39670
|
return `SCRATCH DIRECTORY: .frizz/threads/${sessionId}/ \u2014 yours, free-form, as many files as you like, and nothing is expected in it. A single direct task usually needs none; writing notes is never a substitute for doing the work (${children2}). Nothing in this directory is read automatically; if you want a note back after a compaction, mcp__frizz__goal with post_compaction: true re-sends a prompt of your choosing.`;
|
|
39316
39671
|
}
|
|
39317
39672
|
function frizzConfigBlock(projectDir) {
|
|
39318
|
-
const path3 =
|
|
39673
|
+
const path3 = join33(projectDir, "FRIZZ.md");
|
|
39319
39674
|
let body;
|
|
39320
39675
|
try {
|
|
39321
|
-
const st2 =
|
|
39676
|
+
const st2 = statSync15(path3);
|
|
39322
39677
|
if (!st2.isFile() || st2.size > FRIZZ_MD_MAX_BYTES) return "";
|
|
39323
|
-
body =
|
|
39678
|
+
body = readFileSync22(path3, "utf8").trim();
|
|
39324
39679
|
} catch {
|
|
39325
39680
|
return "";
|
|
39326
39681
|
}
|
|
@@ -39350,17 +39705,17 @@ function effectivePermissionMode(kind, mode) {
|
|
|
39350
39705
|
}
|
|
39351
39706
|
function systemPromptFlags(sessionId, system) {
|
|
39352
39707
|
if (!system) return [];
|
|
39353
|
-
|
|
39708
|
+
mkdirSync16(SYSTEM_PROMPT_DIR, { recursive: true });
|
|
39354
39709
|
const path3 = systemPromptPath(sessionId);
|
|
39355
|
-
|
|
39710
|
+
writeFileSync13(path3, system);
|
|
39356
39711
|
return ["--append-system-prompt-file", path3];
|
|
39357
39712
|
}
|
|
39358
39713
|
function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env, slug) {
|
|
39359
39714
|
const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
|
|
39360
39715
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
39361
39716
|
if (!pluginDir) return void 0;
|
|
39362
|
-
const scriptPath =
|
|
39363
|
-
if (!
|
|
39717
|
+
const scriptPath = join33(pluginDir, "bin", FRIZZ_MCP.script);
|
|
39718
|
+
if (!existsSync13(scriptPath)) return void 0;
|
|
39364
39719
|
return {
|
|
39365
39720
|
scriptPath,
|
|
39366
39721
|
stateDir,
|
|
@@ -39441,12 +39796,12 @@ function buildClaudeResumeCommand(opts) {
|
|
|
39441
39796
|
}
|
|
39442
39797
|
function createDispatcher(deps) {
|
|
39443
39798
|
const readBoardSource = deps.readBoard ?? readBoard;
|
|
39444
|
-
const frizzDir =
|
|
39799
|
+
const frizzDir = join33(deps.project.dir, ".frizz");
|
|
39445
39800
|
const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
|
|
39446
39801
|
function cleanupPrewrites(built) {
|
|
39447
39802
|
for (const path3 of new Set(built.prewrite.map((file) => file.path))) {
|
|
39448
39803
|
try {
|
|
39449
|
-
|
|
39804
|
+
rmSync10(path3, { force: true });
|
|
39450
39805
|
} catch {
|
|
39451
39806
|
}
|
|
39452
39807
|
}
|
|
@@ -39454,7 +39809,7 @@ function createDispatcher(deps) {
|
|
|
39454
39809
|
function cleanupDispatchFiles(scratchRel, built, sessionId) {
|
|
39455
39810
|
cleanupPrewrites(built);
|
|
39456
39811
|
try {
|
|
39457
|
-
|
|
39812
|
+
rmSync10(join33(deps.project.dir, scratchRel), { force: true, recursive: true });
|
|
39458
39813
|
} catch {
|
|
39459
39814
|
}
|
|
39460
39815
|
cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
|
|
@@ -39943,11 +40298,11 @@ var init_dispatch = __esm({
|
|
|
39943
40298
|
|
|
39944
40299
|
// packages/server/src/board.ts
|
|
39945
40300
|
import {
|
|
39946
|
-
realpathSync as
|
|
40301
|
+
realpathSync as realpathSync10,
|
|
39947
40302
|
watch as fsWatch
|
|
39948
40303
|
} from "node:fs";
|
|
39949
40304
|
import { homedir as homedir14 } from "node:os";
|
|
39950
|
-
import { dirname as
|
|
40305
|
+
import { dirname as dirname15, join as join34 } from "node:path";
|
|
39951
40306
|
import watcher from "@parcel/watcher";
|
|
39952
40307
|
function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
|
|
39953
40308
|
if (!liveness) return false;
|
|
@@ -39996,7 +40351,7 @@ function registeredLegacyFileIsTerminal(projectDir, slug) {
|
|
|
39996
40351
|
return status === "done" || status === "dismissed";
|
|
39997
40352
|
}
|
|
39998
40353
|
function isBoardRelevantFrizzPath(roots, path3) {
|
|
39999
|
-
return path3.endsWith(".md") && roots.has(
|
|
40354
|
+
return path3.endsWith(".md") && roots.has(dirname15(path3));
|
|
40000
40355
|
}
|
|
40001
40356
|
function futureSnooze(row, nowMs) {
|
|
40002
40357
|
const parsed = SnoozeUntil.safeParse(row.snoozed_until);
|
|
@@ -40856,10 +41211,10 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
40856
41211
|
if (parcelSub || stopped) return Promise.resolve();
|
|
40857
41212
|
if (watchSetup) return watchSetup;
|
|
40858
41213
|
const setup = (async () => {
|
|
40859
|
-
const dir =
|
|
41214
|
+
const dir = join34(project.dir, ".frizz");
|
|
40860
41215
|
const roots = /* @__PURE__ */ new Set([dir]);
|
|
40861
41216
|
try {
|
|
40862
|
-
roots.add(
|
|
41217
|
+
roots.add(realpathSync10(dir));
|
|
40863
41218
|
} catch {
|
|
40864
41219
|
}
|
|
40865
41220
|
const next = await subscribe(
|
|
@@ -40871,7 +41226,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
40871
41226
|
}
|
|
40872
41227
|
if (events.some((event) => isBoardRelevantFrizzPath(roots, event.path))) scheduleRebuild();
|
|
40873
41228
|
},
|
|
40874
|
-
{ ignore: FRIZZ_WATCH_IGNORED_DIRS.map((name) =>
|
|
41229
|
+
{ ignore: FRIZZ_WATCH_IGNORED_DIRS.map((name) => join34(dir, name)) }
|
|
40875
41230
|
);
|
|
40876
41231
|
if (stopped) {
|
|
40877
41232
|
await next.unsubscribe();
|
|
@@ -43988,7 +44343,7 @@ var init_resume = __esm({
|
|
|
43988
44343
|
});
|
|
43989
44344
|
|
|
43990
44345
|
// packages/server/src/backend/claude.ts
|
|
43991
|
-
import { join as
|
|
44346
|
+
import { join as join35 } from "node:path";
|
|
43992
44347
|
function toolResultText2(content) {
|
|
43993
44348
|
if (typeof content === "string") return content;
|
|
43994
44349
|
if (!Array.isArray(content)) return "";
|
|
@@ -44007,7 +44362,7 @@ function parseClaudeLine(line) {
|
|
|
44007
44362
|
const at2 = typeof rec.timestamp === "string" ? rec.timestamp : void 0;
|
|
44008
44363
|
const out = [];
|
|
44009
44364
|
if (rec.type === "assistant") {
|
|
44010
|
-
const
|
|
44365
|
+
const stop2 = typeof rec.message?.stop_reason === "string" ? rec.message.stop_reason : void 0;
|
|
44011
44366
|
const content = rec.message?.content;
|
|
44012
44367
|
let lastText;
|
|
44013
44368
|
if (Array.isArray(content)) {
|
|
@@ -44016,13 +44371,13 @@ function parseClaudeLine(line) {
|
|
|
44016
44371
|
const b = block;
|
|
44017
44372
|
if (b.type === "text" && typeof b.text === "string") {
|
|
44018
44373
|
lastText = b.text;
|
|
44019
|
-
out.push({ kind: "assistant-text", at: at2, text: b.text, final:
|
|
44374
|
+
out.push({ kind: "assistant-text", at: at2, text: b.text, final: stop2 === "end_turn" });
|
|
44020
44375
|
} else if (b.type === "tool_use") {
|
|
44021
44376
|
out.push({ kind: "tool-call", at: at2, id: typeof b.id === "string" ? b.id : "", name: typeof b.name === "string" ? b.name : "", input: b.input });
|
|
44022
44377
|
}
|
|
44023
44378
|
}
|
|
44024
44379
|
}
|
|
44025
|
-
if (
|
|
44380
|
+
if (stop2 === "end_turn") out.push({ kind: "turn-end", at: at2, finalText: lastText });
|
|
44026
44381
|
return out;
|
|
44027
44382
|
}
|
|
44028
44383
|
if (rec.type === "user" && rec.isMeta !== true) {
|
|
@@ -44079,7 +44434,7 @@ function createClaudeBackend(opts) {
|
|
|
44079
44434
|
return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
|
|
44080
44435
|
},
|
|
44081
44436
|
transcriptPath(sessionId) {
|
|
44082
|
-
return
|
|
44437
|
+
return join35(opts.logDir, `${sessionId}.jsonl`);
|
|
44083
44438
|
},
|
|
44084
44439
|
parseLine(line) {
|
|
44085
44440
|
return parseClaudeLine(line);
|
|
@@ -44104,10 +44459,10 @@ var init_claude = __esm({
|
|
|
44104
44459
|
});
|
|
44105
44460
|
|
|
44106
44461
|
// packages/server/src/backend/acp-transcript.ts
|
|
44107
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
44108
|
-
import { dirname as
|
|
44462
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync15, mkdirSync as mkdirSync17, readFileSync as readFileSync23 } from "node:fs";
|
|
44463
|
+
import { dirname as dirname16, join as join36 } from "node:path";
|
|
44109
44464
|
function acpTranscriptPath(stateDir, sessionId) {
|
|
44110
|
-
return
|
|
44465
|
+
return join36(stateDir, ACP_TRANSCRIPT_DIR, `${sessionId}.jsonl`);
|
|
44111
44466
|
}
|
|
44112
44467
|
function parseAcpRecord(line) {
|
|
44113
44468
|
if (!line.trim()) return void 0;
|
|
@@ -44308,8 +44663,8 @@ var init_acp_transcript = __esm({
|
|
|
44308
44663
|
AcpTranscriptWriter = class {
|
|
44309
44664
|
constructor(path3) {
|
|
44310
44665
|
this.path = path3;
|
|
44311
|
-
|
|
44312
|
-
if (!
|
|
44666
|
+
mkdirSync17(dirname16(path3), { recursive: true });
|
|
44667
|
+
if (!existsSync15(path3)) appendFileSync3(path3, "");
|
|
44313
44668
|
}
|
|
44314
44669
|
append(record) {
|
|
44315
44670
|
appendFileSync3(this.path, JSON.stringify(record) + "\n");
|
|
@@ -44696,15 +45051,15 @@ var init_acp_rpc = __esm({
|
|
|
44696
45051
|
import { spawn as spawn7 } from "node:child_process";
|
|
44697
45052
|
import { createConnection as createConnection2 } from "node:net";
|
|
44698
45053
|
import { createHash as createHash14, randomUUID as randomUUID15 } from "node:crypto";
|
|
44699
|
-
import { existsSync as
|
|
44700
|
-
import { join as
|
|
45054
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync18, readFileSync as readFileSync24, readdirSync as readdirSync9, unlinkSync as unlinkSync4 } from "node:fs";
|
|
45055
|
+
import { join as join37 } from "node:path";
|
|
44701
45056
|
import { PassThrough as PassThrough3, Writable as Writable3 } from "node:stream";
|
|
44702
45057
|
import { StringDecoder as StringDecoder5 } from "node:string_decoder";
|
|
44703
45058
|
function daemonDir2(stateDir) {
|
|
44704
|
-
return
|
|
45059
|
+
return join37(stateDir, "acp-daemon");
|
|
44705
45060
|
}
|
|
44706
45061
|
function acpDaemonRecordPath(stateDir, sessionId) {
|
|
44707
|
-
return
|
|
45062
|
+
return join37(daemonDir2(stateDir), `${sessionId}.json`);
|
|
44708
45063
|
}
|
|
44709
45064
|
function acpDaemonSocketPath(stateDir, sessionId) {
|
|
44710
45065
|
const key = createHash14("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
|
|
@@ -44720,7 +45075,7 @@ function pidAlive4(pid) {
|
|
|
44720
45075
|
}
|
|
44721
45076
|
function readAcpDaemonRecord(stateDir, sessionId) {
|
|
44722
45077
|
try {
|
|
44723
|
-
const value = JSON.parse(
|
|
45078
|
+
const value = JSON.parse(readFileSync24(acpDaemonRecordPath(stateDir, sessionId), "utf8"));
|
|
44724
45079
|
if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
44725
45080
|
return {
|
|
44726
45081
|
threadSlug: typeof value.threadSlug === "string" ? value.threadSlug : "",
|
|
@@ -44766,7 +45121,7 @@ async function stopAcpDaemon(stateDir, sessionId, timeoutMs = 1e4) {
|
|
|
44766
45121
|
}
|
|
44767
45122
|
function forkDaemon2(options) {
|
|
44768
45123
|
const { stateDir, sessionId } = options;
|
|
44769
|
-
|
|
45124
|
+
mkdirSync18(daemonDir2(stateDir), { recursive: true });
|
|
44770
45125
|
const record = acpDaemonRecordPath(stateDir, sessionId);
|
|
44771
45126
|
try {
|
|
44772
45127
|
unlinkSync4(record);
|
|
@@ -44962,7 +45317,7 @@ var init_acp_host = __esm({
|
|
|
44962
45317
|
}
|
|
44963
45318
|
if (process.platform !== "win32") {
|
|
44964
45319
|
const stale = acpDaemonSocketPath(stateDir, sessionId);
|
|
44965
|
-
if (
|
|
45320
|
+
if (existsSync16(stale) && !liveAcpDaemonRecord(stateDir, sessionId)) {
|
|
44966
45321
|
try {
|
|
44967
45322
|
unlinkSync4(stale);
|
|
44968
45323
|
} catch {
|
|
@@ -71654,7 +72009,7 @@ var init_claude_context_window = __esm({
|
|
|
71654
72009
|
});
|
|
71655
72010
|
|
|
71656
72011
|
// packages/server/src/backend/claude-agent-sdk.ts
|
|
71657
|
-
import { delimiter as delimiter3, isAbsolute as
|
|
72012
|
+
import { delimiter as delimiter3, isAbsolute as isAbsolute9 } from "node:path";
|
|
71658
72013
|
function sanitizeProviderChildEnvironment(environment) {
|
|
71659
72014
|
const sanitized = { ...environment };
|
|
71660
72015
|
for (const key of Object.keys(sanitized)) {
|
|
@@ -71796,24 +72151,24 @@ var init_claude_models = __esm({
|
|
|
71796
72151
|
});
|
|
71797
72152
|
|
|
71798
72153
|
// packages/server/src/backend/codex-app-server-diagnostics.ts
|
|
71799
|
-
import { appendFileSync as appendFileSync5, mkdirSync as
|
|
71800
|
-
import { join as
|
|
72154
|
+
import { appendFileSync as appendFileSync5, mkdirSync as mkdirSync20, renameSync as renameSync9, statSync as statSync17 } from "node:fs";
|
|
72155
|
+
import { join as join39 } from "node:path";
|
|
71801
72156
|
function codexDiagnosticLogPath(stateDir, projectId) {
|
|
71802
|
-
return
|
|
72157
|
+
return join39(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
|
|
71803
72158
|
}
|
|
71804
72159
|
function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
|
|
71805
|
-
const dir =
|
|
72160
|
+
const dir = join39(stateDir, "codex-app-server");
|
|
71806
72161
|
const path3 = codexDiagnosticLogPath(stateDir, projectId);
|
|
71807
72162
|
let ensured = false;
|
|
71808
72163
|
return (event) => {
|
|
71809
72164
|
if (event.event === "stderr") return;
|
|
71810
72165
|
try {
|
|
71811
72166
|
if (!ensured) {
|
|
71812
|
-
|
|
72167
|
+
mkdirSync20(dir, { recursive: true });
|
|
71813
72168
|
ensured = true;
|
|
71814
72169
|
}
|
|
71815
72170
|
try {
|
|
71816
|
-
if (
|
|
72171
|
+
if (statSync17(path3).size > MAX_BYTES2) renameSync9(path3, `${path3}.1`);
|
|
71817
72172
|
} catch {
|
|
71818
72173
|
}
|
|
71819
72174
|
appendFileSync5(path3, `${JSON.stringify({ at: now().toISOString(), ...event })}
|
|
@@ -71832,9 +72187,9 @@ var init_codex_app_server_diagnostics = __esm({
|
|
|
71832
72187
|
|
|
71833
72188
|
// packages/server/src/backend/stale-socket-sweep.ts
|
|
71834
72189
|
import { execFile as execFile9 } from "node:child_process";
|
|
71835
|
-
import { readdirSync as
|
|
72190
|
+
import { readdirSync as readdirSync11, unlinkSync as unlinkSync6 } from "node:fs";
|
|
71836
72191
|
import { connect as connectSocket } from "node:net";
|
|
71837
|
-
import { join as
|
|
72192
|
+
import { join as join40 } from "node:path";
|
|
71838
72193
|
function parseLsofSocketNames(stdout) {
|
|
71839
72194
|
const referenced = /* @__PURE__ */ new Set();
|
|
71840
72195
|
for (const line of stdout.split("\n")) {
|
|
@@ -71851,7 +72206,7 @@ function sweepStaleSockets(options, deps = {}) {
|
|
|
71851
72206
|
const keep = new Set(options.keep ?? []);
|
|
71852
72207
|
let candidates;
|
|
71853
72208
|
try {
|
|
71854
|
-
candidates = (deps.readdir ??
|
|
72209
|
+
candidates = (deps.readdir ?? readdirSync11)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join40(options.dir, name)).filter((path3) => !keep.has(path3));
|
|
71855
72210
|
} catch {
|
|
71856
72211
|
return;
|
|
71857
72212
|
}
|
|
@@ -71901,8 +72256,8 @@ var init_stale_socket_sweep = __esm({
|
|
|
71901
72256
|
|
|
71902
72257
|
// packages/server/src/orphan-reaper.ts
|
|
71903
72258
|
import { execFile as execFile10 } from "node:child_process";
|
|
71904
|
-
import { readFileSync as
|
|
71905
|
-
import { dirname as
|
|
72259
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
72260
|
+
import { dirname as dirname18 } from "node:path";
|
|
71906
72261
|
import { promisify as promisify8 } from "node:util";
|
|
71907
72262
|
function firstTokenBasename(command) {
|
|
71908
72263
|
const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
|
|
@@ -72131,7 +72486,7 @@ async function sweepOrphansOnce(deps = {}) {
|
|
|
72131
72486
|
}
|
|
72132
72487
|
function sweepStaleBrokerSockets() {
|
|
72133
72488
|
try {
|
|
72134
|
-
sweepStaleSockets({ dir:
|
|
72489
|
+
sweepStaleSockets({ dir: dirname18(claudeBrokerSocketPath("", "")), prefix: CLAUDE_BROKER_SOCKET_PREFIX });
|
|
72135
72490
|
} catch {
|
|
72136
72491
|
}
|
|
72137
72492
|
}
|
|
@@ -72208,7 +72563,7 @@ var init_orphan_reaper = __esm({
|
|
|
72208
72563
|
defaultExec = async (file, args) => (await execFileAsync6(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout;
|
|
72209
72564
|
defaultReadEnv = (pid) => {
|
|
72210
72565
|
try {
|
|
72211
|
-
return
|
|
72566
|
+
return readFileSync26(`/proc/${pid}/environ`, "utf8");
|
|
72212
72567
|
} catch {
|
|
72213
72568
|
return null;
|
|
72214
72569
|
}
|
|
@@ -72228,7 +72583,7 @@ var init_orphan_reaper = __esm({
|
|
|
72228
72583
|
});
|
|
72229
72584
|
|
|
72230
72585
|
// packages/server/src/context.ts
|
|
72231
|
-
import { join as
|
|
72586
|
+
import { join as join41 } from "node:path";
|
|
72232
72587
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
72233
72588
|
import { homedir as homedir15 } from "node:os";
|
|
72234
72589
|
function reconcileSessions(storage) {
|
|
@@ -72380,8 +72735,9 @@ async function createContext(opts = {}) {
|
|
|
72380
72735
|
function createContextUnchecked(opts, resources) {
|
|
72381
72736
|
const home = opts.home ?? homedir15();
|
|
72382
72737
|
const project = opts.project ?? resolveProject();
|
|
72383
|
-
const storage = createStorage(opts.database ??
|
|
72738
|
+
const storage = createStorage(opts.database ?? join41(project.stateDir, "ui.db"), project.id);
|
|
72384
72739
|
resources.storage = storage;
|
|
72740
|
+
clearSecrets(project.stateDir);
|
|
72385
72741
|
const bus = new Bus();
|
|
72386
72742
|
const transcriptChange = new Emitter();
|
|
72387
72743
|
const bootId = randomUUID16();
|
|
@@ -72797,6 +73153,7 @@ var init_context = __esm({
|
|
|
72797
73153
|
init_bus();
|
|
72798
73154
|
init_project();
|
|
72799
73155
|
init_storage();
|
|
73156
|
+
init_secret_files();
|
|
72800
73157
|
init_settings();
|
|
72801
73158
|
init_dispatch_preferences();
|
|
72802
73159
|
init_quota();
|
|
@@ -75492,8 +75849,8 @@ var init_server = __esm({
|
|
|
75492
75849
|
});
|
|
75493
75850
|
|
|
75494
75851
|
// packages/server/src/repair.ts
|
|
75495
|
-
import { existsSync as
|
|
75496
|
-
import { basename as basename7, dirname as
|
|
75852
|
+
import { existsSync as existsSync18, readFileSync as readFileSync27, writeFileSync as writeFileSync14 } from "node:fs";
|
|
75853
|
+
import { basename as basename7, dirname as dirname19, resolve as resolve9 } from "node:path";
|
|
75497
75854
|
function quoteValue(v) {
|
|
75498
75855
|
if (/^[\w./#:+-]+$/.test(v)) return v;
|
|
75499
75856
|
return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -75505,10 +75862,10 @@ function deriveTitle(body, slug) {
|
|
|
75505
75862
|
function repairThreadFile(frizzDir, file) {
|
|
75506
75863
|
const root = resolve9(frizzDir);
|
|
75507
75864
|
const abs = resolve9(root, file);
|
|
75508
|
-
if (
|
|
75865
|
+
if (dirname19(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
|
|
75509
75866
|
if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
|
|
75510
|
-
if (!
|
|
75511
|
-
const content =
|
|
75867
|
+
if (!existsSync18(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
|
|
75868
|
+
const content = readFileSync27(abs, "utf8");
|
|
75512
75869
|
const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
|
|
75513
75870
|
if (firstLine2?.trim() === "---") {
|
|
75514
75871
|
throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
|
|
@@ -75523,7 +75880,7 @@ function repairThreadFile(frizzDir, file) {
|
|
|
75523
75880
|
"---",
|
|
75524
75881
|
""
|
|
75525
75882
|
].join("\n");
|
|
75526
|
-
|
|
75883
|
+
writeFileSync14(abs, frontmatter + content);
|
|
75527
75884
|
return { slug };
|
|
75528
75885
|
}
|
|
75529
75886
|
var RepairError, REPAIR_STATUS_TEXT;
|
|
@@ -75665,10 +76022,10 @@ var init_edited_files = __esm({
|
|
|
75665
76022
|
});
|
|
75666
76023
|
|
|
75667
76024
|
// packages/server/src/repo-files.ts
|
|
75668
|
-
import { execFileSync as
|
|
76025
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
75669
76026
|
import path2 from "node:path";
|
|
75670
76027
|
function git(args, cwd) {
|
|
75671
|
-
return
|
|
76028
|
+
return execFileSync5("git", args, {
|
|
75672
76029
|
cwd,
|
|
75673
76030
|
encoding: "utf8",
|
|
75674
76031
|
env: { ...process.env, LC_ALL: "C" },
|
|
@@ -75709,7 +76066,7 @@ function probeIgnored(projectDir, inside) {
|
|
|
75709
76066
|
return /* @__PURE__ */ new Set();
|
|
75710
76067
|
}
|
|
75711
76068
|
try {
|
|
75712
|
-
const out =
|
|
76069
|
+
const out = execFileSync5("git", ["check-ignore", "-z", "--stdin"], {
|
|
75713
76070
|
cwd: projectDir,
|
|
75714
76071
|
encoding: "utf8",
|
|
75715
76072
|
env: { ...process.env, LC_ALL: "C" },
|
|
@@ -75736,7 +76093,7 @@ var init_repo_files = __esm({
|
|
|
75736
76093
|
});
|
|
75737
76094
|
|
|
75738
76095
|
// cc-worker/hooks/bash-background.mjs
|
|
75739
|
-
import { readFileSync as
|
|
76096
|
+
import { readFileSync as readFileSync28, realpathSync as realpathSync12 } from "node:fs";
|
|
75740
76097
|
import { basename as basename8 } from "node:path";
|
|
75741
76098
|
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
|
|
75742
76099
|
function emit(obj) {
|
|
@@ -75874,7 +76231,7 @@ function evaluateBashBackgroundHook(input, env = process.env) {
|
|
|
75874
76231
|
}
|
|
75875
76232
|
};
|
|
75876
76233
|
}
|
|
75877
|
-
function isDirectHookExecution(argv1, moduleUrl, realpath =
|
|
76234
|
+
function isDirectHookExecution(argv1, moduleUrl, realpath = realpathSync12) {
|
|
75878
76235
|
if (typeof argv1 !== "string" || basename8(argv1) !== "bash-background.mjs") return false;
|
|
75879
76236
|
if (pathToFileURL(argv1).href === moduleUrl) return true;
|
|
75880
76237
|
try {
|
|
@@ -75891,7 +76248,7 @@ var init_bash_background = __esm({
|
|
|
75891
76248
|
if (isDirectHookExecution(process.argv[1], import.meta.url)) {
|
|
75892
76249
|
try {
|
|
75893
76250
|
const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
|
|
75894
|
-
emit(evaluateBashBackgroundHook(JSON.parse(
|
|
76251
|
+
emit(evaluateBashBackgroundHook(JSON.parse(readFileSync28(0, "utf8")), env));
|
|
75895
76252
|
} catch {
|
|
75896
76253
|
emit({});
|
|
75897
76254
|
}
|
|
@@ -75900,10 +76257,10 @@ var init_bash_background = __esm({
|
|
|
75900
76257
|
});
|
|
75901
76258
|
|
|
75902
76259
|
// packages/server/src/transcript.ts
|
|
75903
|
-
import { closeSync as
|
|
76260
|
+
import { closeSync as closeSync15, existsSync as existsSync19, fstatSync as fstatSync3, mkdirSync as mkdirSync21, openSync as openSync16, readdirSync as readdirSync12, readFileSync as readFileSync29, readSync as readSync8, renameSync as renameSync10, statSync as statSync18, unlinkSync as unlinkSync7, writeFileSync as writeFileSync15 } from "node:fs";
|
|
75904
76261
|
import { createHash as createHash15 } from "node:crypto";
|
|
75905
76262
|
import { StringDecoder as StringDecoder6 } from "node:string_decoder";
|
|
75906
|
-
import { join as
|
|
76263
|
+
import { join as join42 } from "node:path";
|
|
75907
76264
|
import { homedir as homedir16 } from "node:os";
|
|
75908
76265
|
function formatTokens(n) {
|
|
75909
76266
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
@@ -76507,18 +76864,18 @@ function looksLikeImage(buf, ext) {
|
|
|
76507
76864
|
}
|
|
76508
76865
|
function pruneScreenshotCache() {
|
|
76509
76866
|
try {
|
|
76510
|
-
const entries2 =
|
|
76867
|
+
const entries2 = readdirSync12(SCREENSHOT_CACHE_DIR).filter((n) => !n.startsWith("."));
|
|
76511
76868
|
if (entries2.length <= SCREENSHOT_CACHE_MAX) return;
|
|
76512
76869
|
const byMtime = entries2.map((n) => {
|
|
76513
76870
|
try {
|
|
76514
|
-
return { n, m:
|
|
76871
|
+
return { n, m: statSync18(join42(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
|
|
76515
76872
|
} catch {
|
|
76516
76873
|
return { n, m: 0 };
|
|
76517
76874
|
}
|
|
76518
76875
|
}).sort((a, b) => b.m - a.m);
|
|
76519
76876
|
for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
|
|
76520
76877
|
try {
|
|
76521
|
-
unlinkSync7(
|
|
76878
|
+
unlinkSync7(join42(SCREENSHOT_CACHE_DIR, n));
|
|
76522
76879
|
} catch {
|
|
76523
76880
|
}
|
|
76524
76881
|
}
|
|
@@ -76548,15 +76905,15 @@ function persistBase64Image(mediaType, data, idKey) {
|
|
|
76548
76905
|
const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
|
|
76549
76906
|
if (!ext || !data) return void 0;
|
|
76550
76907
|
const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
76551
|
-
const path3 =
|
|
76908
|
+
const path3 = join42(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
|
|
76552
76909
|
try {
|
|
76553
|
-
if (
|
|
76910
|
+
if (existsSync19(path3)) return path3;
|
|
76554
76911
|
if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
|
|
76555
76912
|
const buf = Buffer.from(data, "base64");
|
|
76556
76913
|
if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
|
|
76557
|
-
|
|
76558
|
-
const tmp =
|
|
76559
|
-
|
|
76914
|
+
mkdirSync21(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
76915
|
+
const tmp = join42(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
76916
|
+
writeFileSync15(tmp, buf);
|
|
76560
76917
|
renameSync10(tmp, path3);
|
|
76561
76918
|
pruneScreenshotCache();
|
|
76562
76919
|
return path3;
|
|
@@ -76570,15 +76927,15 @@ function persistSentFile(srcPath, idKey) {
|
|
|
76570
76927
|
const outExt = ext === "jpeg" ? "jpg" : ext;
|
|
76571
76928
|
try {
|
|
76572
76929
|
const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
76573
|
-
const dest =
|
|
76574
|
-
if (
|
|
76575
|
-
const size =
|
|
76930
|
+
const dest = join42(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
|
|
76931
|
+
if (existsSync19(dest)) return dest;
|
|
76932
|
+
const size = statSync18(srcPath).size;
|
|
76576
76933
|
if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
|
|
76577
|
-
const buf =
|
|
76934
|
+
const buf = readFileSync29(srcPath);
|
|
76578
76935
|
if (!looksLikeImage(buf, outExt)) return void 0;
|
|
76579
|
-
|
|
76580
|
-
const tmp =
|
|
76581
|
-
|
|
76936
|
+
mkdirSync21(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
76937
|
+
const tmp = join42(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
76938
|
+
writeFileSync15(tmp, buf);
|
|
76582
76939
|
renameSync10(tmp, dest);
|
|
76583
76940
|
pruneScreenshotCache();
|
|
76584
76941
|
return dest;
|
|
@@ -76996,7 +77353,7 @@ function readTranscript(project, sessionId) {
|
|
|
76996
77353
|
const identityPrefix = `claude:${sessionId}`;
|
|
76997
77354
|
let fd2;
|
|
76998
77355
|
try {
|
|
76999
|
-
fd2 =
|
|
77356
|
+
fd2 = openSync16(path3, "r");
|
|
77000
77357
|
const st2 = fstatSync3(fd2);
|
|
77001
77358
|
const size = st2.size;
|
|
77002
77359
|
const fileId = `${st2.dev}:${st2.ino}:${Math.trunc(st2.birthtimeMs)}`;
|
|
@@ -77010,12 +77367,12 @@ function readTranscript(project, sessionId) {
|
|
|
77010
77367
|
} catch {
|
|
77011
77368
|
return [];
|
|
77012
77369
|
} finally {
|
|
77013
|
-
if (fd2 !== void 0)
|
|
77370
|
+
if (fd2 !== void 0) closeSync15(fd2);
|
|
77014
77371
|
}
|
|
77015
77372
|
}
|
|
77016
77373
|
function verifyIncrementalParse(path3, identityPrefix, incremental) {
|
|
77017
77374
|
try {
|
|
77018
|
-
const fresh = parseTranscript(
|
|
77375
|
+
const fresh = parseTranscript(readFileSync29(path3, "utf8"), identityPrefix);
|
|
77019
77376
|
const a = JSON.stringify(incremental);
|
|
77020
77377
|
const b = JSON.stringify(fresh);
|
|
77021
77378
|
if (a !== b) {
|
|
@@ -77035,16 +77392,16 @@ function verifyIncrementalParse(path3, identityPrefix, incremental) {
|
|
|
77035
77392
|
}
|
|
77036
77393
|
}
|
|
77037
77394
|
function logDirOf(project) {
|
|
77038
|
-
return
|
|
77395
|
+
return join42(homedir16(), ".claude", "projects", project.cwdSlug);
|
|
77039
77396
|
}
|
|
77040
77397
|
function resolveTranscriptPath(project, sessionId) {
|
|
77041
|
-
const path3 =
|
|
77398
|
+
const path3 = join42(logDirOf(project), `${sessionId}.jsonl`);
|
|
77042
77399
|
try {
|
|
77043
|
-
if (
|
|
77400
|
+
if (statSync18(path3).size > 0) return path3;
|
|
77044
77401
|
} catch {
|
|
77045
77402
|
}
|
|
77046
77403
|
const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
|
|
77047
|
-
return stranded ?
|
|
77404
|
+
return stranded ? join42(stranded, `${sessionId}.jsonl`) : path3;
|
|
77048
77405
|
}
|
|
77049
77406
|
function projectCodexTranscript(raw2, identityPrefix = "codex") {
|
|
77050
77407
|
const out = [];
|
|
@@ -78112,7 +78469,7 @@ function sourceForThread(project, storage, slug, backendFor) {
|
|
|
78112
78469
|
}
|
|
78113
78470
|
if (!FOREIGN_SESSION_ID_RE.test(slug)) return void 0;
|
|
78114
78471
|
const claudePath = resolveTranscriptPath(project, slug);
|
|
78115
|
-
if (
|
|
78472
|
+
if (existsSync19(claudePath)) {
|
|
78116
78473
|
return { slug, sessionId: slug, nativeId: slug, backend: "claude", runtimeGeneration: 0, path: claudePath };
|
|
78117
78474
|
}
|
|
78118
78475
|
const rollout = (backendFor?.("codex") ?? defaultCodexBackend()).transcriptPath(slug);
|
|
@@ -78148,7 +78505,7 @@ function discoveredClaudeSource(project, storage, slug, expectedNativeId) {
|
|
|
78148
78505
|
function fixedSnapshot(source) {
|
|
78149
78506
|
let fd2;
|
|
78150
78507
|
try {
|
|
78151
|
-
fd2 =
|
|
78508
|
+
fd2 = openSync16(source.path, "r");
|
|
78152
78509
|
const before = fstatSync3(fd2);
|
|
78153
78510
|
if (!Number.isSafeInteger(before.size) || before.size < 0) throw new Error("transcript is too large to page safely");
|
|
78154
78511
|
const after = fstatSync3(fd2);
|
|
@@ -78158,7 +78515,7 @@ function fixedSnapshot(source) {
|
|
|
78158
78515
|
const size = before.size;
|
|
78159
78516
|
const path3 = source.path;
|
|
78160
78517
|
const readRange = (from, length) => {
|
|
78161
|
-
const rfd =
|
|
78518
|
+
const rfd = openSync16(path3, "r");
|
|
78162
78519
|
try {
|
|
78163
78520
|
const st2 = fstatSync3(rfd);
|
|
78164
78521
|
if (st2.dev !== before.dev || st2.ino !== before.ino || st2.size < size) {
|
|
@@ -78174,7 +78531,7 @@ function fixedSnapshot(source) {
|
|
|
78174
78531
|
}
|
|
78175
78532
|
return filled === want ? buf : buf.subarray(0, filled);
|
|
78176
78533
|
} finally {
|
|
78177
|
-
|
|
78534
|
+
closeSync15(rfd);
|
|
78178
78535
|
}
|
|
78179
78536
|
};
|
|
78180
78537
|
let allBytes;
|
|
@@ -78200,7 +78557,7 @@ function fixedSnapshot(source) {
|
|
|
78200
78557
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return void 0;
|
|
78201
78558
|
throw error;
|
|
78202
78559
|
} finally {
|
|
78203
|
-
if (fd2 !== void 0)
|
|
78560
|
+
if (fd2 !== void 0) closeSync15(fd2);
|
|
78204
78561
|
}
|
|
78205
78562
|
}
|
|
78206
78563
|
function projectSnapshot(snapshot) {
|
|
@@ -78384,7 +78741,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
|
|
|
78384
78741
|
}
|
|
78385
78742
|
function readCodexTranscriptFile(absPath, nativeId = absPath) {
|
|
78386
78743
|
try {
|
|
78387
|
-
return parseCodexTranscript(
|
|
78744
|
+
return parseCodexTranscript(readFileSync29(absPath, "utf8"), `codex:${nativeId}`);
|
|
78388
78745
|
} catch {
|
|
78389
78746
|
return [];
|
|
78390
78747
|
}
|
|
@@ -78452,7 +78809,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
|
|
|
78452
78809
|
function readTranscriptFile(absPath) {
|
|
78453
78810
|
try {
|
|
78454
78811
|
const pathKey = createHash15("sha256").update(absPath).digest("base64url").slice(0, 16);
|
|
78455
|
-
return parseTranscript(
|
|
78812
|
+
return parseTranscript(readFileSync29(absPath, "utf8"), `claude-file:${pathKey}`);
|
|
78456
78813
|
} catch {
|
|
78457
78814
|
return [];
|
|
78458
78815
|
}
|
|
@@ -78916,11 +79273,11 @@ var init_external_terminal = __esm({
|
|
|
78916
79273
|
});
|
|
78917
79274
|
|
|
78918
79275
|
// packages/server/src/background-shell-output.ts
|
|
78919
|
-
import { closeSync as
|
|
79276
|
+
import { closeSync as closeSync16, fstatSync as fstatSync4, openSync as openSync17, readSync as readSync9 } from "node:fs";
|
|
78920
79277
|
function readBackgroundShellOutput(path3, maxBytes = OUTPUT_TAIL_BYTES) {
|
|
78921
79278
|
let fd2;
|
|
78922
79279
|
try {
|
|
78923
|
-
fd2 =
|
|
79280
|
+
fd2 = openSync17(path3, "r");
|
|
78924
79281
|
const size = fstatSync4(fd2).size;
|
|
78925
79282
|
const length = Math.min(size, maxBytes);
|
|
78926
79283
|
const offset = Math.max(0, size - length);
|
|
@@ -78936,7 +79293,7 @@ function readBackgroundShellOutput(path3, maxBytes = OUTPUT_TAIL_BYTES) {
|
|
|
78936
79293
|
} catch {
|
|
78937
79294
|
return { output: "", truncated: false };
|
|
78938
79295
|
} finally {
|
|
78939
|
-
if (fd2 !== void 0)
|
|
79296
|
+
if (fd2 !== void 0) closeSync16(fd2);
|
|
78940
79297
|
}
|
|
78941
79298
|
}
|
|
78942
79299
|
function readHead2(fd2, length) {
|
|
@@ -78953,7 +79310,7 @@ function readHead2(fd2, length) {
|
|
|
78953
79310
|
function backgroundShellLineCount(path3) {
|
|
78954
79311
|
let fd2;
|
|
78955
79312
|
try {
|
|
78956
|
-
fd2 =
|
|
79313
|
+
fd2 = openSync17(path3, "r");
|
|
78957
79314
|
const stat2 = fstatSync4(fd2);
|
|
78958
79315
|
const size = stat2.size;
|
|
78959
79316
|
let state = scans.get(path3);
|
|
@@ -79004,7 +79361,7 @@ function backgroundShellLineCount(path3) {
|
|
|
79004
79361
|
} catch {
|
|
79005
79362
|
return void 0;
|
|
79006
79363
|
} finally {
|
|
79007
|
-
if (fd2 !== void 0)
|
|
79364
|
+
if (fd2 !== void 0) closeSync16(fd2);
|
|
79008
79365
|
}
|
|
79009
79366
|
}
|
|
79010
79367
|
var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, FINGERPRINT_BYTES, ANSI_ESCAPE_RE, scans;
|
|
@@ -79022,15 +79379,15 @@ var init_background_shell_output = __esm({
|
|
|
79022
79379
|
});
|
|
79023
79380
|
|
|
79024
79381
|
// packages/server/src/frizz-md.ts
|
|
79025
|
-
import { execFileSync as
|
|
79026
|
-
import { existsSync as
|
|
79027
|
-
import { join as
|
|
79382
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
79383
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync16 } from "node:fs";
|
|
79384
|
+
import { join as join43 } from "node:path";
|
|
79028
79385
|
function frizzMdPath(projectDir) {
|
|
79029
|
-
return
|
|
79386
|
+
return join43(projectDir, "FRIZZ.md");
|
|
79030
79387
|
}
|
|
79031
79388
|
function git2(args, cwd) {
|
|
79032
79389
|
try {
|
|
79033
|
-
return
|
|
79390
|
+
return execFileSync6("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim() || null;
|
|
79034
79391
|
} catch {
|
|
79035
79392
|
return null;
|
|
79036
79393
|
}
|
|
@@ -79043,7 +79400,7 @@ function defaultBranch(projectDir) {
|
|
|
79043
79400
|
}
|
|
79044
79401
|
function frizzMdStatus(projectDir, storage) {
|
|
79045
79402
|
return {
|
|
79046
|
-
exists:
|
|
79403
|
+
exists: existsSync20(frizzMdPath(projectDir)),
|
|
79047
79404
|
skipped: storage.getSetting(SKIP_SETTING) !== void 0,
|
|
79048
79405
|
defaultBranch: defaultBranch(projectDir)
|
|
79049
79406
|
};
|
|
@@ -79051,7 +79408,7 @@ function frizzMdStatus(projectDir, storage) {
|
|
|
79051
79408
|
function createFrizzMd(projectDir, answers) {
|
|
79052
79409
|
const path3 = frizzMdPath(projectDir);
|
|
79053
79410
|
try {
|
|
79054
|
-
|
|
79411
|
+
writeFileSync16(path3, composeFrizzMd(answers, defaultBranch(projectDir)), { encoding: "utf8", flag: "wx" });
|
|
79055
79412
|
} catch (error) {
|
|
79056
79413
|
if (error.code === "EEXIST") throw new Error("This project already has a FRIZZ.md.");
|
|
79057
79414
|
throw error;
|
|
@@ -79071,15 +79428,15 @@ var init_frizz_md2 = __esm({
|
|
|
79071
79428
|
});
|
|
79072
79429
|
|
|
79073
79430
|
// packages/server/src/image-header.ts
|
|
79074
|
-
import { closeSync as
|
|
79075
|
-
import { extname } from "node:path";
|
|
79431
|
+
import { closeSync as closeSync17, openSync as openSync18, readSync as readSync10, statSync as statSync19 } from "node:fs";
|
|
79432
|
+
import { extname as extname2 } from "node:path";
|
|
79076
79433
|
function readHead3(path3, budget) {
|
|
79077
79434
|
let fd2;
|
|
79078
79435
|
try {
|
|
79079
|
-
const size =
|
|
79436
|
+
const size = statSync19(path3).size;
|
|
79080
79437
|
if (size === 0) return void 0;
|
|
79081
79438
|
const buffer = Buffer.alloc(Math.min(size, budget));
|
|
79082
|
-
fd2 =
|
|
79439
|
+
fd2 = openSync18(path3, "r");
|
|
79083
79440
|
const read = readSync10(fd2, buffer, 0, buffer.length, 0);
|
|
79084
79441
|
return read === buffer.length ? buffer : buffer.subarray(0, read);
|
|
79085
79442
|
} catch {
|
|
@@ -79087,7 +79444,7 @@ function readHead3(path3, budget) {
|
|
|
79087
79444
|
} finally {
|
|
79088
79445
|
if (fd2 !== void 0) {
|
|
79089
79446
|
try {
|
|
79090
|
-
|
|
79447
|
+
closeSync17(fd2);
|
|
79091
79448
|
} catch {
|
|
79092
79449
|
}
|
|
79093
79450
|
}
|
|
@@ -79180,7 +79537,7 @@ function svg(head) {
|
|
|
79180
79537
|
return void 0;
|
|
79181
79538
|
}
|
|
79182
79539
|
function svgDeclaresColour(path3) {
|
|
79183
|
-
if (
|
|
79540
|
+
if (extname2(path3).toLowerCase() !== ".svg") return void 0;
|
|
79184
79541
|
const head = readHead3(path3, 512 * 1024);
|
|
79185
79542
|
if (!head) return void 0;
|
|
79186
79543
|
const source = head.toString("utf8");
|
|
@@ -79192,7 +79549,7 @@ function svgDeclaresColour(path3) {
|
|
|
79192
79549
|
return false;
|
|
79193
79550
|
}
|
|
79194
79551
|
function imageDimensions(path3) {
|
|
79195
|
-
const extension2 =
|
|
79552
|
+
const extension2 = extname2(path3).toLowerCase();
|
|
79196
79553
|
const budget = extension2 === ".jpg" || extension2 === ".jpeg" ? JPEG_SCAN_BYTES : HEAD_BYTES2;
|
|
79197
79554
|
const head = readHead3(path3, budget);
|
|
79198
79555
|
if (!head) return void 0;
|
|
@@ -79454,11 +79811,11 @@ function run(argv) {
|
|
|
79454
79811
|
});
|
|
79455
79812
|
|
|
79456
79813
|
// packages/server/src/router.ts
|
|
79457
|
-
import { readFileSync as
|
|
79458
|
-
import { join as
|
|
79814
|
+
import { readFileSync as readFileSync30, statSync as statSync20 } from "node:fs";
|
|
79815
|
+
import { join as join44, resolve as resolve10 } from "node:path";
|
|
79459
79816
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
79460
|
-
import { basename as basename9, dirname as
|
|
79461
|
-
import { existsSync as
|
|
79817
|
+
import { basename as basename9, dirname as dirname20 } from "node:path";
|
|
79818
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync22, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
|
|
79462
79819
|
import { homedir as homedir17 } from "node:os";
|
|
79463
79820
|
function validateGithubDispatchProfile(input, codexModels) {
|
|
79464
79821
|
if (input.backend === "acp") return;
|
|
@@ -79632,11 +79989,11 @@ function projectCard(entry, stale) {
|
|
|
79632
79989
|
function addProjectAtPath(input, home = homedir17()) {
|
|
79633
79990
|
const typed = input.trim();
|
|
79634
79991
|
if (!typed) throw new Error("Enter a folder path.");
|
|
79635
|
-
const expanded = typed === "~" || typed.startsWith("~/") ?
|
|
79992
|
+
const expanded = typed === "~" || typed.startsWith("~/") ? join44(home, typed.slice(1)) : typed;
|
|
79636
79993
|
const absolute = resolve10(expanded);
|
|
79637
79994
|
let stats;
|
|
79638
79995
|
try {
|
|
79639
|
-
stats =
|
|
79996
|
+
stats = statSync20(absolute);
|
|
79640
79997
|
} catch {
|
|
79641
79998
|
throw new Error(`No folder at ${absolute}`);
|
|
79642
79999
|
}
|
|
@@ -79661,15 +80018,15 @@ function storeProjectIcon(id2, name, bytes) {
|
|
|
79661
80018
|
if (!entry) throw new Error("No such project.");
|
|
79662
80019
|
if (bytes.length === 0) throw new Error("That file is empty.");
|
|
79663
80020
|
const path3 = customIconPath(id2, `.${extension2}`);
|
|
79664
|
-
|
|
79665
|
-
|
|
80021
|
+
mkdirSync22(dirname20(path3), { recursive: true });
|
|
80022
|
+
writeFileSync17(path3, bytes);
|
|
79666
80023
|
if (!imageDimensions(path3)) {
|
|
79667
|
-
|
|
80024
|
+
rmSync12(path3, { force: true });
|
|
79668
80025
|
throw new Error("That file does not look like an image Frizz can draw.");
|
|
79669
80026
|
}
|
|
79670
80027
|
for (const stale of PROJECT_ICON_EXTENSIONS) {
|
|
79671
80028
|
const other = customIconPath(id2, `.${stale}`);
|
|
79672
|
-
if (other !== path3)
|
|
80029
|
+
if (other !== path3) rmSync12(other, { force: true });
|
|
79673
80030
|
}
|
|
79674
80031
|
const updated = setProjectIcon(id2, path3);
|
|
79675
80032
|
if (!updated) throw new Error("No such project.");
|
|
@@ -79683,7 +80040,7 @@ function iconPicker(id2) {
|
|
|
79683
80040
|
function setProjectIconFromFile(id2, file) {
|
|
79684
80041
|
let bytes;
|
|
79685
80042
|
try {
|
|
79686
|
-
bytes =
|
|
80043
|
+
bytes = readFileSync30(file);
|
|
79687
80044
|
} catch {
|
|
79688
80045
|
throw new Error("That file could not be read.");
|
|
79689
80046
|
}
|
|
@@ -79716,7 +80073,7 @@ function mergeSubAgentSteers(messages, steers) {
|
|
|
79716
80073
|
return merged;
|
|
79717
80074
|
}
|
|
79718
80075
|
function createRouter(ctx) {
|
|
79719
|
-
const frizzDir =
|
|
80076
|
+
const frizzDir = join44(ctx.project.dir, ".frizz");
|
|
79720
80077
|
const openRoots = openableFileRoots(ctx.project);
|
|
79721
80078
|
function isAutoTitledSession(slug) {
|
|
79722
80079
|
return ctx.storage.getSession(slug)?.title_auto === 1;
|
|
@@ -79824,15 +80181,24 @@ function createRouter(ctx) {
|
|
|
79824
80181
|
for (const q2 of ctx.storage.listThreadQuestions(slug, { openOnly: true })) {
|
|
79825
80182
|
const spec = parseQuestionSpec(q2.spec);
|
|
79826
80183
|
if (!spec) continue;
|
|
79827
|
-
out.push(
|
|
80184
|
+
out.push(questionView(slug, q2.id, spec, q2.asked_at));
|
|
79828
80185
|
}
|
|
79829
80186
|
return out;
|
|
79830
80187
|
}
|
|
80188
|
+
function questionView(slug, id2, spec, askedAtMs) {
|
|
80189
|
+
return {
|
|
80190
|
+
id: id2,
|
|
80191
|
+
spec,
|
|
80192
|
+
askedAt: new Date(askedAtMs).toISOString(),
|
|
80193
|
+
...spec.secret ? { secretPath: secretFilePath(ctx.project.stateDir, slug, id2) } : {}
|
|
80194
|
+
};
|
|
80195
|
+
}
|
|
79831
80196
|
function cancelQuestionsForAutonomy(slug) {
|
|
79832
80197
|
const now = Date.now();
|
|
79833
80198
|
let cancelled = 0;
|
|
79834
80199
|
for (const q2 of ctx.storage.listThreadQuestions(slug, { openOnly: true })) {
|
|
79835
|
-
|
|
80200
|
+
const spec = parseQuestionSpec(q2.spec);
|
|
80201
|
+
if (spec?.danger || spec?.secret) continue;
|
|
79836
80202
|
if (ctx.storage.dismissThreadQuestion(q2.id, now)) cancelled++;
|
|
79837
80203
|
}
|
|
79838
80204
|
return cancelled;
|
|
@@ -80170,14 +80536,14 @@ function createRouter(ctx) {
|
|
|
80170
80536
|
ctx.storage.listSubAgentSteers(input.slug, input.id)
|
|
80171
80537
|
);
|
|
80172
80538
|
const steer = subAgentSteerable(input.slug, input.id);
|
|
80173
|
-
const
|
|
80539
|
+
const stop2 = subAgentStoppable(input.slug, input.id);
|
|
80174
80540
|
return {
|
|
80175
80541
|
messages,
|
|
80176
80542
|
state: info.state,
|
|
80177
80543
|
steerable: steer.sessionId !== null,
|
|
80178
80544
|
steerNote: steer.sessionId === null ? steer.note : null,
|
|
80179
|
-
stoppable:
|
|
80180
|
-
stopNote:
|
|
80545
|
+
stoppable: stop2.sessionId !== null,
|
|
80546
|
+
stopNote: stop2.sessionId === null ? stop2.note : null
|
|
80181
80547
|
};
|
|
80182
80548
|
}
|
|
80183
80549
|
}),
|
|
@@ -80255,13 +80621,13 @@ function createRouter(ctx) {
|
|
|
80255
80621
|
const info = ctx.tailer.backgroundShell?.(input.slug, input.id);
|
|
80256
80622
|
if (!info) return { command: null, output: "", truncated: false, state: "gone", stoppable: false, stopNote: null };
|
|
80257
80623
|
const content = info.outputFile ? readBackgroundShellOutput(info.outputFile) : { output: "", truncated: false };
|
|
80258
|
-
const
|
|
80624
|
+
const stop2 = subAgentStoppable(input.slug, input.id);
|
|
80259
80625
|
return {
|
|
80260
80626
|
command: info.command ?? null,
|
|
80261
80627
|
...content,
|
|
80262
80628
|
state: info.state,
|
|
80263
|
-
stoppable:
|
|
80264
|
-
stopNote:
|
|
80629
|
+
stoppable: stop2.sessionId !== null,
|
|
80630
|
+
stopNote: stop2.sessionId === null ? stop2.note : null
|
|
80265
80631
|
};
|
|
80266
80632
|
}
|
|
80267
80633
|
}),
|
|
@@ -81295,7 +81661,7 @@ ${gapNote}` : input.message;
|
|
|
81295
81661
|
throw new Error("Reopen this thread before asking a question on it");
|
|
81296
81662
|
}
|
|
81297
81663
|
const goal = autonomousGoal(row);
|
|
81298
|
-
if (goal) {
|
|
81664
|
+
if (goal && !input.questions.every((q2) => q2.secret)) {
|
|
81299
81665
|
throw new Error(
|
|
81300
81666
|
`This thread is running autonomously \u2014 decide it yourself and proceed. Its standing instruction is:
|
|
81301
81667
|
|
|
@@ -81311,7 +81677,7 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
81311
81677
|
const id2 = `qst_${randomUUID17().replace(/-/g, "").slice(0, 12)}`;
|
|
81312
81678
|
ctx.storage.clearThreadDone(input.slug);
|
|
81313
81679
|
ctx.storage.askThreadQuestion({ id: id2, slug: input.slug, spec: JSON.stringify(spec), askedAtMs: now });
|
|
81314
|
-
return
|
|
81680
|
+
return questionView(input.slug, id2, spec, now);
|
|
81315
81681
|
});
|
|
81316
81682
|
ctx.board.refresh();
|
|
81317
81683
|
return { registered, open: openQuestionViews(input.slug) };
|
|
@@ -81336,7 +81702,14 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
81336
81702
|
for (const answer of input.answers) {
|
|
81337
81703
|
const q2 = ctx.storage.getThreadQuestion(answer.questionId);
|
|
81338
81704
|
if (!q2 || q2.thread_slug !== input.slug || q2.state !== "open") continue;
|
|
81339
|
-
|
|
81705
|
+
let stored = answer;
|
|
81706
|
+
if (parseQuestionSpec(q2.spec)?.secret) {
|
|
81707
|
+
const value = answer.text?.trim() ?? "";
|
|
81708
|
+
if (!value) continue;
|
|
81709
|
+
const path3 = serveSecret(ctx.project.stateDir, input.slug, q2.id, value);
|
|
81710
|
+
stored = { questionId: answer.questionId, question: answer.question, chosen: [], text: secretAnswerText(path3) };
|
|
81711
|
+
}
|
|
81712
|
+
if (ctx.storage.answerThreadQuestion(answer.questionId, JSON.stringify(stored), now)) answered.push(answer.questionId);
|
|
81340
81713
|
}
|
|
81341
81714
|
if (answered.length > 0) {
|
|
81342
81715
|
ctx.board.refresh();
|
|
@@ -81930,11 +82303,11 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
81930
82303
|
output: ProjectCard,
|
|
81931
82304
|
handler: async ({ input }) => {
|
|
81932
82305
|
for (const extension2 of PROJECT_ICON_EXTENSIONS) {
|
|
81933
|
-
|
|
82306
|
+
rmSync12(customIconPath(input.id, `.${extension2}`), { force: true });
|
|
81934
82307
|
}
|
|
81935
82308
|
const updated = clearProjectIcon(input.id);
|
|
81936
82309
|
if (!updated) throw new Error("No such project.");
|
|
81937
|
-
return projectCard(updated, !
|
|
82310
|
+
return projectCard(updated, !existsSync21(updated.path));
|
|
81938
82311
|
}
|
|
81939
82312
|
}),
|
|
81940
82313
|
/**
|
|
@@ -81975,7 +82348,7 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
81975
82348
|
}
|
|
81976
82349
|
const updated = renameProject(entry.id, { name: name === basename9(path3) ? null : name, slug: name });
|
|
81977
82350
|
if (!updated) throw new Error("No such project.");
|
|
81978
|
-
return projectCard(updated, !
|
|
82351
|
+
return projectCard(updated, !existsSync21(updated.path));
|
|
81979
82352
|
}
|
|
81980
82353
|
}),
|
|
81981
82354
|
/**
|
|
@@ -82179,6 +82552,7 @@ var init_router5 = __esm({
|
|
|
82179
82552
|
init_server();
|
|
82180
82553
|
init_src();
|
|
82181
82554
|
init_context();
|
|
82555
|
+
init_secret_files();
|
|
82182
82556
|
init_acp_agents();
|
|
82183
82557
|
init_storage();
|
|
82184
82558
|
init_usage_limit();
|
|
@@ -82235,144 +82609,8 @@ var init_router5 = __esm({
|
|
|
82235
82609
|
}
|
|
82236
82610
|
});
|
|
82237
82611
|
|
|
82238
|
-
// packages/server/src/local-origin.ts
|
|
82239
|
-
import { isIP } from "node:net";
|
|
82240
|
-
function publicAuthority(policy) {
|
|
82241
|
-
const raw2 = policy?.publicOrigin;
|
|
82242
|
-
if (!raw2) return null;
|
|
82243
|
-
let url;
|
|
82244
|
-
try {
|
|
82245
|
-
url = new URL(raw2);
|
|
82246
|
-
} catch {
|
|
82247
|
-
return null;
|
|
82248
|
-
}
|
|
82249
|
-
if (url.origin !== raw2) return null;
|
|
82250
|
-
return {
|
|
82251
|
-
hostname: normalizedHostname(url.hostname),
|
|
82252
|
-
port: explicitPort(url),
|
|
82253
|
-
authority: url.host.toLowerCase(),
|
|
82254
|
-
scheme: url.protocol === "https:" ? "https" : "http"
|
|
82255
|
-
};
|
|
82256
|
-
}
|
|
82257
|
-
function acceptsHostname(hostname, policy) {
|
|
82258
|
-
if (LOCAL_HOSTNAMES.has(hostname)) return true;
|
|
82259
|
-
if (!policy?.exposed) return false;
|
|
82260
|
-
if (isIP(hostname) !== 0) return true;
|
|
82261
|
-
return (policy.allowedHosts ?? []).some((allowed) => allowed === "*" || allowed.toLowerCase() === hostname);
|
|
82262
|
-
}
|
|
82263
|
-
function oneHeader(value) {
|
|
82264
|
-
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
82265
|
-
}
|
|
82266
|
-
function normalizedHostname(hostname) {
|
|
82267
|
-
const lower = hostname.toLowerCase();
|
|
82268
|
-
return lower.startsWith("[") && lower.endsWith("]") ? lower.slice(1, -1) : lower;
|
|
82269
|
-
}
|
|
82270
|
-
function explicitPort(url) {
|
|
82271
|
-
if (url.port) return Number(url.port);
|
|
82272
|
-
return url.protocol === "https:" ? 443 : 80;
|
|
82273
|
-
}
|
|
82274
|
-
function validExpectedPort(port2) {
|
|
82275
|
-
return Number.isInteger(port2) && port2 >= 1 && port2 <= 65535;
|
|
82276
|
-
}
|
|
82277
|
-
function parseLocalHttpOrigin(value, expectedPort, policy) {
|
|
82278
|
-
const raw2 = oneHeader(value);
|
|
82279
|
-
if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim()) return null;
|
|
82280
|
-
const declared = publicAuthority(policy);
|
|
82281
|
-
if (declared && raw2 === policy?.publicOrigin) return declared;
|
|
82282
|
-
let url;
|
|
82283
|
-
try {
|
|
82284
|
-
url = new URL(raw2);
|
|
82285
|
-
} catch {
|
|
82286
|
-
return null;
|
|
82287
|
-
}
|
|
82288
|
-
if (url.protocol !== "http:" || url.origin !== raw2) return null;
|
|
82289
|
-
const hostname = normalizedHostname(url.hostname);
|
|
82290
|
-
if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
|
|
82291
|
-
return { hostname, port: expectedPort, authority: url.host, scheme: "http" };
|
|
82292
|
-
}
|
|
82293
|
-
function parseLocalHost(value, expectedPort, policy) {
|
|
82294
|
-
const raw2 = oneHeader(value);
|
|
82295
|
-
if (!raw2 || !validExpectedPort(expectedPort) || raw2 !== raw2.trim() || raw2.includes(",")) return null;
|
|
82296
|
-
let url;
|
|
82297
|
-
try {
|
|
82298
|
-
url = new URL(`http://${raw2}`);
|
|
82299
|
-
} catch {
|
|
82300
|
-
return null;
|
|
82301
|
-
}
|
|
82302
|
-
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) return null;
|
|
82303
|
-
if (url.host.toLowerCase() !== raw2.toLowerCase()) return null;
|
|
82304
|
-
const hostname = normalizedHostname(url.hostname);
|
|
82305
|
-
const declared = publicAuthority(policy);
|
|
82306
|
-
if (declared && hostname === declared.hostname) {
|
|
82307
|
-
return url.port === "" || Number(url.port) === declared.port ? declared : null;
|
|
82308
|
-
}
|
|
82309
|
-
if (!acceptsHostname(hostname, policy) || explicitPort(url) !== expectedPort) return null;
|
|
82310
|
-
return { hostname, port: expectedPort, authority: url.host.toLowerCase(), scheme: "http" };
|
|
82311
|
-
}
|
|
82312
|
-
function hasForwardedAuthority(headers) {
|
|
82313
|
-
return FORWARDED_HEADERS.some((name) => headers[name] !== void 0);
|
|
82314
|
-
}
|
|
82315
|
-
function forwardedAuthorityAllowed(headers, host, policy) {
|
|
82316
|
-
if (!hasForwardedAuthority(headers)) return true;
|
|
82317
|
-
const declared = publicAuthority(policy);
|
|
82318
|
-
return !!declared && declared.hostname === host.hostname;
|
|
82319
|
-
}
|
|
82320
|
-
function isTrustedLocalHttpRequest(headers, expectedPort, allowMissingOrigin = false, policy) {
|
|
82321
|
-
const host = parseLocalHost(headers.host, expectedPort, policy);
|
|
82322
|
-
if (!host) return false;
|
|
82323
|
-
if (!forwardedAuthorityAllowed(headers, host, policy)) return false;
|
|
82324
|
-
if (headers.origin === void 0) return allowMissingOrigin;
|
|
82325
|
-
const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
|
|
82326
|
-
return !!origin && host.hostname === origin.hostname && host.port === origin.port;
|
|
82327
|
-
}
|
|
82328
|
-
function allowedLocalCorsOrigin(origin, expectedPort, policy) {
|
|
82329
|
-
return parseLocalHttpOrigin(origin, expectedPort, policy) ? origin : void 0;
|
|
82330
|
-
}
|
|
82331
|
-
function isTrustedLocalWebSocketRequest(req, expectedPort = req.socket.localPort, policy) {
|
|
82332
|
-
if (!validExpectedPort(expectedPort)) return false;
|
|
82333
|
-
const headers = req.headers;
|
|
82334
|
-
const host = parseLocalHost(headers.host, expectedPort, policy);
|
|
82335
|
-
if (!host || !forwardedAuthorityAllowed(headers, host, policy)) return false;
|
|
82336
|
-
const origin = parseLocalHttpOrigin(headers.origin, expectedPort, policy);
|
|
82337
|
-
return !!origin && host.hostname === origin.hostname && host.port === origin.port;
|
|
82338
|
-
}
|
|
82339
|
-
function rejectWebSocketUpgrade(socket, status = 403, reason = "Forbidden") {
|
|
82340
|
-
const body = `${reason}
|
|
82341
|
-
`;
|
|
82342
|
-
const response = [
|
|
82343
|
-
`HTTP/1.1 ${status} ${reason}`,
|
|
82344
|
-
"Connection: close",
|
|
82345
|
-
"Content-Type: text/plain; charset=utf-8",
|
|
82346
|
-
`Content-Length: ${Buffer.byteLength(body)}`,
|
|
82347
|
-
"",
|
|
82348
|
-
body
|
|
82349
|
-
].join("\r\n");
|
|
82350
|
-
try {
|
|
82351
|
-
socket.end(response);
|
|
82352
|
-
} catch {
|
|
82353
|
-
try {
|
|
82354
|
-
socket.destroy();
|
|
82355
|
-
} catch {
|
|
82356
|
-
}
|
|
82357
|
-
}
|
|
82358
|
-
}
|
|
82359
|
-
var LOCAL_HOSTNAMES, FORWARDED_HEADERS;
|
|
82360
|
-
var init_local_origin = __esm({
|
|
82361
|
-
"packages/server/src/local-origin.ts"() {
|
|
82362
|
-
"use strict";
|
|
82363
|
-
LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
82364
|
-
FORWARDED_HEADERS = [
|
|
82365
|
-
"forwarded",
|
|
82366
|
-
"x-forwarded-for",
|
|
82367
|
-
"x-forwarded-host",
|
|
82368
|
-
"x-forwarded-port",
|
|
82369
|
-
"x-forwarded-proto"
|
|
82370
|
-
];
|
|
82371
|
-
}
|
|
82372
|
-
});
|
|
82373
|
-
|
|
82374
82612
|
// packages/server/src/compression.ts
|
|
82375
|
-
import { brotliCompressSync, gzipSync, constants as
|
|
82613
|
+
import { brotliCompressSync, gzipSync, constants as constants5 } from "node:zlib";
|
|
82376
82614
|
function negotiateEncoding(acceptEncoding) {
|
|
82377
82615
|
if (!acceptEncoding) return null;
|
|
82378
82616
|
const offers = /* @__PURE__ */ new Map();
|
|
@@ -82395,9 +82633,9 @@ function negotiateEncoding(acceptEncoding) {
|
|
|
82395
82633
|
function compress(body, encoding) {
|
|
82396
82634
|
const out = encoding === "br" ? brotliCompressSync(body, {
|
|
82397
82635
|
params: {
|
|
82398
|
-
[
|
|
82636
|
+
[constants5.BROTLI_PARAM_QUALITY]: 4,
|
|
82399
82637
|
// Telling brotli the input size lets it size its window instead of guessing.
|
|
82400
|
-
[
|
|
82638
|
+
[constants5.BROTLI_PARAM_SIZE_HINT]: body.byteLength
|
|
82401
82639
|
}
|
|
82402
82640
|
}) : gzipSync(body, { level: 6 });
|
|
82403
82641
|
return Uint8Array.from(out);
|
|
@@ -82417,87 +82655,10 @@ var init_compression = __esm({
|
|
|
82417
82655
|
}
|
|
82418
82656
|
});
|
|
82419
82657
|
|
|
82420
|
-
// packages/server/src/local-image.ts
|
|
82421
|
-
import { createReadStream, realpathSync as realpathSync12, statSync as statSync20 } from "node:fs";
|
|
82422
|
-
import { extname as extname2, isAbsolute as isAbsolute9 } from "node:path";
|
|
82423
|
-
function resolveLocalImage(rawPath, range) {
|
|
82424
|
-
if (rawPath) rawPath = normalizeLocalPath(rawPath);
|
|
82425
|
-
if (!rawPath || !isAbsolute9(rawPath)) return { status: 400 };
|
|
82426
|
-
const contentType = CONTENT_TYPE[extname2(rawPath).toLowerCase()];
|
|
82427
|
-
if (!contentType) return { status: 400 };
|
|
82428
|
-
let real;
|
|
82429
|
-
try {
|
|
82430
|
-
real = realpathSync12(rawPath);
|
|
82431
|
-
} catch {
|
|
82432
|
-
return { status: 404 };
|
|
82433
|
-
}
|
|
82434
|
-
let size;
|
|
82435
|
-
try {
|
|
82436
|
-
const stat2 = statSync20(real);
|
|
82437
|
-
if (!stat2.isFile()) return { status: 404 };
|
|
82438
|
-
size = stat2.size;
|
|
82439
|
-
} catch {
|
|
82440
|
-
return { status: 404 };
|
|
82441
|
-
}
|
|
82442
|
-
const span = range ? byteRange(range, size) : null;
|
|
82443
|
-
if (span === "unsatisfiable") return { status: 416, size };
|
|
82444
|
-
if (span) return { status: 206, contentType, file: real, size, start: span.start, end: span.end };
|
|
82445
|
-
return { status: 200, contentType, file: real, size, start: 0, end: size - 1 };
|
|
82446
|
-
}
|
|
82447
|
-
function byteRange(header, size) {
|
|
82448
|
-
const match2 = /^bytes=(\d*)-(\d*)$/.exec(header.trim());
|
|
82449
|
-
if (!match2) return null;
|
|
82450
|
-
const [, first, last] = match2;
|
|
82451
|
-
if (first === "" && last === "") return null;
|
|
82452
|
-
if (first === "") {
|
|
82453
|
-
const suffix = Number(last);
|
|
82454
|
-
if (suffix === 0 || size === 0) return "unsatisfiable";
|
|
82455
|
-
return { start: Math.max(size - suffix, 0), end: size - 1 };
|
|
82456
|
-
}
|
|
82457
|
-
const start = Number(first);
|
|
82458
|
-
if (last !== "" && Number(last) < start) return null;
|
|
82459
|
-
if (start >= size) return "unsatisfiable";
|
|
82460
|
-
return { start, end: last === "" ? size - 1 : Math.min(Number(last), size - 1) };
|
|
82461
|
-
}
|
|
82462
|
-
function localImageHeaders(result) {
|
|
82463
|
-
return {
|
|
82464
|
-
"content-type": result.contentType,
|
|
82465
|
-
"content-length": String(result.end - result.start + 1),
|
|
82466
|
-
"accept-ranges": "bytes",
|
|
82467
|
-
"cache-control": "private, max-age=60",
|
|
82468
|
-
...result.status === 206 ? { "content-range": `bytes ${result.start}-${result.end}/${result.size}` } : {}
|
|
82469
|
-
};
|
|
82470
|
-
}
|
|
82471
|
-
function localImageStream(result) {
|
|
82472
|
-
if (result.end < result.start) return null;
|
|
82473
|
-
return createReadStream(result.file, { start: result.start, end: result.end });
|
|
82474
|
-
}
|
|
82475
|
-
var IMAGE_CONTENT_TYPE, VIDEO_CONTENT_TYPE, CONTENT_TYPE;
|
|
82476
|
-
var init_local_image = __esm({
|
|
82477
|
-
"packages/server/src/local-image.ts"() {
|
|
82478
|
-
"use strict";
|
|
82479
|
-
init_local_path();
|
|
82480
|
-
IMAGE_CONTENT_TYPE = {
|
|
82481
|
-
".png": "image/png",
|
|
82482
|
-
".jpg": "image/jpeg",
|
|
82483
|
-
".jpeg": "image/jpeg",
|
|
82484
|
-
".gif": "image/gif",
|
|
82485
|
-
".webp": "image/webp"
|
|
82486
|
-
};
|
|
82487
|
-
VIDEO_CONTENT_TYPE = {
|
|
82488
|
-
".mp4": "video/mp4",
|
|
82489
|
-
".m4v": "video/mp4",
|
|
82490
|
-
".webm": "video/webm",
|
|
82491
|
-
".mov": "video/quicktime"
|
|
82492
|
-
};
|
|
82493
|
-
CONTENT_TYPE = { ...IMAGE_CONTENT_TYPE, ...VIDEO_CONTENT_TYPE };
|
|
82494
|
-
}
|
|
82495
|
-
});
|
|
82496
|
-
|
|
82497
82658
|
// packages/server/src/project-icon.ts
|
|
82498
|
-
import { readFileSync as
|
|
82659
|
+
import { readFileSync as readFileSync31, readdirSync as readdirSync13, realpathSync as realpathSync13, statSync as statSync21 } from "node:fs";
|
|
82499
82660
|
import { homedir as homedir18 } from "node:os";
|
|
82500
|
-
import { basename as basename10, dirname as
|
|
82661
|
+
import { basename as basename10, dirname as dirname21, extname as extname3, join as join45, relative as relative2, sep as sep4 } from "node:path";
|
|
82501
82662
|
function normalizeStem(stem) {
|
|
82502
82663
|
const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
|
|
82503
82664
|
const normalized = sized.replace(VARIANT_SUFFIX, "");
|
|
@@ -82515,11 +82676,11 @@ function sizeScore(dimensions) {
|
|
|
82515
82676
|
return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
|
|
82516
82677
|
}
|
|
82517
82678
|
function under(root, relativeDirectory) {
|
|
82518
|
-
return relativeDirectory ?
|
|
82679
|
+
return relativeDirectory ? join45(root, relativeDirectory) : root;
|
|
82519
82680
|
}
|
|
82520
82681
|
function listFiles(directory) {
|
|
82521
82682
|
try {
|
|
82522
|
-
return
|
|
82683
|
+
return readdirSync13(directory, { withFileTypes: true }).filter((entry) => entry.isFile() || entry.isSymbolicLink()).map((entry) => entry.name);
|
|
82523
82684
|
} catch {
|
|
82524
82685
|
return [];
|
|
82525
82686
|
}
|
|
@@ -82528,7 +82689,7 @@ function iconDirectories(root) {
|
|
|
82528
82689
|
let children2;
|
|
82529
82690
|
try {
|
|
82530
82691
|
children2 = new Set(
|
|
82531
|
-
|
|
82692
|
+
readdirSync13(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name)
|
|
82532
82693
|
);
|
|
82533
82694
|
} catch {
|
|
82534
82695
|
return [root];
|
|
@@ -82537,19 +82698,19 @@ function iconDirectories(root) {
|
|
|
82537
82698
|
for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
|
|
82538
82699
|
for (const host of HOST_DIRECTORIES) {
|
|
82539
82700
|
if (!children2.has(host)) continue;
|
|
82540
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
82701
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join45(root, host), asset));
|
|
82541
82702
|
}
|
|
82542
82703
|
for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
|
|
82543
82704
|
for (const container of WORKSPACE_CONTAINERS) {
|
|
82544
82705
|
if (!children2.has(container)) continue;
|
|
82545
82706
|
let members;
|
|
82546
82707
|
try {
|
|
82547
|
-
members =
|
|
82708
|
+
members = readdirSync13(join45(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
82548
82709
|
} catch {
|
|
82549
82710
|
continue;
|
|
82550
82711
|
}
|
|
82551
82712
|
for (const member of members) {
|
|
82552
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
82713
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join45(root, container, member), asset));
|
|
82553
82714
|
}
|
|
82554
82715
|
}
|
|
82555
82716
|
return [...new Set(directories)];
|
|
@@ -82557,13 +82718,13 @@ function iconDirectories(root) {
|
|
|
82557
82718
|
function manifestIcons(manifestPath) {
|
|
82558
82719
|
let parsed;
|
|
82559
82720
|
try {
|
|
82560
|
-
parsed = JSON.parse(
|
|
82721
|
+
parsed = JSON.parse(readFileSync31(manifestPath, "utf8"));
|
|
82561
82722
|
} catch {
|
|
82562
82723
|
return [];
|
|
82563
82724
|
}
|
|
82564
82725
|
if (!Array.isArray(parsed?.icons)) return [];
|
|
82565
|
-
const directory =
|
|
82566
|
-
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) =>
|
|
82726
|
+
const directory = dirname21(manifestPath);
|
|
82727
|
+
return parsed.icons.map((icon) => typeof icon?.src === "string" ? icon.src : void 0).filter((src) => !!src && !/^(https?:)?\/\//u.test(src) && !src.startsWith("data:")).map((src) => join45(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
|
|
82567
82728
|
}
|
|
82568
82729
|
function projectIconCandidates(root) {
|
|
82569
82730
|
const projectStem = normalizeStem(basename10(root)).normalized;
|
|
@@ -82582,10 +82743,10 @@ function projectIconCandidates(root) {
|
|
|
82582
82743
|
for (const name of listFiles(directory)) {
|
|
82583
82744
|
const extension2 = extname3(name).toLowerCase();
|
|
82584
82745
|
if (MANIFEST_NAMES.includes(name.toLowerCase())) {
|
|
82585
|
-
for (const icon of manifestIcons(
|
|
82746
|
+
for (const icon of manifestIcons(join45(directory, name))) {
|
|
82586
82747
|
if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
|
|
82587
82748
|
fromManifest.add(icon);
|
|
82588
|
-
files.push({ path: icon, directory:
|
|
82749
|
+
files.push({ path: icon, directory: dirname21(icon) });
|
|
82589
82750
|
}
|
|
82590
82751
|
}
|
|
82591
82752
|
continue;
|
|
@@ -82593,7 +82754,7 @@ function projectIconCandidates(root) {
|
|
|
82593
82754
|
if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
|
|
82594
82755
|
const stem = name.slice(0, name.length - extension2.length);
|
|
82595
82756
|
if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
|
|
82596
|
-
files.push({ path:
|
|
82757
|
+
files.push({ path: join45(directory, name), directory });
|
|
82597
82758
|
if (files.length >= MAX_CANDIDATES) break;
|
|
82598
82759
|
}
|
|
82599
82760
|
}
|
|
@@ -82658,7 +82819,7 @@ function resolveProjectIconResponse(id2, options = {}) {
|
|
|
82658
82819
|
});
|
|
82659
82820
|
if (!roots.some((root) => real === root || real.startsWith(root + sep4))) return { status: 404 };
|
|
82660
82821
|
try {
|
|
82661
|
-
return { status: 200, contentType, body:
|
|
82822
|
+
return { status: 200, contentType, body: readFileSync31(real) };
|
|
82662
82823
|
} catch {
|
|
82663
82824
|
return { status: 404 };
|
|
82664
82825
|
}
|
|
@@ -82770,11 +82931,11 @@ var init_project_icon = __esm({
|
|
|
82770
82931
|
});
|
|
82771
82932
|
|
|
82772
82933
|
// packages/server/src/local-visualization.ts
|
|
82773
|
-
import { readdirSync as
|
|
82774
|
-
import { join as
|
|
82934
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync32, realpathSync as realpathSync14, statSync as statSync22 } from "node:fs";
|
|
82935
|
+
import { join as join46, sep as sep5 } from "node:path";
|
|
82775
82936
|
function children(path3, pattern) {
|
|
82776
82937
|
try {
|
|
82777
|
-
return
|
|
82938
|
+
return readdirSync14(path3, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
|
|
82778
82939
|
} catch {
|
|
82779
82940
|
return [];
|
|
82780
82941
|
}
|
|
@@ -82783,7 +82944,7 @@ function isUnder2(path3, root) {
|
|
|
82783
82944
|
return path3 === root || path3.startsWith(root.endsWith(sep5) ? root : root + sep5);
|
|
82784
82945
|
}
|
|
82785
82946
|
function resolveFragment(projectDir, sessionId, file) {
|
|
82786
|
-
const base =
|
|
82947
|
+
const base = join46(projectDir, ".codex", "visualizations");
|
|
82787
82948
|
let projectReal;
|
|
82788
82949
|
let baseReal;
|
|
82789
82950
|
try {
|
|
@@ -82794,12 +82955,12 @@ function resolveFragment(projectDir, sessionId, file) {
|
|
|
82794
82955
|
}
|
|
82795
82956
|
if (!isUnder2(baseReal, projectReal)) return null;
|
|
82796
82957
|
for (const year of children(base, YEAR_PART)) {
|
|
82797
|
-
const yearDir =
|
|
82958
|
+
const yearDir = join46(base, year);
|
|
82798
82959
|
for (const month of children(yearDir, DATE_PART)) {
|
|
82799
|
-
const monthDir =
|
|
82960
|
+
const monthDir = join46(yearDir, month);
|
|
82800
82961
|
for (const day of children(monthDir, DATE_PART)) {
|
|
82801
|
-
const sessionRoot =
|
|
82802
|
-
const candidate =
|
|
82962
|
+
const sessionRoot = join46(baseReal, year, month, day, sessionId);
|
|
82963
|
+
const candidate = join46(monthDir, day, sessionId, file);
|
|
82803
82964
|
try {
|
|
82804
82965
|
const real = realpathSync14(candidate);
|
|
82805
82966
|
if (isUnder2(real, sessionRoot) && statSync22(real).isFile()) return real;
|
|
@@ -82889,7 +83050,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
|
|
|
82889
83050
|
try {
|
|
82890
83051
|
const size = statSync22(path3).size;
|
|
82891
83052
|
if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
|
|
82892
|
-
fragment =
|
|
83053
|
+
fragment = readFileSync32(path3, "utf8");
|
|
82893
83054
|
} catch {
|
|
82894
83055
|
return { status: 404 };
|
|
82895
83056
|
}
|
|
@@ -82931,9 +83092,9 @@ var init_local_visualization = __esm({
|
|
|
82931
83092
|
});
|
|
82932
83093
|
|
|
82933
83094
|
// packages/server/src/app.ts
|
|
82934
|
-
import { mkdirSync as
|
|
83095
|
+
import { mkdirSync as mkdirSync23, writeFileSync as writeFileSync18 } from "node:fs";
|
|
82935
83096
|
import { Readable } from "node:stream";
|
|
82936
|
-
import { join as
|
|
83097
|
+
import { join as join47 } from "node:path";
|
|
82937
83098
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
82938
83099
|
function createApp(ctx, options = {}) {
|
|
82939
83100
|
const app = new Hono2();
|
|
@@ -82994,8 +83155,8 @@ function createApp(ctx, options = {}) {
|
|
|
82994
83155
|
const supplied = c.req.header("x-frizz-launch-token");
|
|
82995
83156
|
if (!options.controlToken || !supplied || supplied !== options.controlToken) return c.text("Forbidden", 403);
|
|
82996
83157
|
if (!options.requestOwnerStop) return c.text("Owner control unavailable", 503);
|
|
82997
|
-
const
|
|
82998
|
-
|
|
83158
|
+
const stop2 = setTimeout(options.requestOwnerStop, 25);
|
|
83159
|
+
stop2.unref();
|
|
82999
83160
|
return c.json({ accepted: true }, 202);
|
|
83000
83161
|
});
|
|
83001
83162
|
app.get(frizzRoute("/local-image"), (c) => {
|
|
@@ -83040,11 +83201,11 @@ function createApp(ctx, options = {}) {
|
|
|
83040
83201
|
if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
|
|
83041
83202
|
const ext = `.${attachmentExtension(name)}`;
|
|
83042
83203
|
const buf = Buffer.from(body.data, "base64");
|
|
83043
|
-
const dir =
|
|
83044
|
-
|
|
83204
|
+
const dir = join47(ctx.project.stateDir, "attachments");
|
|
83205
|
+
mkdirSync23(dir, { recursive: true });
|
|
83045
83206
|
const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
|
|
83046
|
-
const path3 =
|
|
83047
|
-
|
|
83207
|
+
const path3 = join47(dir, `${Date.now()}-${randomUUID18().slice(0, 8)}-${base}${ext}`);
|
|
83208
|
+
writeFileSync18(path3, buf);
|
|
83048
83209
|
return c.json({ path: path3 });
|
|
83049
83210
|
});
|
|
83050
83211
|
app.get(
|
|
@@ -83964,7 +84125,7 @@ var init_app_socket = __esm({
|
|
|
83964
84125
|
|
|
83965
84126
|
// packages/server/src/local-file-watch.ts
|
|
83966
84127
|
import { statSync as statSync23, watch } from "node:fs";
|
|
83967
|
-
import { basename as basename11, dirname as
|
|
84128
|
+
import { basename as basename11, dirname as dirname22 } from "node:path";
|
|
83968
84129
|
function stampOf(path3) {
|
|
83969
84130
|
try {
|
|
83970
84131
|
const s = statSync23(path3, { bigint: true });
|
|
@@ -83987,7 +84148,7 @@ function watchLocalFile(path3, onChange) {
|
|
|
83987
84148
|
let entry = entries.get(path3);
|
|
83988
84149
|
if (!entry) {
|
|
83989
84150
|
const name = basename11(path3);
|
|
83990
|
-
const watcher2 = watch(
|
|
84151
|
+
const watcher2 = watch(dirname22(path3), { persistent: false }, (_event, changed) => {
|
|
83991
84152
|
if (changed !== null && changed !== void 0 && changed.toString() !== name) return;
|
|
83992
84153
|
const current = entries.get(path3);
|
|
83993
84154
|
if (!current) return;
|
|
@@ -84023,10 +84184,10 @@ var init_local_file_watch = __esm({
|
|
|
84023
84184
|
});
|
|
84024
84185
|
|
|
84025
84186
|
// packages/server/src/boot-progress.ts
|
|
84026
|
-
import { mkdirSync as
|
|
84027
|
-
import { basename as basename12, dirname as
|
|
84187
|
+
import { mkdirSync as mkdirSync24, readFileSync as readFileSync33, renameSync as renameSync11, rmSync as rmSync13, writeFileSync as writeFileSync19 } from "node:fs";
|
|
84188
|
+
import { basename as basename12, dirname as dirname23, join as join48 } from "node:path";
|
|
84028
84189
|
function bootProgressPath(stateDir) {
|
|
84029
|
-
return
|
|
84190
|
+
return join48(stateDir, BOOT_PROGRESS_NAME);
|
|
84030
84191
|
}
|
|
84031
84192
|
function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
84032
84193
|
if (!stateDir) {
|
|
@@ -84046,9 +84207,9 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
84046
84207
|
lastAt = now;
|
|
84047
84208
|
step++;
|
|
84048
84209
|
try {
|
|
84049
|
-
|
|
84050
|
-
const temp =
|
|
84051
|
-
|
|
84210
|
+
mkdirSync24(dirname23(path3), { recursive: true, mode: 448 });
|
|
84211
|
+
const temp = join48(dirname23(path3), `.${basename12(path3)}.${process.pid}.tmp`);
|
|
84212
|
+
writeFileSync19(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
|
|
84052
84213
|
`, "utf8");
|
|
84053
84214
|
renameSync11(temp, path3);
|
|
84054
84215
|
} catch {
|
|
@@ -84057,7 +84218,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
84057
84218
|
return Object.assign(write, {
|
|
84058
84219
|
done: () => {
|
|
84059
84220
|
try {
|
|
84060
|
-
|
|
84221
|
+
rmSync13(path3, { force: true });
|
|
84061
84222
|
} catch {
|
|
84062
84223
|
}
|
|
84063
84224
|
}
|
|
@@ -84073,13 +84234,13 @@ var init_boot_progress = __esm({
|
|
|
84073
84234
|
});
|
|
84074
84235
|
|
|
84075
84236
|
// packages/server/src/runtime-lease.ts
|
|
84076
|
-
import { existsSync as
|
|
84077
|
-
import { dirname as
|
|
84237
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync25, readdirSync as readdirSync15, readFileSync as readFileSync34, unlinkSync as unlinkSync8, writeFileSync as writeFileSync20 } from "node:fs";
|
|
84238
|
+
import { dirname as dirname24, join as join49 } from "node:path";
|
|
84078
84239
|
function runtimeVersionDir(bin) {
|
|
84079
|
-
let dir =
|
|
84240
|
+
let dir = dirname24(bin);
|
|
84080
84241
|
for (let step = 0; step < MAX_ASCENT; step++) {
|
|
84081
|
-
if (
|
|
84082
|
-
const parent =
|
|
84242
|
+
if (existsSync22(join49(dir, PROVISIONED_MARKER))) return dir;
|
|
84243
|
+
const parent = dirname24(dir);
|
|
84083
84244
|
if (parent === dir) return void 0;
|
|
84084
84245
|
dir = parent;
|
|
84085
84246
|
}
|
|
@@ -84097,11 +84258,11 @@ function leaseRuntime(bin, role) {
|
|
|
84097
84258
|
const versionDir = runtimeVersionDir(bin);
|
|
84098
84259
|
if (!versionDir) return () => {
|
|
84099
84260
|
};
|
|
84100
|
-
const path3 =
|
|
84261
|
+
const path3 = join49(versionDir, LEASES_DIR, `${process.pid}.json`);
|
|
84101
84262
|
try {
|
|
84102
|
-
|
|
84263
|
+
mkdirSync25(dirname24(path3), { recursive: true });
|
|
84103
84264
|
const lease = { pid: process.pid, role, bin, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
84104
|
-
|
|
84265
|
+
writeFileSync20(path3, JSON.stringify(lease));
|
|
84105
84266
|
} catch {
|
|
84106
84267
|
return () => {
|
|
84107
84268
|
};
|
|
@@ -84114,20 +84275,20 @@ function leaseRuntime(bin, role) {
|
|
|
84114
84275
|
};
|
|
84115
84276
|
}
|
|
84116
84277
|
function liveRuntimeLeases(versionDir) {
|
|
84117
|
-
const dir =
|
|
84278
|
+
const dir = join49(versionDir, LEASES_DIR);
|
|
84118
84279
|
let names;
|
|
84119
84280
|
try {
|
|
84120
|
-
names =
|
|
84281
|
+
names = readdirSync15(dir);
|
|
84121
84282
|
} catch {
|
|
84122
84283
|
return [];
|
|
84123
84284
|
}
|
|
84124
84285
|
const live = [];
|
|
84125
84286
|
for (const name of names) {
|
|
84126
84287
|
if (!name.endsWith(".json")) continue;
|
|
84127
|
-
const path3 =
|
|
84288
|
+
const path3 = join49(dir, name);
|
|
84128
84289
|
let lease;
|
|
84129
84290
|
try {
|
|
84130
|
-
lease = JSON.parse(
|
|
84291
|
+
lease = JSON.parse(readFileSync34(path3, "utf8"));
|
|
84131
84292
|
} catch {
|
|
84132
84293
|
continue;
|
|
84133
84294
|
}
|
|
@@ -84156,27 +84317,27 @@ var init_runtime_lease = __esm({
|
|
|
84156
84317
|
// packages/server/src/runtimes.ts
|
|
84157
84318
|
import { createHash as createHash17 } from "node:crypto";
|
|
84158
84319
|
import {
|
|
84159
|
-
chmodSync as
|
|
84160
|
-
closeSync as
|
|
84161
|
-
existsSync as
|
|
84162
|
-
mkdirSync as
|
|
84163
|
-
openSync as
|
|
84164
|
-
readFileSync as
|
|
84165
|
-
readdirSync as
|
|
84320
|
+
chmodSync as chmodSync4,
|
|
84321
|
+
closeSync as closeSync18,
|
|
84322
|
+
existsSync as existsSync23,
|
|
84323
|
+
mkdirSync as mkdirSync26,
|
|
84324
|
+
openSync as openSync19,
|
|
84325
|
+
readFileSync as readFileSync35,
|
|
84326
|
+
readdirSync as readdirSync16,
|
|
84166
84327
|
renameSync as renameSync12,
|
|
84167
|
-
rmSync as
|
|
84328
|
+
rmSync as rmSync14,
|
|
84168
84329
|
statSync as statSync24,
|
|
84169
|
-
writeFileSync as
|
|
84170
|
-
writeSync as
|
|
84330
|
+
writeFileSync as writeFileSync21,
|
|
84331
|
+
writeSync as writeSync3
|
|
84171
84332
|
} from "node:fs";
|
|
84172
|
-
import { dirname as
|
|
84333
|
+
import { dirname as dirname25, isAbsolute as isAbsolute10, join as join50, normalize, relative as relative3, sep as sep6 } from "node:path";
|
|
84173
84334
|
import { Readable as Readable2, Transform, Writable as Writable4 } from "node:stream";
|
|
84174
84335
|
import { pipeline } from "node:stream/promises";
|
|
84175
84336
|
import { createGunzip } from "node:zlib";
|
|
84176
84337
|
function runtimesRoot(env = process.env) {
|
|
84177
84338
|
const override = env[RUNTIMES_DIR_ENV];
|
|
84178
84339
|
if (override && isAbsolute10(override)) return override;
|
|
84179
|
-
return
|
|
84340
|
+
return join50(frizzRoots().cache, "runtimes");
|
|
84180
84341
|
}
|
|
84181
84342
|
function isMusl() {
|
|
84182
84343
|
if (process.platform !== "linux") return false;
|
|
@@ -84193,16 +84354,16 @@ function runtimeCoordinates(backend, platform3 = process.platform, arch = proces
|
|
|
84193
84354
|
return { pkg: "@openai/codex", packageVersion: `${CODEX_VERSION}-${platform3}-${arch}`, label: CODEX_VERSION, binary: `codex${exe2}` };
|
|
84194
84355
|
}
|
|
84195
84356
|
function provisionedBinary(backend, root, label) {
|
|
84196
|
-
const dir =
|
|
84357
|
+
const dir = join50(root, backend, label);
|
|
84197
84358
|
let marker;
|
|
84198
84359
|
try {
|
|
84199
|
-
marker = JSON.parse(
|
|
84360
|
+
marker = JSON.parse(readFileSync35(join50(dir, MARKER), "utf8"));
|
|
84200
84361
|
} catch {
|
|
84201
84362
|
return void 0;
|
|
84202
84363
|
}
|
|
84203
84364
|
if (typeof marker.binary !== "string" || marker.label !== label) return void 0;
|
|
84204
|
-
const bin =
|
|
84205
|
-
return
|
|
84365
|
+
const bin = join50(dir, marker.binary);
|
|
84366
|
+
return existsSync23(bin) ? bin : void 0;
|
|
84206
84367
|
}
|
|
84207
84368
|
function octal(buffer, offset, length) {
|
|
84208
84369
|
const text2 = buffer.toString("latin1", offset, offset + length).replace(/\0.*$/su, "").trim();
|
|
@@ -84216,26 +84377,26 @@ function safeEntryPath(dest, name) {
|
|
|
84216
84377
|
if (parts.length < 2) return void 0;
|
|
84217
84378
|
const rel = normalize(parts.slice(1).join(sep6));
|
|
84218
84379
|
if (isAbsolute10(rel) || rel === ".." || rel.startsWith(`..${sep6}`)) return void 0;
|
|
84219
|
-
const full =
|
|
84380
|
+
const full = join50(dest, rel);
|
|
84220
84381
|
const back = relative3(dest, full);
|
|
84221
84382
|
if (back.startsWith("..") || isAbsolute10(back)) return void 0;
|
|
84222
84383
|
return full;
|
|
84223
84384
|
}
|
|
84224
84385
|
function locateBinary(dir, backend, binary) {
|
|
84225
84386
|
if (backend === "claude") {
|
|
84226
|
-
const direct =
|
|
84227
|
-
return
|
|
84387
|
+
const direct = join50(dir, binary);
|
|
84388
|
+
return existsSync23(direct) ? direct : void 0;
|
|
84228
84389
|
}
|
|
84229
|
-
const vendor =
|
|
84390
|
+
const vendor = join50(dir, "vendor");
|
|
84230
84391
|
let triples;
|
|
84231
84392
|
try {
|
|
84232
|
-
triples =
|
|
84393
|
+
triples = readdirSync16(vendor);
|
|
84233
84394
|
} catch {
|
|
84234
84395
|
return void 0;
|
|
84235
84396
|
}
|
|
84236
84397
|
for (const triple of triples) {
|
|
84237
|
-
const candidate =
|
|
84238
|
-
if (
|
|
84398
|
+
const candidate = join50(vendor, triple, "bin", binary);
|
|
84399
|
+
if (existsSync23(candidate)) return candidate;
|
|
84239
84400
|
}
|
|
84240
84401
|
return void 0;
|
|
84241
84402
|
}
|
|
@@ -84250,12 +84411,12 @@ async function provisionRuntime(backend, options) {
|
|
|
84250
84411
|
const registry = options.registry ?? REGISTRY;
|
|
84251
84412
|
const progress = options.onProgress ?? (() => {
|
|
84252
84413
|
});
|
|
84253
|
-
const backendDir =
|
|
84254
|
-
const finalDir =
|
|
84255
|
-
const partial =
|
|
84256
|
-
|
|
84257
|
-
|
|
84258
|
-
|
|
84414
|
+
const backendDir = join50(root, backend);
|
|
84415
|
+
const finalDir = join50(backendDir, coordinates.label);
|
|
84416
|
+
const partial = join50(backendDir, `.partial-${coordinates.label}-${process.pid}`);
|
|
84417
|
+
mkdirSync26(backendDir, { recursive: true });
|
|
84418
|
+
rmSync14(partial, { recursive: true, force: true });
|
|
84419
|
+
mkdirSync26(partial);
|
|
84259
84420
|
try {
|
|
84260
84421
|
const manifestUrl = `${registry}/${coordinates.pkg.replace("/", "%2F")}/${coordinates.packageVersion}`;
|
|
84261
84422
|
progress(`resolving ${coordinates.pkg}@${coordinates.packageVersion}`);
|
|
@@ -84289,7 +84450,7 @@ async function provisionRuntime(backend, options) {
|
|
|
84289
84450
|
if (digest !== integrity) throw new Error(`integrity mismatch for ${tarball}: expected ${integrity}, got ${digest}`);
|
|
84290
84451
|
const bin = locateBinary(partial, backend, coordinates.binary);
|
|
84291
84452
|
if (!bin) throw new Error(`${coordinates.pkg}@${coordinates.packageVersion} unpacked without a ${coordinates.binary} binary`);
|
|
84292
|
-
if (process.platform !== "win32")
|
|
84453
|
+
if (process.platform !== "win32") chmodSync4(bin, 493);
|
|
84293
84454
|
const marker = {
|
|
84294
84455
|
backend,
|
|
84295
84456
|
label: coordinates.label,
|
|
@@ -84299,7 +84460,7 @@ async function provisionRuntime(backend, options) {
|
|
|
84299
84460
|
binary: relative3(partial, bin),
|
|
84300
84461
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
84301
84462
|
};
|
|
84302
|
-
|
|
84463
|
+
writeFileSync21(join50(partial, MARKER), `${JSON.stringify(marker, null, 2)}
|
|
84303
84464
|
`, "utf8");
|
|
84304
84465
|
const rename2 = options.rename ?? renameSync12;
|
|
84305
84466
|
try {
|
|
@@ -84308,36 +84469,36 @@ async function provisionRuntime(backend, options) {
|
|
|
84308
84469
|
rename2(partial, finalDir);
|
|
84309
84470
|
break;
|
|
84310
84471
|
} catch (err) {
|
|
84311
|
-
if (attempt >= RENAME_ATTEMPTS || !TRANSIENT_HANDLE_CODES.has(errorCode4(err) ?? "") ||
|
|
84472
|
+
if (attempt >= RENAME_ATTEMPTS || !TRANSIENT_HANDLE_CODES.has(errorCode4(err) ?? "") || existsSync23(finalDir)) throw err;
|
|
84312
84473
|
await new Promise((resolve13) => setTimeout(resolve13, options.retryDelayMs ?? RENAME_RETRY_DELAY_MS));
|
|
84313
84474
|
}
|
|
84314
84475
|
}
|
|
84315
84476
|
} catch (err) {
|
|
84316
84477
|
const theirs = provisionedBinary(backend, root, coordinates.label);
|
|
84317
84478
|
if (!theirs) throw err;
|
|
84318
|
-
|
|
84479
|
+
rmSync14(partial, { recursive: true, force: true });
|
|
84319
84480
|
return { bin: theirs, label: coordinates.label, fetched: false };
|
|
84320
84481
|
}
|
|
84321
84482
|
progress("ready");
|
|
84322
|
-
return { bin:
|
|
84483
|
+
return { bin: join50(finalDir, marker.binary), label: coordinates.label, fetched: true };
|
|
84323
84484
|
} catch (err) {
|
|
84324
|
-
|
|
84485
|
+
rmSync14(partial, { recursive: true, force: true });
|
|
84325
84486
|
throw err;
|
|
84326
84487
|
}
|
|
84327
84488
|
}
|
|
84328
84489
|
function sweepRuntimes(backend, root, keepLabel, now = Date.now(), deps = {}) {
|
|
84329
84490
|
const rm2 = deps.rm ?? defaultSweepRm;
|
|
84330
|
-
const backendDir =
|
|
84491
|
+
const backendDir = join50(root, backend);
|
|
84331
84492
|
let entries2;
|
|
84332
84493
|
try {
|
|
84333
|
-
entries2 =
|
|
84494
|
+
entries2 = readdirSync16(backendDir);
|
|
84334
84495
|
} catch {
|
|
84335
84496
|
return { removed: [], kept: [] };
|
|
84336
84497
|
}
|
|
84337
84498
|
const sweep = { removed: [], kept: [] };
|
|
84338
84499
|
for (const entry of entries2) {
|
|
84339
84500
|
if (entry === keepLabel) continue;
|
|
84340
|
-
const full =
|
|
84501
|
+
const full = join50(backendDir, entry);
|
|
84341
84502
|
if (entry.startsWith(".partial-")) {
|
|
84342
84503
|
try {
|
|
84343
84504
|
if (now - statSync24(full).mtimeMs < 24 * 60 * 60 * 1e3) continue;
|
|
@@ -84463,7 +84624,7 @@ var init_runtimes = __esm({
|
|
|
84463
84624
|
}
|
|
84464
84625
|
}
|
|
84465
84626
|
_final(callback) {
|
|
84466
|
-
if (this.fd !== void 0)
|
|
84627
|
+
if (this.fd !== void 0) closeSync18(this.fd);
|
|
84467
84628
|
this.fd = void 0;
|
|
84468
84629
|
callback(this.remaining > 0 ? new Error("tarball ended inside a file entry") : null);
|
|
84469
84630
|
}
|
|
@@ -84520,7 +84681,7 @@ var init_runtimes = __esm({
|
|
|
84520
84681
|
return;
|
|
84521
84682
|
case "5": {
|
|
84522
84683
|
const dir = safeEntryPath(this.dest, name);
|
|
84523
|
-
if (dir)
|
|
84684
|
+
if (dir) mkdirSync26(dir, { recursive: true });
|
|
84524
84685
|
return;
|
|
84525
84686
|
}
|
|
84526
84687
|
case "0":
|
|
@@ -84528,8 +84689,8 @@ var init_runtimes = __esm({
|
|
|
84528
84689
|
case "7": {
|
|
84529
84690
|
const file = safeEntryPath(this.dest, name);
|
|
84530
84691
|
if (!file) return;
|
|
84531
|
-
|
|
84532
|
-
this.fd =
|
|
84692
|
+
mkdirSync26(dirname25(file), { recursive: true });
|
|
84693
|
+
this.fd = openSync19(file, "w", octal(header, 100, 8) & 511 || 420);
|
|
84533
84694
|
this.written.push(file);
|
|
84534
84695
|
return;
|
|
84535
84696
|
}
|
|
@@ -84538,13 +84699,13 @@ var init_runtimes = __esm({
|
|
|
84538
84699
|
}
|
|
84539
84700
|
}
|
|
84540
84701
|
sink(bytes) {
|
|
84541
|
-
if (this.fd !== void 0)
|
|
84702
|
+
if (this.fd !== void 0) writeSync3(this.fd, bytes);
|
|
84542
84703
|
else if (this.nameBuffer) this.nameBuffer.push(Buffer.from(bytes));
|
|
84543
84704
|
else if (this.paxBuffer) this.paxBuffer.push(Buffer.from(bytes));
|
|
84544
84705
|
}
|
|
84545
84706
|
finishEntry() {
|
|
84546
84707
|
if (this.fd !== void 0) {
|
|
84547
|
-
|
|
84708
|
+
closeSync18(this.fd);
|
|
84548
84709
|
this.fd = void 0;
|
|
84549
84710
|
}
|
|
84550
84711
|
if (this.nameBuffer) {
|
|
@@ -84572,7 +84733,7 @@ var init_runtimes = __esm({
|
|
|
84572
84733
|
RENAME_RETRY_DELAY_MS = 200;
|
|
84573
84734
|
TRANSIENT_HANDLE_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
84574
84735
|
errorCode4 = (err) => err?.code;
|
|
84575
|
-
defaultSweepRm = (path3) =>
|
|
84736
|
+
defaultSweepRm = (path3) => rmSync14(path3, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
84576
84737
|
}
|
|
84577
84738
|
});
|
|
84578
84739
|
|
|
@@ -85108,18 +85269,18 @@ var init_legacy_project_db = __esm({
|
|
|
85108
85269
|
});
|
|
85109
85270
|
|
|
85110
85271
|
// packages/server/src/frizz-db.ts
|
|
85111
|
-
import { existsSync as
|
|
85112
|
-
import { basename as basename13, dirname as
|
|
85272
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync27, readdirSync as readdirSync17, renameSync as renameSync13, statSync as statSync25 } from "node:fs";
|
|
85273
|
+
import { basename as basename13, dirname as dirname26, join as join51 } from "node:path";
|
|
85113
85274
|
function frizzDatabaseLocation(options) {
|
|
85114
85275
|
if (options.stateDir !== void 0) {
|
|
85115
|
-
const projectsDir =
|
|
85276
|
+
const projectsDir = dirname26(options.stateDir);
|
|
85116
85277
|
if (basename13(projectsDir) === "projects") {
|
|
85117
|
-
return { path: options.path ??
|
|
85278
|
+
return { path: options.path ?? join51(dirname26(projectsDir), "ui.db"), projectsDir };
|
|
85118
85279
|
}
|
|
85119
|
-
return { path: options.path ??
|
|
85280
|
+
return { path: options.path ?? join51(options.stateDir, "ui.db"), projectsDir: void 0 };
|
|
85120
85281
|
}
|
|
85121
85282
|
const data = options.home ? frizzPaths({ home: options.home }).data : frizzRoots().data;
|
|
85122
|
-
return { path: options.path ??
|
|
85283
|
+
return { path: options.path ?? join51(data, "ui.db"), projectsDir: join51(data, "projects") };
|
|
85123
85284
|
}
|
|
85124
85285
|
function ensureFrizzSchema(db2) {
|
|
85125
85286
|
db2.exec(`
|
|
@@ -85138,7 +85299,7 @@ function ensureFrizzSchema(db2) {
|
|
|
85138
85299
|
}
|
|
85139
85300
|
function openFrizzDatabase(options = {}) {
|
|
85140
85301
|
const { path: path3, projectsDir } = frizzDatabaseLocation(options);
|
|
85141
|
-
|
|
85302
|
+
mkdirSync27(dirname26(path3), { recursive: true });
|
|
85142
85303
|
const db2 = new sqlite_default(path3);
|
|
85143
85304
|
db2.pragma("busy_timeout = 5000");
|
|
85144
85305
|
db2.pragma("journal_mode = WAL");
|
|
@@ -85150,10 +85311,10 @@ function openFrizzDatabase(options = {}) {
|
|
|
85150
85311
|
);
|
|
85151
85312
|
for (const projectId of retiredLegacyProjectIds(projectsDir)) {
|
|
85152
85313
|
if (alreadyImported.has(projectId)) continue;
|
|
85153
|
-
const dir =
|
|
85314
|
+
const dir = join51(projectsDir, projectId);
|
|
85154
85315
|
try {
|
|
85155
|
-
renameSync13(
|
|
85156
|
-
db2.prepare("INSERT INTO imported_project (project_id, source, rows, imported_at) VALUES (?, ?, 0, ?)").run(projectId,
|
|
85316
|
+
renameSync13(join51(dir, "ui.db.imported"), join51(dir, "ui.db"));
|
|
85317
|
+
db2.prepare("INSERT INTO imported_project (project_id, source, rows, imported_at) VALUES (?, ?, 0, ?)").run(projectId, join51(dir, "ui.db"), (/* @__PURE__ */ new Date()).toISOString());
|
|
85157
85318
|
alreadyImported.add(projectId);
|
|
85158
85319
|
log.info("frizz-db", `${projectId}: restored ui.db.imported to ui.db and recorded it as imported`);
|
|
85159
85320
|
} catch (error) {
|
|
@@ -85163,7 +85324,7 @@ function openFrizzDatabase(options = {}) {
|
|
|
85163
85324
|
}
|
|
85164
85325
|
for (const projectId of legacyProjectIds(projectsDir)) {
|
|
85165
85326
|
if (alreadyImported.has(projectId)) continue;
|
|
85166
|
-
const legacyPath =
|
|
85327
|
+
const legacyPath = join51(projectsDir, projectId, "ui.db");
|
|
85167
85328
|
try {
|
|
85168
85329
|
const rows = importLegacyProject(db2, projectId, legacyPath);
|
|
85169
85330
|
imported.push({ projectId, rows });
|
|
@@ -85193,10 +85354,10 @@ function openFrizzDatabase(options = {}) {
|
|
|
85193
85354
|
};
|
|
85194
85355
|
}
|
|
85195
85356
|
function projectIdsWithFile(projectsDir, file) {
|
|
85196
|
-
if (!
|
|
85197
|
-
return
|
|
85357
|
+
if (!existsSync24(projectsDir)) return [];
|
|
85358
|
+
return readdirSync17(projectsDir).filter((name) => {
|
|
85198
85359
|
try {
|
|
85199
|
-
return statSync25(
|
|
85360
|
+
return statSync25(join51(projectsDir, name, file)).isFile();
|
|
85200
85361
|
} catch {
|
|
85201
85362
|
return false;
|
|
85202
85363
|
}
|
|
@@ -85206,7 +85367,7 @@ function legacyProjectIds(projectsDir) {
|
|
|
85206
85367
|
return projectIdsWithFile(projectsDir, "ui.db");
|
|
85207
85368
|
}
|
|
85208
85369
|
function retiredLegacyProjectIds(projectsDir) {
|
|
85209
|
-
return projectIdsWithFile(projectsDir, "ui.db.imported").filter((id2) => !
|
|
85370
|
+
return projectIdsWithFile(projectsDir, "ui.db.imported").filter((id2) => !existsSync24(join51(projectsDir, id2, "ui.db")));
|
|
85210
85371
|
}
|
|
85211
85372
|
function tableColumns(db2, schema, table) {
|
|
85212
85373
|
return db2.prepare(`PRAGMA ${schema}.table_info(${table})`).all().map((c) => c.name);
|
|
@@ -85360,9 +85521,9 @@ var init_tenant_prime = __esm({
|
|
|
85360
85521
|
});
|
|
85361
85522
|
|
|
85362
85523
|
// packages/server/src/project-teardown.ts
|
|
85363
|
-
import { rmSync as
|
|
85524
|
+
import { rmSync as rmSync15 } from "node:fs";
|
|
85364
85525
|
import { homedir as homedir19 } from "node:os";
|
|
85365
|
-
import { dirname as
|
|
85526
|
+
import { dirname as dirname27, resolve as resolve11 } from "node:path";
|
|
85366
85527
|
async function stopProjectWorkers(ctx) {
|
|
85367
85528
|
let stopped = 0;
|
|
85368
85529
|
for (const row of ctx.storage.allSessions()) {
|
|
@@ -85382,10 +85543,10 @@ function deleteProjectState(projectId, home = homedir19()) {
|
|
|
85382
85543
|
if (!/^[\w.-]+$/u.test(projectId) || projectId === "." || projectId === "..") {
|
|
85383
85544
|
throw new Error(`Refusing to delete state for a malformed project id: ${projectId}`);
|
|
85384
85545
|
}
|
|
85385
|
-
if (
|
|
85546
|
+
if (dirname27(resolve11(target)) !== resolve11(dirname27(projectStateDir("x", home)))) {
|
|
85386
85547
|
throw new Error(`Refusing to delete ${target} \u2014 it is not a project state directory`);
|
|
85387
85548
|
}
|
|
85388
|
-
|
|
85549
|
+
rmSync15(target, { recursive: true, force: true });
|
|
85389
85550
|
}
|
|
85390
85551
|
var init_project_teardown = __esm({
|
|
85391
85552
|
"packages/server/src/project-teardown.ts"() {
|
|
@@ -85411,11 +85572,11 @@ __export(index_exports, {
|
|
|
85411
85572
|
unknownProjectPage: () => unknownProjectPage
|
|
85412
85573
|
});
|
|
85413
85574
|
import { createServer } from "node:http";
|
|
85414
|
-
import { readFileSync as
|
|
85415
|
-
import { dirname as
|
|
85575
|
+
import { readFileSync as readFileSync36, existsSync as existsSync25, statSync as statSync26 } from "node:fs";
|
|
85576
|
+
import { dirname as dirname28, join as join52, resolve as resolve12, extname as extname4, posix as posix2, sep as sep7 } from "node:path";
|
|
85416
85577
|
function readServerAddressHolder(path3) {
|
|
85417
85578
|
try {
|
|
85418
|
-
const value = JSON.parse(
|
|
85579
|
+
const value = JSON.parse(readFileSync36(path3, "utf8"));
|
|
85419
85580
|
if (typeof value?.pid !== "number") return void 0;
|
|
85420
85581
|
return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
|
|
85421
85582
|
} catch {
|
|
@@ -85540,12 +85701,12 @@ function staticIsFresh(req, etag, mtimeMs) {
|
|
|
85540
85701
|
}
|
|
85541
85702
|
function serveStatic(distDir, req, res) {
|
|
85542
85703
|
const rel = posix2.normalize((req.url ?? "/").split("?")[0].replace(/\\/g, "/")).replace(/^(\.\.[/\\])+/, "");
|
|
85543
|
-
let file =
|
|
85544
|
-
if (!file.startsWith(distDir + sep7)) file =
|
|
85545
|
-
if (!
|
|
85704
|
+
let file = join52(distDir, rel === "/" ? "index.html" : rel);
|
|
85705
|
+
if (!file.startsWith(distDir + sep7)) file = join52(distDir, "index.html");
|
|
85706
|
+
if (!existsSync25(file)) file = join52(distDir, "index.html");
|
|
85546
85707
|
try {
|
|
85547
85708
|
const stats = statSync26(file);
|
|
85548
|
-
const cacheControl = file.startsWith(
|
|
85709
|
+
const cacheControl = file.startsWith(join52(distDir, "assets") + sep7) ? STATIC_CACHE_IMMUTABLE : STATIC_CACHE_REVALIDATE;
|
|
85549
85710
|
const etag = `"${stats.size.toString(16)}-${Math.trunc(stats.mtimeMs).toString(16)}"`;
|
|
85550
85711
|
const headers = {
|
|
85551
85712
|
"content-type": MIME[extname4(file)] ?? "application/octet-stream",
|
|
@@ -85561,7 +85722,7 @@ function serveStatic(distDir, req, res) {
|
|
|
85561
85722
|
res.end();
|
|
85562
85723
|
return;
|
|
85563
85724
|
}
|
|
85564
|
-
let body =
|
|
85725
|
+
let body = readFileSync36(file);
|
|
85565
85726
|
const accept = req.headers["accept-encoding"];
|
|
85566
85727
|
const encoding = negotiateEncoding(Array.isArray(accept) ? accept.join(",") : accept);
|
|
85567
85728
|
if (encoding && shouldCompress(new Headers({ "content-type": headers["content-type"] }), body.byteLength)) {
|
|
@@ -85818,7 +85979,7 @@ async function startServer(opts = {}) {
|
|
|
85818
85979
|
if (statusPath && statusIdentity) runtime.removeStatus(statusPath, statusIdentity);
|
|
85819
85980
|
if (statusPath && statusIdentity) {
|
|
85820
85981
|
try {
|
|
85821
|
-
runtime.removeStatus(serverAddressPathForStateDir(
|
|
85982
|
+
runtime.removeStatus(serverAddressPathForStateDir(dirname28(statusPath)), statusIdentity);
|
|
85822
85983
|
} catch {
|
|
85823
85984
|
}
|
|
85824
85985
|
}
|
|
@@ -85950,7 +86111,7 @@ async function startServer(opts = {}) {
|
|
|
85950
86111
|
}
|
|
85951
86112
|
statusPath = serverLockPathFor(ctx.project);
|
|
85952
86113
|
const webRoot = resolve12(import.meta.dirname, "..", "..", "web");
|
|
85953
|
-
const distDir = opts.webDistDir ? resolve12(opts.webDistDir) :
|
|
86114
|
+
const distDir = opts.webDistDir ? resolve12(opts.webDistDir) : join52(webRoot, "dist");
|
|
85954
86115
|
startupPhase = "Vite";
|
|
85955
86116
|
if (opts.dev) {
|
|
85956
86117
|
try {
|
|
@@ -86028,7 +86189,7 @@ async function startServer(opts = {}) {
|
|
|
86028
86189
|
if (vite) {
|
|
86029
86190
|
vite.middlewares(req, res, () => {
|
|
86030
86191
|
try {
|
|
86031
|
-
const html =
|
|
86192
|
+
const html = readFileSync36(join52(webRoot, "index.html"), "utf8");
|
|
86032
86193
|
void vite.transformIndexHtml(url, html).then((out) => {
|
|
86033
86194
|
res.writeHead(200, { "content-type": "text/html" });
|
|
86034
86195
|
res.end(out);
|
|
@@ -86040,7 +86201,7 @@ async function startServer(opts = {}) {
|
|
|
86040
86201
|
});
|
|
86041
86202
|
return;
|
|
86042
86203
|
}
|
|
86043
|
-
if (
|
|
86204
|
+
if (existsSync25(distDir)) {
|
|
86044
86205
|
serveStatic(distDir, req, res);
|
|
86045
86206
|
return;
|
|
86046
86207
|
}
|
|
@@ -86234,7 +86395,7 @@ var init_index = __esm({
|
|
|
86234
86395
|
}
|
|
86235
86396
|
};
|
|
86236
86397
|
isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
|
|
86237
|
-
serverLockPathFor = (project) =>
|
|
86398
|
+
serverLockPathFor = (project) => join52(project.stateDir, "server.lock");
|
|
86238
86399
|
MIME = {
|
|
86239
86400
|
".html": "text/html",
|
|
86240
86401
|
".js": "text/javascript",
|
|
@@ -86257,8 +86418,316 @@ init_project();
|
|
|
86257
86418
|
init_project_launch();
|
|
86258
86419
|
init_shutdown();
|
|
86259
86420
|
init_logging();
|
|
86260
|
-
import { existsSync as
|
|
86261
|
-
import { join as
|
|
86421
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
86422
|
+
import { join as join53 } from "node:path";
|
|
86423
|
+
|
|
86424
|
+
// packages/server/src/access-codes.ts
|
|
86425
|
+
import { randomBytes, timingSafeEqual, createHmac } from "node:crypto";
|
|
86426
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
86427
|
+
import { dirname as dirname6, join as join9 } from "node:path";
|
|
86428
|
+
var DEFAULT_CODE_TTL_MS = 5 * 6e4;
|
|
86429
|
+
var DEFAULT_SESSION_TTL_MS = 30 * 24 * 60 * 6e4;
|
|
86430
|
+
var SESSION_EPOCH = 1;
|
|
86431
|
+
var SESSION_KEY_FILE = "session-key";
|
|
86432
|
+
var SESSION_EPOCH_FILE = "session-epoch";
|
|
86433
|
+
function writeSessionKey(path3, key) {
|
|
86434
|
+
mkdirSync7(dirname6(path3), { recursive: true });
|
|
86435
|
+
writeFileSync6(path3, key, { mode: 384 });
|
|
86436
|
+
try {
|
|
86437
|
+
chmodSync(path3, 384);
|
|
86438
|
+
} catch {
|
|
86439
|
+
}
|
|
86440
|
+
}
|
|
86441
|
+
function rotateSessionKey(stateDir) {
|
|
86442
|
+
const key = randomBytes(32);
|
|
86443
|
+
writeSessionKey(join9(stateDir, SESSION_KEY_FILE), key);
|
|
86444
|
+
return key;
|
|
86445
|
+
}
|
|
86446
|
+
function readSessionEpoch(stateDir) {
|
|
86447
|
+
try {
|
|
86448
|
+
const parsed = JSON.parse(readFileSync6(join9(stateDir, SESSION_EPOCH_FILE), "utf8"));
|
|
86449
|
+
return Number.isInteger(parsed?.epoch) && parsed.epoch >= 0 ? parsed.epoch : 0;
|
|
86450
|
+
} catch {
|
|
86451
|
+
return 0;
|
|
86452
|
+
}
|
|
86453
|
+
}
|
|
86454
|
+
function advanceSessionEpoch(stateDir, epoch = SESSION_EPOCH) {
|
|
86455
|
+
const from = readSessionEpoch(stateDir);
|
|
86456
|
+
if (from >= epoch) return { advanced: false, epoch: from };
|
|
86457
|
+
const keyPath = join9(stateDir, SESSION_KEY_FILE);
|
|
86458
|
+
const rotatedKey = existsSync4(keyPath);
|
|
86459
|
+
if (rotatedKey) rotateSessionKey(stateDir);
|
|
86460
|
+
mkdirSync7(stateDir, { recursive: true });
|
|
86461
|
+
writeFileSync6(
|
|
86462
|
+
join9(stateDir, SESSION_EPOCH_FILE),
|
|
86463
|
+
JSON.stringify({ epoch, advancedAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
86464
|
+
{ mode: 384 }
|
|
86465
|
+
);
|
|
86466
|
+
return { advanced: true, from, to: epoch, rotatedKey };
|
|
86467
|
+
}
|
|
86468
|
+
function sessionEpochLogLine(advance, signedOut) {
|
|
86469
|
+
if (!advance.advanced || !advance.rotatedKey) return null;
|
|
86470
|
+
const count = signedOut === null ? "an unknown number of" : String(signedOut);
|
|
86471
|
+
return `session epoch ${advance.from} -> ${advance.to}: rotated the session key and signed out ${count} recorded remote device(s); every older remote session is refused`;
|
|
86472
|
+
}
|
|
86473
|
+
|
|
86474
|
+
// packages/server/src/session-epoch-child.ts
|
|
86475
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
86476
|
+
import { join as join10 } from "node:path";
|
|
86477
|
+
|
|
86478
|
+
// packages/server/src/restart-supervisor.ts
|
|
86479
|
+
init_local_origin();
|
|
86480
|
+
init_local_image();
|
|
86481
|
+
|
|
86482
|
+
// packages/server/src/supervisor-pages.ts
|
|
86483
|
+
var BASE_STYLE = `
|
|
86484
|
+
*,*::before,*::after{box-sizing:border-box}
|
|
86485
|
+
:root{
|
|
86486
|
+
color-scheme:dark;
|
|
86487
|
+
--bg:#0d0e10;--panel:#131519;--panel-2:#181b20;
|
|
86488
|
+
--border:#26282d;--border-strong:#33363c;--control-border:#26282d;--control-strong:#33363c;
|
|
86489
|
+
--fg:#e6e7e9;--muted:#8b8f96;--accent:#e8b923;--danger:#fca5a5;
|
|
86490
|
+
--focus-border:color-mix(in srgb,var(--accent) 55%,transparent);--focus-ring:color-mix(in srgb,var(--accent) 22%,transparent);
|
|
86491
|
+
--sans:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
|
|
86492
|
+
--mono:ui-monospace,"JetBrains Mono","SF Mono","Cascadia Mono",Menlo,Consolas,monospace;
|
|
86493
|
+
--ease:cubic-bezier(0,0,.2,1);
|
|
86494
|
+
}
|
|
86495
|
+
:root[data-theme=light]{
|
|
86496
|
+
color-scheme:light;
|
|
86497
|
+
--bg:#f7f7f7;--panel:#fff;--panel-2:#fafafa;
|
|
86498
|
+
--border:#dedede;--border-strong:#cecece;--control-border:#858585;--control-strong:#7d7d7d;
|
|
86499
|
+
--fg:#292929;--muted:#606060;--accent:#416896;--danger:#cf222e;
|
|
86500
|
+
--focus-border:#416896;--focus-ring:#416896;
|
|
86501
|
+
}
|
|
86502
|
+
@media(prefers-color-scheme:light){
|
|
86503
|
+
:root:not([data-theme]){
|
|
86504
|
+
color-scheme:light;
|
|
86505
|
+
--bg:#f7f7f7;--panel:#fff;--panel-2:#fafafa;
|
|
86506
|
+
--border:#dedede;--border-strong:#cecece;--control-border:#858585;--control-strong:#7d7d7d;
|
|
86507
|
+
--fg:#292929;--muted:#606060;--accent:#416896;--danger:#cf222e;
|
|
86508
|
+
--focus-border:#416896;--focus-ring:#416896;
|
|
86509
|
+
}
|
|
86510
|
+
}
|
|
86511
|
+
html,body{background:var(--bg)}
|
|
86512
|
+
body{
|
|
86513
|
+
margin:0;min-height:100vh;min-height:100dvh;
|
|
86514
|
+
display:flex;align-items:center;justify-content:center;padding:24px;
|
|
86515
|
+
color:var(--fg);font-family:var(--sans);font-size:12.5px;line-height:1.55;
|
|
86516
|
+
-webkit-font-smoothing:antialiased;
|
|
86517
|
+
}
|
|
86518
|
+
main{width:100%;max-width:28rem;padding:18px;border:1px solid var(--border-strong);border-radius:12px;background:var(--panel-2)}
|
|
86519
|
+
h1{margin:0;display:flex;align-items:baseline;gap:7px;font-size:14px;font-weight:600;letter-spacing:-.01em;line-height:1.4}
|
|
86520
|
+
p{margin:0;text-wrap:pretty}
|
|
86521
|
+
.detail{margin-top:7px;color:color-mix(in srgb,var(--fg) 88%,transparent)}
|
|
86522
|
+
.note{margin-top:12px;padding-top:11px;border-top:1px solid var(--border);color:var(--muted);font-size:11.5px;line-height:1.6}
|
|
86523
|
+
code{font-family:var(--mono);font-size:.92em;padding:.1em .35em;border-radius:4px;background:var(--panel);border:1px solid var(--border);white-space:nowrap}
|
|
86524
|
+
[hidden]{display:none!important}
|
|
86525
|
+
`.trim();
|
|
86526
|
+
var RECOVERY_STYLE = `
|
|
86527
|
+
.actions{margin-top:14px;display:flex;flex-wrap:wrap;gap:8px}
|
|
86528
|
+
/* ErrorBoundary's ACTION_CLASS, one size up for a page that is alone in a viewport. */
|
|
86529
|
+
.btn{
|
|
86530
|
+
appearance:none;display:inline-flex;align-items:center;
|
|
86531
|
+
border:1px solid var(--control-border);border-radius:6px;background:transparent;
|
|
86532
|
+
padding:5px 10px;font:inherit;font-size:11.5px;color:color-mix(in srgb,var(--fg) 90%,transparent);
|
|
86533
|
+
cursor:pointer;text-decoration:none;
|
|
86534
|
+
transition:background-color 120ms var(--ease),border-color 120ms var(--ease),color 120ms var(--ease);
|
|
86535
|
+
}
|
|
86536
|
+
.btn:hover{background:var(--panel);border-color:var(--control-strong);color:var(--fg)}
|
|
86537
|
+
.btn:focus-visible{outline:none;border-color:var(--focus-border);box-shadow:0 0 0 2px var(--focus-ring)}
|
|
86538
|
+
.btn:disabled{opacity:.5;pointer-events:none}
|
|
86539
|
+
/* min-height holds the slot open while it is LIVE, so a changing status line never nudges the card;
|
|
86540
|
+
:empty collapses it when there is nothing live to say, so a halted card has no trailing gutter. */
|
|
86541
|
+
.probe{margin-top:12px;font-family:var(--mono);font-size:11px;line-height:1.5;color:var(--muted);min-height:1.5em}
|
|
86542
|
+
.probe:empty{margin-top:0;min-height:0}
|
|
86543
|
+
/* RestartFailureNotice's block, at this altitude: a supervisor \`message\` is raw build output, and it
|
|
86544
|
+
reads as what it is \u2014 a terminal excerpt \u2014 only inside a scrolling mono box. */
|
|
86545
|
+
.log{
|
|
86546
|
+
margin-top:10px;max-height:16rem;overflow:auto;white-space:pre-wrap;overflow-wrap:break-word;
|
|
86547
|
+
border:1px solid var(--border);border-radius:6px;background:var(--panel);padding:8px 10px;
|
|
86548
|
+
font-family:var(--mono);font-size:11px;line-height:1.6;color:color-mix(in srgb,var(--fg) 70%,transparent);
|
|
86549
|
+
}
|
|
86550
|
+
|
|
86551
|
+
/* THE LIVE DOT, and it is the app's own \`.frizz-live-dot\` \u2014 same 6px, same 28%/14% halo, same 1.25s
|
|
86552
|
+
cadence \u2014 because it means the same thing here that it means there: work is in flight.
|
|
86553
|
+
|
|
86554
|
+
Alignment is an INK problem. A baseline-aligned flex item with no text of its own contributes its
|
|
86555
|
+
BORDER-BOX BOTTOM as the baseline, so the dot's ink centre lands 3px above it while the cap band's
|
|
86556
|
+
centre sits 0.5cap above it. \`cap\` is the resolved font's own cap height, so the correction holds
|
|
86557
|
+
at any size, with nothing to re-measure when the type scale moves. The em spelling is the fallback for a browser without the unit (.35em ~= 0.5 x a
|
|
86558
|
+
0.7em cap) and is overwritten wherever \`cap\` parses. */
|
|
86559
|
+
.dot{
|
|
86560
|
+
width:6px;height:6px;flex:0 0 auto;border-radius:9999px;background:var(--accent);
|
|
86561
|
+
box-shadow:0 0 0 1px color-mix(in srgb,var(--accent) 28%,transparent);
|
|
86562
|
+
animation:frizz-live-pulse 1.25s ease-in-out infinite;
|
|
86563
|
+
transform:translateY(calc(3px - .35em));
|
|
86564
|
+
transform:translateY(calc(3px - .5cap));
|
|
86565
|
+
}
|
|
86566
|
+
.dot[data-state=idle]{animation:none;background:var(--muted);box-shadow:none}
|
|
86567
|
+
.dot[data-state=bad]{animation:none;background:var(--danger);box-shadow:0 0 0 1px color-mix(in srgb,var(--danger) 28%,transparent)}
|
|
86568
|
+
@keyframes frizz-live-pulse{50%{opacity:.62;box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 14%,transparent)}}
|
|
86569
|
+
@media (prefers-reduced-motion:reduce){
|
|
86570
|
+
.dot{animation:none;background:transparent;border:2px solid var(--accent);box-shadow:none}
|
|
86571
|
+
.dot[data-state=idle]{border-color:var(--muted)}
|
|
86572
|
+
.dot[data-state=bad]{border-color:var(--danger);background:transparent}
|
|
86573
|
+
}
|
|
86574
|
+
|
|
86575
|
+
/* The app's \`.shimmer-text\`: a highlight sweeping muted text is how this product says "working", and
|
|
86576
|
+
the probe line is the only thing on the page that is. */
|
|
86577
|
+
.probe[data-live=yes]{
|
|
86578
|
+
color:transparent;
|
|
86579
|
+
background:linear-gradient(90deg,var(--muted) 0%,var(--muted) 35%,var(--fg) 50%,var(--muted) 65%,var(--muted) 100%) 0 0/200% 100%;
|
|
86580
|
+
-webkit-background-clip:text;background-clip:text;
|
|
86581
|
+
animation:frizz-shimmer 2.2s linear infinite;
|
|
86582
|
+
}
|
|
86583
|
+
@keyframes frizz-shimmer{from{background-position:200% 0}to{background-position:-200% 0}}
|
|
86584
|
+
@media (prefers-reduced-motion:reduce){
|
|
86585
|
+
.probe[data-live=yes]{animation:none;background:none;color:var(--muted)}
|
|
86586
|
+
}
|
|
86587
|
+
`.trim();
|
|
86588
|
+
var RECOVERY_SCRIPT = `
|
|
86589
|
+
(function(){
|
|
86590
|
+
var target=document.body.dataset.target||"/"
|
|
86591
|
+
var heading=document.getElementById("heading")
|
|
86592
|
+
var detail=document.getElementById("detail")
|
|
86593
|
+
var probe=document.getElementById("probe")
|
|
86594
|
+
var log=document.getElementById("log")
|
|
86595
|
+
var dot=document.getElementById("dot")
|
|
86596
|
+
var restart=document.getElementById("restart")
|
|
86597
|
+
var BUDGET=120000,MIN=600,MAX=4000,GROWTH=1.4
|
|
86598
|
+
var delay=MIN,deadline=Date.now()+BUDGET,timer=0,stopped=false,busy=false,told=""
|
|
86599
|
+
|
|
86600
|
+
function say(text,live){probe.textContent=text;probe.setAttribute("data-live",live?"yes":"no")}
|
|
86601
|
+
function halt(text,bad){stopped=true;clearTimeout(timer);dot.setAttribute("data-state",bad?"bad":"idle");say(text,false)}
|
|
86602
|
+
function showLog(message){if(message){log.textContent=message;log.hidden=false}else{log.hidden=true}}
|
|
86603
|
+
function resume(){stopped=false;busy=false;delay=MIN;deadline=Date.now()+BUDGET;dot.removeAttribute("data-state");clearTimeout(timer);timer=setTimeout(tick,0)}
|
|
86604
|
+
|
|
86605
|
+
// 503 is this proxy's own "no child". Every other answer \u2014 200, 404, even a 500 from the app \u2014 means
|
|
86606
|
+
// something is listening again, and the reader's own URL is the right thing to ask.
|
|
86607
|
+
function alive(){
|
|
86608
|
+
return fetch(target,{method:"HEAD",cache:"no-store",credentials:"same-origin"})
|
|
86609
|
+
.then(function(r){return r.status!==503}).catch(function(){return false})
|
|
86610
|
+
}
|
|
86611
|
+
function readStatus(){
|
|
86612
|
+
return fetch("/_frizz/control/status",{cache:"no-store",headers:{"cache-control":"no-store"}})
|
|
86613
|
+
.then(function(r){return r.ok?r.json():null})
|
|
86614
|
+
.then(function(b){return b&&b.protocol===1?b:null}).catch(function(){return null})
|
|
86615
|
+
}
|
|
86616
|
+
|
|
86617
|
+
// An unreachable launcher leaves the server-rendered copy alone: it is already right for the case
|
|
86618
|
+
// that rendered it, and guessing over it would be worse than saying nothing.
|
|
86619
|
+
function narrate(status){
|
|
86620
|
+
if(!status||status.state===told)return
|
|
86621
|
+
told=status.state
|
|
86622
|
+
if(status.state==="failed"){
|
|
86623
|
+
heading.textContent="Frizz did not restart"
|
|
86624
|
+
// Not a second copy of the note below it \u2014 a lead-in to the log, which is the next thing down.
|
|
86625
|
+
detail.textContent="The launcher could not bring the application server back, and reported this:"
|
|
86626
|
+
showLog(status.message||"The launcher gave no reason.")
|
|
86627
|
+
halt("",true)
|
|
86628
|
+
return
|
|
86629
|
+
}
|
|
86630
|
+
showLog("")
|
|
86631
|
+
if(status.state==="restarting"){
|
|
86632
|
+
heading.textContent="Frizz is restarting"
|
|
86633
|
+
detail.textContent="The application server is coming back up."
|
|
86634
|
+
}
|
|
86635
|
+
}
|
|
86636
|
+
|
|
86637
|
+
function tick(){
|
|
86638
|
+
if(stopped||busy)return
|
|
86639
|
+
// A hidden tab neither polls nor spends its budget; visibilitychange starts the loop again.
|
|
86640
|
+
if(document.hidden)return
|
|
86641
|
+
alive().then(function(up){
|
|
86642
|
+
if(up){say("Frizz is back. Reloading.",true);location.replace(target);return}
|
|
86643
|
+
return readStatus().then(function(status){
|
|
86644
|
+
narrate(status)
|
|
86645
|
+
if(stopped)return
|
|
86646
|
+
if(Date.now()>deadline){halt("No answer after 2m. This page stopped checking.",false);return}
|
|
86647
|
+
delay=Math.min(MAX,delay*GROWTH)
|
|
86648
|
+
say("Waiting for Frizz",true)
|
|
86649
|
+
timer=setTimeout(tick,delay)
|
|
86650
|
+
})
|
|
86651
|
+
})
|
|
86652
|
+
}
|
|
86653
|
+
|
|
86654
|
+
document.addEventListener("visibilitychange",function(){
|
|
86655
|
+
if(document.hidden||stopped||busy)return
|
|
86656
|
+
resume()
|
|
86657
|
+
})
|
|
86658
|
+
|
|
86659
|
+
restart.addEventListener("click",function(){
|
|
86660
|
+
if(busy)return
|
|
86661
|
+
busy=true;stopped=false;told="";clearTimeout(timer)
|
|
86662
|
+
restart.disabled=true;restart.textContent="Restarting"
|
|
86663
|
+
dot.removeAttribute("data-state");showLog("");say("Restarting Frizz",true)
|
|
86664
|
+
fetch("/_frizz/control/restart",{method:"POST",headers:{"cache-control":"no-store"}})
|
|
86665
|
+
.then(function(r){return r.json().catch(function(){return null}).then(function(b){return{ok:r.ok,status:r.status,body:b}})})
|
|
86666
|
+
.catch(function(){return{ok:false,status:0,body:null}})
|
|
86667
|
+
.then(function(r){
|
|
86668
|
+
restart.disabled=false;restart.textContent="Restart Frizz";busy=false
|
|
86669
|
+
if(!r.ok){
|
|
86670
|
+
heading.textContent="Frizz did not restart"
|
|
86671
|
+
detail.textContent="The launcher could not bring the application server back, and reported this:"
|
|
86672
|
+
showLog((r.body&&r.body.message)||("The launcher refused the restart ("+(r.status||"no response")+")."))
|
|
86673
|
+
halt("",true)
|
|
86674
|
+
return
|
|
86675
|
+
}
|
|
86676
|
+
// Accepted. The probe, not this response, decides whether the child is actually back.
|
|
86677
|
+
resume()
|
|
86678
|
+
})
|
|
86679
|
+
})
|
|
86680
|
+
|
|
86681
|
+
say("Waiting for Frizz",true)
|
|
86682
|
+
tick()
|
|
86683
|
+
})()
|
|
86684
|
+
`.trim();
|
|
86685
|
+
|
|
86686
|
+
// packages/server/src/restart-supervisor.ts
|
|
86687
|
+
init_src();
|
|
86688
|
+
var SUPERVISOR_CONTROL_PREFIX = "/_frizz/control";
|
|
86689
|
+
var SUPERVISOR_RESTART_PATH = `${SUPERVISOR_CONTROL_PREFIX}/restart`;
|
|
86690
|
+
var SUPERVISOR_UPDATE_RESTART_PATH = `${SUPERVISOR_CONTROL_PREFIX}/update-restart`;
|
|
86691
|
+
var SUPERVISOR_STATUS_PATH = `${SUPERVISOR_CONTROL_PREFIX}/status`;
|
|
86692
|
+
var SUPERVISOR_ACCESS_CODE_PATH = `${SUPERVISOR_CONTROL_PREFIX}/access-code`;
|
|
86693
|
+
var SUPERVISOR_SESSIONS_PATH = `${SUPERVISOR_CONTROL_PREFIX}/sessions`;
|
|
86694
|
+
var SUPERVISOR_SIGN_OUT_PATH = `${SUPERVISOR_CONTROL_PREFIX}/sign-out`;
|
|
86695
|
+
var LOCAL_IMAGE_PATH = new RegExp(`^${FRIZZ_ROUTE_PREFIX}(?:/[^/]+)?/local-image$`);
|
|
86696
|
+
|
|
86697
|
+
// packages/server/src/session-epoch-child.ts
|
|
86698
|
+
async function signOutOlderSessionEpoch(options) {
|
|
86699
|
+
const advance = advanceSessionEpoch(options.stateDir, options.epoch ?? SESSION_EPOCH);
|
|
86700
|
+
if (!advance.advanced || !advance.rotatedKey) return { advance, signedOut: 0 };
|
|
86701
|
+
const port2 = supervisorPort(options.stateDir, options.supervisorPid);
|
|
86702
|
+
if (port2 === void 0) return { advance, signedOut: null };
|
|
86703
|
+
try {
|
|
86704
|
+
const response = await (options.fetcher ?? fetch)(`http://127.0.0.1:${port2}${SUPERVISOR_SESSIONS_PATH}`, {
|
|
86705
|
+
method: "POST",
|
|
86706
|
+
// Node's fetch sends no Origin, and the control plane wants one on a POST: name the loopback
|
|
86707
|
+
// authority, as `frizz --sign-out` does.
|
|
86708
|
+
headers: { origin: `http://127.0.0.1:${port2}`, "content-type": "application/json" },
|
|
86709
|
+
body: JSON.stringify({ all: true }),
|
|
86710
|
+
signal: AbortSignal.timeout(5e3)
|
|
86711
|
+
});
|
|
86712
|
+
if (response.status === 409) return { advance, signedOut: 0 };
|
|
86713
|
+
if (!response.ok) return { advance, signedOut: null };
|
|
86714
|
+
const body = await response.json().catch(() => void 0);
|
|
86715
|
+
return { advance, signedOut: typeof body?.signedOut === "number" ? body.signedOut : null };
|
|
86716
|
+
} catch {
|
|
86717
|
+
return { advance, signedOut: null };
|
|
86718
|
+
}
|
|
86719
|
+
}
|
|
86720
|
+
function supervisorPort(stateDir, supervisorPid) {
|
|
86721
|
+
try {
|
|
86722
|
+
const status = JSON.parse(readFileSync7(join10(stateDir, "dev-supervisor.lock"), "utf8"));
|
|
86723
|
+
if (status.pid !== supervisorPid) return void 0;
|
|
86724
|
+
return Number.isInteger(status.port) && status.port > 0 && status.port <= 65535 ? status.port : void 0;
|
|
86725
|
+
} catch {
|
|
86726
|
+
return void 0;
|
|
86727
|
+
}
|
|
86728
|
+
}
|
|
86729
|
+
|
|
86730
|
+
// packages/server/src/dev-child.ts
|
|
86262
86731
|
process.on("uncaughtException", (error) => {
|
|
86263
86732
|
log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
|
|
86264
86733
|
process.exit(1);
|
|
@@ -86313,9 +86782,9 @@ try {
|
|
|
86313
86782
|
["FRIZZ_SCRIPTS_DIR", process.env.FRIZZ_SCRIPTS_DIR, "index.mjs"],
|
|
86314
86783
|
["FRIZZ_WORKER_PLUGIN_DIR", process.env.FRIZZ_WORKER_PLUGIN_DIR, ".claude-plugin/plugin.json"]
|
|
86315
86784
|
];
|
|
86316
|
-
if (!
|
|
86785
|
+
if (!existsSync26(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
|
|
86317
86786
|
for (const [name, directory, requiredFile] of required) {
|
|
86318
|
-
if (!directory || !
|
|
86787
|
+
if (!directory || !existsSync26(join53(directory, requiredFile)))
|
|
86319
86788
|
throw new Error(`stable artifact launch is missing verified ${name}`);
|
|
86320
86789
|
}
|
|
86321
86790
|
}
|
|
@@ -86335,8 +86804,14 @@ try {
|
|
|
86335
86804
|
port: server.port,
|
|
86336
86805
|
bootId: server.ctx.bootId
|
|
86337
86806
|
});
|
|
86807
|
+
if (process.connected) {
|
|
86808
|
+
void signOutOlderSessionEpoch({ stateDir: target.stateDir, supervisorPid: process.ppid }).then(({ advance, signedOut }) => {
|
|
86809
|
+
const line = sessionEpochLogLine(advance, signedOut);
|
|
86810
|
+
if (line) log.warn("dev-child", `${line} (a launcher older than this release refuses the rest from its next start)`);
|
|
86811
|
+
}).catch((error) => log.warn("dev-child", `session epoch: ${error instanceof Error ? error.message : error}`));
|
|
86812
|
+
}
|
|
86338
86813
|
let shuttingDown = false;
|
|
86339
|
-
const
|
|
86814
|
+
const stop2 = async () => {
|
|
86340
86815
|
if (shuttingDown) return;
|
|
86341
86816
|
shuttingDown = true;
|
|
86342
86817
|
const force = setTimeout(() => process.exit(1), 15e3);
|
|
@@ -86359,9 +86834,9 @@ try {
|
|
|
86359
86834
|
process.exit(1);
|
|
86360
86835
|
}
|
|
86361
86836
|
};
|
|
86362
|
-
shutdown =
|
|
86363
|
-
process.on("SIGINT", () => void
|
|
86364
|
-
process.on("SIGTERM", () => void
|
|
86837
|
+
shutdown = stop2;
|
|
86838
|
+
process.on("SIGINT", () => void stop2());
|
|
86839
|
+
process.on("SIGTERM", () => void stop2());
|
|
86365
86840
|
} catch (err) {
|
|
86366
86841
|
log.error("dev-child", `failed to start: ${err instanceof Error ? err.stack ?? err.message : err}`);
|
|
86367
86842
|
process.exit(1);
|