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