frizz-server 0.15.17 → 0.15.18
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 +1106 -615
- package/package.json +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-BCWz80uN.js → abnfDiagram-VRR7QNED-CN39SboF.js} +1 -1
- package/web-dist/assets/{arc-DDtkTWyk.js → arc-BTVl3fKG.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-BQiZAFL1.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-BpRbm_s5.js → architectureDiagram-ZJ3FMSHR-CLNnuVr7.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-_kGtJSW2.js → blockDiagram-677ZJIJ3-bTZNRjJP.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-D8XwDoiY.js → c4Diagram-LMCZKHZV-DeekS0uP.js} +1 -1
- package/web-dist/assets/channel-B7pe0_FG.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-BUGbBNz_.js → chunk-32BRIVSS-CAVyehgA.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-Dc0eyYJe.js → chunk-52WLFC77-C_ljp3lt.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-CNP8apQ_.js → chunk-C7G6YPKG-BPdDxqsZ.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-m5klG9uB.js → chunk-EX3LRPZG-DWH-e06D.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-CHO58JFl.js → chunk-FWX5IMBZ-yrfMig6k.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-DjH-r82r.js → chunk-HOUHSVGY-DOIBrNRJ.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-DkYjEd46.js → chunk-ICXQ74PX-kstLL_Nj.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-D89rLIxX.js → chunk-MOJQB5TN-DDtU29dE.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-Db2MBETv.js → chunk-OGEWGWER-D2c91oEJ.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-Dtdx_z8j.js → chunk-PUDLZKDR-3Z2pVgx9.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-XYvD_xYq.js → chunk-Q4XR5HBZ-rmeb4GSY.js} +1 -1
- package/web-dist/assets/{chunk-RYQCIY6F-CZ7RTprX.js → chunk-RYQCIY6F-DE9FW0LM.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-CoAVJiNJ.js → chunk-V7JOEXUC-CNvw-r6K.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-DbjEHErZ.js → chunk-VAUOI2AC-DUK5u-DN.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-4BB6eLCK.js → chunk-VR4S4FIN-8Qx2Il0y.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-Cuvm_fLi.js → chunk-WYO6CB5R-Ch0_cnOf.js} +1 -1
- package/web-dist/assets/{chunk-XXDRQBXY-CvLzx99l.js → chunk-XXDRQBXY-Bmd-5yN2.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-BccJcRbi.js → chunk-ZGVPDNZ5-MvQyLrp9.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-CRHph3JZ.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-CRHph3JZ.js +1 -0
- package/web-dist/assets/{cose-bilkent-JH36ORCC-BfwT-16i.js → cose-bilkent-JH36ORCC-BmksLZVW.js} +1 -1
- package/web-dist/assets/{cynefin-VYW2F7L2-DbZ1V36t.js → cynefin-VYW2F7L2-nkrhmZuY.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-mFI_mDt-.js → cynefinDiagram-TSTJHNR4-Cn3BNg8k.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-BldEgHyl.js → dagre-VKFMJZFB-CTLouEOu.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-CWSdOHjN.js → diagram-FQU43EPY-u58-2525.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-CohHPpmC.js → diagram-G47NLZAW-Cqsb2-PB.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-CY9SIr04.js → diagram-NH7WQ7WH-8nRCmdGE.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-D1ChaJcq.js → diagram-OA4YK3LP-BNuiXQqV.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-Bng85j-O.js → diagram-WEI45ONY-B0hi_GgE.js} +1 -1
- package/web-dist/assets/{dist-Dn2m7SMF.js → dist-D3Kuxfbr.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-CcHfTwsR.js → ebnfDiagram-CCIWWBDH-C5EWDVC_.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-D9XptUTi.js → erDiagram-Q63AITRT-BLphelWe.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-C45ENNHn.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-aHbgmUdC.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-CpDcHWNC.js → ganttDiagram-NO4QXBWP-Dr-DMNOU.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-dskxWshP.js → gitGraph-TEB2WS4Q-eyuwOTFC.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-Gm-g6rXY.js → gitGraphDiagram-IHSO6WYX-BGcdlMUE.js} +1 -1
- package/web-dist/assets/index-C1G_Iq1d.js +337 -0
- package/web-dist/assets/index-DN7SaNCi.css +2 -0
- package/web-dist/assets/{info-DKCQHKI2-DfBWPig9.js → info-DKCQHKI2-T83_1t8S.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-RA1gm_5G.js → infoDiagram-FWYZ7A6U-BZ7ZHiPE.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DMO4tlB7.js → ishikawaDiagram-FXEZZL3T-BbGaZkdX.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-CGn0Vfft.js → journeyDiagram-5HDEW3XC-74db34k8.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-qRxs3pxC.js → kanban-definition-HUTT4EX6-_LDBnhu3.js} +1 -1
- package/web-dist/assets/{line-BihkNjKV.js → line-BSQ-_Ld3.js} +1 -1
- package/web-dist/assets/{linear-CbcYjraG.js → linear-TtekQ35r.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-CstJtBOd.js → mermaid-parser.core-C02mLVGD.js} +3 -3
- package/web-dist/assets/{mermaid.core-CAoFTj5o.js → mermaid.core-5-Q5DE5L.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-Dobyf2TY.js → mindmap-definition-LN4V7U3C-D3OsE9M2.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-BV-_zRVl.js → packet-7NZHBO7P-ChHw2m9w.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-CoWfyvfk.js → pegDiagram-2B236MQR-Be0eWdVa.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-ptQFpYwJ.js → pie-RZYD4A2V-Y5I7o_6T.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-DCYSn0kJ.js → pieDiagram-ENE6RG2P-BVzIUwYC.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-D-IhKJdt.js → quadrantDiagram-ABIIQ3AL--WcNeUJ5.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-CqtSeYcU.js → radar-I7S5WNFK-_iLcxlOU.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-CejeX1m0.js → railroad-3IZDKUUU-DUaKyIjl.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-nyOfFXMk.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-D4SI1We5.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-CWKTA2jO.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-CLMVsbkb.js → railroadDiagram-RFXS5EU6-JC2ENdbW.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-J6ovU2nZ.js → requirementDiagram-TGXJPOKE-CZISQjoj.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-BN1Wcnxg.js → sankeyDiagram-HTMAVEWB-B88W28-Q.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-CnDSUjeE.js → sequenceDiagram-DBY2YBRQ-BsoQQ4qC.js} +1 -1
- package/web-dist/assets/{src-ie67lQl7.js → src-GZyi5f3X.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-CDvDw5S6.js → stateDiagram-2N3HPSRC-DO6yDa4d.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BXMrHzjW.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-BmljTUhI.js → swimlanes-5IMT3BWC-zONynGJq.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-5NqpA4rx.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-CjA-qR6O.js → timeline-definition-FHXFAJF6-ChT_IFLs.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-CHKGsZbS.js → treeView-QDETBFTQ-BzNyoCOf.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-CqU-nL1w.js → treemap-6X3UGDF4-BGbFAuCU.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-BwQcxcel.js → vennDiagram-L72KCM5P-CNyyMggu.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-Bo8e8N-h.js → wardley-OPB4EBWU-uHhpiyKg.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-ByioZC4m.js → wardleyDiagram-EHGQE667-gYBm-Ips.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-B48Vy_EL.js → xychartDiagram-FW5EYKEG-BhuHU_17.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-BSM-tgTt.js +0 -1
- package/web-dist/assets/channel-BwwaRyUv.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DTgWbehh.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DTgWbehh.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-vqzohKbi.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-CYPLykok.js +0 -1
- package/web-dist/assets/index-Bi4vNYho.css +0 -2
- package/web-dist/assets/index-C5sCt0eh.js +0 -334
- package/web-dist/assets/railroad-abnf-AHOZXSZD-D858Ks1V.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-CnKN0qs5.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-CG_oVFtv.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-CWmRITC6.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BTxJqUkH.js +0 -8
package/dist/dev-child.js
CHANGED
|
@@ -654,7 +654,7 @@ var init_project_identity = __esm({
|
|
|
654
654
|
|
|
655
655
|
// packages/server/src/project-root.ts
|
|
656
656
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
657
|
-
import { closeSync as closeSync2, existsSync as existsSync2, fsyncSync as fsyncSync2, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync3, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
657
|
+
import { closeSync as closeSync2, existsSync as existsSync2, fsyncSync as fsyncSync2, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync3, realpathSync as realpathSync2, renameSync as renameSync2, rmSync as rmSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
658
658
|
import { homedir as homedir3 } from "node:os";
|
|
659
659
|
import { dirname as dirname3, join as join4, parse, resolve as resolve3 } from "node:path";
|
|
660
660
|
function projectIdPath(root) {
|
|
@@ -741,6 +741,17 @@ function isHomeDirectory(dir, home = homedir3()) {
|
|
|
741
741
|
return false;
|
|
742
742
|
}
|
|
743
743
|
}
|
|
744
|
+
function isWorldWritable(dir, platform3 = process.platform) {
|
|
745
|
+
if (platform3 === "win32") return false;
|
|
746
|
+
try {
|
|
747
|
+
return (statSync2(dir).mode & 2) !== 0;
|
|
748
|
+
} catch {
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
function refuseWorldWritableProject(dir) {
|
|
753
|
+
if (isWorldWritable(dir)) throw new Error(`A folder every account can write to cannot be a project: ${dir}`);
|
|
754
|
+
}
|
|
744
755
|
function existingProjectId(dir) {
|
|
745
756
|
const fromFile = readProjectIdFile(dir);
|
|
746
757
|
if (fromFile) return fromFile;
|
|
@@ -10669,7 +10680,7 @@ var init_types = __esm({
|
|
|
10669
10680
|
* upgrade if you are experiencing issues.
|
|
10670
10681
|
*/
|
|
10671
10682
|
merge(merging) {
|
|
10672
|
-
const
|
|
10683
|
+
const merged2 = new _ZodObject({
|
|
10673
10684
|
unknownKeys: merging._def.unknownKeys,
|
|
10674
10685
|
catchall: merging._def.catchall,
|
|
10675
10686
|
shape: () => ({
|
|
@@ -10678,7 +10689,7 @@ var init_types = __esm({
|
|
|
10678
10689
|
}),
|
|
10679
10690
|
typeName: ZodFirstPartyTypeKind.ZodObject
|
|
10680
10691
|
});
|
|
10681
|
-
return
|
|
10692
|
+
return merged2;
|
|
10682
10693
|
}
|
|
10683
10694
|
// merge<
|
|
10684
10695
|
// Incoming extends AnyZodObject,
|
|
@@ -11045,8 +11056,8 @@ var init_types = __esm({
|
|
|
11045
11056
|
if (isAborted(parsedLeft) || isAborted(parsedRight)) {
|
|
11046
11057
|
return INVALID;
|
|
11047
11058
|
}
|
|
11048
|
-
const
|
|
11049
|
-
if (!
|
|
11059
|
+
const merged2 = mergeValues(parsedLeft.value, parsedRight.value);
|
|
11060
|
+
if (!merged2.valid) {
|
|
11050
11061
|
addIssueToContext(ctx, {
|
|
11051
11062
|
code: ZodIssueCode.invalid_intersection_types
|
|
11052
11063
|
});
|
|
@@ -11055,7 +11066,7 @@ var init_types = __esm({
|
|
|
11055
11066
|
if (isDirty(parsedLeft) || isDirty(parsedRight)) {
|
|
11056
11067
|
status.dirty();
|
|
11057
11068
|
}
|
|
11058
|
-
return { status: status.value, value:
|
|
11069
|
+
return { status: status.value, value: merged2.data };
|
|
11059
11070
|
};
|
|
11060
11071
|
if (ctx.common.async) {
|
|
11061
11072
|
return Promise.all([
|
|
@@ -13874,16 +13885,22 @@ function askedQuestionFaults(q2) {
|
|
|
13874
13885
|
return faults;
|
|
13875
13886
|
}
|
|
13876
13887
|
function secretAnswerText(path3) {
|
|
13877
|
-
return
|
|
13888
|
+
return `${SECRET_ANSWER_PREFIX}${quotePath(path3)} \u2014 it can be read ONCE, within ${SECRET_TTL_MS / 6e4}m; never print it)`;
|
|
13878
13889
|
}
|
|
13879
13890
|
function quotePath(value) {
|
|
13880
13891
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
13881
13892
|
}
|
|
13893
|
+
function answerPicksText(chosen, text2) {
|
|
13894
|
+
const note = text2?.trim() ?? "";
|
|
13895
|
+
if (chosen.length === 0) return note;
|
|
13896
|
+
if (chosen.length === 1 && !note) return chosen[0];
|
|
13897
|
+
return [chosen.map((label) => `${ANSWER_PICK_PREFIX}${label}`).join("\n"), note].filter(Boolean).join("\n\n");
|
|
13898
|
+
}
|
|
13882
13899
|
function questionAnswerMessage(answers, dismissed = []) {
|
|
13883
13900
|
if (answers.length === 0) return questionsCancelledWakeMessage(dismissed.length);
|
|
13884
13901
|
const rows = [];
|
|
13885
13902
|
const push = (a, followUp) => {
|
|
13886
|
-
const said =
|
|
13903
|
+
const said = answerPicksText(a.chosen, a.text);
|
|
13887
13904
|
rows.push(`${followUp ? `${ANSWER_FOLLOW_UP_MARKER} ` : ""}\u201C${a.question}\u201D \u2192 ${indentAnswerContinuation(said || "(no answer)")}`);
|
|
13888
13905
|
for (const child of a.followUps ?? []) push(child, true);
|
|
13889
13906
|
};
|
|
@@ -14058,6 +14075,25 @@ function parseAgentMessage(text2) {
|
|
|
14058
14075
|
if (!body.trim() || !from) return void 0;
|
|
14059
14076
|
return { from, body };
|
|
14060
14077
|
}
|
|
14078
|
+
function decodeXmlAttribute(value) {
|
|
14079
|
+
return value.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
14080
|
+
}
|
|
14081
|
+
function parseCrossSessionMessage(text2) {
|
|
14082
|
+
let rest = text2.trim();
|
|
14083
|
+
const preamble = CROSS_SESSION_PREAMBLE.exec(rest);
|
|
14084
|
+
if (preamble) rest = rest.slice(preamble[0].length);
|
|
14085
|
+
const m = CROSS_SESSION_WRAPPER.exec(rest);
|
|
14086
|
+
if (!m) return void 0;
|
|
14087
|
+
const after = rest.slice(m[0].length).trim();
|
|
14088
|
+
if (after && !after.startsWith(CROSS_SESSION_GUIDANCE)) return void 0;
|
|
14089
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
14090
|
+
for (const [, key, value] of m[1].matchAll(XML_ATTRIBUTE)) attributes.set(key, decodeXmlAttribute(value).trim());
|
|
14091
|
+
const body = m[2].trim();
|
|
14092
|
+
if (!body) return void 0;
|
|
14093
|
+
const name = attributes.get("from-name") || void 0;
|
|
14094
|
+
const socket = attributes.get("from") || void 0;
|
|
14095
|
+
return { ...name ? { name } : {}, ...socket ? { socket } : {}, body };
|
|
14096
|
+
}
|
|
14061
14097
|
function wakeItemTail(item) {
|
|
14062
14098
|
return `${item.at ? ` at ${item.at}` : ""}${item.url ? `: ${item.url}` : ""}`;
|
|
14063
14099
|
}
|
|
@@ -14127,7 +14163,7 @@ function parseGithubWakeSteer(text2) {
|
|
|
14127
14163
|
function frizzRoute(path3) {
|
|
14128
14164
|
return `${FRIZZ_ROUTE_PREFIX}${path3.startsWith("/") ? path3 : `/${path3}`}`;
|
|
14129
14165
|
}
|
|
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;
|
|
14166
|
+
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_ANSWER_PREFIX, SECRET_TTL_MS, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, SettledQuestionView, ThreadSettledQuestionsResult, BURIED_ANSWERS_HEADER, ANSWER_FOLLOW_UP_MARKER, ANSWER_CONTINUATION_INDENT, indentAnswerContinuation, ANSWER_PICK_PREFIX, 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, CROSS_SESSION_PREAMBLE, CROSS_SESSION_WRAPPER, CROSS_SESSION_GUIDANCE, XML_ATTRIBUTE, 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;
|
|
14131
14167
|
var init_src = __esm({
|
|
14132
14168
|
"packages/shared/src/index.ts"() {
|
|
14133
14169
|
"use strict";
|
|
@@ -14826,6 +14862,7 @@ var init_src = __esm({
|
|
|
14826
14862
|
* worker can prepare the command that reads it before the human has answered. */
|
|
14827
14863
|
secretPath: external_exports.string().optional()
|
|
14828
14864
|
}).strict();
|
|
14865
|
+
SECRET_ANSWER_PREFIX = "(secret ready at ";
|
|
14829
14866
|
SECRET_TTL_MS = 15 * 6e4;
|
|
14830
14867
|
AskResult = external_exports.object({
|
|
14831
14868
|
registered: external_exports.array(RegisteredQuestionView),
|
|
@@ -14886,6 +14923,7 @@ var init_src = __esm({
|
|
|
14886
14923
|
ANSWER_CONTINUATION_INDENT = " ";
|
|
14887
14924
|
indentAnswerContinuation = (text2) => text2.replace(/\n/g, `
|
|
14888
14925
|
${ANSWER_CONTINUATION_INDENT}`);
|
|
14926
|
+
ANSWER_PICK_PREFIX = "- [x] ";
|
|
14889
14927
|
DISMISSED_ANSWER = "(dismissed \u2014 decide it yourself; do not re-ask)";
|
|
14890
14928
|
MarkOwnDoneInput = external_exports.object({
|
|
14891
14929
|
slug: ThreadSlug,
|
|
@@ -15745,6 +15783,10 @@ ${DISPATCH_TASK_BANNER}
|
|
|
15745
15783
|
WAKE_DELIVERY_TOKEN_LINE = /(?:^|\n)[ \t]*<!-- frizz-wake:[A-Za-z0-9_-]+ -->[ \t]*(?=\n|$)/g;
|
|
15746
15784
|
NOISE_PREFIXES = ["<task-notification>", "[SYSTEM NOTIFICATION", "<system-reminder>", "<frizz-", "[frizz]"];
|
|
15747
15785
|
AGENT_MESSAGE_WRAPPER = /^<agent-message from="([^"]*)">\n?([\s\S]*?)\n?<\/agent-message>\s*$/;
|
|
15786
|
+
CROSS_SESSION_PREAMBLE = /^Another Claude session sent a message(?: while you were working)?:\n/;
|
|
15787
|
+
CROSS_SESSION_WRAPPER = /^<cross-session-message\b([^>]*)>\n?([\s\S]*?)\n?<\/cross-session-message>/;
|
|
15788
|
+
CROSS_SESSION_GUIDANCE = "This came from another Claude session";
|
|
15789
|
+
XML_ATTRIBUTE = /([a-z][a-z-]*)="([^"]*)"/g;
|
|
15748
15790
|
GithubWakeItem = external_exports.object({
|
|
15749
15791
|
label: external_exports.string(),
|
|
15750
15792
|
// the activity's noun ("comment", "approval", "change request", …)
|
|
@@ -16235,6 +16277,20 @@ ${DISPATCH_TASK_BANNER}
|
|
|
16235
16277
|
// pairing, and `projectTranscriptPeerNames` uses this id to ask it. Never a drawer key on its own —
|
|
16236
16278
|
// that is `peerDispatchId`, which the same pass can also supply once this resolves.
|
|
16237
16279
|
peerSenderTaskId: external_exports.string().optional(),
|
|
16280
|
+
// ANOTHER TOP-LEVEL SESSION wrote this user turn — a thread messaging this one through Claude Code's
|
|
16281
|
+
// cross-session channel (see parseCrossSessionMessage), most often the coordinator thread that spawned
|
|
16282
|
+
// it. Not the human, and not a sub-agent either: the chat draws it as an expandable hairline naming
|
|
16283
|
+
// the sending thread, with the body one click away. `displayText` carries the unwrapped body.
|
|
16284
|
+
//
|
|
16285
|
+
// `name` is the sender's Claude Code session name, the fallback label. `thread` is the Frizz thread
|
|
16286
|
+
// behind it, filled in by the server from the sender's socket (session-peer.ts) — absent when the
|
|
16287
|
+
// sender is not a Frizz thread or is gone without having been resolved, and then the line names the
|
|
16288
|
+
// session without a link. `project` is the URL slug of the sender's project.
|
|
16289
|
+
sessionPeer: external_exports.object({
|
|
16290
|
+
name: external_exports.string().optional(),
|
|
16291
|
+
socket: external_exports.string().optional(),
|
|
16292
|
+
thread: external_exports.object({ project: external_exports.string().optional(), slug: external_exports.string(), title: external_exports.string() }).optional()
|
|
16293
|
+
}).optional(),
|
|
16238
16294
|
// FRIZZ REFUSED the ```awaiting fence this message ends in — it named something that is not running,
|
|
16239
16295
|
// or named nothing at all, or used a retired line kind (see `isParkCorrection`). The fence is not a
|
|
16240
16296
|
// park, so the chat draws nothing for it: an hourglass card with a park button asserts a wait that
|
|
@@ -16831,7 +16887,7 @@ function summarizeLinkedPrs(nodes) {
|
|
|
16831
16887
|
if (!Array.isArray(nodes)) return void 0;
|
|
16832
16888
|
let count = 0;
|
|
16833
16889
|
let open;
|
|
16834
|
-
let
|
|
16890
|
+
let merged2;
|
|
16835
16891
|
for (const node of nodes) {
|
|
16836
16892
|
const n = node;
|
|
16837
16893
|
const number = typeof n?.number === "number" ? n.number : Number(n?.number);
|
|
@@ -16842,9 +16898,9 @@ function summarizeLinkedPrs(nodes) {
|
|
|
16842
16898
|
const pr2 = { count: 0, number, url: typeof n?.url === "string" ? n.url : "", state };
|
|
16843
16899
|
if (typeof n?.isDraft === "boolean") pr2.isDraft = n.isDraft;
|
|
16844
16900
|
if (state === "OPEN") open ??= pr2;
|
|
16845
|
-
else
|
|
16901
|
+
else merged2 ??= pr2;
|
|
16846
16902
|
}
|
|
16847
|
-
const primary = open ??
|
|
16903
|
+
const primary = open ?? merged2;
|
|
16848
16904
|
return primary ? { ...primary, count } : void 0;
|
|
16849
16905
|
}
|
|
16850
16906
|
function linkedPrQuery(numbers) {
|
|
@@ -17149,7 +17205,9 @@ function projectFromRegistryEntry(entry, home = homedir5()) {
|
|
|
17149
17205
|
};
|
|
17150
17206
|
}
|
|
17151
17207
|
function resolveProject(cwd = process.cwd(), home = homedir5(), env = process.env) {
|
|
17152
|
-
const
|
|
17208
|
+
const root = resolveProjectDir(cwd);
|
|
17209
|
+
refuseWorldWritableProject(root);
|
|
17210
|
+
const identity = resolveProjectIdentity(root, home);
|
|
17153
17211
|
const dir = identity.root;
|
|
17154
17212
|
const id2 = registerAndReconcile(dir, identity.id, home);
|
|
17155
17213
|
const stateDir = projectStateDir(id2, home);
|
|
@@ -17229,7 +17287,7 @@ import {
|
|
|
17229
17287
|
readFileSync as readFileSync5,
|
|
17230
17288
|
renameSync as renameSync4,
|
|
17231
17289
|
rmSync as rmSync4,
|
|
17232
|
-
statSync as
|
|
17290
|
+
statSync as statSync3,
|
|
17233
17291
|
writeFileSync as writeFileSync4
|
|
17234
17292
|
} from "node:fs";
|
|
17235
17293
|
import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute2, join as join7 } from "node:path";
|
|
@@ -17296,7 +17354,7 @@ function quarantine(path3, suffix) {
|
|
|
17296
17354
|
}
|
|
17297
17355
|
function pathAge(path3) {
|
|
17298
17356
|
try {
|
|
17299
|
-
return Date.now() -
|
|
17357
|
+
return Date.now() - statSync3(path3).mtimeMs;
|
|
17300
17358
|
} catch {
|
|
17301
17359
|
return void 0;
|
|
17302
17360
|
}
|
|
@@ -17927,7 +17985,7 @@ import {
|
|
|
17927
17985
|
openSync as openSync5,
|
|
17928
17986
|
readdirSync as readdirSync2,
|
|
17929
17987
|
rmSync as rmSync5,
|
|
17930
|
-
statSync as
|
|
17988
|
+
statSync as statSync4,
|
|
17931
17989
|
symlinkSync,
|
|
17932
17990
|
writeFileSync as writeFileSync5,
|
|
17933
17991
|
writeSync
|
|
@@ -17972,7 +18030,7 @@ function pruneRunLogs(dir, keep = RETAINED_RUNS, days = RETAINED_DAYS, now = Dat
|
|
|
17972
18030
|
}
|
|
17973
18031
|
const dated = entries2.map((name) => {
|
|
17974
18032
|
try {
|
|
17975
|
-
return { name, at:
|
|
18033
|
+
return { name, at: statSync4(join8(dir, name)).mtimeMs };
|
|
17976
18034
|
} catch {
|
|
17977
18035
|
return { name, at: 0 };
|
|
17978
18036
|
}
|
|
@@ -18101,6 +18159,69 @@ var init_logging = __esm({
|
|
|
18101
18159
|
}
|
|
18102
18160
|
});
|
|
18103
18161
|
|
|
18162
|
+
// packages/server/src/access-codes.ts
|
|
18163
|
+
import { randomBytes, timingSafeEqual, createHmac } from "node:crypto";
|
|
18164
|
+
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
18165
|
+
import { dirname as dirname6, join as join9 } from "node:path";
|
|
18166
|
+
function describeDevice(userAgent) {
|
|
18167
|
+
const ua2 = userAgent ?? "";
|
|
18168
|
+
if (!ua2.trim()) return "unknown device";
|
|
18169
|
+
const os3 = /iPhone/i.test(ua2) ? "iPhone" : /iPad/i.test(ua2) ? "iPad" : /Android/i.test(ua2) ? "Android" : /Mac OS X|Macintosh/i.test(ua2) ? "macOS" : /Windows/i.test(ua2) ? "Windows" : /Linux/i.test(ua2) ? "Linux" : "unknown device";
|
|
18170
|
+
const browser = /Edg\//i.test(ua2) ? "Edge" : /OPR\/|Opera/i.test(ua2) ? "Opera" : /Firefox\//i.test(ua2) ? "Firefox" : /Chrome\//i.test(ua2) ? "Chrome" : /Safari\//i.test(ua2) ? "Safari" : "";
|
|
18171
|
+
return browser ? `${browser} on ${os3}` : os3;
|
|
18172
|
+
}
|
|
18173
|
+
function writeSessionKey(path3, key) {
|
|
18174
|
+
mkdirSync7(dirname6(path3), { recursive: true });
|
|
18175
|
+
writeFileSync6(path3, key, { mode: 384 });
|
|
18176
|
+
try {
|
|
18177
|
+
chmodSync(path3, 384);
|
|
18178
|
+
} catch {
|
|
18179
|
+
}
|
|
18180
|
+
}
|
|
18181
|
+
function rotateSessionKey(stateDir) {
|
|
18182
|
+
const key = randomBytes(32);
|
|
18183
|
+
writeSessionKey(join9(stateDir, SESSION_KEY_FILE), key);
|
|
18184
|
+
return key;
|
|
18185
|
+
}
|
|
18186
|
+
function readSessionEpoch(stateDir) {
|
|
18187
|
+
try {
|
|
18188
|
+
const parsed = JSON.parse(readFileSync6(join9(stateDir, SESSION_EPOCH_FILE), "utf8"));
|
|
18189
|
+
return Number.isInteger(parsed?.epoch) && parsed.epoch >= 0 ? parsed.epoch : 0;
|
|
18190
|
+
} catch {
|
|
18191
|
+
return 0;
|
|
18192
|
+
}
|
|
18193
|
+
}
|
|
18194
|
+
function advanceSessionEpoch(stateDir, epoch = SESSION_EPOCH) {
|
|
18195
|
+
const from = readSessionEpoch(stateDir);
|
|
18196
|
+
if (from >= epoch) return { advanced: false, epoch: from };
|
|
18197
|
+
const keyPath = join9(stateDir, SESSION_KEY_FILE);
|
|
18198
|
+
const rotatedKey = existsSync4(keyPath);
|
|
18199
|
+
if (rotatedKey) rotateSessionKey(stateDir);
|
|
18200
|
+
mkdirSync7(stateDir, { recursive: true });
|
|
18201
|
+
writeFileSync6(
|
|
18202
|
+
join9(stateDir, SESSION_EPOCH_FILE),
|
|
18203
|
+
JSON.stringify({ epoch, advancedAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
18204
|
+
{ mode: 384 }
|
|
18205
|
+
);
|
|
18206
|
+
return { advanced: true, from, to: epoch, rotatedKey };
|
|
18207
|
+
}
|
|
18208
|
+
function sessionEpochLogLine(advance, signedOut) {
|
|
18209
|
+
if (!advance.advanced || !advance.rotatedKey) return null;
|
|
18210
|
+
const count = signedOut === null ? "an unknown number of" : String(signedOut);
|
|
18211
|
+
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`;
|
|
18212
|
+
}
|
|
18213
|
+
var DEFAULT_CODE_TTL_MS, DEFAULT_SESSION_TTL_MS, SESSION_EPOCH, SESSION_KEY_FILE, SESSION_EPOCH_FILE;
|
|
18214
|
+
var init_access_codes = __esm({
|
|
18215
|
+
"packages/server/src/access-codes.ts"() {
|
|
18216
|
+
"use strict";
|
|
18217
|
+
DEFAULT_CODE_TTL_MS = 5 * 6e4;
|
|
18218
|
+
DEFAULT_SESSION_TTL_MS = 30 * 24 * 60 * 6e4;
|
|
18219
|
+
SESSION_EPOCH = 1;
|
|
18220
|
+
SESSION_KEY_FILE = "session-key";
|
|
18221
|
+
SESSION_EPOCH_FILE = "session-epoch";
|
|
18222
|
+
}
|
|
18223
|
+
});
|
|
18224
|
+
|
|
18104
18225
|
// packages/server/src/local-origin.ts
|
|
18105
18226
|
import { isIP } from "node:net";
|
|
18106
18227
|
function publicAuthority(policy) {
|
|
@@ -18248,7 +18369,7 @@ var init_local_path = __esm({
|
|
|
18248
18369
|
});
|
|
18249
18370
|
|
|
18250
18371
|
// packages/server/src/local-image.ts
|
|
18251
|
-
import { createReadStream, realpathSync as realpathSync5, statSync as
|
|
18372
|
+
import { createReadStream, realpathSync as realpathSync5, statSync as statSync5 } from "node:fs";
|
|
18252
18373
|
import { extname, isAbsolute as isAbsolute3 } from "node:path";
|
|
18253
18374
|
function resolveLocalImage(rawPath, range) {
|
|
18254
18375
|
if (rawPath) rawPath = normalizeLocalPath(rawPath);
|
|
@@ -18263,7 +18384,7 @@ function resolveLocalImage(rawPath, range) {
|
|
|
18263
18384
|
}
|
|
18264
18385
|
let size;
|
|
18265
18386
|
try {
|
|
18266
|
-
const stat2 =
|
|
18387
|
+
const stat2 = statSync5(real);
|
|
18267
18388
|
if (!stat2.isFile()) return { status: 404 };
|
|
18268
18389
|
size = stat2.size;
|
|
18269
18390
|
} catch {
|
|
@@ -18324,6 +18445,163 @@ var init_local_image = __esm({
|
|
|
18324
18445
|
}
|
|
18325
18446
|
});
|
|
18326
18447
|
|
|
18448
|
+
// packages/server/src/audit.ts
|
|
18449
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18450
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
18451
|
+
import { appendFileSync as appendFileSync2, chmodSync as chmodSync2, mkdirSync as mkdirSync8 } from "node:fs";
|
|
18452
|
+
import { dirname as dirname7, join as join10 } from "node:path";
|
|
18453
|
+
function bounded(value) {
|
|
18454
|
+
return typeof value === "string" && value.length > 0 ? value.slice(0, STAMP_FIELD_MAX) : void 0;
|
|
18455
|
+
}
|
|
18456
|
+
function decodeCallerStamp(value) {
|
|
18457
|
+
if (!value) return void 0;
|
|
18458
|
+
try {
|
|
18459
|
+
const parsed = JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
18460
|
+
if (!parsed || typeof parsed !== "object" || !VIAS.includes(parsed.via)) return void 0;
|
|
18461
|
+
const host = bounded(parsed.host);
|
|
18462
|
+
const clientIp = bounded(parsed.clientIp);
|
|
18463
|
+
return {
|
|
18464
|
+
via: parsed.via,
|
|
18465
|
+
remote: bounded(parsed.remote) ?? null,
|
|
18466
|
+
...host ? { host } : {},
|
|
18467
|
+
...clientIp ? { clientIp } : {},
|
|
18468
|
+
session: bounded(parsed.session) ?? null
|
|
18469
|
+
};
|
|
18470
|
+
} catch {
|
|
18471
|
+
return void 0;
|
|
18472
|
+
}
|
|
18473
|
+
}
|
|
18474
|
+
function requestOriginFrom(input) {
|
|
18475
|
+
const device = describeDevice(input.userAgent);
|
|
18476
|
+
const stamp = decodeCallerStamp(input.caller);
|
|
18477
|
+
if (stamp) return { ...stamp, device };
|
|
18478
|
+
return { via: "direct", remote: input.socketRemote ?? null, session: null, device };
|
|
18479
|
+
}
|
|
18480
|
+
function withRequestOrigin(origin, fn2) {
|
|
18481
|
+
return requestOrigin.run(origin, fn2);
|
|
18482
|
+
}
|
|
18483
|
+
function currentRequestOrigin() {
|
|
18484
|
+
return requestOrigin.getStore() ?? { via: "internal" };
|
|
18485
|
+
}
|
|
18486
|
+
function textDigest(text2) {
|
|
18487
|
+
return { chars: text2.length, sha256: createHash5("sha256").update(text2).digest("hex") };
|
|
18488
|
+
}
|
|
18489
|
+
function auditLogPathForStateDir(stateDir) {
|
|
18490
|
+
return join10(dirname7(serverAddressPathForStateDir(stateDir)), "logs", "audit.jsonl");
|
|
18491
|
+
}
|
|
18492
|
+
function fileAuditLog(path3) {
|
|
18493
|
+
let secured = false;
|
|
18494
|
+
return {
|
|
18495
|
+
append(record) {
|
|
18496
|
+
mkdirSync8(dirname7(path3), { recursive: true, mode: 448 });
|
|
18497
|
+
appendFileSync2(path3, `${JSON.stringify(record)}
|
|
18498
|
+
`, { mode: 384 });
|
|
18499
|
+
if (!secured) {
|
|
18500
|
+
try {
|
|
18501
|
+
chmodSync2(path3, 384);
|
|
18502
|
+
} catch {
|
|
18503
|
+
}
|
|
18504
|
+
secured = true;
|
|
18505
|
+
}
|
|
18506
|
+
}
|
|
18507
|
+
};
|
|
18508
|
+
}
|
|
18509
|
+
function originSummary(origin) {
|
|
18510
|
+
if (origin.via === "internal") return "internal";
|
|
18511
|
+
const parts = [origin.via];
|
|
18512
|
+
if (origin.host) parts.push(origin.host);
|
|
18513
|
+
if (origin.remote) parts.push(`from ${origin.remote}`);
|
|
18514
|
+
if (origin.clientIp) parts.push(`client ${origin.clientIp}`);
|
|
18515
|
+
if (origin.session) parts.push(`session ${origin.session}`);
|
|
18516
|
+
parts.push(`(${origin.device})`);
|
|
18517
|
+
return parts.join(" ");
|
|
18518
|
+
}
|
|
18519
|
+
function auditSummary(record) {
|
|
18520
|
+
const target = [record.project.dir ?? record.project.id, record.thread].filter(Boolean).join(" ");
|
|
18521
|
+
const outcome = record.outcome === "ok" ? "ok" : `refused: ${record.error ?? "unknown error"}`;
|
|
18522
|
+
return `${record.action} ${outcome}${target ? ` \u2014 ${target}` : ""} \u2014 via ${originSummary(record.origin)}`;
|
|
18523
|
+
}
|
|
18524
|
+
function recordAudit(log3, build) {
|
|
18525
|
+
let record;
|
|
18526
|
+
try {
|
|
18527
|
+
const { action, outcome, error, project, thread, servedBy, detail: detail2 } = build();
|
|
18528
|
+
record = {
|
|
18529
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
18530
|
+
action,
|
|
18531
|
+
outcome,
|
|
18532
|
+
...error !== void 0 ? { error } : {},
|
|
18533
|
+
project,
|
|
18534
|
+
...thread !== void 0 ? { thread } : {},
|
|
18535
|
+
origin: currentRequestOrigin(),
|
|
18536
|
+
...servedBy !== void 0 ? { servedBy } : {},
|
|
18537
|
+
...detail2 !== void 0 ? { detail: detail2 } : {}
|
|
18538
|
+
};
|
|
18539
|
+
log.info("audit", auditSummary(record));
|
|
18540
|
+
log3?.append(record);
|
|
18541
|
+
} catch (error) {
|
|
18542
|
+
try {
|
|
18543
|
+
const what = record ? `${record.action} (${record.outcome})` : "an action";
|
|
18544
|
+
log.error("audit", `could not record ${what}: ${error instanceof Error ? error.message : String(error)}`);
|
|
18545
|
+
} catch {
|
|
18546
|
+
}
|
|
18547
|
+
}
|
|
18548
|
+
}
|
|
18549
|
+
function merged(base, extra) {
|
|
18550
|
+
return {
|
|
18551
|
+
project: extra?.project ?? base.project,
|
|
18552
|
+
thread: extra?.thread ?? base.thread,
|
|
18553
|
+
detail: base.detail || extra?.detail ? { ...base.detail, ...extra?.detail } : void 0
|
|
18554
|
+
};
|
|
18555
|
+
}
|
|
18556
|
+
async function audited(log3, action, base, run3, options = {}) {
|
|
18557
|
+
let fields = {};
|
|
18558
|
+
let unreadable;
|
|
18559
|
+
try {
|
|
18560
|
+
fields = typeof base === "function" ? base() : base;
|
|
18561
|
+
} catch (error) {
|
|
18562
|
+
unreadable = error;
|
|
18563
|
+
}
|
|
18564
|
+
const entry = (from) => ({
|
|
18565
|
+
project: from.project ?? { id: null, dir: null },
|
|
18566
|
+
...from.thread ? { thread: from.thread } : {},
|
|
18567
|
+
...options.servedBy ? { servedBy: options.servedBy } : {},
|
|
18568
|
+
...from.detail || unreadable !== void 0 ? { detail: { ...unreadable !== void 0 ? { auditError: messageOf(unreadable) } : {}, ...from.detail } } : {}
|
|
18569
|
+
});
|
|
18570
|
+
let result;
|
|
18571
|
+
try {
|
|
18572
|
+
result = await run3();
|
|
18573
|
+
} catch (error) {
|
|
18574
|
+
recordAudit(log3, () => ({ action, outcome: "refused", error: messageOf(error), ...entry(fields) }));
|
|
18575
|
+
throw error;
|
|
18576
|
+
}
|
|
18577
|
+
recordAudit(log3, () => {
|
|
18578
|
+
let extra;
|
|
18579
|
+
try {
|
|
18580
|
+
extra = options.onResult?.(result);
|
|
18581
|
+
} catch (error) {
|
|
18582
|
+
extra = { detail: { auditError: messageOf(error) } };
|
|
18583
|
+
}
|
|
18584
|
+
return { action, outcome: "ok", ...entry(merged(fields, extra)) };
|
|
18585
|
+
});
|
|
18586
|
+
return result;
|
|
18587
|
+
}
|
|
18588
|
+
function messageOf(error) {
|
|
18589
|
+
return error instanceof Error ? error.message : String(error);
|
|
18590
|
+
}
|
|
18591
|
+
var CALLER_HEADER, VIAS, STAMP_FIELD_MAX, requestOrigin;
|
|
18592
|
+
var init_audit = __esm({
|
|
18593
|
+
"packages/server/src/audit.ts"() {
|
|
18594
|
+
"use strict";
|
|
18595
|
+
init_access_codes();
|
|
18596
|
+
init_frizz_paths();
|
|
18597
|
+
init_logging();
|
|
18598
|
+
CALLER_HEADER = "x-frizz-caller";
|
|
18599
|
+
VIAS = ["public", "network", "loopback"];
|
|
18600
|
+
STAMP_FIELD_MAX = 200;
|
|
18601
|
+
requestOrigin = new AsyncLocalStorage();
|
|
18602
|
+
}
|
|
18603
|
+
});
|
|
18604
|
+
|
|
18327
18605
|
// packages/server/src/bus.ts
|
|
18328
18606
|
var Bus, Emitter;
|
|
18329
18607
|
var init_bus = __esm({
|
|
@@ -21468,13 +21746,13 @@ var init_storage = __esm({
|
|
|
21468
21746
|
|
|
21469
21747
|
// packages/server/src/secret-files.ts
|
|
21470
21748
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
21471
|
-
import { chmodSync as
|
|
21472
|
-
import { dirname as
|
|
21749
|
+
import { chmodSync as chmodSync3, closeSync as closeSync5, constants, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync9, openSync as openSync6, readdirSync as readdirSync3, rmdirSync, rmSync as rmSync6, writeFileSync as writeFileSync7, writeSync as writeSync2 } from "node:fs";
|
|
21750
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
21473
21751
|
function secretsRoot(stateDir) {
|
|
21474
|
-
return
|
|
21752
|
+
return join12(stateDir, "secrets");
|
|
21475
21753
|
}
|
|
21476
21754
|
function secretFilePath(stateDir, slug, questionId) {
|
|
21477
|
-
return
|
|
21755
|
+
return join12(secretsRoot(stateDir), slug, questionId);
|
|
21478
21756
|
}
|
|
21479
21757
|
function stop(path3) {
|
|
21480
21758
|
const entry = served.get(path3);
|
|
@@ -21482,7 +21760,7 @@ function stop(path3) {
|
|
|
21482
21760
|
served.delete(path3);
|
|
21483
21761
|
rmSync6(path3, { force: true });
|
|
21484
21762
|
try {
|
|
21485
|
-
rmdirSync(
|
|
21763
|
+
rmdirSync(dirname8(path3));
|
|
21486
21764
|
} catch {
|
|
21487
21765
|
}
|
|
21488
21766
|
}
|
|
@@ -21490,12 +21768,12 @@ function serveSecret(stateDir, slug, questionId, value, opts = {}) {
|
|
|
21490
21768
|
const now = opts.now ?? Date.now;
|
|
21491
21769
|
const expiresAt = now() + (opts.ttlMs ?? SECRET_TTL_MS);
|
|
21492
21770
|
const root = secretsRoot(stateDir);
|
|
21493
|
-
const dir =
|
|
21771
|
+
const dir = join12(root, slug);
|
|
21494
21772
|
const path3 = secretFilePath(stateDir, slug, questionId);
|
|
21495
21773
|
stop(path3);
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21774
|
+
mkdirSync9(dir, { recursive: true, mode: 448 });
|
|
21775
|
+
chmodSync3(root, 448);
|
|
21776
|
+
chmodSync3(dir, 448);
|
|
21499
21777
|
if ((opts.platform ?? process.platform) === "win32") {
|
|
21500
21778
|
writeFileSync7(path3, value, { mode: 384 });
|
|
21501
21779
|
const timer2 = setInterval(() => {
|
|
@@ -21538,7 +21816,7 @@ function clearSecrets(stateDir) {
|
|
|
21538
21816
|
return 0;
|
|
21539
21817
|
}
|
|
21540
21818
|
for (const thread of threads) {
|
|
21541
|
-
const dir =
|
|
21819
|
+
const dir = join12(root, thread);
|
|
21542
21820
|
let entries2;
|
|
21543
21821
|
try {
|
|
21544
21822
|
if (!lstatSync(dir).isDirectory()) {
|
|
@@ -21550,7 +21828,7 @@ function clearSecrets(stateDir) {
|
|
|
21550
21828
|
continue;
|
|
21551
21829
|
}
|
|
21552
21830
|
for (const entry of entries2) {
|
|
21553
|
-
const path3 =
|
|
21831
|
+
const path3 = join12(dir, entry);
|
|
21554
21832
|
if (served.has(path3)) continue;
|
|
21555
21833
|
rmSync6(path3, { force: true });
|
|
21556
21834
|
removed++;
|
|
@@ -21573,10 +21851,10 @@ var init_secret_files = __esm({
|
|
|
21573
21851
|
});
|
|
21574
21852
|
|
|
21575
21853
|
// packages/server/src/machine-config.ts
|
|
21576
|
-
import { closeSync as closeSync6, fsyncSync as fsyncSync5, mkdirSync as
|
|
21577
|
-
import { dirname as
|
|
21854
|
+
import { closeSync as closeSync6, fsyncSync as fsyncSync5, mkdirSync as mkdirSync10, openSync as openSync7, readFileSync as readFileSync8, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
21855
|
+
import { dirname as dirname9, join as join13 } from "node:path";
|
|
21578
21856
|
function machineConfigPath(home) {
|
|
21579
|
-
return
|
|
21857
|
+
return join13(frizzPaths({ home }).data, "config.json");
|
|
21580
21858
|
}
|
|
21581
21859
|
function readAll(home) {
|
|
21582
21860
|
let raw2;
|
|
@@ -21589,7 +21867,7 @@ function readAll(home) {
|
|
|
21589
21867
|
}
|
|
21590
21868
|
function writeAll(home, all) {
|
|
21591
21869
|
const path3 = machineConfigPath(home);
|
|
21592
|
-
|
|
21870
|
+
mkdirSync10(dirname9(path3), { recursive: true });
|
|
21593
21871
|
const temp = `${path3}.${process.pid}.tmp`;
|
|
21594
21872
|
let fd2;
|
|
21595
21873
|
try {
|
|
@@ -21635,9 +21913,9 @@ var init_machine_config = __esm({
|
|
|
21635
21913
|
|
|
21636
21914
|
// packages/server/src/settings.ts
|
|
21637
21915
|
import { readFileSync as readFileSync9, rmSync as rmSync8 } from "node:fs";
|
|
21638
|
-
import { join as
|
|
21916
|
+
import { join as join14 } from "node:path";
|
|
21639
21917
|
function legacyMachineSettingsPath(home) {
|
|
21640
|
-
return
|
|
21918
|
+
return join14(frizzPaths({ home }).data, "settings.json");
|
|
21641
21919
|
}
|
|
21642
21920
|
function pickMachine(settings) {
|
|
21643
21921
|
return Object.fromEntries(MACHINE_KEYS.map((key) => [key, settings[key]]));
|
|
@@ -21820,15 +22098,15 @@ function redactUserInfoToken(raw2, options) {
|
|
|
21820
22098
|
return `${parts.username}${parts.delimiter}${replacement(options, parts.password)}`;
|
|
21821
22099
|
}
|
|
21822
22100
|
function hasCurlCommandContext(source, offset) {
|
|
21823
|
-
const
|
|
22101
|
+
const bounded2 = source.slice(Math.max(0, offset - 1024), offset);
|
|
21824
22102
|
const separator = Math.max(
|
|
21825
|
-
|
|
21826
|
-
|
|
21827
|
-
|
|
21828
|
-
|
|
21829
|
-
|
|
22103
|
+
bounded2.lastIndexOf("\n"),
|
|
22104
|
+
bounded2.lastIndexOf("\r"),
|
|
22105
|
+
bounded2.lastIndexOf(";"),
|
|
22106
|
+
bounded2.lastIndexOf("&"),
|
|
22107
|
+
bounded2.lastIndexOf("|")
|
|
21830
22108
|
);
|
|
21831
|
-
const segment =
|
|
22109
|
+
const segment = bounded2.slice(separator + 1);
|
|
21832
22110
|
return segment.split(/[ \t]+/u).some((token) => CURL_EXECUTABLE_RE.test(unquote(token)));
|
|
21833
22111
|
}
|
|
21834
22112
|
function redactCredentialSyntax(raw2, options = {}) {
|
|
@@ -21978,8 +22256,8 @@ var init_codex_error = __esm({
|
|
|
21978
22256
|
});
|
|
21979
22257
|
|
|
21980
22258
|
// packages/server/src/discover.ts
|
|
21981
|
-
import { readdirSync as readdirSync4, statSync as
|
|
21982
|
-
import { dirname as
|
|
22259
|
+
import { readdirSync as readdirSync4, statSync as statSync6, openSync as openSync8, readSync, closeSync as closeSync7 } from "node:fs";
|
|
22260
|
+
import { dirname as dirname10, join as join15 } from "node:path";
|
|
21983
22261
|
function sentinelFor(sessionId) {
|
|
21984
22262
|
return `threads/${sessionId}/`;
|
|
21985
22263
|
}
|
|
@@ -22016,10 +22294,10 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
22016
22294
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
22017
22295
|
const id2 = name.slice(0, -".jsonl".length);
|
|
22018
22296
|
if (!id2 || id2 === sessionId || exclude?.has(id2)) continue;
|
|
22019
|
-
const path3 =
|
|
22297
|
+
const path3 = join15(logDir, name);
|
|
22020
22298
|
let mtime;
|
|
22021
22299
|
try {
|
|
22022
|
-
mtime =
|
|
22300
|
+
mtime = statSync6(path3).mtimeMs;
|
|
22023
22301
|
} catch {
|
|
22024
22302
|
continue;
|
|
22025
22303
|
}
|
|
@@ -22034,7 +22312,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
22034
22312
|
}
|
|
22035
22313
|
function mtimeOfNonEmpty(path3) {
|
|
22036
22314
|
try {
|
|
22037
|
-
const st2 =
|
|
22315
|
+
const st2 = statSync6(path3, { throwIfNoEntry: false });
|
|
22038
22316
|
return st2 && st2.size > 0 ? st2.mtimeMs : void 0;
|
|
22039
22317
|
} catch {
|
|
22040
22318
|
return void 0;
|
|
@@ -22044,7 +22322,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
|
|
|
22044
22322
|
const name = `${sessionId}.jsonl`;
|
|
22045
22323
|
const better = (best2, dir) => {
|
|
22046
22324
|
if (dir === logDir) return best2;
|
|
22047
|
-
const at2 = mtimeOfNonEmpty(
|
|
22325
|
+
const at2 = mtimeOfNonEmpty(join15(dir, name));
|
|
22048
22326
|
if (at2 === void 0) return best2;
|
|
22049
22327
|
return !best2 || at2 > best2.mtimeMs ? { dir, mtimeMs: at2 } : best2;
|
|
22050
22328
|
};
|
|
@@ -22053,11 +22331,11 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
|
|
|
22053
22331
|
if (best) return best.dir;
|
|
22054
22332
|
let entries2;
|
|
22055
22333
|
try {
|
|
22056
|
-
entries2 = readdirSync4(
|
|
22334
|
+
entries2 = readdirSync4(dirname10(logDir), { withFileTypes: true }).filter((e14) => e14.isDirectory()).map((e14) => e14.name);
|
|
22057
22335
|
} catch {
|
|
22058
22336
|
return void 0;
|
|
22059
22337
|
}
|
|
22060
|
-
for (const entry of entries2) best = better(best,
|
|
22338
|
+
for (const entry of entries2) best = better(best, join15(dirname10(logDir), entry));
|
|
22061
22339
|
if (!best) return void 0;
|
|
22062
22340
|
memo3.add(best.dir);
|
|
22063
22341
|
return best.dir;
|
|
@@ -22143,22 +22421,22 @@ var init_types2 = __esm({
|
|
|
22143
22421
|
});
|
|
22144
22422
|
|
|
22145
22423
|
// packages/server/src/session-files.ts
|
|
22146
|
-
import { chmodSync as
|
|
22147
|
-
import { join as
|
|
22424
|
+
import { chmodSync as chmodSync4, lstatSync as lstatSync2, mkdirSync as mkdirSync11, rmSync as rmSync9, writeFileSync as writeFileSync9 } from "node:fs";
|
|
22425
|
+
import { join as join16 } from "node:path";
|
|
22148
22426
|
function systemPromptPath(sessionId) {
|
|
22149
22427
|
if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
|
|
22150
|
-
return
|
|
22428
|
+
return join16(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
|
|
22151
22429
|
}
|
|
22152
22430
|
function mcpConfigPath(sessionId) {
|
|
22153
22431
|
if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
|
|
22154
|
-
return
|
|
22432
|
+
return join16(MCP_CONFIG_DIR, `${sessionId}.json`);
|
|
22155
22433
|
}
|
|
22156
22434
|
function writeMcpConfigFile(sessionId, mcpServers) {
|
|
22157
22435
|
const path3 = mcpConfigPath(sessionId);
|
|
22158
|
-
|
|
22159
|
-
|
|
22436
|
+
mkdirSync11(MCP_CONFIG_DIR, { recursive: true, mode: 448 });
|
|
22437
|
+
chmodSync4(MCP_CONFIG_DIR, 448);
|
|
22160
22438
|
writeFileSync9(path3, JSON.stringify({ mcpServers }), { mode: 384 });
|
|
22161
|
-
|
|
22439
|
+
chmodSync4(path3, 384);
|
|
22162
22440
|
return path3;
|
|
22163
22441
|
}
|
|
22164
22442
|
function isDirectDirectory(path3) {
|
|
@@ -22179,7 +22457,7 @@ function pathAbsent(path3) {
|
|
|
22179
22457
|
}
|
|
22180
22458
|
function unlinkDirectChild(parent, filename) {
|
|
22181
22459
|
if (!isDirectDirectory(parent)) return pathAbsent(parent);
|
|
22182
|
-
const child =
|
|
22460
|
+
const child = join16(parent, filename);
|
|
22183
22461
|
try {
|
|
22184
22462
|
rmSync9(child, { force: true });
|
|
22185
22463
|
} catch {
|
|
@@ -22189,12 +22467,12 @@ function unlinkDirectChild(parent, filename) {
|
|
|
22189
22467
|
}
|
|
22190
22468
|
function cleanupAdoptionSessionFiles(projectDir, sessionId) {
|
|
22191
22469
|
if (!SESSION_ID_RE.test(sessionId)) return false;
|
|
22192
|
-
const frizzDir =
|
|
22470
|
+
const frizzDir = join16(projectDir, ".frizz");
|
|
22193
22471
|
let clean = true;
|
|
22194
22472
|
if (isDirectDirectory(frizzDir)) {
|
|
22195
|
-
const threads =
|
|
22473
|
+
const threads = join16(frizzDir, "threads");
|
|
22196
22474
|
if (isDirectDirectory(threads)) {
|
|
22197
|
-
const child =
|
|
22475
|
+
const child = join16(threads, sessionId);
|
|
22198
22476
|
try {
|
|
22199
22477
|
rmSync9(child, { recursive: true, force: true });
|
|
22200
22478
|
} catch {
|
|
@@ -22448,10 +22726,10 @@ var init_adoption_recovery = __esm({
|
|
|
22448
22726
|
});
|
|
22449
22727
|
|
|
22450
22728
|
// packages/server/src/backend/codex-models.ts
|
|
22451
|
-
import { join as
|
|
22729
|
+
import { join as join17 } from "node:path";
|
|
22452
22730
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
22453
22731
|
function cachePath(codexHome) {
|
|
22454
|
-
return
|
|
22732
|
+
return join17(codexHome, "models_cache.json");
|
|
22455
22733
|
}
|
|
22456
22734
|
function toCodexModel(raw2) {
|
|
22457
22735
|
if (!raw2 || typeof raw2 !== "object") return void 0;
|
|
@@ -23182,10 +23460,10 @@ var init_claude_agent_sdk_protocol = __esm({
|
|
|
23182
23460
|
});
|
|
23183
23461
|
|
|
23184
23462
|
// packages/server/src/backend/claude-broker-diagnostics.ts
|
|
23185
|
-
import { appendFileSync as
|
|
23186
|
-
import { join as
|
|
23463
|
+
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync12, readFileSync as readFileSync11, renameSync as renameSync6, statSync as statSync7 } from "node:fs";
|
|
23464
|
+
import { join as join18 } from "node:path";
|
|
23187
23465
|
function claudeBrokerDiagnosticLogPath(stateDir, sessionId) {
|
|
23188
|
-
return
|
|
23466
|
+
return join18(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
|
|
23189
23467
|
}
|
|
23190
23468
|
function readClaudeBrokerExit(stateDir, sessionId, generation) {
|
|
23191
23469
|
if (!generation) return null;
|
|
@@ -23290,10 +23568,10 @@ var init_daemon_tree = __esm({
|
|
|
23290
23568
|
});
|
|
23291
23569
|
|
|
23292
23570
|
// packages/server/src/backend/ipc-path.ts
|
|
23293
|
-
import { join as
|
|
23571
|
+
import { join as join19 } from "node:path";
|
|
23294
23572
|
function frizzIpcPath(name) {
|
|
23295
23573
|
if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
|
|
23296
|
-
return
|
|
23574
|
+
return join19(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
|
|
23297
23575
|
}
|
|
23298
23576
|
var init_ipc_path = __esm({
|
|
23299
23577
|
"packages/server/src/backend/ipc-path.ts"() {
|
|
@@ -23303,9 +23581,9 @@ var init_ipc_path = __esm({
|
|
|
23303
23581
|
|
|
23304
23582
|
// packages/server/src/backend/claude-broker-host.ts
|
|
23305
23583
|
import { spawn } from "node:child_process";
|
|
23306
|
-
import { createHash as
|
|
23307
|
-
import { accessSync, constants as fsConstants, mkdirSync as
|
|
23308
|
-
import { delimiter, dirname as
|
|
23584
|
+
import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
|
|
23585
|
+
import { accessSync, constants as fsConstants, mkdirSync as mkdirSync13, readFileSync as readFileSync12, readdirSync as readdirSync5, unlinkSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
23586
|
+
import { delimiter, dirname as dirname11, isAbsolute as isAbsolute4, join as join20 } from "node:path";
|
|
23309
23587
|
function windowsShimTarget(shimPath) {
|
|
23310
23588
|
let body;
|
|
23311
23589
|
try {
|
|
@@ -23315,7 +23593,7 @@ function windowsShimTarget(shimPath) {
|
|
|
23315
23593
|
}
|
|
23316
23594
|
const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
|
|
23317
23595
|
if (!target) return void 0;
|
|
23318
|
-
const full =
|
|
23596
|
+
const full = join20(dirname11(shimPath), target);
|
|
23319
23597
|
try {
|
|
23320
23598
|
accessSync(full, fsConstants.F_OK);
|
|
23321
23599
|
return full;
|
|
@@ -23336,17 +23614,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
23336
23614
|
for (const dir of searchPath(env).split(delimiter)) {
|
|
23337
23615
|
if (!dir) continue;
|
|
23338
23616
|
if (windows) {
|
|
23339
|
-
const exe2 =
|
|
23617
|
+
const exe2 = join20(dir, `${candidate}.exe`);
|
|
23340
23618
|
try {
|
|
23341
23619
|
accessSync(exe2, fsConstants.F_OK);
|
|
23342
23620
|
return exe2;
|
|
23343
23621
|
} catch {
|
|
23344
23622
|
}
|
|
23345
|
-
const viaShim = windowsShimTarget(
|
|
23623
|
+
const viaShim = windowsShimTarget(join20(dir, `${candidate}.cmd`));
|
|
23346
23624
|
if (viaShim) return viaShim;
|
|
23347
23625
|
continue;
|
|
23348
23626
|
}
|
|
23349
|
-
const full =
|
|
23627
|
+
const full = join20(dir, candidate);
|
|
23350
23628
|
try {
|
|
23351
23629
|
accessSync(full, fsConstants.X_OK);
|
|
23352
23630
|
return full;
|
|
@@ -23356,22 +23634,22 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
23356
23634
|
throw new Error(`Claude session broker: could not resolve '${candidate}' to an absolute executable path on PATH (the SDK requires one)`);
|
|
23357
23635
|
}
|
|
23358
23636
|
function claudeBrokerSocketPath(stateDir, sessionId) {
|
|
23359
|
-
const key =
|
|
23637
|
+
const key = createHash6("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
|
|
23360
23638
|
return frizzIpcPath(`frizz-claude-${key}`);
|
|
23361
23639
|
}
|
|
23362
23640
|
function claudeBrokerRecordPath(stateDir, sessionId) {
|
|
23363
|
-
const key =
|
|
23364
|
-
return
|
|
23641
|
+
const key = createHash6("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
23642
|
+
return join20(stateDir, "claude-broker", `${key}.json`);
|
|
23365
23643
|
}
|
|
23366
23644
|
function claudeBrokerRetirementPath(stateDir, sessionId) {
|
|
23367
|
-
const key =
|
|
23368
|
-
return
|
|
23645
|
+
const key = createHash6("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
23646
|
+
return join20(stateDir, "claude-broker", `${key}.retired`);
|
|
23369
23647
|
}
|
|
23370
23648
|
function markBrokerRetired(stateDir, sessionId, reason, generation) {
|
|
23371
23649
|
const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
|
|
23372
23650
|
try {
|
|
23373
23651
|
const path3 = claudeBrokerRetirementPath(stateDir, sessionId);
|
|
23374
|
-
|
|
23652
|
+
mkdirSync13(dirname11(path3), { recursive: true });
|
|
23375
23653
|
writeFileSync10(path3, JSON.stringify(mark));
|
|
23376
23654
|
} catch {
|
|
23377
23655
|
}
|
|
@@ -23432,7 +23710,7 @@ function liveBrokerRecord(recordPath2) {
|
|
|
23432
23710
|
return null;
|
|
23433
23711
|
}
|
|
23434
23712
|
function liveBrokerRecords(stateDir) {
|
|
23435
|
-
const dir =
|
|
23713
|
+
const dir = join20(stateDir, "claude-broker");
|
|
23436
23714
|
let names;
|
|
23437
23715
|
try {
|
|
23438
23716
|
names = readdirSync5(dir);
|
|
@@ -23442,7 +23720,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
23442
23720
|
const out = [];
|
|
23443
23721
|
for (const name of names) {
|
|
23444
23722
|
if (!name.endsWith(".json")) continue;
|
|
23445
|
-
const record = liveBrokerRecord(
|
|
23723
|
+
const record = liveBrokerRecord(join20(dir, name));
|
|
23446
23724
|
if (record) out.push(record);
|
|
23447
23725
|
}
|
|
23448
23726
|
return out;
|
|
@@ -23450,7 +23728,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
23450
23728
|
function forkBroker(options) {
|
|
23451
23729
|
const socketPath = claudeBrokerSocketPath(options.stateDir, options.sessionId);
|
|
23452
23730
|
const recordPath2 = claudeBrokerRecordPath(options.stateDir, options.sessionId);
|
|
23453
|
-
|
|
23731
|
+
mkdirSync13(dirname11(recordPath2), { recursive: true });
|
|
23454
23732
|
const generation = randomUUID8();
|
|
23455
23733
|
const config = {
|
|
23456
23734
|
socketPath,
|
|
@@ -24060,7 +24338,7 @@ var init_delivery_ledger = __esm({
|
|
|
24060
24338
|
});
|
|
24061
24339
|
|
|
24062
24340
|
// packages/server/src/codex-subagents.ts
|
|
24063
|
-
import { closeSync as closeSync8, openSync as openSync9, readSync as readSync2, statSync as
|
|
24341
|
+
import { closeSync as closeSync8, openSync as openSync9, readSync as readSync2, statSync as statSync8 } from "node:fs";
|
|
24064
24342
|
function createCodexSubAgentTracker(deps) {
|
|
24065
24343
|
const findRollouts = deps.findRollouts ?? ((ids) => findRolloutsByIds(ids, deps.codexHome));
|
|
24066
24344
|
const readAppended = deps.readAppended ?? defaultReadAppended;
|
|
@@ -24252,7 +24530,7 @@ function agentLabel(path3) {
|
|
|
24252
24530
|
function defaultReadAppended(path3, offset) {
|
|
24253
24531
|
let size;
|
|
24254
24532
|
try {
|
|
24255
|
-
size =
|
|
24533
|
+
size = statSync8(path3).size;
|
|
24256
24534
|
} catch {
|
|
24257
24535
|
return void 0;
|
|
24258
24536
|
}
|
|
@@ -24393,16 +24671,16 @@ var init_completion_relay = __esm({
|
|
|
24393
24671
|
});
|
|
24394
24672
|
|
|
24395
24673
|
// packages/server/src/tail-cache.ts
|
|
24396
|
-
import { createHash as
|
|
24397
|
-
import { closeSync as closeSync9, openSync as openSync10, readFileSync as readFileSync13, readSync as readSync3, statSync as
|
|
24398
|
-
import { join as
|
|
24674
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
24675
|
+
import { closeSync as closeSync9, openSync as openSync10, readFileSync as readFileSync13, readSync as readSync3, statSync as statSync9 } from "node:fs";
|
|
24676
|
+
import { join as join21 } from "node:path";
|
|
24399
24677
|
function foldSchemaDigest(dir = import.meta.dirname) {
|
|
24400
24678
|
if (foldSchemaMemo) return foldSchemaMemo;
|
|
24401
|
-
const hash =
|
|
24679
|
+
const hash = createHash7("sha256").update("frizz-tail-state-v1\0");
|
|
24402
24680
|
let read = 0;
|
|
24403
24681
|
for (const name of FOLD_SOURCES) {
|
|
24404
24682
|
try {
|
|
24405
|
-
hash.update(name).update("\0").update(readFileSync13(
|
|
24683
|
+
hash.update(name).update("\0").update(readFileSync13(join21(dir, name)));
|
|
24406
24684
|
read++;
|
|
24407
24685
|
} catch {
|
|
24408
24686
|
hash.update(name).update("\0missing\0");
|
|
@@ -24432,7 +24710,7 @@ function measureFence(path3, offset) {
|
|
|
24432
24710
|
if (!Number.isSafeInteger(offset) || offset <= 0) return null;
|
|
24433
24711
|
let fd2;
|
|
24434
24712
|
try {
|
|
24435
|
-
const stat2 =
|
|
24713
|
+
const stat2 = statSync9(path3);
|
|
24436
24714
|
if (stat2.size < offset) return null;
|
|
24437
24715
|
fd2 = openSync10(path3, "r");
|
|
24438
24716
|
const window = Math.min(SAMPLE_BYTES, offset);
|
|
@@ -24441,7 +24719,7 @@ function measureFence(path3, offset) {
|
|
|
24441
24719
|
const tail = Buffer.allocUnsafe(window);
|
|
24442
24720
|
const tailRead = readSync3(fd2, tail, 0, window, offset - window);
|
|
24443
24721
|
if (headRead !== window || tailRead !== window) return null;
|
|
24444
|
-
const contentDigest =
|
|
24722
|
+
const contentDigest = createHash7("sha256").update(String(offset)).update("\0").update(head).update("\0").update(tail).digest("hex").slice(0, 32);
|
|
24445
24723
|
return {
|
|
24446
24724
|
offset,
|
|
24447
24725
|
size: stat2.size,
|
|
@@ -24605,11 +24883,11 @@ var init_tail_cache = __esm({
|
|
|
24605
24883
|
});
|
|
24606
24884
|
|
|
24607
24885
|
// packages/server/src/tailer.ts
|
|
24608
|
-
import { statSync as
|
|
24886
|
+
import { statSync as statSync10, openSync as openSync11, readSync as readSync4, closeSync as closeSync10, readdirSync as readdirSync6, realpathSync as realpathSync6, mkdirSync as mkdirSync14, writeFileSync as writeFileSync11, readFileSync as readFileSync14, existsSync as existsSync7 } from "node:fs";
|
|
24609
24887
|
import { execFile as execFile2 } from "node:child_process";
|
|
24610
|
-
import { createHash as
|
|
24888
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
24611
24889
|
import { promisify as promisify2 } from "node:util";
|
|
24612
|
-
import { basename as basename4, join as
|
|
24890
|
+
import { basename as basename4, join as join22, win32 } from "node:path";
|
|
24613
24891
|
import { homedir as homedir7 } from "node:os";
|
|
24614
24892
|
function pendingCallDeadline(tail) {
|
|
24615
24893
|
const resolved2 = /* @__PURE__ */ new Set();
|
|
@@ -25136,7 +25414,7 @@ function launchTaskId(text2) {
|
|
|
25136
25414
|
function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
25137
25415
|
let names;
|
|
25138
25416
|
try {
|
|
25139
|
-
names = readdirSync6(
|
|
25417
|
+
names = readdirSync6(join22(sessionDir, "subagents"));
|
|
25140
25418
|
} catch {
|
|
25141
25419
|
return [];
|
|
25142
25420
|
}
|
|
@@ -25147,7 +25425,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
25147
25425
|
if (!agentId) continue;
|
|
25148
25426
|
let parsed;
|
|
25149
25427
|
try {
|
|
25150
|
-
parsed = JSON.parse(readFileSync14(
|
|
25428
|
+
parsed = JSON.parse(readFileSync14(join22(sessionDir, "subagents", name), "utf8"));
|
|
25151
25429
|
} catch {
|
|
25152
25430
|
continue;
|
|
25153
25431
|
}
|
|
@@ -25161,7 +25439,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
25161
25439
|
agentType: text2(meta.agentType),
|
|
25162
25440
|
parentAgentId: text2(meta.parentAgentId),
|
|
25163
25441
|
spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
|
|
25164
|
-
spawnedAtMs: mtimeMs(
|
|
25442
|
+
spawnedAtMs: mtimeMs(join22(sessionDir, "subagents", name))
|
|
25165
25443
|
});
|
|
25166
25444
|
}
|
|
25167
25445
|
return out;
|
|
@@ -25287,7 +25565,7 @@ function trackCompletions(state, rec) {
|
|
|
25287
25565
|
const monitorTimedOut = isMonitorTimeoutEvent(block);
|
|
25288
25566
|
const terminal = status === "completed" || status === "failed" || status === "killed" ? status : status === "stopped" || monitorTimedOut ? "killed" : void 0;
|
|
25289
25567
|
if (!terminal) continue;
|
|
25290
|
-
const fingerprint =
|
|
25568
|
+
const fingerprint = createHash8("sha1").update(block).digest("hex").slice(0, 16);
|
|
25291
25569
|
const repeatOf = /* @__PURE__ */ new Set();
|
|
25292
25570
|
for (const id2 of blockTaskIds(block)) {
|
|
25293
25571
|
if (state.foldedTerminals?.get(id2) === fingerprint) repeatOf.add(id2);
|
|
@@ -25650,13 +25928,13 @@ function isPermMarker(v) {
|
|
|
25650
25928
|
}
|
|
25651
25929
|
function defaultMtimeMs(path3) {
|
|
25652
25930
|
try {
|
|
25653
|
-
return
|
|
25931
|
+
return statSync10(path3).mtimeMs;
|
|
25654
25932
|
} catch {
|
|
25655
25933
|
return void 0;
|
|
25656
25934
|
}
|
|
25657
25935
|
}
|
|
25658
25936
|
function defaultLogDir(project) {
|
|
25659
|
-
return
|
|
25937
|
+
return join22(homedir7(), ".claude", "projects", project.cwdSlug);
|
|
25660
25938
|
}
|
|
25661
25939
|
function defaultReadPermMarker(project) {
|
|
25662
25940
|
if (!project.stateDir) return () => void 0;
|
|
@@ -25788,7 +26066,7 @@ function createTailer(deps) {
|
|
|
25788
26066
|
return paneDead(row.slug);
|
|
25789
26067
|
}
|
|
25790
26068
|
const defaultBackend = {
|
|
25791
|
-
transcriptPath: (sessionId) =>
|
|
26069
|
+
transcriptPath: (sessionId) => join22(logDir, `${sessionId}.jsonl`),
|
|
25792
26070
|
foldLine: (state, line) => {
|
|
25793
26071
|
const rec = parseLine(line);
|
|
25794
26072
|
if (rec) applyRecord(state, rec);
|
|
@@ -25830,7 +26108,7 @@ function createTailer(deps) {
|
|
|
25830
26108
|
function blockedUntil(path3, m) {
|
|
25831
26109
|
let size;
|
|
25832
26110
|
try {
|
|
25833
|
-
size =
|
|
26111
|
+
size = statSync10(path3).size;
|
|
25834
26112
|
} catch {
|
|
25835
26113
|
return void 0;
|
|
25836
26114
|
}
|
|
@@ -25956,7 +26234,7 @@ ${ask}`;
|
|
|
25956
26234
|
return state.path.replace(/\.jsonl$/, "");
|
|
25957
26235
|
}
|
|
25958
26236
|
function descendantSidecars(state) {
|
|
25959
|
-
const at2 = mtimeMs(
|
|
26237
|
+
const at2 = mtimeMs(join22(sessionDirOf(state), "subagents"));
|
|
25960
26238
|
const cached2 = descendantIndex.get(state.slug);
|
|
25961
26239
|
if (cached2 && cached2.at === at2) return cached2.all;
|
|
25962
26240
|
const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
|
|
@@ -25970,7 +26248,7 @@ ${ask}`;
|
|
|
25970
26248
|
return descendantIndex.get(state.slug)?.byToolUse.get(id2);
|
|
25971
26249
|
}
|
|
25972
26250
|
function descendantTranscript(state, meta) {
|
|
25973
|
-
return
|
|
26251
|
+
return join22(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
|
|
25974
26252
|
}
|
|
25975
26253
|
function subAgentDescendantTasks(slug, id2) {
|
|
25976
26254
|
const state = states.get(slug);
|
|
@@ -26318,10 +26596,10 @@ ${ask}`;
|
|
|
26318
26596
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
26319
26597
|
const id2 = name.slice(0, -".jsonl".length);
|
|
26320
26598
|
if (!id2 || registered.has(id2)) continue;
|
|
26321
|
-
const path3 =
|
|
26599
|
+
const path3 = join22(logDir, name);
|
|
26322
26600
|
let mtime;
|
|
26323
26601
|
try {
|
|
26324
|
-
mtime =
|
|
26602
|
+
mtime = statSync10(path3).mtimeMs;
|
|
26325
26603
|
} catch {
|
|
26326
26604
|
continue;
|
|
26327
26605
|
}
|
|
@@ -26369,6 +26647,18 @@ ${ask}`;
|
|
|
26369
26647
|
if (state.lastActivityAt !== prevActivity || state.lastAssistant !== prevAssistant || state.model !== prevModel || state.effort !== prevEffort || state.permissionMode !== prevPermissionMode) dirty = true;
|
|
26370
26648
|
return dirty;
|
|
26371
26649
|
}
|
|
26650
|
+
const crossSessionOnLine = deps.onCrossSessionMessage ? (line) => {
|
|
26651
|
+
if (!line.includes("cross-session-message")) return;
|
|
26652
|
+
let rec;
|
|
26653
|
+
try {
|
|
26654
|
+
rec = JSON.parse(line);
|
|
26655
|
+
} catch {
|
|
26656
|
+
return;
|
|
26657
|
+
}
|
|
26658
|
+
if (rec.type !== "queue-operation" || rec.operation !== "enqueue" || typeof rec.content !== "string") return;
|
|
26659
|
+
const peer = parseCrossSessionMessage(rec.content);
|
|
26660
|
+
if (peer) deps.onCrossSessionMessage(peer);
|
|
26661
|
+
} : void 0;
|
|
26372
26662
|
function chainOnLine(a, b) {
|
|
26373
26663
|
if (!a) return b;
|
|
26374
26664
|
if (!b) return a;
|
|
@@ -26474,7 +26764,7 @@ ${ask}`;
|
|
|
26474
26764
|
if (entry.path !== state.path) {
|
|
26475
26765
|
let derivedSize = 0;
|
|
26476
26766
|
try {
|
|
26477
|
-
derivedSize =
|
|
26767
|
+
derivedSize = statSync10(state.path).size;
|
|
26478
26768
|
} catch {
|
|
26479
26769
|
derivedSize = 0;
|
|
26480
26770
|
}
|
|
@@ -26531,7 +26821,7 @@ ${ask}`;
|
|
|
26531
26821
|
function consume(state, backend, onLine) {
|
|
26532
26822
|
let size;
|
|
26533
26823
|
try {
|
|
26534
|
-
size =
|
|
26824
|
+
size = statSync10(state.path).size;
|
|
26535
26825
|
} catch {
|
|
26536
26826
|
return;
|
|
26537
26827
|
}
|
|
@@ -26589,8 +26879,8 @@ ${ask}`;
|
|
|
26589
26879
|
`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)}`
|
|
26590
26880
|
);
|
|
26591
26881
|
try {
|
|
26592
|
-
|
|
26593
|
-
writeFileSync11(
|
|
26882
|
+
mkdirSync14(stallLogDir, { recursive: true });
|
|
26883
|
+
writeFileSync11(join22(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
|
|
26594
26884
|
captured_at: ${new Date(now()).toISOString()}
|
|
26595
26885
|
|
|
26596
26886
|
${detail2}
|
|
@@ -26600,10 +26890,10 @@ ${detail2}
|
|
|
26600
26890
|
}
|
|
26601
26891
|
function relocatedTranscript(state) {
|
|
26602
26892
|
const name = `${state.nativeSessionId}.jsonl`;
|
|
26603
|
-
const home =
|
|
26893
|
+
const home = join22(logDir, name);
|
|
26604
26894
|
const homeAt = home === state.path ? void 0 : mtimeOfNonEmpty(home);
|
|
26605
26895
|
const dir = discoverTranscriptDir(logDir, state.nativeSessionId);
|
|
26606
|
-
const sibling = dir ?
|
|
26896
|
+
const sibling = dir ? join22(dir, name) : void 0;
|
|
26607
26897
|
const siblingAt = sibling && sibling !== state.path ? mtimeOfNonEmpty(sibling) : void 0;
|
|
26608
26898
|
if (homeAt === void 0) return siblingAt === void 0 ? void 0 : sibling;
|
|
26609
26899
|
if (siblingAt === void 0) return home;
|
|
@@ -26638,7 +26928,7 @@ ${detail2}
|
|
|
26638
26928
|
}
|
|
26639
26929
|
let size = 0;
|
|
26640
26930
|
try {
|
|
26641
|
-
size =
|
|
26931
|
+
size = statSync10(state.path).size;
|
|
26642
26932
|
} catch {
|
|
26643
26933
|
size = 0;
|
|
26644
26934
|
}
|
|
@@ -26655,7 +26945,7 @@ ${detail2}
|
|
|
26655
26945
|
state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
|
|
26656
26946
|
const strandedDir = discoverTranscriptDir(logDir, row.session_id);
|
|
26657
26947
|
if (strandedDir) {
|
|
26658
|
-
state.path =
|
|
26948
|
+
state.path = join22(strandedDir, `${row.session_id}.jsonl`);
|
|
26659
26949
|
state.offset = 0;
|
|
26660
26950
|
state.partial = "";
|
|
26661
26951
|
state.primed = false;
|
|
@@ -26679,7 +26969,7 @@ ${detail2}
|
|
|
26679
26969
|
committed = false;
|
|
26680
26970
|
}
|
|
26681
26971
|
if (!committed) return false;
|
|
26682
|
-
state.path =
|
|
26972
|
+
state.path = join22(logDir, `${found}.jsonl`);
|
|
26683
26973
|
state.offset = 0;
|
|
26684
26974
|
state.partial = "";
|
|
26685
26975
|
state.primed = false;
|
|
@@ -26739,7 +27029,7 @@ ${detail2}
|
|
|
26739
27029
|
continue;
|
|
26740
27030
|
}
|
|
26741
27031
|
if (!state) {
|
|
26742
|
-
const path3 = backend.transcriptPath(nativeId) ??
|
|
27032
|
+
const path3 = backend.transcriptPath(nativeId) ?? join22(logDir, `${nativeId}.jsonl`);
|
|
26743
27033
|
state = newTailState(row.slug, row.session_id, path3, false, nativeId, runtimeGeneration);
|
|
26744
27034
|
state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
|
|
26745
27035
|
hydrateFromCache(state, row, nativeId);
|
|
@@ -26815,7 +27105,7 @@ ${detail2}
|
|
|
26815
27105
|
const rowLedger = row.delivery_ledger ?? null;
|
|
26816
27106
|
const ledgerDrifted = rowLedger !== (state.deliveryLedgerSeen ?? null);
|
|
26817
27107
|
const ledger = ledgerFold(row, nowMs, state);
|
|
26818
|
-
consume(state, backend, chainOnLine(ledger.onLine, codexSubAgentOnLine(row, state)));
|
|
27108
|
+
consume(state, backend, chainOnLine(chainOnLine(ledger.onLine, codexSubAgentOnLine(row, state)), crossSessionOnLine));
|
|
26819
27109
|
state.codexSubAgents?.poll(nowMs);
|
|
26820
27110
|
const ledgerResult = ledger.finish();
|
|
26821
27111
|
state.deliveryLedgerSeen = ledgerResult.changed ? ledgerResult.value : rowLedger;
|
|
@@ -27207,14 +27497,14 @@ var init_tailer = __esm({
|
|
|
27207
27497
|
});
|
|
27208
27498
|
|
|
27209
27499
|
// packages/server/src/backend/codex.ts
|
|
27210
|
-
import { join as
|
|
27500
|
+
import { join as join23 } from "node:path";
|
|
27211
27501
|
import { homedir as homedir8 } from "node:os";
|
|
27212
|
-
import { readdirSync as readdirSync7, statSync as
|
|
27502
|
+
import { readdirSync as readdirSync7, statSync as statSync11, readFileSync as readFileSync15, openSync as openSync12, readSync as readSync5, closeSync as closeSync11 } from "node:fs";
|
|
27213
27503
|
function defaultCodexHome() {
|
|
27214
|
-
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME :
|
|
27504
|
+
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join23(homedir8(), ".codex");
|
|
27215
27505
|
}
|
|
27216
27506
|
function sessionsDir(codexHome) {
|
|
27217
|
-
return
|
|
27507
|
+
return join23(codexHome, "sessions");
|
|
27218
27508
|
}
|
|
27219
27509
|
function codexSandbox(mode) {
|
|
27220
27510
|
switch (mode) {
|
|
@@ -27660,17 +27950,17 @@ function collectRollouts(dir, out, budget) {
|
|
|
27660
27950
|
const files = entries2.filter((e14) => e14.isFile() && e14.name.startsWith("rollout-") && e14.name.endsWith(".jsonl")).sort(descByName);
|
|
27661
27951
|
for (const d of dirs) {
|
|
27662
27952
|
if (budget.n <= 0) return;
|
|
27663
|
-
collectRollouts(
|
|
27953
|
+
collectRollouts(join23(dir, d.name), out, budget);
|
|
27664
27954
|
}
|
|
27665
27955
|
for (const f of files) {
|
|
27666
27956
|
if (budget.n <= 0) return;
|
|
27667
27957
|
let mtimeMs;
|
|
27668
27958
|
try {
|
|
27669
|
-
mtimeMs =
|
|
27959
|
+
mtimeMs = statSync11(join23(dir, f.name)).mtimeMs;
|
|
27670
27960
|
} catch {
|
|
27671
27961
|
continue;
|
|
27672
27962
|
}
|
|
27673
|
-
out.push({ path:
|
|
27963
|
+
out.push({ path: join23(dir, f.name), mtimeMs });
|
|
27674
27964
|
budget.n--;
|
|
27675
27965
|
}
|
|
27676
27966
|
}
|
|
@@ -27714,8 +28004,8 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
|
|
|
27714
28004
|
const out = /* @__PURE__ */ new Map();
|
|
27715
28005
|
let raw2;
|
|
27716
28006
|
try {
|
|
27717
|
-
const path3 =
|
|
27718
|
-
if (
|
|
28007
|
+
const path3 = join23(codexHome, "session_index.jsonl");
|
|
28008
|
+
if (statSync11(path3).size > SESSION_INDEX_MAX_BYTES) return out;
|
|
27719
28009
|
raw2 = readFileSync15(path3, "utf8");
|
|
27720
28010
|
} catch {
|
|
27721
28011
|
return out;
|
|
@@ -27918,19 +28208,19 @@ function searchPath2(env) {
|
|
|
27918
28208
|
function vendoredNativeBeside(launcherJs, arch, access) {
|
|
27919
28209
|
const triple = WINDOWS_TRIPLE[arch];
|
|
27920
28210
|
if (!triple) return void 0;
|
|
27921
|
-
const { dirname:
|
|
27922
|
-
const pkgRoot =
|
|
28211
|
+
const { dirname: dirname31, join: join56 } = win322;
|
|
28212
|
+
const pkgRoot = dirname31(dirname31(launcherJs));
|
|
27923
28213
|
const platformPkg = `codex-win32-${arch}`;
|
|
27924
28214
|
const vendorRoots = [
|
|
27925
|
-
|
|
28215
|
+
join56(pkgRoot, "node_modules", "@openai", platformPkg, "vendor"),
|
|
27926
28216
|
// nested under the package
|
|
27927
|
-
|
|
28217
|
+
join56(dirname31(pkgRoot), platformPkg, "vendor"),
|
|
27928
28218
|
// hoisted beside it: <prefix>\node_modules\@openai\<pkg>
|
|
27929
|
-
|
|
28219
|
+
join56(pkgRoot, "vendor")
|
|
27930
28220
|
// the pre-platform-package layout, binaries inside @openai/codex itself
|
|
27931
28221
|
];
|
|
27932
28222
|
for (const root of vendorRoots) {
|
|
27933
|
-
const exe2 =
|
|
28223
|
+
const exe2 = join56(root, triple, "bin", "codex.exe");
|
|
27934
28224
|
if (access(exe2, "exists")) return exe2;
|
|
27935
28225
|
}
|
|
27936
28226
|
return void 0;
|
|
@@ -30254,7 +30544,7 @@ var require_websocket = __commonJS({
|
|
|
30254
30544
|
var http = __require("http");
|
|
30255
30545
|
var net2 = __require("net");
|
|
30256
30546
|
var tls = __require("tls");
|
|
30257
|
-
var { randomBytes: randomBytes2, createHash:
|
|
30547
|
+
var { randomBytes: randomBytes2, createHash: createHash19 } = __require("crypto");
|
|
30258
30548
|
var { Duplex, Readable: Readable3 } = __require("stream");
|
|
30259
30549
|
var { URL: URL2 } = __require("url");
|
|
30260
30550
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -30922,7 +31212,7 @@ var require_websocket = __commonJS({
|
|
|
30922
31212
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
30923
31213
|
return;
|
|
30924
31214
|
}
|
|
30925
|
-
const digest =
|
|
31215
|
+
const digest = createHash19("sha1").update(key + GUID).digest("base64");
|
|
30926
31216
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
30927
31217
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
30928
31218
|
return;
|
|
@@ -31291,7 +31581,7 @@ var require_websocket_server = __commonJS({
|
|
|
31291
31581
|
var EventEmitter = __require("events");
|
|
31292
31582
|
var http = __require("http");
|
|
31293
31583
|
var { Duplex } = __require("stream");
|
|
31294
|
-
var { createHash:
|
|
31584
|
+
var { createHash: createHash19 } = __require("crypto");
|
|
31295
31585
|
var extension2 = require_extension();
|
|
31296
31586
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
31297
31587
|
var subprotocol2 = require_subprotocol();
|
|
@@ -31598,7 +31888,7 @@ var require_websocket_server = __commonJS({
|
|
|
31598
31888
|
);
|
|
31599
31889
|
}
|
|
31600
31890
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
31601
|
-
const digest =
|
|
31891
|
+
const digest = createHash19("sha1").update(key + GUID).digest("base64");
|
|
31602
31892
|
const headers = [
|
|
31603
31893
|
"HTTP/1.1 101 Switching Protocols",
|
|
31604
31894
|
"Upgrade: websocket",
|
|
@@ -31761,19 +32051,19 @@ var init_codex_mcp = __esm({
|
|
|
31761
32051
|
import { spawn as spawn2 } from "node:child_process";
|
|
31762
32052
|
import { connect } from "node:net";
|
|
31763
32053
|
import { Agent as HttpAgent } from "node:http";
|
|
31764
|
-
import { createHash as
|
|
31765
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
31766
|
-
import { join as
|
|
32054
|
+
import { createHash as createHash9, randomUUID as randomUUID9 } from "node:crypto";
|
|
32055
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync15, readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync12 } from "node:fs";
|
|
32056
|
+
import { join as join24 } from "node:path";
|
|
31767
32057
|
import { PassThrough, Writable } from "node:stream";
|
|
31768
32058
|
import { StringDecoder } from "node:string_decoder";
|
|
31769
32059
|
function nativeDir(stateDir) {
|
|
31770
|
-
return
|
|
32060
|
+
return join24(stateDir, "codex-app-server-native");
|
|
31771
32061
|
}
|
|
31772
32062
|
function nativeRecordPath(stateDir, projectId) {
|
|
31773
|
-
return
|
|
32063
|
+
return join24(nativeDir(stateDir), `${projectId}.json`);
|
|
31774
32064
|
}
|
|
31775
32065
|
function nativeListenSocketPath(stateDir, projectId) {
|
|
31776
|
-
const key =
|
|
32066
|
+
const key = createHash9("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
31777
32067
|
return frizzIpcPath(`frizz-codex-native-${key}`);
|
|
31778
32068
|
}
|
|
31779
32069
|
function pidAlive2(pid) {
|
|
@@ -31943,7 +32233,7 @@ function attach(record, timeoutMs) {
|
|
|
31943
32233
|
}
|
|
31944
32234
|
async function startListener(options) {
|
|
31945
32235
|
const { stateDir, projectId } = options;
|
|
31946
|
-
|
|
32236
|
+
mkdirSync15(nativeDir(stateDir), { recursive: true });
|
|
31947
32237
|
const socketPath = nativeListenSocketPath(stateDir, projectId);
|
|
31948
32238
|
if (existsSync8(socketPath) && !await socketAccepting(socketPath)) {
|
|
31949
32239
|
try {
|
|
@@ -32041,19 +32331,19 @@ var init_codex_app_server_native = __esm({
|
|
|
32041
32331
|
// packages/server/src/backend/codex-app-server-host.ts
|
|
32042
32332
|
import { spawn as spawn3 } from "node:child_process";
|
|
32043
32333
|
import { createConnection } from "node:net";
|
|
32044
|
-
import { createHash as
|
|
32045
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
32046
|
-
import { join as
|
|
32334
|
+
import { createHash as createHash10, randomUUID as randomUUID10 } from "node:crypto";
|
|
32335
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync16, readFileSync as readFileSync18, unlinkSync as unlinkSync3 } from "node:fs";
|
|
32336
|
+
import { join as join25 } from "node:path";
|
|
32047
32337
|
import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
|
|
32048
32338
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
32049
32339
|
function daemonDir(stateDir) {
|
|
32050
|
-
return
|
|
32340
|
+
return join25(stateDir, "codex-app-server");
|
|
32051
32341
|
}
|
|
32052
32342
|
function recordPath(stateDir, projectId) {
|
|
32053
|
-
return
|
|
32343
|
+
return join25(daemonDir(stateDir), `${projectId}.json`);
|
|
32054
32344
|
}
|
|
32055
32345
|
function codexAppServerSocketPath(stateDir, projectId) {
|
|
32056
|
-
const key =
|
|
32346
|
+
const key = createHash10("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
32057
32347
|
return frizzIpcPath(`frizz-codex-${key}`);
|
|
32058
32348
|
}
|
|
32059
32349
|
function pidAlive3(pid) {
|
|
@@ -32133,7 +32423,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
32133
32423
|
}
|
|
32134
32424
|
function forkDaemon(options) {
|
|
32135
32425
|
const { stateDir, projectId } = options;
|
|
32136
|
-
|
|
32426
|
+
mkdirSync16(daemonDir(stateDir), { recursive: true });
|
|
32137
32427
|
const record = recordPath(stateDir, projectId);
|
|
32138
32428
|
try {
|
|
32139
32429
|
unlinkSync3(record);
|
|
@@ -32348,15 +32638,15 @@ var init_codex_app_server_host = __esm({
|
|
|
32348
32638
|
});
|
|
32349
32639
|
|
|
32350
32640
|
// packages/server/src/backend/claude-quota.ts
|
|
32351
|
-
import { join as
|
|
32641
|
+
import { join as join26 } from "node:path";
|
|
32352
32642
|
import { homedir as homedir9, platform } from "node:os";
|
|
32353
|
-
import { createHash as
|
|
32643
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
32354
32644
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
32355
32645
|
import { execFile as execFile3 } from "node:child_process";
|
|
32356
32646
|
import { promisify as promisify3 } from "node:util";
|
|
32357
32647
|
function claudeConfigDir() {
|
|
32358
32648
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32359
|
-
return override && override.trim() ? override :
|
|
32649
|
+
return override && override.trim() ? override : join26(homedir9(), ".claude");
|
|
32360
32650
|
}
|
|
32361
32651
|
function tokenFromCredentialsJson(raw2) {
|
|
32362
32652
|
let doc;
|
|
@@ -32385,7 +32675,7 @@ async function readKeychainToken() {
|
|
|
32385
32675
|
}
|
|
32386
32676
|
async function readAccessToken(configDir) {
|
|
32387
32677
|
try {
|
|
32388
|
-
const fromFile = tokenFromCredentialsJson(await readFile(
|
|
32678
|
+
const fromFile = tokenFromCredentialsJson(await readFile(join26(configDir, ".credentials.json"), "utf8"));
|
|
32389
32679
|
if (fromFile) return fromFile;
|
|
32390
32680
|
} catch {
|
|
32391
32681
|
}
|
|
@@ -32457,10 +32747,10 @@ function retryAtFrom(res, now) {
|
|
|
32457
32747
|
return now + Math.min(backoff, RATE_LIMIT_MAX_BACKOFF_MS);
|
|
32458
32748
|
}
|
|
32459
32749
|
function cachePaths(cacheDir, configDir) {
|
|
32460
|
-
const profile =
|
|
32750
|
+
const profile = createHash11("sha256").update(configDir).digest("hex").slice(0, 12);
|
|
32461
32751
|
return {
|
|
32462
|
-
data:
|
|
32463
|
-
lock:
|
|
32752
|
+
data: join26(cacheDir, `claude-${profile}.json`),
|
|
32753
|
+
lock: join26(cacheDir, `claude-${profile}.lock`)
|
|
32464
32754
|
};
|
|
32465
32755
|
}
|
|
32466
32756
|
async function readShared(path3) {
|
|
@@ -32672,7 +32962,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
|
|
|
32672
32962
|
async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
32673
32963
|
const now = (deps.now ?? Date.now)();
|
|
32674
32964
|
const configDir = claudeConfigDir();
|
|
32675
|
-
const cacheDir = deps.cacheDir ??
|
|
32965
|
+
const cacheDir = deps.cacheDir ?? join26(frizzRoots().cache, "quota-cache");
|
|
32676
32966
|
try {
|
|
32677
32967
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
32678
32968
|
} catch {
|
|
@@ -32686,7 +32976,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
|
32686
32976
|
async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
|
|
32687
32977
|
const now = (deps.now ?? Date.now)();
|
|
32688
32978
|
const configDir = claudeConfigDir();
|
|
32689
|
-
const cacheDir = deps.cacheDir ??
|
|
32979
|
+
const cacheDir = deps.cacheDir ?? join26(frizzRoots().cache, "quota-cache");
|
|
32690
32980
|
const paths = cachePaths(cacheDir, configDir);
|
|
32691
32981
|
try {
|
|
32692
32982
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
@@ -32793,19 +33083,19 @@ var init_claude_quota = __esm({
|
|
|
32793
33083
|
});
|
|
32794
33084
|
|
|
32795
33085
|
// packages/server/src/backend/auth-status.ts
|
|
32796
|
-
import { join as
|
|
33086
|
+
import { join as join27 } from "node:path";
|
|
32797
33087
|
import { homedir as homedir10, platform as platform2 } from "node:os";
|
|
32798
|
-
import { readFileSync as readFileSync19, statSync as
|
|
33088
|
+
import { readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
|
|
32799
33089
|
import { execFile as execFile4 } from "node:child_process";
|
|
32800
33090
|
import { promisify as promisify4 } from "node:util";
|
|
32801
33091
|
function claudeConfigDir2() {
|
|
32802
33092
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32803
|
-
return override && override.trim() ? override :
|
|
33093
|
+
return override && override.trim() ? override : join27(homedir10(), ".claude");
|
|
32804
33094
|
}
|
|
32805
33095
|
function claudeFileState(configDir) {
|
|
32806
33096
|
let raw2;
|
|
32807
33097
|
try {
|
|
32808
|
-
raw2 = readFileSync19(
|
|
33098
|
+
raw2 = readFileSync19(join27(configDir, ".credentials.json"), "utf8");
|
|
32809
33099
|
} catch (err) {
|
|
32810
33100
|
return err.code === "ENOENT" ? "absent" : "error";
|
|
32811
33101
|
}
|
|
@@ -32838,7 +33128,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
32838
33128
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
|
|
32839
33129
|
let raw2;
|
|
32840
33130
|
try {
|
|
32841
|
-
raw2 = readFileSync19(
|
|
33131
|
+
raw2 = readFileSync19(join27(codexHome, "auth.json"), "utf8");
|
|
32842
33132
|
} catch (err) {
|
|
32843
33133
|
return err.code === "ENOENT" ? "signed-out" : "unknown";
|
|
32844
33134
|
}
|
|
@@ -32858,7 +33148,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
32858
33148
|
function readCodexAccountId(codexHome = defaultCodexHome()) {
|
|
32859
33149
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return void 0;
|
|
32860
33150
|
try {
|
|
32861
|
-
const doc = JSON.parse(readFileSync19(
|
|
33151
|
+
const doc = JSON.parse(readFileSync19(join27(codexHome, "auth.json"), "utf8"));
|
|
32862
33152
|
if (!doc || typeof doc !== "object") return void 0;
|
|
32863
33153
|
const tokens = doc.tokens;
|
|
32864
33154
|
if (!tokens || typeof tokens !== "object") return void 0;
|
|
@@ -32917,12 +33207,12 @@ function asEmail(value) {
|
|
|
32917
33207
|
}
|
|
32918
33208
|
function claudeAccountFile() {
|
|
32919
33209
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32920
|
-
return override && override.trim() ?
|
|
33210
|
+
return override && override.trim() ? join27(override, ".claude.json") : join27(homedir10(), ".claude.json");
|
|
32921
33211
|
}
|
|
32922
33212
|
function readClaudeAccountEmail(path3 = claudeAccountFile()) {
|
|
32923
33213
|
let stat2;
|
|
32924
33214
|
try {
|
|
32925
|
-
stat2 =
|
|
33215
|
+
stat2 = statSync12(path3);
|
|
32926
33216
|
} catch {
|
|
32927
33217
|
return void 0;
|
|
32928
33218
|
}
|
|
@@ -32941,7 +33231,7 @@ function readClaudeAccountEmail(path3 = claudeAccountFile()) {
|
|
|
32941
33231
|
function readCodexAccountEmail(codexHome = defaultCodexHome()) {
|
|
32942
33232
|
let doc;
|
|
32943
33233
|
try {
|
|
32944
|
-
doc = JSON.parse(readFileSync19(
|
|
33234
|
+
doc = JSON.parse(readFileSync19(join27(codexHome, "auth.json"), "utf8"));
|
|
32945
33235
|
} catch {
|
|
32946
33236
|
return void 0;
|
|
32947
33237
|
}
|
|
@@ -33066,7 +33356,7 @@ var init_codex_execution_health = __esm({
|
|
|
33066
33356
|
});
|
|
33067
33357
|
|
|
33068
33358
|
// packages/server/src/backend/codex-app-server.ts
|
|
33069
|
-
import { createHash as
|
|
33359
|
+
import { createHash as createHash12, randomUUID as randomUUID11 } from "node:crypto";
|
|
33070
33360
|
import { existsSync as existsSync10 } from "node:fs";
|
|
33071
33361
|
import { StringDecoder as StringDecoder3 } from "node:string_decoder";
|
|
33072
33362
|
function selectCodexHostKind(flagValue, platform3, hasSpawn) {
|
|
@@ -33085,21 +33375,21 @@ function compareCodexVersions(a, b) {
|
|
|
33085
33375
|
for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] < y[i] ? -1 : 1;
|
|
33086
33376
|
return 0;
|
|
33087
33377
|
}
|
|
33088
|
-
function codexVersionVerdict(received,
|
|
33378
|
+
function codexVersionVerdict(received, audited2 = CODEX_APP_SERVER_SUPPORTED_VERSION) {
|
|
33089
33379
|
if (!received) {
|
|
33090
|
-
return { kind: "refused", message: `Codex app-server did not report a parseable frizz/<version> user agent; expected ${
|
|
33380
|
+
return { kind: "refused", message: `Codex app-server did not report a parseable frizz/<version> user agent; expected ${audited2}` };
|
|
33091
33381
|
}
|
|
33092
|
-
const cmp = compareCodexVersions(received,
|
|
33382
|
+
const cmp = compareCodexVersions(received, audited2);
|
|
33093
33383
|
if (cmp === 0) return { kind: "audited" };
|
|
33094
33384
|
if (cmp < 0) {
|
|
33095
33385
|
return {
|
|
33096
33386
|
kind: "refused",
|
|
33097
|
-
message: `Codex app-server ${received} is older than the audited protocol ${
|
|
33387
|
+
message: `Codex app-server ${received} is older than the audited protocol ${audited2}. Upgrade codex (\`npm i -g @openai/codex\`) \u2014 frizz sends parameters this build may not accept.`
|
|
33098
33388
|
};
|
|
33099
33389
|
}
|
|
33100
33390
|
return {
|
|
33101
33391
|
kind: "ahead",
|
|
33102
|
-
message: `Codex app-server ${received} is NEWER than frizz's audited protocol ${
|
|
33392
|
+
message: `Codex app-server ${received} is NEWER than frizz's audited protocol ${audited2} \u2014 running anyway (the protocol is additive and unknown fields are ignored). If Codex threads misbehave, re-audit and re-pin. Run \`npm test -- codex-protocol-conformance\` to check frizz's params against this binary's own schema.`
|
|
33103
33393
|
};
|
|
33104
33394
|
}
|
|
33105
33395
|
function isCodexSandboxMode(value) {
|
|
@@ -33414,7 +33704,7 @@ function canonicalJson2(value) {
|
|
|
33414
33704
|
return JSON.stringify(normalize2(value));
|
|
33415
33705
|
}
|
|
33416
33706
|
function logicalRequestId(method, parts) {
|
|
33417
|
-
const digest =
|
|
33707
|
+
const digest = createHash12("sha256").update(JSON.stringify([method, ...parts])).digest("hex");
|
|
33418
33708
|
return `codex-${digest}`;
|
|
33419
33709
|
}
|
|
33420
33710
|
function requestFingerprint(value) {
|
|
@@ -33424,7 +33714,7 @@ function requestFingerprint(value) {
|
|
|
33424
33714
|
delete record.startedAtMs;
|
|
33425
33715
|
delete record.autoResolutionMs;
|
|
33426
33716
|
}
|
|
33427
|
-
return
|
|
33717
|
+
return createHash12("sha256").update(canonicalJson2(normalized)).digest("hex");
|
|
33428
33718
|
}
|
|
33429
33719
|
function decision(id2, semantic, label) {
|
|
33430
33720
|
return { id: id2, semantic, label };
|
|
@@ -36339,11 +36629,11 @@ var init_codex_app_server = __esm({
|
|
|
36339
36629
|
});
|
|
36340
36630
|
|
|
36341
36631
|
// packages/server/src/backend/codex-quota.ts
|
|
36342
|
-
import { join as
|
|
36343
|
-
import { readdirSync as readdirSync8, statSync as
|
|
36632
|
+
import { join as join28 } from "node:path";
|
|
36633
|
+
import { readdirSync as readdirSync8, statSync as statSync13, openSync as openSync13, readSync as readSync6, fstatSync, closeSync as closeSync12 } from "node:fs";
|
|
36344
36634
|
import { spawn as spawn4 } from "node:child_process";
|
|
36345
36635
|
function sessionsDir2(codexHome) {
|
|
36346
|
-
return
|
|
36636
|
+
return join28(codexHome, "sessions");
|
|
36347
36637
|
}
|
|
36348
36638
|
function newestRollouts(dir, out, budget) {
|
|
36349
36639
|
if (budget.n <= 0) return;
|
|
@@ -36357,11 +36647,11 @@ function newestRollouts(dir, out, budget) {
|
|
|
36357
36647
|
const files = entries2.filter((e14) => e14.isFile() && e14.name.startsWith("rollout-") && e14.name.endsWith(".jsonl")).map((e14) => e14.name).sort(descByName2);
|
|
36358
36648
|
for (const d of dirs) {
|
|
36359
36649
|
if (budget.n <= 0) return;
|
|
36360
|
-
newestRollouts(
|
|
36650
|
+
newestRollouts(join28(dir, d), out, budget);
|
|
36361
36651
|
}
|
|
36362
36652
|
for (const f of files) {
|
|
36363
36653
|
if (budget.n <= 0) return;
|
|
36364
|
-
out.push(
|
|
36654
|
+
out.push(join28(dir, f));
|
|
36365
36655
|
budget.n--;
|
|
36366
36656
|
}
|
|
36367
36657
|
}
|
|
@@ -36433,7 +36723,7 @@ function readCodexQuotaFromRollouts(codexHome = defaultCodexHome()) {
|
|
|
36433
36723
|
newestRollouts(sessionsDir2(codexHome), rollouts, { n: 8 });
|
|
36434
36724
|
const byMtime = rollouts.map((path3) => {
|
|
36435
36725
|
try {
|
|
36436
|
-
return { path: path3, mtimeMs:
|
|
36726
|
+
return { path: path3, mtimeMs: statSync13(path3).mtimeMs };
|
|
36437
36727
|
} catch {
|
|
36438
36728
|
return void 0;
|
|
36439
36729
|
}
|
|
@@ -36634,9 +36924,9 @@ var init_quota = __esm({
|
|
|
36634
36924
|
|
|
36635
36925
|
// packages/server/src/local-file.ts
|
|
36636
36926
|
import { spawn as spawn5 } from "node:child_process";
|
|
36637
|
-
import { existsSync as existsSync11, readFileSync as readFileSync20, realpathSync as realpathSync7, statSync as
|
|
36927
|
+
import { existsSync as existsSync11, readFileSync as readFileSync20, realpathSync as realpathSync7, statSync as statSync14 } from "node:fs";
|
|
36638
36928
|
import { homedir as homedir11 } from "node:os";
|
|
36639
|
-
import { dirname as
|
|
36929
|
+
import { dirname as dirname12, isAbsolute as isAbsolute5, join as join29, resolve as resolve5, sep as sep2 } from "node:path";
|
|
36640
36930
|
function isUnder(real, root) {
|
|
36641
36931
|
let rootReal;
|
|
36642
36932
|
try {
|
|
@@ -36648,12 +36938,12 @@ function isUnder(real, root) {
|
|
|
36648
36938
|
return real === rootReal || real.startsWith(rootReal.endsWith(sep2) ? rootReal : rootReal + sep2);
|
|
36649
36939
|
}
|
|
36650
36940
|
try {
|
|
36651
|
-
const trusted2 =
|
|
36941
|
+
const trusted2 = statSync14(rootReal, { bigint: true });
|
|
36652
36942
|
if (!trusted2.isDirectory() || trusted2.ino === 0n) return false;
|
|
36653
36943
|
for (let ancestor = real; ; ) {
|
|
36654
|
-
const actual =
|
|
36944
|
+
const actual = statSync14(ancestor, { bigint: true });
|
|
36655
36945
|
if (actual.dev === trusted2.dev && actual.ino === trusted2.ino) return true;
|
|
36656
|
-
const parent =
|
|
36946
|
+
const parent = dirname12(ancestor);
|
|
36657
36947
|
if (parent === ancestor) return false;
|
|
36658
36948
|
ancestor = parent;
|
|
36659
36949
|
}
|
|
@@ -36672,7 +36962,7 @@ function resolveLocalFile(rawPath, roots) {
|
|
|
36672
36962
|
}
|
|
36673
36963
|
if (!roots.some((root) => isUnder(real, root))) throw new Error("Local file is outside Frizz's trusted roots");
|
|
36674
36964
|
try {
|
|
36675
|
-
if (!
|
|
36965
|
+
if (!statSync14(real).isFile()) throw new Error("Local path is not a regular file");
|
|
36676
36966
|
} catch (error) {
|
|
36677
36967
|
if (error instanceof Error && error.message === "Local path is not a regular file") throw error;
|
|
36678
36968
|
throw new Error("Local file was not found");
|
|
@@ -36682,7 +36972,7 @@ function resolveLocalFile(rawPath, roots) {
|
|
|
36682
36972
|
function resolveOpenableFile(raw2, projectDir, roots, home = homedir11()) {
|
|
36683
36973
|
const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
|
|
36684
36974
|
if (!trimmed) return null;
|
|
36685
|
-
const abs = trimmed === "~" ? home : /^~[\/\\]/.test(trimmed) ?
|
|
36975
|
+
const abs = trimmed === "~" ? home : /^~[\/\\]/.test(trimmed) ? join29(home, trimmed.slice(2)) : isAbsolute5(trimmed) ? trimmed : resolve5(projectDir, trimmed);
|
|
36686
36976
|
try {
|
|
36687
36977
|
return resolveLocalFile(abs, roots);
|
|
36688
36978
|
} catch {
|
|
@@ -36740,7 +37030,7 @@ function localFileOpenCommand(path3, selected, options = {}) {
|
|
|
36740
37030
|
const exists = options.exists ?? existsSync11;
|
|
36741
37031
|
const localAppData = env.LOCALAPPDATA;
|
|
36742
37032
|
if (localAppData) {
|
|
36743
|
-
const exe2 =
|
|
37033
|
+
const exe2 = join29(localAppData, ...editor.exe);
|
|
36744
37034
|
if (exists(exe2)) return { command: exe2, args: [path3] };
|
|
36745
37035
|
}
|
|
36746
37036
|
if (/["%\r\n]/u.test(path3)) throw new Error(`cannot hand ${path3} to the ${editor.shim} shim through cmd.exe`);
|
|
@@ -37006,7 +37296,7 @@ var init_claude_model_upgrade = __esm({
|
|
|
37006
37296
|
// packages/server/src/frizz.ts
|
|
37007
37297
|
import { execFile as execFile6 } from "node:child_process";
|
|
37008
37298
|
import { lstatSync as lstatSync3, realpathSync as realpathSync8 } from "node:fs";
|
|
37009
|
-
import { basename as basename5, dirname as
|
|
37299
|
+
import { basename as basename5, dirname as dirname13, join as join30, resolve as resolve6 } from "node:path";
|
|
37010
37300
|
import { promisify as promisify5 } from "node:util";
|
|
37011
37301
|
function frizzScriptsDir() {
|
|
37012
37302
|
if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
|
|
@@ -37015,11 +37305,11 @@ function frizzScriptsDir() {
|
|
|
37015
37305
|
function directFrizzRoot(projectDir) {
|
|
37016
37306
|
try {
|
|
37017
37307
|
const projectRoot = realpathSync8(projectDir);
|
|
37018
|
-
const path3 =
|
|
37308
|
+
const path3 = join30(projectRoot, ".frizz");
|
|
37019
37309
|
const stat2 = lstatSync3(path3);
|
|
37020
37310
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
37021
37311
|
const real = realpathSync8(path3);
|
|
37022
|
-
return
|
|
37312
|
+
return dirname13(real) === projectRoot && basename5(real) === ".frizz" ? real : null;
|
|
37023
37313
|
} catch {
|
|
37024
37314
|
return null;
|
|
37025
37315
|
}
|
|
@@ -37029,7 +37319,7 @@ function frizzDirExists(projectDir) {
|
|
|
37029
37319
|
}
|
|
37030
37320
|
async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
37031
37321
|
if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
|
|
37032
|
-
const { stdout } = await execFileP("node", [
|
|
37322
|
+
const { stdout } = await execFileP("node", [join30(scriptsDir, "index.mjs"), "--json"], {
|
|
37033
37323
|
cwd: projectDir,
|
|
37034
37324
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
|
|
37035
37325
|
maxBuffer: 32 * 1024 * 1024
|
|
@@ -37054,7 +37344,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
|
37054
37344
|
};
|
|
37055
37345
|
}
|
|
37056
37346
|
async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
|
|
37057
|
-
await execFileP("node", [
|
|
37347
|
+
await execFileP("node", [join30(scriptsDir, "thread-update.mjs"), slug, ...args], {
|
|
37058
37348
|
cwd: projectDir,
|
|
37059
37349
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
|
|
37060
37350
|
});
|
|
@@ -37190,7 +37480,7 @@ var init_awaiting = __esm({
|
|
|
37190
37480
|
// packages/server/src/backend/project-mcp-servers.ts
|
|
37191
37481
|
import { readFileSync as readFileSync21 } from "node:fs";
|
|
37192
37482
|
import { homedir as homedir12 } from "node:os";
|
|
37193
|
-
import { join as
|
|
37483
|
+
import { join as join31 } from "node:path";
|
|
37194
37484
|
function readJsonObject(path3) {
|
|
37195
37485
|
try {
|
|
37196
37486
|
const parsed = JSON.parse(readFileSync21(path3, "utf8"));
|
|
@@ -37286,15 +37576,15 @@ function projectMcpServers(cwd, options = {}) {
|
|
|
37286
37576
|
const env = options.env ?? process.env;
|
|
37287
37577
|
const home = options.home ?? homedir12();
|
|
37288
37578
|
const configOverride = options.claudeConfigDir ?? (env.CLAUDE_CONFIG_DIR?.trim() ? env.CLAUDE_CONFIG_DIR.trim() : void 0);
|
|
37289
|
-
const accountFile = configOverride ?
|
|
37290
|
-
const userSettingsFile =
|
|
37579
|
+
const accountFile = configOverride ? join31(configOverride, ".claude.json") : join31(home, ".claude.json");
|
|
37580
|
+
const userSettingsFile = join31(configOverride ?? join31(home, ".claude"), "settings.json");
|
|
37291
37581
|
const account = readJsonObject(accountFile);
|
|
37292
37582
|
const out = userScopeRemoteServers(account, cwd, env);
|
|
37293
|
-
const declared = objectField(readJsonObject(
|
|
37583
|
+
const declared = objectField(readJsonObject(join31(cwd, ".mcp.json")), "mcpServers");
|
|
37294
37584
|
if (!declared) return out;
|
|
37295
37585
|
const approval = collectApproval([
|
|
37296
|
-
readJsonObject(
|
|
37297
|
-
readJsonObject(
|
|
37586
|
+
readJsonObject(join31(cwd, ".claude", "settings.json")),
|
|
37587
|
+
readJsonObject(join31(cwd, ".claude", "settings.local.json")),
|
|
37298
37588
|
readJsonObject(userSettingsFile),
|
|
37299
37589
|
objectField(objectField(account, "projects"), cwd)
|
|
37300
37590
|
]);
|
|
@@ -37319,17 +37609,17 @@ var init_project_mcp_servers = __esm({
|
|
|
37319
37609
|
|
|
37320
37610
|
// packages/server/src/worker-plugin-dir.ts
|
|
37321
37611
|
import { existsSync as existsSync12 } from "node:fs";
|
|
37322
|
-
import { dirname as
|
|
37612
|
+
import { dirname as dirname14, join as join32 } from "node:path";
|
|
37323
37613
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
37324
37614
|
function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
|
|
37325
37615
|
const override = env.FRIZZ_WORKER_PLUGIN_DIR;
|
|
37326
|
-
if (override && existsSync12(
|
|
37616
|
+
if (override && existsSync12(join32(override, ".claude-plugin", "plugin.json")))
|
|
37327
37617
|
return override;
|
|
37328
|
-
let current =
|
|
37618
|
+
let current = dirname14(fileURLToPath3(moduleUrl));
|
|
37329
37619
|
for (; ; ) {
|
|
37330
|
-
const candidate =
|
|
37331
|
-
if (existsSync12(
|
|
37332
|
-
const parent =
|
|
37620
|
+
const candidate = join32(current, "cc-worker");
|
|
37621
|
+
if (existsSync12(join32(candidate, ".claude-plugin", "plugin.json"))) return candidate;
|
|
37622
|
+
const parent = dirname14(current);
|
|
37333
37623
|
if (parent === current) return void 0;
|
|
37334
37624
|
current = parent;
|
|
37335
37625
|
}
|
|
@@ -38463,11 +38753,11 @@ checks. Depth scales with blast radius and yields to the project's conventions.`
|
|
|
38463
38753
|
});
|
|
38464
38754
|
|
|
38465
38755
|
// packages/server/src/backend/acp-agents.ts
|
|
38466
|
-
import { accessSync as accessSync3, constants as constants2, statSync as
|
|
38467
|
-
import { delimiter as delimiter2, isAbsolute as isAbsolute7, join as
|
|
38756
|
+
import { accessSync as accessSync3, constants as constants2, statSync as statSync15 } from "node:fs";
|
|
38757
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute7, join as join33 } from "node:path";
|
|
38468
38758
|
function isExecutableFile(path3) {
|
|
38469
38759
|
try {
|
|
38470
|
-
if (!
|
|
38760
|
+
if (!statSync15(path3).isFile()) return false;
|
|
38471
38761
|
if (process.platform !== "win32") accessSync3(path3, constants2.X_OK);
|
|
38472
38762
|
return true;
|
|
38473
38763
|
} catch {
|
|
@@ -38480,9 +38770,9 @@ function findOnPath(command, env = process.env) {
|
|
|
38480
38770
|
const exts = process.platform === "win32" ? ["", ...(env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")] : [""];
|
|
38481
38771
|
for (const dir of dirs) {
|
|
38482
38772
|
for (const ext of exts) {
|
|
38483
|
-
const candidate =
|
|
38773
|
+
const candidate = join33(dir, command + ext.toLowerCase());
|
|
38484
38774
|
if (isExecutableFile(candidate)) return candidate;
|
|
38485
|
-
if (ext && isExecutableFile(
|
|
38775
|
+
if (ext && isExecutableFile(join33(dir, command + ext))) return join33(dir, command + ext);
|
|
38486
38776
|
}
|
|
38487
38777
|
}
|
|
38488
38778
|
return void 0;
|
|
@@ -39499,9 +39789,9 @@ var init_claude_agent_broker_bridge = __esm({
|
|
|
39499
39789
|
});
|
|
39500
39790
|
|
|
39501
39791
|
// packages/server/src/dispatch.ts
|
|
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
|
|
39503
|
-
import { basename as basename6, join as
|
|
39504
|
-
import { createHash as
|
|
39792
|
+
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 statSync16, writeFileSync as writeFileSync13, mkdirSync as mkdirSync17, rmSync as rmSync10 } from "node:fs";
|
|
39793
|
+
import { basename as basename6, join as join34, dirname as dirname15 } from "node:path";
|
|
39794
|
+
import { createHash as createHash13, randomUUID as randomUUID13 } from "node:crypto";
|
|
39505
39795
|
function fallbackTitle(prompt) {
|
|
39506
39796
|
const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
|
|
39507
39797
|
let allWords = firstLine2.split(/\s+/).filter(Boolean);
|
|
@@ -39519,7 +39809,7 @@ function fallbackTitle(prompt) {
|
|
|
39519
39809
|
}
|
|
39520
39810
|
function resolveSlug(frizzDir, base, taken) {
|
|
39521
39811
|
base = ThreadSlug.parse(base);
|
|
39522
|
-
const isTaken = (slug) => existsSync13(
|
|
39812
|
+
const isTaken = (slug) => existsSync13(join34(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
|
|
39523
39813
|
if (!isTaken(base)) return base;
|
|
39524
39814
|
for (let n = 2; ; n++) {
|
|
39525
39815
|
const suffix = `-${n}`;
|
|
@@ -39536,16 +39826,16 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
39536
39826
|
if (!parsed.success) return null;
|
|
39537
39827
|
try {
|
|
39538
39828
|
const projectRoot = realpathSync9(projectDir);
|
|
39539
|
-
const frizzPath =
|
|
39829
|
+
const frizzPath = join34(projectRoot, ".frizz");
|
|
39540
39830
|
const frizzStat = lstatSync4(frizzPath);
|
|
39541
39831
|
if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
|
|
39542
39832
|
const realFrizz = realpathSync9(frizzPath);
|
|
39543
|
-
if (
|
|
39544
|
-
const path3 =
|
|
39833
|
+
if (dirname15(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
|
|
39834
|
+
const path3 = join34(realFrizz, `${parsed.data}.md`);
|
|
39545
39835
|
const before = lstatSync4(path3);
|
|
39546
39836
|
if (!before.isFile() || before.isSymbolicLink()) return null;
|
|
39547
39837
|
const realPath = realpathSync9(path3);
|
|
39548
|
-
if (
|
|
39838
|
+
if (dirname15(realPath) !== realFrizz || basename6(realPath) !== `${parsed.data}.md`) return null;
|
|
39549
39839
|
let contents;
|
|
39550
39840
|
let openedBefore;
|
|
39551
39841
|
let openedAfter;
|
|
@@ -39570,7 +39860,7 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
39570
39860
|
size: after.size,
|
|
39571
39861
|
mtimeMs: after.mtimeMs,
|
|
39572
39862
|
ctimeMs: after.ctimeMs,
|
|
39573
|
-
digest:
|
|
39863
|
+
digest: createHash13("sha256").update(contents).digest("hex")
|
|
39574
39864
|
};
|
|
39575
39865
|
} catch {
|
|
39576
39866
|
return null;
|
|
@@ -39585,9 +39875,9 @@ function boardAuthorizesAdoption(board, slug) {
|
|
|
39585
39875
|
return !board.errorItems.some((item) => item.file === `${slug}.md`);
|
|
39586
39876
|
}
|
|
39587
39877
|
function ensureSafeDirectDirectory(parent, name) {
|
|
39588
|
-
const path3 =
|
|
39878
|
+
const path3 = join34(parent, name);
|
|
39589
39879
|
try {
|
|
39590
|
-
|
|
39880
|
+
mkdirSync17(path3);
|
|
39591
39881
|
} catch (error) {
|
|
39592
39882
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
39593
39883
|
if (code !== "EEXIST") throw error;
|
|
@@ -39595,7 +39885,7 @@ function ensureSafeDirectDirectory(parent, name) {
|
|
|
39595
39885
|
const stat2 = lstatSync4(path3);
|
|
39596
39886
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("unsafe project directory");
|
|
39597
39887
|
const real = realpathSync9(path3);
|
|
39598
|
-
if (
|
|
39888
|
+
if (dirname15(real) !== parent || basename6(real) !== name) throw new Error("unsafe project directory");
|
|
39599
39889
|
return real;
|
|
39600
39890
|
}
|
|
39601
39891
|
function scratchDirRelPath(sessionId) {
|
|
@@ -39615,8 +39905,8 @@ function loadWorkerPrompt(kind = "claude") {
|
|
|
39615
39905
|
function monitorScriptsDir() {
|
|
39616
39906
|
const plugin = workerPluginDir();
|
|
39617
39907
|
if (!plugin) return void 0;
|
|
39618
|
-
const dir =
|
|
39619
|
-
return existsSync13(
|
|
39908
|
+
const dir = join34(plugin, "skills", "gh", "scripts");
|
|
39909
|
+
return existsSync13(join34(dir, "ci-watch.mjs")) ? dir : void 0;
|
|
39620
39910
|
}
|
|
39621
39911
|
function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
39622
39912
|
if (!hookScript || !sessionId) return {};
|
|
@@ -39628,7 +39918,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
39628
39918
|
}
|
|
39629
39919
|
]
|
|
39630
39920
|
});
|
|
39631
|
-
const bashBackgroundHook =
|
|
39921
|
+
const bashBackgroundHook = join34(dirname15(hookScript), "bash-background.mjs");
|
|
39632
39922
|
return {
|
|
39633
39923
|
bypass_hook_trust: true,
|
|
39634
39924
|
hooks: {
|
|
@@ -39654,7 +39944,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
39654
39944
|
}
|
|
39655
39945
|
function scratchpadHookScript() {
|
|
39656
39946
|
const plugin = workerPluginDir();
|
|
39657
|
-
return plugin ?
|
|
39947
|
+
return plugin ? join34(plugin, "hooks", "scratchpad.mjs") : void 0;
|
|
39658
39948
|
}
|
|
39659
39949
|
function composePrompt(sessionId, prompt, kind = "claude") {
|
|
39660
39950
|
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.";
|
|
@@ -39670,10 +39960,10 @@ function scratchpadOrientation(sessionId, kind = "claude") {
|
|
|
39670
39960
|
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.`;
|
|
39671
39961
|
}
|
|
39672
39962
|
function frizzConfigBlock(projectDir) {
|
|
39673
|
-
const path3 =
|
|
39963
|
+
const path3 = join34(projectDir, "FRIZZ.md");
|
|
39674
39964
|
let body;
|
|
39675
39965
|
try {
|
|
39676
|
-
const st2 =
|
|
39966
|
+
const st2 = statSync16(path3);
|
|
39677
39967
|
if (!st2.isFile() || st2.size > FRIZZ_MD_MAX_BYTES) return "";
|
|
39678
39968
|
body = readFileSync22(path3, "utf8").trim();
|
|
39679
39969
|
} catch {
|
|
@@ -39705,7 +39995,7 @@ function effectivePermissionMode(kind, mode) {
|
|
|
39705
39995
|
}
|
|
39706
39996
|
function systemPromptFlags(sessionId, system) {
|
|
39707
39997
|
if (!system) return [];
|
|
39708
|
-
|
|
39998
|
+
mkdirSync17(SYSTEM_PROMPT_DIR, { recursive: true });
|
|
39709
39999
|
const path3 = systemPromptPath(sessionId);
|
|
39710
40000
|
writeFileSync13(path3, system);
|
|
39711
40001
|
return ["--append-system-prompt-file", path3];
|
|
@@ -39714,7 +40004,7 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
|
|
|
39714
40004
|
const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
|
|
39715
40005
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
39716
40006
|
if (!pluginDir) return void 0;
|
|
39717
|
-
const scriptPath =
|
|
40007
|
+
const scriptPath = join34(pluginDir, "bin", FRIZZ_MCP.script);
|
|
39718
40008
|
if (!existsSync13(scriptPath)) return void 0;
|
|
39719
40009
|
return {
|
|
39720
40010
|
scriptPath,
|
|
@@ -39796,7 +40086,7 @@ function buildClaudeResumeCommand(opts) {
|
|
|
39796
40086
|
}
|
|
39797
40087
|
function createDispatcher(deps) {
|
|
39798
40088
|
const readBoardSource = deps.readBoard ?? readBoard;
|
|
39799
|
-
const frizzDir =
|
|
40089
|
+
const frizzDir = join34(deps.project.dir, ".frizz");
|
|
39800
40090
|
const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
|
|
39801
40091
|
function cleanupPrewrites(built) {
|
|
39802
40092
|
for (const path3 of new Set(built.prewrite.map((file) => file.path))) {
|
|
@@ -39809,7 +40099,7 @@ function createDispatcher(deps) {
|
|
|
39809
40099
|
function cleanupDispatchFiles(scratchRel, built, sessionId) {
|
|
39810
40100
|
cleanupPrewrites(built);
|
|
39811
40101
|
try {
|
|
39812
|
-
rmSync10(
|
|
40102
|
+
rmSync10(join34(deps.project.dir, scratchRel), { force: true, recursive: true });
|
|
39813
40103
|
} catch {
|
|
39814
40104
|
}
|
|
39815
40105
|
cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
|
|
@@ -40302,7 +40592,7 @@ import {
|
|
|
40302
40592
|
watch as fsWatch
|
|
40303
40593
|
} from "node:fs";
|
|
40304
40594
|
import { homedir as homedir14 } from "node:os";
|
|
40305
|
-
import { dirname as
|
|
40595
|
+
import { dirname as dirname16, join as join35 } from "node:path";
|
|
40306
40596
|
import watcher from "@parcel/watcher";
|
|
40307
40597
|
function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
|
|
40308
40598
|
if (!liveness) return false;
|
|
@@ -40351,7 +40641,7 @@ function registeredLegacyFileIsTerminal(projectDir, slug) {
|
|
|
40351
40641
|
return status === "done" || status === "dismissed";
|
|
40352
40642
|
}
|
|
40353
40643
|
function isBoardRelevantFrizzPath(roots, path3) {
|
|
40354
|
-
return path3.endsWith(".md") && roots.has(
|
|
40644
|
+
return path3.endsWith(".md") && roots.has(dirname16(path3));
|
|
40355
40645
|
}
|
|
40356
40646
|
function futureSnooze(row, nowMs) {
|
|
40357
40647
|
const parsed = SnoozeUntil.safeParse(row.snoozed_until);
|
|
@@ -41211,7 +41501,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
41211
41501
|
if (parcelSub || stopped) return Promise.resolve();
|
|
41212
41502
|
if (watchSetup) return watchSetup;
|
|
41213
41503
|
const setup = (async () => {
|
|
41214
|
-
const dir =
|
|
41504
|
+
const dir = join35(project.dir, ".frizz");
|
|
41215
41505
|
const roots = /* @__PURE__ */ new Set([dir]);
|
|
41216
41506
|
try {
|
|
41217
41507
|
roots.add(realpathSync10(dir));
|
|
@@ -41226,7 +41516,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
41226
41516
|
}
|
|
41227
41517
|
if (events.some((event) => isBoardRelevantFrizzPath(roots, event.path))) scheduleRebuild();
|
|
41228
41518
|
},
|
|
41229
|
-
{ ignore: FRIZZ_WATCH_IGNORED_DIRS.map((name) =>
|
|
41519
|
+
{ ignore: FRIZZ_WATCH_IGNORED_DIRS.map((name) => join35(dir, name)) }
|
|
41230
41520
|
);
|
|
41231
41521
|
if (stopped) {
|
|
41232
41522
|
await next.unsubscribe();
|
|
@@ -41332,6 +41622,100 @@ var init_board = __esm({
|
|
|
41332
41622
|
}
|
|
41333
41623
|
});
|
|
41334
41624
|
|
|
41625
|
+
// packages/server/src/session-peer.ts
|
|
41626
|
+
import { mkdirSync as mkdirSync18, readFileSync as readFileSync23, renameSync as renameSync8, writeFileSync as writeFileSync14 } from "node:fs";
|
|
41627
|
+
import { homedir as homedir15 } from "node:os";
|
|
41628
|
+
import { dirname as dirname17, join as join36 } from "node:path";
|
|
41629
|
+
function claudeSessionDirs(env = process.env, home = homedir15()) {
|
|
41630
|
+
const dirs = [join36(home, ".claude", "sessions")];
|
|
41631
|
+
const override = env.CLAUDE_CONFIG_DIR?.trim();
|
|
41632
|
+
if (override) dirs.unshift(join36(override, "sessions"));
|
|
41633
|
+
return [...new Set(dirs)];
|
|
41634
|
+
}
|
|
41635
|
+
function sessionIdForPeerSocket(peer, dirs) {
|
|
41636
|
+
const socket = peer.socket?.replace(/^uds:/, "");
|
|
41637
|
+
const pid = socket ? SOCKET_PID.exec(socket)?.[1] : void 0;
|
|
41638
|
+
if (!socket || !pid) return void 0;
|
|
41639
|
+
for (const dir of dirs) {
|
|
41640
|
+
let entry;
|
|
41641
|
+
try {
|
|
41642
|
+
entry = JSON.parse(readFileSync23(join36(dir, `${pid}.json`), "utf8"));
|
|
41643
|
+
} catch {
|
|
41644
|
+
continue;
|
|
41645
|
+
}
|
|
41646
|
+
if (entry.messagingSocketPath !== socket) continue;
|
|
41647
|
+
if (peer.name && typeof entry.name === "string" && entry.name !== peer.name) continue;
|
|
41648
|
+
if (typeof entry.sessionId === "string" && entry.sessionId) return entry.sessionId;
|
|
41649
|
+
}
|
|
41650
|
+
return void 0;
|
|
41651
|
+
}
|
|
41652
|
+
function createSessionPeerResolver(deps) {
|
|
41653
|
+
const sessionDirs = deps.sessionDirs ?? (() => claudeSessionDirs());
|
|
41654
|
+
let remembered;
|
|
41655
|
+
const load = () => {
|
|
41656
|
+
if (remembered) return remembered;
|
|
41657
|
+
remembered = {};
|
|
41658
|
+
if (deps.memoryFile) {
|
|
41659
|
+
try {
|
|
41660
|
+
const parsed = JSON.parse(readFileSync23(deps.memoryFile, "utf8"));
|
|
41661
|
+
if (parsed && typeof parsed === "object") {
|
|
41662
|
+
for (const [k10, v] of Object.entries(parsed)) if (typeof v === "string") remembered[k10] = v;
|
|
41663
|
+
}
|
|
41664
|
+
} catch {
|
|
41665
|
+
}
|
|
41666
|
+
}
|
|
41667
|
+
return remembered;
|
|
41668
|
+
};
|
|
41669
|
+
const remember = (key, sessionId) => {
|
|
41670
|
+
const all = load();
|
|
41671
|
+
if (all[key] === sessionId) return;
|
|
41672
|
+
all[key] = sessionId;
|
|
41673
|
+
if (!deps.memoryFile) return;
|
|
41674
|
+
try {
|
|
41675
|
+
mkdirSync18(dirname17(deps.memoryFile), { recursive: true });
|
|
41676
|
+
const tmp = `${deps.memoryFile}.${process.pid}.tmp`;
|
|
41677
|
+
writeFileSync14(tmp, JSON.stringify(all));
|
|
41678
|
+
renameSync8(tmp, deps.memoryFile);
|
|
41679
|
+
} catch {
|
|
41680
|
+
}
|
|
41681
|
+
};
|
|
41682
|
+
return (peer, receiverProjectId) => {
|
|
41683
|
+
if (!peer.socket) return void 0;
|
|
41684
|
+
const key = `${peer.socket}
|
|
41685
|
+
${peer.name ?? ""}`;
|
|
41686
|
+
const live = sessionIdForPeerSocket(peer, sessionDirs());
|
|
41687
|
+
if (live) remember(key, live);
|
|
41688
|
+
const sessionId = live ?? load()[key];
|
|
41689
|
+
const found = sessionId ? deps.findThread(sessionId) : void 0;
|
|
41690
|
+
if (!found) return void 0;
|
|
41691
|
+
const { projectId, project, ...thread } = found;
|
|
41692
|
+
return projectId === receiverProjectId || !project ? thread : { ...thread, project };
|
|
41693
|
+
};
|
|
41694
|
+
}
|
|
41695
|
+
function projectTranscriptSessionPeers(messages, resolve13) {
|
|
41696
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
41697
|
+
let changed = false;
|
|
41698
|
+
const out = messages.map((message) => {
|
|
41699
|
+
const peer = message.sessionPeer;
|
|
41700
|
+
if (!peer?.socket) return message;
|
|
41701
|
+
const key = `${peer.socket}
|
|
41702
|
+
${peer.name ?? ""}`;
|
|
41703
|
+
if (!cache2.has(key)) cache2.set(key, resolve13(peer));
|
|
41704
|
+
const thread = cache2.get(key);
|
|
41705
|
+
if (!thread) return message;
|
|
41706
|
+
changed = true;
|
|
41707
|
+
return { ...message, sessionPeer: { ...peer, thread } };
|
|
41708
|
+
});
|
|
41709
|
+
return changed ? out : messages;
|
|
41710
|
+
}
|
|
41711
|
+
var SOCKET_PID;
|
|
41712
|
+
var init_session_peer = __esm({
|
|
41713
|
+
"packages/server/src/session-peer.ts"() {
|
|
41714
|
+
"use strict";
|
|
41715
|
+
SOCKET_PID = /[\\/](\d+)\.sock$/;
|
|
41716
|
+
}
|
|
41717
|
+
});
|
|
41718
|
+
|
|
41335
41719
|
// packages/server/src/wake-store.ts
|
|
41336
41720
|
function isQuietWindowExempt(hintKey) {
|
|
41337
41721
|
return WAKE_QUIET_EXEMPT_HINT_PREFIXES.some((prefix) => hintKey.startsWith(prefix));
|
|
@@ -42209,7 +42593,7 @@ var init_pr_watch_noise = __esm({
|
|
|
42209
42593
|
// packages/server/src/scheduler.ts
|
|
42210
42594
|
import { execFile as execFile8 } from "node:child_process";
|
|
42211
42595
|
import { promisify as promisify7 } from "node:util";
|
|
42212
|
-
import { createHash as
|
|
42596
|
+
import { createHash as createHash14, randomUUID as randomUUID14 } from "node:crypto";
|
|
42213
42597
|
function failureSignature(rollup) {
|
|
42214
42598
|
const ids = [];
|
|
42215
42599
|
for (const c of Array.isArray(rollup) ? rollup : []) {
|
|
@@ -42219,7 +42603,7 @@ function failureSignature(rollup) {
|
|
|
42219
42603
|
ids.push(`${label}@${c.detailsUrl ?? c.targetUrl ?? c.completedAt ?? ""}`);
|
|
42220
42604
|
}
|
|
42221
42605
|
if (ids.length === 0) return "";
|
|
42222
|
-
return
|
|
42606
|
+
return createHash14("sha1").update(ids.sort().join("\n")).digest("hex").slice(0, 12);
|
|
42223
42607
|
}
|
|
42224
42608
|
function ghPrViewArgs(ref) {
|
|
42225
42609
|
return ["pr", "view", String(ref.number), "--repo", `${ref.owner}/${ref.repo}`, "--json", "state,mergedAt,statusCheckRollup,headRefOid,mergeable,reviewDecision"];
|
|
@@ -42307,7 +42691,7 @@ function githubWatchStatus(pr2, polledAt) {
|
|
|
42307
42691
|
};
|
|
42308
42692
|
}
|
|
42309
42693
|
function wakeDeliveryId(slug, sessionId, fenceId) {
|
|
42310
|
-
return
|
|
42694
|
+
return createHash14("sha256").update(slug).update("\0").update(sessionId).update("\0").update(fenceId).digest("hex");
|
|
42311
42695
|
}
|
|
42312
42696
|
function limitFenceId(fault) {
|
|
42313
42697
|
return `${LIMIT_FENCE_PREFIX}${fault.at}`;
|
|
@@ -42322,7 +42706,7 @@ function isReportFenceId(fenceId) {
|
|
|
42322
42706
|
return fenceId.startsWith(`${REPORT_FENCE_PREFIX}:`);
|
|
42323
42707
|
}
|
|
42324
42708
|
function snoozeFenceId(until, prompt) {
|
|
42325
|
-
const digest =
|
|
42709
|
+
const digest = createHash14("sha256").update(prompt).digest("hex").slice(0, 16);
|
|
42326
42710
|
return `${SNOOZE_FENCE_PREFIX}:${until}:${digest}`;
|
|
42327
42711
|
}
|
|
42328
42712
|
function isSnoozeFenceId(fenceId) {
|
|
@@ -42453,7 +42837,7 @@ function isOwnWatchExpiredFenceId(fenceId) {
|
|
|
42453
42837
|
return fenceId.startsWith(`${OWN_WATCH_EXPIRED_FENCE_PREFIX}:`);
|
|
42454
42838
|
}
|
|
42455
42839
|
function questionAnswerFenceId(ids) {
|
|
42456
|
-
return `${QUESTION_ANSWER_FENCE_PREFIX}:${
|
|
42840
|
+
return `${QUESTION_ANSWER_FENCE_PREFIX}:${createHash14("sha256").update([...ids].sort().join(",")).digest("hex").slice(0, 16)}`;
|
|
42457
42841
|
}
|
|
42458
42842
|
function isQuestionAnswerFenceId(fenceId) {
|
|
42459
42843
|
return fenceId.startsWith(`${QUESTION_ANSWER_FENCE_PREFIX}:`);
|
|
@@ -43440,8 +43824,8 @@ ${clock}`;
|
|
|
43440
43824
|
// replaces it re-derives that clause from a cursor the superseded report never got to advance.
|
|
43441
43825
|
...(() => {
|
|
43442
43826
|
const all = [...held?.changes ?? [], ...changes];
|
|
43443
|
-
const
|
|
43444
|
-
return
|
|
43827
|
+
const merged2 = [...new Set(all)];
|
|
43828
|
+
return merged2.length ? { changes: merged2 } : {};
|
|
43445
43829
|
})()
|
|
43446
43830
|
};
|
|
43447
43831
|
const review = carried.items.length > 0 ? formatGithubWakeSteer({ ref: key, items: carried.items, omitted: carried.omitted }) : void 0;
|
|
@@ -44343,7 +44727,7 @@ var init_resume = __esm({
|
|
|
44343
44727
|
});
|
|
44344
44728
|
|
|
44345
44729
|
// packages/server/src/backend/claude.ts
|
|
44346
|
-
import { join as
|
|
44730
|
+
import { join as join37 } from "node:path";
|
|
44347
44731
|
function toolResultText2(content) {
|
|
44348
44732
|
if (typeof content === "string") return content;
|
|
44349
44733
|
if (!Array.isArray(content)) return "";
|
|
@@ -44434,7 +44818,7 @@ function createClaudeBackend(opts) {
|
|
|
44434
44818
|
return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
|
|
44435
44819
|
},
|
|
44436
44820
|
transcriptPath(sessionId) {
|
|
44437
|
-
return
|
|
44821
|
+
return join37(opts.logDir, `${sessionId}.jsonl`);
|
|
44438
44822
|
},
|
|
44439
44823
|
parseLine(line) {
|
|
44440
44824
|
return parseClaudeLine(line);
|
|
@@ -44459,10 +44843,10 @@ var init_claude = __esm({
|
|
|
44459
44843
|
});
|
|
44460
44844
|
|
|
44461
44845
|
// packages/server/src/backend/acp-transcript.ts
|
|
44462
|
-
import { appendFileSync as
|
|
44463
|
-
import { dirname as
|
|
44846
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync15, mkdirSync as mkdirSync19, readFileSync as readFileSync24 } from "node:fs";
|
|
44847
|
+
import { dirname as dirname18, join as join38 } from "node:path";
|
|
44464
44848
|
function acpTranscriptPath(stateDir, sessionId) {
|
|
44465
|
-
return
|
|
44849
|
+
return join38(stateDir, ACP_TRANSCRIPT_DIR, `${sessionId}.jsonl`);
|
|
44466
44850
|
}
|
|
44467
44851
|
function parseAcpRecord(line) {
|
|
44468
44852
|
if (!line.trim()) return void 0;
|
|
@@ -44663,11 +45047,11 @@ var init_acp_transcript = __esm({
|
|
|
44663
45047
|
AcpTranscriptWriter = class {
|
|
44664
45048
|
constructor(path3) {
|
|
44665
45049
|
this.path = path3;
|
|
44666
|
-
|
|
44667
|
-
if (!existsSync15(path3))
|
|
45050
|
+
mkdirSync19(dirname18(path3), { recursive: true });
|
|
45051
|
+
if (!existsSync15(path3)) appendFileSync4(path3, "");
|
|
44668
45052
|
}
|
|
44669
45053
|
append(record) {
|
|
44670
|
-
|
|
45054
|
+
appendFileSync4(this.path, JSON.stringify(record) + "\n");
|
|
44671
45055
|
}
|
|
44672
45056
|
};
|
|
44673
45057
|
TOOL_TEXT_MAX = 12e3;
|
|
@@ -45050,19 +45434,19 @@ var init_acp_rpc = __esm({
|
|
|
45050
45434
|
// packages/server/src/backend/acp-host.ts
|
|
45051
45435
|
import { spawn as spawn7 } from "node:child_process";
|
|
45052
45436
|
import { createConnection as createConnection2 } from "node:net";
|
|
45053
|
-
import { createHash as
|
|
45054
|
-
import { existsSync as existsSync16, mkdirSync as
|
|
45055
|
-
import { join as
|
|
45437
|
+
import { createHash as createHash15, randomUUID as randomUUID15 } from "node:crypto";
|
|
45438
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync20, readFileSync as readFileSync25, readdirSync as readdirSync9, unlinkSync as unlinkSync4 } from "node:fs";
|
|
45439
|
+
import { join as join39 } from "node:path";
|
|
45056
45440
|
import { PassThrough as PassThrough3, Writable as Writable3 } from "node:stream";
|
|
45057
45441
|
import { StringDecoder as StringDecoder5 } from "node:string_decoder";
|
|
45058
45442
|
function daemonDir2(stateDir) {
|
|
45059
|
-
return
|
|
45443
|
+
return join39(stateDir, "acp-daemon");
|
|
45060
45444
|
}
|
|
45061
45445
|
function acpDaemonRecordPath(stateDir, sessionId) {
|
|
45062
|
-
return
|
|
45446
|
+
return join39(daemonDir2(stateDir), `${sessionId}.json`);
|
|
45063
45447
|
}
|
|
45064
45448
|
function acpDaemonSocketPath(stateDir, sessionId) {
|
|
45065
|
-
const key =
|
|
45449
|
+
const key = createHash15("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
|
|
45066
45450
|
return frizzIpcPath(`frizz-acp-${key}`);
|
|
45067
45451
|
}
|
|
45068
45452
|
function pidAlive4(pid) {
|
|
@@ -45075,7 +45459,7 @@ function pidAlive4(pid) {
|
|
|
45075
45459
|
}
|
|
45076
45460
|
function readAcpDaemonRecord(stateDir, sessionId) {
|
|
45077
45461
|
try {
|
|
45078
|
-
const value = JSON.parse(
|
|
45462
|
+
const value = JSON.parse(readFileSync25(acpDaemonRecordPath(stateDir, sessionId), "utf8"));
|
|
45079
45463
|
if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
45080
45464
|
return {
|
|
45081
45465
|
threadSlug: typeof value.threadSlug === "string" ? value.threadSlug : "",
|
|
@@ -45121,7 +45505,7 @@ async function stopAcpDaemon(stateDir, sessionId, timeoutMs = 1e4) {
|
|
|
45121
45505
|
}
|
|
45122
45506
|
function forkDaemon2(options) {
|
|
45123
45507
|
const { stateDir, sessionId } = options;
|
|
45124
|
-
|
|
45508
|
+
mkdirSync20(daemonDir2(stateDir), { recursive: true });
|
|
45125
45509
|
const record = acpDaemonRecordPath(stateDir, sessionId);
|
|
45126
45510
|
try {
|
|
45127
45511
|
unlinkSync4(record);
|
|
@@ -72151,27 +72535,27 @@ var init_claude_models = __esm({
|
|
|
72151
72535
|
});
|
|
72152
72536
|
|
|
72153
72537
|
// packages/server/src/backend/codex-app-server-diagnostics.ts
|
|
72154
|
-
import { appendFileSync as
|
|
72155
|
-
import { join as
|
|
72538
|
+
import { appendFileSync as appendFileSync6, mkdirSync as mkdirSync22, renameSync as renameSync10, statSync as statSync18 } from "node:fs";
|
|
72539
|
+
import { join as join41 } from "node:path";
|
|
72156
72540
|
function codexDiagnosticLogPath(stateDir, projectId) {
|
|
72157
|
-
return
|
|
72541
|
+
return join41(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
|
|
72158
72542
|
}
|
|
72159
72543
|
function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
|
|
72160
|
-
const dir =
|
|
72544
|
+
const dir = join41(stateDir, "codex-app-server");
|
|
72161
72545
|
const path3 = codexDiagnosticLogPath(stateDir, projectId);
|
|
72162
72546
|
let ensured = false;
|
|
72163
72547
|
return (event) => {
|
|
72164
72548
|
if (event.event === "stderr") return;
|
|
72165
72549
|
try {
|
|
72166
72550
|
if (!ensured) {
|
|
72167
|
-
|
|
72551
|
+
mkdirSync22(dir, { recursive: true });
|
|
72168
72552
|
ensured = true;
|
|
72169
72553
|
}
|
|
72170
72554
|
try {
|
|
72171
|
-
if (
|
|
72555
|
+
if (statSync18(path3).size > MAX_BYTES2) renameSync10(path3, `${path3}.1`);
|
|
72172
72556
|
} catch {
|
|
72173
72557
|
}
|
|
72174
|
-
|
|
72558
|
+
appendFileSync6(path3, `${JSON.stringify({ at: now().toISOString(), ...event })}
|
|
72175
72559
|
`);
|
|
72176
72560
|
} catch {
|
|
72177
72561
|
}
|
|
@@ -72189,7 +72573,7 @@ var init_codex_app_server_diagnostics = __esm({
|
|
|
72189
72573
|
import { execFile as execFile9 } from "node:child_process";
|
|
72190
72574
|
import { readdirSync as readdirSync11, unlinkSync as unlinkSync6 } from "node:fs";
|
|
72191
72575
|
import { connect as connectSocket } from "node:net";
|
|
72192
|
-
import { join as
|
|
72576
|
+
import { join as join42 } from "node:path";
|
|
72193
72577
|
function parseLsofSocketNames(stdout) {
|
|
72194
72578
|
const referenced = /* @__PURE__ */ new Set();
|
|
72195
72579
|
for (const line of stdout.split("\n")) {
|
|
@@ -72206,7 +72590,7 @@ function sweepStaleSockets(options, deps = {}) {
|
|
|
72206
72590
|
const keep = new Set(options.keep ?? []);
|
|
72207
72591
|
let candidates;
|
|
72208
72592
|
try {
|
|
72209
|
-
candidates = (deps.readdir ?? readdirSync11)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) =>
|
|
72593
|
+
candidates = (deps.readdir ?? readdirSync11)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join42(options.dir, name)).filter((path3) => !keep.has(path3));
|
|
72210
72594
|
} catch {
|
|
72211
72595
|
return;
|
|
72212
72596
|
}
|
|
@@ -72256,8 +72640,8 @@ var init_stale_socket_sweep = __esm({
|
|
|
72256
72640
|
|
|
72257
72641
|
// packages/server/src/orphan-reaper.ts
|
|
72258
72642
|
import { execFile as execFile10 } from "node:child_process";
|
|
72259
|
-
import { readFileSync as
|
|
72260
|
-
import { dirname as
|
|
72643
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
72644
|
+
import { dirname as dirname20 } from "node:path";
|
|
72261
72645
|
import { promisify as promisify8 } from "node:util";
|
|
72262
72646
|
function firstTokenBasename(command) {
|
|
72263
72647
|
const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
|
|
@@ -72486,7 +72870,7 @@ async function sweepOrphansOnce(deps = {}) {
|
|
|
72486
72870
|
}
|
|
72487
72871
|
function sweepStaleBrokerSockets() {
|
|
72488
72872
|
try {
|
|
72489
|
-
sweepStaleSockets({ dir:
|
|
72873
|
+
sweepStaleSockets({ dir: dirname20(claudeBrokerSocketPath("", "")), prefix: CLAUDE_BROKER_SOCKET_PREFIX });
|
|
72490
72874
|
} catch {
|
|
72491
72875
|
}
|
|
72492
72876
|
}
|
|
@@ -72563,7 +72947,7 @@ var init_orphan_reaper = __esm({
|
|
|
72563
72947
|
defaultExec = async (file, args) => (await execFileAsync6(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout;
|
|
72564
72948
|
defaultReadEnv = (pid) => {
|
|
72565
72949
|
try {
|
|
72566
|
-
return
|
|
72950
|
+
return readFileSync27(`/proc/${pid}/environ`, "utf8");
|
|
72567
72951
|
} catch {
|
|
72568
72952
|
return null;
|
|
72569
72953
|
}
|
|
@@ -72583,9 +72967,9 @@ var init_orphan_reaper = __esm({
|
|
|
72583
72967
|
});
|
|
72584
72968
|
|
|
72585
72969
|
// packages/server/src/context.ts
|
|
72586
|
-
import { join as
|
|
72970
|
+
import { join as join43 } from "node:path";
|
|
72587
72971
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
72588
|
-
import { homedir as
|
|
72972
|
+
import { homedir as homedir16 } from "node:os";
|
|
72589
72973
|
function reconcileSessions(storage) {
|
|
72590
72974
|
for (const row of storage.allSessions()) {
|
|
72591
72975
|
if (isHeadlessRow(row)) continue;
|
|
@@ -72733,9 +73117,9 @@ async function createContext(opts = {}) {
|
|
|
72733
73117
|
}
|
|
72734
73118
|
}
|
|
72735
73119
|
function createContextUnchecked(opts, resources) {
|
|
72736
|
-
const home = opts.home ??
|
|
73120
|
+
const home = opts.home ?? homedir16();
|
|
72737
73121
|
const project = opts.project ?? resolveProject();
|
|
72738
|
-
const storage = createStorage(opts.database ??
|
|
73122
|
+
const storage = createStorage(opts.database ?? join43(project.stateDir, "ui.db"), project.id);
|
|
72739
73123
|
resources.storage = storage;
|
|
72740
73124
|
clearSecrets(project.stateDir);
|
|
72741
73125
|
const bus = new Bus();
|
|
@@ -72950,10 +73334,30 @@ function createContextUnchecked(opts, resources) {
|
|
|
72950
73334
|
}
|
|
72951
73335
|
void claudeBroker?.warmUp();
|
|
72952
73336
|
opts.startup?.afterPhase?.("Claude broker bridge");
|
|
73337
|
+
const sessionPeerResolver = createSessionPeerResolver({
|
|
73338
|
+
findThread: (sessionId) => {
|
|
73339
|
+
const open = [{ project, storage }, ...(opts.activeTenants?.() ?? []).filter((t) => t.project.id !== project.id)];
|
|
73340
|
+
for (const tenant of open) {
|
|
73341
|
+
const rows = tenant.storage?.allSessions() ?? [];
|
|
73342
|
+
const row = rows.find((r) => r.session_id === sessionId || r.agent_session_id === sessionId || r.transcript_id === sessionId);
|
|
73343
|
+
if (!row) continue;
|
|
73344
|
+
const shown = resolveSessionTitle(row, void 0);
|
|
73345
|
+
return {
|
|
73346
|
+
projectId: tenant.project.id,
|
|
73347
|
+
project: findById(tenant.project.id, home)?.slug,
|
|
73348
|
+
slug: row.slug,
|
|
73349
|
+
title: shown.aiTitle || shown.title || row.slug
|
|
73350
|
+
};
|
|
73351
|
+
}
|
|
73352
|
+
return void 0;
|
|
73353
|
+
},
|
|
73354
|
+
memoryFile: join43(frizzRoots().state, "session-peers.json")
|
|
73355
|
+
});
|
|
72953
73356
|
const tailer = createTailer({
|
|
72954
73357
|
project,
|
|
72955
73358
|
storage,
|
|
72956
73359
|
bus,
|
|
73360
|
+
onCrossSessionMessage: (peer) => void sessionPeerResolver(peer, project.id),
|
|
72957
73361
|
backendFor,
|
|
72958
73362
|
codexModels: () => readCodexModels(void 0, opts.codexVersion),
|
|
72959
73363
|
onChange: () => board.refresh(),
|
|
@@ -73138,8 +73542,12 @@ ${wakeDeliveryToken(deliveryId)}`;
|
|
|
73138
73542
|
getDispatchPreferences: (codexModels) => getDispatchPreferences(storage, getSettings(storage, home), home, codexModels),
|
|
73139
73543
|
setDispatchPreference: (update, codexModels) => setDispatchPreference(storage, getSettings(storage, home), home, update, codexModels),
|
|
73140
73544
|
activeTenants: opts.activeTenants,
|
|
73545
|
+
sessionPeerThread: (peer) => sessionPeerResolver(peer, project.id),
|
|
73141
73546
|
teardownProject: opts.teardownProject,
|
|
73142
73547
|
launchProjectId: opts.launchProjectId,
|
|
73548
|
+
// Derived from the state dir, never from `homedir()`, so a sandboxed server audits into its own
|
|
73549
|
+
// sandbox (the reason serverAddressPathForStateDir exists).
|
|
73550
|
+
audit: fileAuditLog(auditLogPathForStateDir(project.stateDir)),
|
|
73143
73551
|
claudeBin: opts.claudeBin,
|
|
73144
73552
|
codexBin: opts.codexBin,
|
|
73145
73553
|
codexVersion: opts.codexVersion
|
|
@@ -73151,6 +73559,8 @@ var init_context = __esm({
|
|
|
73151
73559
|
"use strict";
|
|
73152
73560
|
init_src();
|
|
73153
73561
|
init_bus();
|
|
73562
|
+
init_frizz_paths();
|
|
73563
|
+
init_project_registry();
|
|
73154
73564
|
init_project();
|
|
73155
73565
|
init_storage();
|
|
73156
73566
|
init_secret_files();
|
|
@@ -73159,6 +73569,8 @@ var init_context = __esm({
|
|
|
73159
73569
|
init_quota();
|
|
73160
73570
|
init_claude_quota();
|
|
73161
73571
|
init_board();
|
|
73572
|
+
init_session_peer();
|
|
73573
|
+
init_audit();
|
|
73162
73574
|
init_tailer();
|
|
73163
73575
|
init_dispatch();
|
|
73164
73576
|
init_scheduler();
|
|
@@ -75849,8 +76261,8 @@ var init_server = __esm({
|
|
|
75849
76261
|
});
|
|
75850
76262
|
|
|
75851
76263
|
// packages/server/src/repair.ts
|
|
75852
|
-
import { existsSync as existsSync18, readFileSync as
|
|
75853
|
-
import { basename as basename7, dirname as
|
|
76264
|
+
import { existsSync as existsSync18, readFileSync as readFileSync28, writeFileSync as writeFileSync15 } from "node:fs";
|
|
76265
|
+
import { basename as basename7, dirname as dirname21, resolve as resolve9 } from "node:path";
|
|
75854
76266
|
function quoteValue(v) {
|
|
75855
76267
|
if (/^[\w./#:+-]+$/.test(v)) return v;
|
|
75856
76268
|
return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -75862,10 +76274,10 @@ function deriveTitle(body, slug) {
|
|
|
75862
76274
|
function repairThreadFile(frizzDir, file) {
|
|
75863
76275
|
const root = resolve9(frizzDir);
|
|
75864
76276
|
const abs = resolve9(root, file);
|
|
75865
|
-
if (
|
|
76277
|
+
if (dirname21(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
|
|
75866
76278
|
if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
|
|
75867
76279
|
if (!existsSync18(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
|
|
75868
|
-
const content =
|
|
76280
|
+
const content = readFileSync28(abs, "utf8");
|
|
75869
76281
|
const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
|
|
75870
76282
|
if (firstLine2?.trim() === "---") {
|
|
75871
76283
|
throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
|
|
@@ -75880,7 +76292,7 @@ function repairThreadFile(frizzDir, file) {
|
|
|
75880
76292
|
"---",
|
|
75881
76293
|
""
|
|
75882
76294
|
].join("\n");
|
|
75883
|
-
|
|
76295
|
+
writeFileSync15(abs, frontmatter + content);
|
|
75884
76296
|
return { slug };
|
|
75885
76297
|
}
|
|
75886
76298
|
var RepairError, REPAIR_STATUS_TEXT;
|
|
@@ -76093,7 +76505,7 @@ var init_repo_files = __esm({
|
|
|
76093
76505
|
});
|
|
76094
76506
|
|
|
76095
76507
|
// cc-worker/hooks/bash-background.mjs
|
|
76096
|
-
import { readFileSync as
|
|
76508
|
+
import { readFileSync as readFileSync29, realpathSync as realpathSync12 } from "node:fs";
|
|
76097
76509
|
import { basename as basename8 } from "node:path";
|
|
76098
76510
|
import { fileURLToPath as fileURLToPath4, pathToFileURL } from "node:url";
|
|
76099
76511
|
function emit(obj) {
|
|
@@ -76248,7 +76660,7 @@ var init_bash_background = __esm({
|
|
|
76248
76660
|
if (isDirectHookExecution(process.argv[1], import.meta.url)) {
|
|
76249
76661
|
try {
|
|
76250
76662
|
const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
|
|
76251
|
-
emit(evaluateBashBackgroundHook(JSON.parse(
|
|
76663
|
+
emit(evaluateBashBackgroundHook(JSON.parse(readFileSync29(0, "utf8")), env));
|
|
76252
76664
|
} catch {
|
|
76253
76665
|
emit({});
|
|
76254
76666
|
}
|
|
@@ -76257,11 +76669,11 @@ var init_bash_background = __esm({
|
|
|
76257
76669
|
});
|
|
76258
76670
|
|
|
76259
76671
|
// packages/server/src/transcript.ts
|
|
76260
|
-
import { closeSync as closeSync15, existsSync as existsSync19, fstatSync as fstatSync3, mkdirSync as
|
|
76261
|
-
import { createHash as
|
|
76672
|
+
import { closeSync as closeSync15, existsSync as existsSync19, fstatSync as fstatSync3, mkdirSync as mkdirSync23, openSync as openSync16, readdirSync as readdirSync12, readFileSync as readFileSync30, readSync as readSync8, renameSync as renameSync11, statSync as statSync19, unlinkSync as unlinkSync7, writeFileSync as writeFileSync16 } from "node:fs";
|
|
76673
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
76262
76674
|
import { StringDecoder as StringDecoder6 } from "node:string_decoder";
|
|
76263
|
-
import { join as
|
|
76264
|
-
import { homedir as
|
|
76675
|
+
import { join as join44 } from "node:path";
|
|
76676
|
+
import { homedir as homedir17 } from "node:os";
|
|
76265
76677
|
function formatTokens(n) {
|
|
76266
76678
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
76267
76679
|
if (n >= 1e3) return `${Math.round(n / 1e3)}k`;
|
|
@@ -76317,7 +76729,12 @@ function userDisplayText(text2, first) {
|
|
|
76317
76729
|
projected = stripWakeTrailer(projected);
|
|
76318
76730
|
return projected === text2 ? void 0 : projected;
|
|
76319
76731
|
}
|
|
76732
|
+
function sessionPeerOf(session) {
|
|
76733
|
+
return { ...session.name ? { name: session.name } : {}, ...session.socket ? { socket: session.socket } : {} };
|
|
76734
|
+
}
|
|
76320
76735
|
function userProjection(text2, first) {
|
|
76736
|
+
const session = parseCrossSessionMessage(text2);
|
|
76737
|
+
if (session) return { displayText: session.body, sessionPeer: sessionPeerOf(session) };
|
|
76321
76738
|
const peer = parseAgentMessage(text2);
|
|
76322
76739
|
if (peer) return { displayText: peer.body, peerFrom: peer.from };
|
|
76323
76740
|
const displayText2 = userDisplayText(text2, first);
|
|
@@ -76478,6 +76895,15 @@ function createTranscriptFold(identityPrefix = "claude") {
|
|
|
76478
76895
|
function findQueued(key) {
|
|
76479
76896
|
return queuedPending.find((e14) => e14.key === key && e14.message.queued) ?? queuedPending.find((e14) => e14.key === key);
|
|
76480
76897
|
}
|
|
76898
|
+
function findCrossSessionQueued(text2) {
|
|
76899
|
+
const sent = parseCrossSessionMessage(text2);
|
|
76900
|
+
if (!sent) return void 0;
|
|
76901
|
+
const same = (e14) => {
|
|
76902
|
+
const queued = e14.message.sessionPeer ? parseCrossSessionMessage(e14.key) : void 0;
|
|
76903
|
+
return !!queued && queued.body === sent.body && queued.name === sent.name && queued.socket === sent.socket;
|
|
76904
|
+
};
|
|
76905
|
+
return queuedPending.find((e14) => e14.message.queued && same(e14)) ?? queuedPending.find(same);
|
|
76906
|
+
}
|
|
76481
76907
|
function dropQueued(entry) {
|
|
76482
76908
|
const i = queuedPending.indexOf(entry);
|
|
76483
76909
|
if (i !== -1) queuedPending.splice(i, 1);
|
|
@@ -76573,9 +76999,9 @@ function createTranscriptFold(identityPrefix = "claude") {
|
|
|
76573
76999
|
const str2 = (v) => typeof v === "string" ? v.trim() : "";
|
|
76574
77000
|
const senderTaskId = str2(peerOrigin.senderTaskId);
|
|
76575
77001
|
const dispatchId = senderTaskId ? childDispatchIds.get(senderTaskId) : void 0;
|
|
76576
|
-
const entry = prompt.trim() ? findQueued(prompt) : void 0;
|
|
77002
|
+
const entry = prompt.trim() ? findQueued(prompt) ?? findCrossSessionQueued(prompt) : void 0;
|
|
76577
77003
|
if (entry) {
|
|
76578
|
-
resolveQueued(
|
|
77004
|
+
resolveQueued(entry.key);
|
|
76579
77005
|
if (dispatchId && entry.message.peerFrom) entry.message.peerDispatchId = dispatchId;
|
|
76580
77006
|
const described = dispatchId ? dispatchLabels.get(dispatchId) : void 0;
|
|
76581
77007
|
if (entry.message.peerFrom) {
|
|
@@ -76584,6 +77010,9 @@ function createTranscriptFold(identityPrefix = "claude") {
|
|
|
76584
77010
|
if (senderTaskId) entry.message.peerSenderTaskId = senderTaskId;
|
|
76585
77011
|
}
|
|
76586
77012
|
lastAssistantId = null;
|
|
77013
|
+
} else if (prompt.trim() && parseCrossSessionMessage(prompt)) {
|
|
77014
|
+
out.push({ sourceId, role: "user", text: prompt, ...userProjection(prompt, out.length === 0), tools: [], parts: [], at: thisTs });
|
|
77015
|
+
lastAssistantId = null;
|
|
76587
77016
|
} else {
|
|
76588
77017
|
const parsed = prompt.trim() ? parseAgentMessage(prompt) : void 0;
|
|
76589
77018
|
const describedHere = dispatchId ? dispatchLabels.get(dispatchId) : void 0;
|
|
@@ -76619,7 +77048,16 @@ function createTranscriptFold(identityPrefix = "claude") {
|
|
|
76619
77048
|
const metaText = userText(rec);
|
|
76620
77049
|
if (metaText) {
|
|
76621
77050
|
const key = findQueued(metaText) ? metaText : peerSessionQueuedKey(metaText, unresolvedQueuedKeys());
|
|
76622
|
-
const pending = key === void 0 ? void 0 : findQueued(key);
|
|
77051
|
+
const pending = (key === void 0 ? void 0 : findQueued(key)) ?? findCrossSessionQueued(metaText);
|
|
77052
|
+
if (rec.isSidechain !== true && parseCrossSessionMessage(metaText)) {
|
|
77053
|
+
if (pending) {
|
|
77054
|
+
resolveQueued(pending.key);
|
|
77055
|
+
} else {
|
|
77056
|
+
out.push({ sourceId, role: "user", text: metaText, ...userProjection(metaText, out.length === 0), tools: [], parts: [], at: rec.timestamp });
|
|
77057
|
+
}
|
|
77058
|
+
lastAssistantId = null;
|
|
77059
|
+
return;
|
|
77060
|
+
}
|
|
76623
77061
|
if (pending) {
|
|
76624
77062
|
resolveQueuedThrough(pending);
|
|
76625
77063
|
dropQueued(pending);
|
|
@@ -76868,14 +77306,14 @@ function pruneScreenshotCache() {
|
|
|
76868
77306
|
if (entries2.length <= SCREENSHOT_CACHE_MAX) return;
|
|
76869
77307
|
const byMtime = entries2.map((n) => {
|
|
76870
77308
|
try {
|
|
76871
|
-
return { n, m:
|
|
77309
|
+
return { n, m: statSync19(join44(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
|
|
76872
77310
|
} catch {
|
|
76873
77311
|
return { n, m: 0 };
|
|
76874
77312
|
}
|
|
76875
77313
|
}).sort((a, b) => b.m - a.m);
|
|
76876
77314
|
for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
|
|
76877
77315
|
try {
|
|
76878
|
-
unlinkSync7(
|
|
77316
|
+
unlinkSync7(join44(SCREENSHOT_CACHE_DIR, n));
|
|
76879
77317
|
} catch {
|
|
76880
77318
|
}
|
|
76881
77319
|
}
|
|
@@ -76904,17 +77342,17 @@ function persistDataUrlImage(dataUrl, idKey) {
|
|
|
76904
77342
|
function persistBase64Image(mediaType, data, idKey) {
|
|
76905
77343
|
const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
|
|
76906
77344
|
if (!ext || !data) return void 0;
|
|
76907
|
-
const name =
|
|
76908
|
-
const path3 =
|
|
77345
|
+
const name = createHash16("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
77346
|
+
const path3 = join44(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
|
|
76909
77347
|
try {
|
|
76910
77348
|
if (existsSync19(path3)) return path3;
|
|
76911
77349
|
if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
|
|
76912
77350
|
const buf = Buffer.from(data, "base64");
|
|
76913
77351
|
if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
|
|
76914
|
-
|
|
76915
|
-
const tmp =
|
|
76916
|
-
|
|
76917
|
-
|
|
77352
|
+
mkdirSync23(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
77353
|
+
const tmp = join44(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
77354
|
+
writeFileSync16(tmp, buf);
|
|
77355
|
+
renameSync11(tmp, path3);
|
|
76918
77356
|
pruneScreenshotCache();
|
|
76919
77357
|
return path3;
|
|
76920
77358
|
} catch {
|
|
@@ -76926,17 +77364,17 @@ function persistSentFile(srcPath, idKey) {
|
|
|
76926
77364
|
if (!ATTACHMENT_IMAGE_EXTENSIONS.includes(ext)) return void 0;
|
|
76927
77365
|
const outExt = ext === "jpeg" ? "jpg" : ext;
|
|
76928
77366
|
try {
|
|
76929
|
-
const name =
|
|
76930
|
-
const dest =
|
|
77367
|
+
const name = createHash16("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
77368
|
+
const dest = join44(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
|
|
76931
77369
|
if (existsSync19(dest)) return dest;
|
|
76932
|
-
const size =
|
|
77370
|
+
const size = statSync19(srcPath).size;
|
|
76933
77371
|
if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
|
|
76934
|
-
const buf =
|
|
77372
|
+
const buf = readFileSync30(srcPath);
|
|
76935
77373
|
if (!looksLikeImage(buf, outExt)) return void 0;
|
|
76936
|
-
|
|
76937
|
-
const tmp =
|
|
76938
|
-
|
|
76939
|
-
|
|
77374
|
+
mkdirSync23(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
77375
|
+
const tmp = join44(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
77376
|
+
writeFileSync16(tmp, buf);
|
|
77377
|
+
renameSync11(tmp, dest);
|
|
76940
77378
|
pruneScreenshotCache();
|
|
76941
77379
|
return dest;
|
|
76942
77380
|
} catch {
|
|
@@ -77372,7 +77810,7 @@ function readTranscript(project, sessionId) {
|
|
|
77372
77810
|
}
|
|
77373
77811
|
function verifyIncrementalParse(path3, identityPrefix, incremental) {
|
|
77374
77812
|
try {
|
|
77375
|
-
const fresh = parseTranscript(
|
|
77813
|
+
const fresh = parseTranscript(readFileSync30(path3, "utf8"), identityPrefix);
|
|
77376
77814
|
const a = JSON.stringify(incremental);
|
|
77377
77815
|
const b = JSON.stringify(fresh);
|
|
77378
77816
|
if (a !== b) {
|
|
@@ -77392,16 +77830,16 @@ function verifyIncrementalParse(path3, identityPrefix, incremental) {
|
|
|
77392
77830
|
}
|
|
77393
77831
|
}
|
|
77394
77832
|
function logDirOf(project) {
|
|
77395
|
-
return
|
|
77833
|
+
return join44(homedir17(), ".claude", "projects", project.cwdSlug);
|
|
77396
77834
|
}
|
|
77397
77835
|
function resolveTranscriptPath(project, sessionId) {
|
|
77398
|
-
const path3 =
|
|
77836
|
+
const path3 = join44(logDirOf(project), `${sessionId}.jsonl`);
|
|
77399
77837
|
try {
|
|
77400
|
-
if (
|
|
77838
|
+
if (statSync19(path3).size > 0) return path3;
|
|
77401
77839
|
} catch {
|
|
77402
77840
|
}
|
|
77403
77841
|
const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
|
|
77404
|
-
return stranded ?
|
|
77842
|
+
return stranded ? join44(stranded, `${sessionId}.jsonl`) : path3;
|
|
77405
77843
|
}
|
|
77406
77844
|
function projectCodexTranscript(raw2, identityPrefix = "codex") {
|
|
77407
77845
|
const out = [];
|
|
@@ -77711,7 +78149,7 @@ function countBoundedStart(messages) {
|
|
|
77711
78149
|
let boundary = -1;
|
|
77712
78150
|
for (let i = tail - 1; i >= 0; i--) {
|
|
77713
78151
|
const m = messages[i];
|
|
77714
|
-
if (m.role === "user" && !m.wake && !m.queued && !m.agentInstruction) {
|
|
78152
|
+
if (m.role === "user" && !m.wake && !m.queued && !m.agentInstruction && !m.sessionPeer) {
|
|
77715
78153
|
boundary = i;
|
|
77716
78154
|
break;
|
|
77717
78155
|
}
|
|
@@ -77740,7 +78178,7 @@ function latestTranscriptWindow(messages) {
|
|
|
77740
78178
|
);
|
|
77741
78179
|
if (tools.length === 0) continue;
|
|
77742
78180
|
pinned.push({
|
|
77743
|
-
sourceId: `pinned-bg:${
|
|
78181
|
+
sourceId: `pinned-bg:${createHash16("sha256").update(message.sourceId).digest("base64url").slice(0, 24)}`,
|
|
77744
78182
|
pinnedFromSourceId: message.sourceId,
|
|
77745
78183
|
role: "assistant",
|
|
77746
78184
|
text: "",
|
|
@@ -78536,7 +78974,7 @@ function fixedSnapshot(source) {
|
|
|
78536
78974
|
};
|
|
78537
78975
|
let allBytes;
|
|
78538
78976
|
const fileKey = `${before.dev}:${before.ino}:${Math.trunc(before.birthtimeMs)}`;
|
|
78539
|
-
const transcriptKey =
|
|
78977
|
+
const transcriptKey = createHash16("sha256").update(`${source.slug}\0${source.sessionId}\0${source.nativeId}\0${source.backend}\0${source.runtimeGeneration}\0${fileKey}`).digest("base64url").slice(0, 32);
|
|
78540
78978
|
let rawText;
|
|
78541
78979
|
return {
|
|
78542
78980
|
...source,
|
|
@@ -78569,7 +79007,7 @@ function projectSnapshot(snapshot) {
|
|
|
78569
79007
|
return retireStaleQueuedBubbles([...entry.fold.allMessages()]);
|
|
78570
79008
|
}
|
|
78571
79009
|
function digestPrefix(bytes, length = bytes.length) {
|
|
78572
|
-
return
|
|
79010
|
+
return createHash16("sha256").update(bytes.subarray(0, length)).digest("base64url");
|
|
78573
79011
|
}
|
|
78574
79012
|
function fullDigest(snapshot) {
|
|
78575
79013
|
const key = `${snapshot.fileKey}\0${snapshot.size}`;
|
|
@@ -78579,7 +79017,7 @@ function fullDigest(snapshot) {
|
|
|
78579
79017
|
fullDigestCache.set(key, hit);
|
|
78580
79018
|
return hit;
|
|
78581
79019
|
}
|
|
78582
|
-
const hash =
|
|
79020
|
+
const hash = createHash16("sha256");
|
|
78583
79021
|
for (let at2 = 0; at2 < snapshot.size; ) {
|
|
78584
79022
|
const buf = snapshot.readRange(at2, Math.min(TRANSCRIPT_DECODE_WINDOW, snapshot.size - at2));
|
|
78585
79023
|
if (buf.length === 0) break;
|
|
@@ -78633,7 +79071,7 @@ function pageProjectedTranscript(messages, anchor, limits = {}) {
|
|
|
78633
79071
|
let boundary = 0;
|
|
78634
79072
|
for (let i = anchor - 1; i >= 0; i--) {
|
|
78635
79073
|
const m = messages[i];
|
|
78636
|
-
if (m.role === "user" && !m.wake && !m.queued && !m.agentInstruction) {
|
|
79074
|
+
if (m.role === "user" && !m.wake && !m.queued && !m.agentInstruction && !m.sessionPeer) {
|
|
78637
79075
|
boundary = i;
|
|
78638
79076
|
break;
|
|
78639
79077
|
}
|
|
@@ -78662,7 +79100,7 @@ function emptyTranscriptPage(source) {
|
|
|
78662
79100
|
beforeCursor: null,
|
|
78663
79101
|
hasEarlier: false,
|
|
78664
79102
|
reachedTurnBoundary: true,
|
|
78665
|
-
transcriptKey:
|
|
79103
|
+
transcriptKey: createHash16("sha256").update(keySeed).digest("base64url").slice(0, 32),
|
|
78666
79104
|
editedFiles: []
|
|
78667
79105
|
};
|
|
78668
79106
|
}
|
|
@@ -78741,7 +79179,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
|
|
|
78741
79179
|
}
|
|
78742
79180
|
function readCodexTranscriptFile(absPath, nativeId = absPath) {
|
|
78743
79181
|
try {
|
|
78744
|
-
return parseCodexTranscript(
|
|
79182
|
+
return parseCodexTranscript(readFileSync30(absPath, "utf8"), `codex:${nativeId}`);
|
|
78745
79183
|
} catch {
|
|
78746
79184
|
return [];
|
|
78747
79185
|
}
|
|
@@ -78802,14 +79240,15 @@ function projectTranscriptPeerNames(messages, lookup) {
|
|
|
78802
79240
|
});
|
|
78803
79241
|
return changed ? out : messages;
|
|
78804
79242
|
}
|
|
78805
|
-
function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
|
|
79243
|
+
function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup, sessionPeerLookup) {
|
|
78806
79244
|
const named = peerLookup ? projectTranscriptPeerNames(page.messages, peerLookup) : page.messages;
|
|
78807
|
-
|
|
79245
|
+
const sent = sessionPeerLookup ? projectTranscriptSessionPeers(named, sessionPeerLookup) : named;
|
|
79246
|
+
return { ...page, messages: projectTranscriptAgentLifecycles(sent, lookup) };
|
|
78808
79247
|
}
|
|
78809
79248
|
function readTranscriptFile(absPath) {
|
|
78810
79249
|
try {
|
|
78811
|
-
const pathKey =
|
|
78812
|
-
return parseTranscript(
|
|
79250
|
+
const pathKey = createHash16("sha256").update(absPath).digest("base64url").slice(0, 16);
|
|
79251
|
+
return parseTranscript(readFileSync30(absPath, "utf8"), `claude-file:${pathKey}`);
|
|
78813
79252
|
} catch {
|
|
78814
79253
|
return [];
|
|
78815
79254
|
}
|
|
@@ -78819,6 +79258,7 @@ var init_transcript = __esm({
|
|
|
78819
79258
|
"packages/server/src/transcript.ts"() {
|
|
78820
79259
|
"use strict";
|
|
78821
79260
|
init_src();
|
|
79261
|
+
init_session_peer();
|
|
78822
79262
|
init_types2();
|
|
78823
79263
|
init_delivery_ledger();
|
|
78824
79264
|
init_edited_files();
|
|
@@ -79380,10 +79820,10 @@ var init_background_shell_output = __esm({
|
|
|
79380
79820
|
|
|
79381
79821
|
// packages/server/src/frizz-md.ts
|
|
79382
79822
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
79383
|
-
import { existsSync as existsSync20, writeFileSync as
|
|
79384
|
-
import { join as
|
|
79823
|
+
import { existsSync as existsSync20, writeFileSync as writeFileSync17 } from "node:fs";
|
|
79824
|
+
import { join as join45 } from "node:path";
|
|
79385
79825
|
function frizzMdPath(projectDir) {
|
|
79386
|
-
return
|
|
79826
|
+
return join45(projectDir, "FRIZZ.md");
|
|
79387
79827
|
}
|
|
79388
79828
|
function git2(args, cwd) {
|
|
79389
79829
|
try {
|
|
@@ -79408,7 +79848,7 @@ function frizzMdStatus(projectDir, storage) {
|
|
|
79408
79848
|
function createFrizzMd(projectDir, answers) {
|
|
79409
79849
|
const path3 = frizzMdPath(projectDir);
|
|
79410
79850
|
try {
|
|
79411
|
-
|
|
79851
|
+
writeFileSync17(path3, composeFrizzMd(answers, defaultBranch(projectDir)), { encoding: "utf8", flag: "wx" });
|
|
79412
79852
|
} catch (error) {
|
|
79413
79853
|
if (error.code === "EEXIST") throw new Error("This project already has a FRIZZ.md.");
|
|
79414
79854
|
throw error;
|
|
@@ -79428,12 +79868,12 @@ var init_frizz_md2 = __esm({
|
|
|
79428
79868
|
});
|
|
79429
79869
|
|
|
79430
79870
|
// packages/server/src/image-header.ts
|
|
79431
|
-
import { closeSync as closeSync17, openSync as openSync18, readSync as readSync10, statSync as
|
|
79871
|
+
import { closeSync as closeSync17, openSync as openSync18, readSync as readSync10, statSync as statSync20 } from "node:fs";
|
|
79432
79872
|
import { extname as extname2 } from "node:path";
|
|
79433
79873
|
function readHead3(path3, budget) {
|
|
79434
79874
|
let fd2;
|
|
79435
79875
|
try {
|
|
79436
|
-
const size =
|
|
79876
|
+
const size = statSync20(path3).size;
|
|
79437
79877
|
if (size === 0) return void 0;
|
|
79438
79878
|
const buffer = Buffer.alloc(Math.min(size, budget));
|
|
79439
79879
|
fd2 = openSync18(path3, "r");
|
|
@@ -79811,12 +80251,12 @@ function run(argv) {
|
|
|
79811
80251
|
});
|
|
79812
80252
|
|
|
79813
80253
|
// packages/server/src/router.ts
|
|
79814
|
-
import { readFileSync as
|
|
79815
|
-
import { join as
|
|
80254
|
+
import { readFileSync as readFileSync31, statSync as statSync21 } from "node:fs";
|
|
80255
|
+
import { join as join46, resolve as resolve10 } from "node:path";
|
|
79816
80256
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
79817
|
-
import { basename as basename9, dirname as
|
|
79818
|
-
import { existsSync as existsSync21, mkdirSync as
|
|
79819
|
-
import { homedir as
|
|
80257
|
+
import { basename as basename9, dirname as dirname22 } from "node:path";
|
|
80258
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync24, rmSync as rmSync12, writeFileSync as writeFileSync18 } from "node:fs";
|
|
80259
|
+
import { homedir as homedir18 } from "node:os";
|
|
79820
80260
|
function validateGithubDispatchProfile(input, codexModels) {
|
|
79821
80261
|
if (input.backend === "acp") return;
|
|
79822
80262
|
if (input.effort === void 0) throw new Error(`Unsupported ${input.backend} model/effort pair: ${input.model} / (no effort)`);
|
|
@@ -79986,20 +80426,21 @@ function projectCard(entry, stale) {
|
|
|
79986
80426
|
iconIsCustom: entry.iconSource === "custom" ? true : void 0
|
|
79987
80427
|
};
|
|
79988
80428
|
}
|
|
79989
|
-
function addProjectAtPath(input, home =
|
|
80429
|
+
function addProjectAtPath(input, home = homedir18()) {
|
|
79990
80430
|
const typed = input.trim();
|
|
79991
80431
|
if (!typed) throw new Error("Enter a folder path.");
|
|
79992
|
-
const expanded = typed === "~" || typed.startsWith("~/") ?
|
|
80432
|
+
const expanded = typed === "~" || typed.startsWith("~/") ? join46(home, typed.slice(1)) : typed;
|
|
79993
80433
|
const absolute = resolve10(expanded);
|
|
79994
80434
|
let stats;
|
|
79995
80435
|
try {
|
|
79996
|
-
stats =
|
|
80436
|
+
stats = statSync21(absolute);
|
|
79997
80437
|
} catch {
|
|
79998
80438
|
throw new Error(`No folder at ${absolute}`);
|
|
79999
80439
|
}
|
|
80000
80440
|
if (!stats.isDirectory()) throw new Error(`That is a file, not a folder: ${absolute}`);
|
|
80001
80441
|
const root = chosenProjectRoot(absolute, home);
|
|
80002
80442
|
if (isHomeDirectory(root, home)) throw new Error("The home folder cannot be a project \u2014 choose a folder inside it.");
|
|
80443
|
+
refuseWorldWritableProject(root);
|
|
80003
80444
|
const id2 = ensureProjectIdFile(root, home, existingProjectId(root));
|
|
80004
80445
|
const remoteOwner = resolveProjectLabel(root)?.split("/")[0];
|
|
80005
80446
|
let registered = registerProject({ dir: root, id: id2, remoteOwner }, home);
|
|
@@ -80009,6 +80450,9 @@ function addProjectAtPath(input, home = homedir17()) {
|
|
|
80009
80450
|
if (!registered.entry) throw new Error("Could not register that folder.");
|
|
80010
80451
|
return projectCard(registered.entry, false);
|
|
80011
80452
|
}
|
|
80453
|
+
function addedProject(card) {
|
|
80454
|
+
return { project: { id: card.id, dir: card.path } };
|
|
80455
|
+
}
|
|
80012
80456
|
function storeProjectIcon(id2, name, bytes) {
|
|
80013
80457
|
const extension2 = name.toLowerCase().match(/\.([a-z0-9]+)$/u)?.[1];
|
|
80014
80458
|
if (!extension2 || !PROJECT_ICON_EXTENSIONS.includes(extension2)) {
|
|
@@ -80018,8 +80462,8 @@ function storeProjectIcon(id2, name, bytes) {
|
|
|
80018
80462
|
if (!entry) throw new Error("No such project.");
|
|
80019
80463
|
if (bytes.length === 0) throw new Error("That file is empty.");
|
|
80020
80464
|
const path3 = customIconPath(id2, `.${extension2}`);
|
|
80021
|
-
|
|
80022
|
-
|
|
80465
|
+
mkdirSync24(dirname22(path3), { recursive: true });
|
|
80466
|
+
writeFileSync18(path3, bytes);
|
|
80023
80467
|
if (!imageDimensions(path3)) {
|
|
80024
80468
|
rmSync12(path3, { force: true });
|
|
80025
80469
|
throw new Error("That file does not look like an image Frizz can draw.");
|
|
@@ -80040,7 +80484,7 @@ function iconPicker(id2) {
|
|
|
80040
80484
|
function setProjectIconFromFile(id2, file) {
|
|
80041
80485
|
let bytes;
|
|
80042
80486
|
try {
|
|
80043
|
-
bytes =
|
|
80487
|
+
bytes = readFileSync31(file);
|
|
80044
80488
|
} catch {
|
|
80045
80489
|
throw new Error("That file could not be read.");
|
|
80046
80490
|
}
|
|
@@ -80049,7 +80493,7 @@ function setProjectIconFromFile(id2, file) {
|
|
|
80049
80493
|
}
|
|
80050
80494
|
function mergeSubAgentSteers(messages, steers) {
|
|
80051
80495
|
if (!steers.length) return messages;
|
|
80052
|
-
const
|
|
80496
|
+
const merged2 = [...messages];
|
|
80053
80497
|
for (const steer of steers) {
|
|
80054
80498
|
const at2 = new Date(steer.sent_at).toISOString();
|
|
80055
80499
|
const duplicate = messages.some((message2) => {
|
|
@@ -80066,15 +80510,17 @@ function mergeSubAgentSteers(messages, steers) {
|
|
|
80066
80510
|
parts: [{ kind: "text", text: steer.message }],
|
|
80067
80511
|
at: at2
|
|
80068
80512
|
};
|
|
80069
|
-
const next =
|
|
80070
|
-
if (next === -1)
|
|
80071
|
-
else
|
|
80513
|
+
const next = merged2.findIndex((candidate) => candidate.at !== void 0 && Date.parse(candidate.at) > steer.sent_at);
|
|
80514
|
+
if (next === -1) merged2.push(message);
|
|
80515
|
+
else merged2.splice(next, 0, message);
|
|
80072
80516
|
}
|
|
80073
|
-
return
|
|
80517
|
+
return merged2;
|
|
80074
80518
|
}
|
|
80075
80519
|
function createRouter(ctx) {
|
|
80076
|
-
const frizzDir =
|
|
80520
|
+
const frizzDir = join46(ctx.project.dir, ".frizz");
|
|
80077
80521
|
const openRoots = openableFileRoots(ctx.project);
|
|
80522
|
+
const thisProject = { id: ctx.project.id, dir: ctx.project.dir };
|
|
80523
|
+
const audit = (action, base, run3, onResult) => audited(ctx.audit, action, base, run3, { onResult, servedBy: ctx.project.id });
|
|
80078
80524
|
function isAutoTitledSession(slug) {
|
|
80079
80525
|
return ctx.storage.getSession(slug)?.title_auto === 1;
|
|
80080
80526
|
}
|
|
@@ -80167,6 +80613,16 @@ function createRouter(ctx) {
|
|
|
80167
80613
|
return void 0;
|
|
80168
80614
|
}
|
|
80169
80615
|
}
|
|
80616
|
+
function answerDigest(slug, answer) {
|
|
80617
|
+
const q2 = ctx.storage.getThreadQuestion(answer.questionId);
|
|
80618
|
+
if (q2?.thread_slug === slug && parseQuestionSpec(q2.spec)?.secret) return { questionId: answer.questionId, secret: true };
|
|
80619
|
+
return {
|
|
80620
|
+
questionId: answer.questionId,
|
|
80621
|
+
...answer.chosen.length > 0 ? { chosen: textDigest(answer.chosen.join("\n")) } : {},
|
|
80622
|
+
...answer.text ? { text: textDigest(answer.text) } : {},
|
|
80623
|
+
...answer.followUps?.length ? { followUps: answer.followUps.length } : {}
|
|
80624
|
+
};
|
|
80625
|
+
}
|
|
80170
80626
|
function parseStoredAnswer(raw2) {
|
|
80171
80627
|
if (!raw2) return void 0;
|
|
80172
80628
|
try {
|
|
@@ -80416,7 +80872,7 @@ function createRouter(ctx) {
|
|
|
80416
80872
|
output: TranscriptPage,
|
|
80417
80873
|
handler: async ({ input }) => {
|
|
80418
80874
|
const page = readLatestThreadTranscriptPage(ctx.project, ctx.storage, input.slug, ctx.backendFor);
|
|
80419
|
-
return retireOpsInPage(input.slug, projectTranscriptPageAgentLifecycles(page, (id2) => ctx.tailer.subAgent(input.slug, id2), (taskId) => ctx.tailer.subAgentByTaskId?.(input.slug, taskId)));
|
|
80875
|
+
return retireOpsInPage(input.slug, projectTranscriptPageAgentLifecycles(page, (id2) => ctx.tailer.subAgent(input.slug, id2), (taskId) => ctx.tailer.subAgentByTaskId?.(input.slug, taskId), ctx.sessionPeerThread));
|
|
80420
80876
|
}
|
|
80421
80877
|
}),
|
|
80422
80878
|
// One bounded backward step through the canonical projected transcript. The cursor excludes the
|
|
@@ -80426,7 +80882,7 @@ function createRouter(ctx) {
|
|
|
80426
80882
|
output: TranscriptPage,
|
|
80427
80883
|
handler: async ({ input }) => {
|
|
80428
80884
|
const page = readEarlierThreadTranscriptPage(ctx.project, ctx.storage, input.slug, input.cursor, ctx.backendFor);
|
|
80429
|
-
return retireOpsInPage(input.slug, projectTranscriptPageAgentLifecycles(page, (id2) => ctx.tailer.subAgent(input.slug, id2), (taskId) => ctx.tailer.subAgentByTaskId?.(input.slug, taskId)));
|
|
80885
|
+
return retireOpsInPage(input.slug, projectTranscriptPageAgentLifecycles(page, (id2) => ctx.tailer.subAgent(input.slug, id2), (taskId) => ctx.tailer.subAgentByTaskId?.(input.slug, taskId), ctx.sessionPeerThread));
|
|
80430
80886
|
}
|
|
80431
80887
|
}),
|
|
80432
80888
|
// The thread's ANSWERED registered questions, each with its answer, so the transcript can keep the
|
|
@@ -80471,29 +80927,40 @@ function createRouter(ctx) {
|
|
|
80471
80927
|
interactionResolve: mutation({
|
|
80472
80928
|
input: ResolveInteractionInput,
|
|
80473
80929
|
output: ResolveInteractionResult,
|
|
80474
|
-
handler:
|
|
80475
|
-
|
|
80476
|
-
|
|
80477
|
-
|
|
80478
|
-
|
|
80479
|
-
|
|
80480
|
-
|
|
80481
|
-
}
|
|
80482
|
-
|
|
80483
|
-
|
|
80484
|
-
|
|
80485
|
-
|
|
80486
|
-
|
|
80930
|
+
handler: ({ input }) => audit(
|
|
80931
|
+
"interactionResolve",
|
|
80932
|
+
{
|
|
80933
|
+
project: thisProject,
|
|
80934
|
+
thread: input.slug,
|
|
80935
|
+
// The decision the operator picked and how many values rode with it — never the values, which
|
|
80936
|
+
// can be a secret the interaction asked for.
|
|
80937
|
+
detail: { interactionId: input.interactionId, decisionId: input.decisionId, values: Object.keys(input.values ?? {}).length }
|
|
80938
|
+
},
|
|
80939
|
+
async () => {
|
|
80940
|
+
const scope = interactionScope(input.slug, input.sessionId);
|
|
80941
|
+
const delivery2 = ctx.interactions.providerDelivery(scope, input.interactionId);
|
|
80942
|
+
let result;
|
|
80943
|
+
if (delivery2) {
|
|
80944
|
+
if (!ctx.codexAppServer || !ctx.codexAppServer.ownsInteraction(scope, input.interactionId)) {
|
|
80945
|
+
throw new Error("provider-backed interaction is unavailable until its provider bridge reconnects");
|
|
80946
|
+
}
|
|
80947
|
+
const providerResult = await ctx.codexAppServer.resolveInteraction(scope, input);
|
|
80948
|
+
if (!providerResult) throw new Error("provider-backed interaction lost its durable delivery owner");
|
|
80949
|
+
result = {
|
|
80950
|
+
effect: providerResult.effect === "already-sent" ? "already-queued" : providerResult.effect,
|
|
80951
|
+
interaction: providerResult.interaction
|
|
80952
|
+
};
|
|
80953
|
+
} else {
|
|
80954
|
+
result = ctx.interactions.resolve(scope, input);
|
|
80955
|
+
}
|
|
80956
|
+
const latest = ctx.interactions.get(scope, result.interaction.id) ?? result.interaction;
|
|
80957
|
+
return {
|
|
80958
|
+
effect: latest.lifecycle === "resolved" && (result.effect === "queued" || result.effect === "already-queued") ? "resolved" : result.effect,
|
|
80959
|
+
interaction: interactionForRead(scope, latest)
|
|
80487
80960
|
};
|
|
80488
|
-
}
|
|
80489
|
-
|
|
80490
|
-
|
|
80491
|
-
const latest = ctx.interactions.get(scope, result.interaction.id) ?? result.interaction;
|
|
80492
|
-
return {
|
|
80493
|
-
effect: latest.lifecycle === "resolved" && (result.effect === "queued" || result.effect === "already-queued") ? "resolved" : result.effect,
|
|
80494
|
-
interaction: interactionForRead(scope, latest)
|
|
80495
|
-
};
|
|
80496
|
-
}
|
|
80961
|
+
},
|
|
80962
|
+
(result) => ({ detail: { effect: result.effect } })
|
|
80963
|
+
)
|
|
80497
80964
|
}),
|
|
80498
80965
|
interactionCancel: mutation({
|
|
80499
80966
|
input: CancelInteractionInput,
|
|
@@ -80562,32 +81029,36 @@ function createRouter(ctx) {
|
|
|
80562
81029
|
subAgentSteer: mutation({
|
|
80563
81030
|
input: external_exports.object({ slug: ThreadSlug, id: external_exports.string(), message: external_exports.string().min(1), deliveryId: external_exports.string().min(1).max(200).optional() }).strict(),
|
|
80564
81031
|
output: external_exports.object({ delivered: external_exports.boolean() }),
|
|
80565
|
-
handler:
|
|
80566
|
-
|
|
80567
|
-
|
|
80568
|
-
|
|
81032
|
+
handler: ({ input }) => audit(
|
|
81033
|
+
"subAgentSteer",
|
|
81034
|
+
{ project: thisProject, thread: input.slug, detail: { subAgent: input.id, message: textDigest(input.message) } },
|
|
81035
|
+
async () => {
|
|
81036
|
+
const target = subAgentSteerable(input.slug, input.id);
|
|
81037
|
+
if (target.sessionId === null) {
|
|
81038
|
+
throw new Error(target.note ?? "This sub-agent is no longer running, so it can't be steered");
|
|
81039
|
+
}
|
|
81040
|
+
const bridge = ctx.claudeBroker;
|
|
81041
|
+
if (!bridge) throw new Error("Claude session broker is unavailable; cannot steer this sub-agent");
|
|
81042
|
+
const deliveryId = input.deliveryId ?? randomUUID17();
|
|
81043
|
+
const sentAtMs = Date.now();
|
|
81044
|
+
await bridge.steerSubAgent({
|
|
81045
|
+
threadSlug: input.slug,
|
|
81046
|
+
sessionId: target.sessionId,
|
|
81047
|
+
subAgentId: input.id,
|
|
81048
|
+
text: input.message,
|
|
81049
|
+
deliveryId
|
|
81050
|
+
});
|
|
81051
|
+
ctx.storage.recordSubAgentSteer({
|
|
81052
|
+
slug: input.slug,
|
|
81053
|
+
subAgentId: input.id,
|
|
81054
|
+
deliveryId,
|
|
81055
|
+
message: input.message,
|
|
81056
|
+
sentAtMs
|
|
81057
|
+
});
|
|
81058
|
+
ctx.board.refresh();
|
|
81059
|
+
return { delivered: true };
|
|
80569
81060
|
}
|
|
80570
|
-
|
|
80571
|
-
if (!bridge) throw new Error("Claude session broker is unavailable; cannot steer this sub-agent");
|
|
80572
|
-
const deliveryId = input.deliveryId ?? randomUUID17();
|
|
80573
|
-
const sentAtMs = Date.now();
|
|
80574
|
-
await bridge.steerSubAgent({
|
|
80575
|
-
threadSlug: input.slug,
|
|
80576
|
-
sessionId: target.sessionId,
|
|
80577
|
-
subAgentId: input.id,
|
|
80578
|
-
text: input.message,
|
|
80579
|
-
deliveryId
|
|
80580
|
-
});
|
|
80581
|
-
ctx.storage.recordSubAgentSteer({
|
|
80582
|
-
slug: input.slug,
|
|
80583
|
-
subAgentId: input.id,
|
|
80584
|
-
deliveryId,
|
|
80585
|
-
message: input.message,
|
|
80586
|
-
sentAtMs
|
|
80587
|
-
});
|
|
80588
|
-
ctx.board.refresh();
|
|
80589
|
-
return { delivered: true };
|
|
80590
|
-
}
|
|
81061
|
+
)
|
|
80591
81062
|
}),
|
|
80592
81063
|
subAgentStop: mutation({
|
|
80593
81064
|
input: external_exports.object({ slug: ThreadSlug, id: external_exports.string() }).strict(),
|
|
@@ -80736,18 +81207,40 @@ function createRouter(ctx) {
|
|
|
80736
81207
|
// Omitted ⇒ the dispatcher defaults to "claude", so an old client (no backend field) is
|
|
80737
81208
|
// byte-identical. The resume path needs NO analog — resume reads the backend from the row's
|
|
80738
81209
|
// `backend` column (backendFor(row.backend)), which dispatch already stamped for a codex thread.
|
|
80739
|
-
handler: ({ input }) =>
|
|
81210
|
+
handler: ({ input }) => audit(
|
|
81211
|
+
"dispatch",
|
|
81212
|
+
{
|
|
81213
|
+
project: thisProject,
|
|
81214
|
+
detail: { prompt: textDigest(input.prompt), backend: input.backend ?? "claude", model: input.model ?? null, effort: input.effort ?? null }
|
|
81215
|
+
},
|
|
81216
|
+
() => ctx.dispatcher.dispatch(input, { backend: input.backend }),
|
|
81217
|
+
(result) => ({ thread: result.slug, detail: { sessionId: result.sessionId } })
|
|
81218
|
+
)
|
|
80740
81219
|
}),
|
|
80741
81220
|
// Cold-adopt a pre-existing thread (no session row): spawn a fresh worker on its file.
|
|
80742
81221
|
adoptThread: mutation({
|
|
80743
81222
|
input: AdoptThreadInput,
|
|
80744
81223
|
output: AdoptThreadResult,
|
|
80745
|
-
handler: ({ input }) =>
|
|
81224
|
+
handler: ({ input }) => audit(
|
|
81225
|
+
"adoptThread",
|
|
81226
|
+
{ project: thisProject, thread: input.slug, detail: input.message ? { message: textDigest(input.message) } : void 0 },
|
|
81227
|
+
() => ctx.dispatcher.adopt(input.slug, input.message),
|
|
81228
|
+
(result) => ({ detail: { sessionId: result.sessionId } })
|
|
81229
|
+
)
|
|
80746
81230
|
}),
|
|
80747
81231
|
followUp: mutation({
|
|
80748
81232
|
input: FollowUpInput,
|
|
80749
81233
|
// Wrapped so a delivery that throws keeps the operator's words — see keepFailedFollowUp.
|
|
80750
|
-
handler: ({ input }) =>
|
|
81234
|
+
handler: ({ input }) => audit("followUp", {
|
|
81235
|
+
project: thisProject,
|
|
81236
|
+
thread: input.slug,
|
|
81237
|
+
detail: {
|
|
81238
|
+
sessionId: input.sessionId,
|
|
81239
|
+
message: textDigest(input.message),
|
|
81240
|
+
...input.freshProcess ? { freshProcess: true } : {},
|
|
81241
|
+
...input.interrupt ? { interrupt: true } : {}
|
|
81242
|
+
}
|
|
81243
|
+
}, () => keepFailedFollowUp(input, async (openWriteAhead) => {
|
|
80751
81244
|
await promoteExternalSession(input.slug, input.sessionId);
|
|
80752
81245
|
const row = currentOwnedSession(input.slug, input.sessionId);
|
|
80753
81246
|
if (hasPendingPermissionChange(row)) {
|
|
@@ -80905,7 +81398,7 @@ ${gapNote}` : input.message;
|
|
|
80905
81398
|
appendDelivery(ctx.storage, input.slug, { id: input.deliveryId, text: input.message });
|
|
80906
81399
|
}
|
|
80907
81400
|
ctx.board.refresh();
|
|
80908
|
-
})
|
|
81401
|
+
}))
|
|
80909
81402
|
}),
|
|
80910
81403
|
// The × on a FAILED send's bubble, and the second half of its Edit (the client has already put the
|
|
80911
81404
|
// words back into the prompt box). The only way a failed entry leaves the ledger by hand — nothing
|
|
@@ -81696,27 +82189,32 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
81696
82189
|
answerQuestions: mutation({
|
|
81697
82190
|
input: AnswerQuestionsInput,
|
|
81698
82191
|
output: AnswerQuestionsResult,
|
|
81699
|
-
handler:
|
|
81700
|
-
|
|
81701
|
-
|
|
81702
|
-
|
|
81703
|
-
const
|
|
81704
|
-
|
|
81705
|
-
|
|
81706
|
-
|
|
81707
|
-
|
|
81708
|
-
|
|
81709
|
-
|
|
81710
|
-
|
|
82192
|
+
handler: ({ input }) => audit(
|
|
82193
|
+
"answerQuestions",
|
|
82194
|
+
() => ({ project: thisProject, thread: input.slug, detail: { answers: input.answers.map((answer) => answerDigest(input.slug, answer)) } }),
|
|
82195
|
+
async () => {
|
|
82196
|
+
const now = Date.now();
|
|
82197
|
+
const answered = [];
|
|
82198
|
+
for (const answer of input.answers) {
|
|
82199
|
+
const q2 = ctx.storage.getThreadQuestion(answer.questionId);
|
|
82200
|
+
if (!q2 || q2.thread_slug !== input.slug || q2.state !== "open") continue;
|
|
82201
|
+
let stored = answer;
|
|
82202
|
+
if (parseQuestionSpec(q2.spec)?.secret) {
|
|
82203
|
+
const value = answer.text?.trim() ?? "";
|
|
82204
|
+
if (!value) continue;
|
|
82205
|
+
const path3 = serveSecret(ctx.project.stateDir, input.slug, q2.id, value);
|
|
82206
|
+
stored = { questionId: answer.questionId, question: answer.question, chosen: [], text: secretAnswerText(path3) };
|
|
82207
|
+
}
|
|
82208
|
+
if (ctx.storage.answerThreadQuestion(answer.questionId, JSON.stringify(stored), now)) answered.push(answer.questionId);
|
|
81711
82209
|
}
|
|
81712
|
-
if (
|
|
81713
|
-
|
|
81714
|
-
|
|
81715
|
-
|
|
81716
|
-
|
|
81717
|
-
}
|
|
81718
|
-
|
|
81719
|
-
|
|
82210
|
+
if (answered.length > 0) {
|
|
82211
|
+
ctx.board.refresh();
|
|
82212
|
+
ctx.scheduler.kick();
|
|
82213
|
+
}
|
|
82214
|
+
return { answered, open: openQuestionViews(input.slug) };
|
|
82215
|
+
},
|
|
82216
|
+
(result) => ({ detail: { answered: result.answered } })
|
|
82217
|
+
)
|
|
81720
82218
|
}),
|
|
81721
82219
|
dismissQuestions: mutation({
|
|
81722
82220
|
input: DismissQuestionsInput,
|
|
@@ -82232,16 +82730,22 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
82232
82730
|
/** Live worker daemons this actually killed — 0 unless `deleteData`. Reported, not guessed at. */
|
|
82233
82731
|
stoppedWorkers: external_exports.number().int().nonnegative()
|
|
82234
82732
|
}),
|
|
82235
|
-
handler: async ({ input }) =>
|
|
82236
|
-
|
|
82237
|
-
|
|
82238
|
-
|
|
82239
|
-
|
|
82240
|
-
|
|
82241
|
-
|
|
82242
|
-
|
|
82243
|
-
|
|
82244
|
-
|
|
82733
|
+
handler: async ({ input }) => audit(
|
|
82734
|
+
"projectRemove",
|
|
82735
|
+
// Read BEFORE the removal, which forgets the very entry that names the folder.
|
|
82736
|
+
() => ({ project: { id: input.id, dir: findById(input.id)?.path ?? null }, detail: { deleteData: input.deleteData === true } }),
|
|
82737
|
+
async () => {
|
|
82738
|
+
const entry = findById(input.id);
|
|
82739
|
+
if (!entry) return { removed: false, deletedData: false, stoppedWorkers: 0 };
|
|
82740
|
+
if (ctx.launchProjectId === entry.id) {
|
|
82741
|
+
throw new Error("Frizz is serving from this project, so it cannot be deleted. Restart Frizz from another folder first.");
|
|
82742
|
+
}
|
|
82743
|
+
const deleteData = input.deleteData === true;
|
|
82744
|
+
const { stoppedWorkers } = await ctx.teardownProject?.(entry.id, { stopWorkers: deleteData, deleteState: deleteData }) ?? { closed: false, stoppedWorkers: 0 };
|
|
82745
|
+
return { removed: forgetProject(entry.id), deletedData: deleteData, stoppedWorkers };
|
|
82746
|
+
},
|
|
82747
|
+
(result) => ({ detail: result })
|
|
82748
|
+
)
|
|
82245
82749
|
}),
|
|
82246
82750
|
/**
|
|
82247
82751
|
* Give a project an icon of the operator's choosing.
|
|
@@ -82365,7 +82869,13 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
82365
82869
|
const picked = await pickDirectory();
|
|
82366
82870
|
if (picked.kind !== "unavailable") warmDirectoryPicker();
|
|
82367
82871
|
if (picked.kind !== "picked") return picked;
|
|
82368
|
-
|
|
82872
|
+
const project = await audit(
|
|
82873
|
+
"projectPick",
|
|
82874
|
+
{ project: { id: null, dir: picked.path }, detail: { path: picked.path } },
|
|
82875
|
+
() => addProjectAtPath(picked.path),
|
|
82876
|
+
addedProject
|
|
82877
|
+
);
|
|
82878
|
+
return { kind: "picked", project };
|
|
82369
82879
|
}
|
|
82370
82880
|
}),
|
|
82371
82881
|
/**
|
|
@@ -82388,7 +82898,7 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
82388
82898
|
projectAdd: mutation({
|
|
82389
82899
|
input: external_exports.object({ path: external_exports.string().min(1) }),
|
|
82390
82900
|
output: ProjectCard,
|
|
82391
|
-
handler: async ({ input }) => addProjectAtPath(input.path)
|
|
82901
|
+
handler: async ({ input }) => audit("projectAdd", { project: { id: null, dir: input.path }, detail: { path: input.path } }, () => addProjectAtPath(input.path), addedProject)
|
|
82392
82902
|
}),
|
|
82393
82903
|
/**
|
|
82394
82904
|
* Find which project owns a thread slug.
|
|
@@ -82533,7 +83043,12 @@ Say which way you went and why in your write-up, so the human can course-correct
|
|
|
82533
83043
|
const hydrated = it2.kind === "issue" ? await hydrateIssue(repo, it2.number) : await hydratePr(repo, it2.number);
|
|
82534
83044
|
const prompt = renderGithubPrompt(template, repo, hydrated, slug, it2.kind);
|
|
82535
83045
|
const request = githubDispatcherRequest(input, { prompt, title, slug });
|
|
82536
|
-
const res = await
|
|
83046
|
+
const res = await audit(
|
|
83047
|
+
"githubDispatch",
|
|
83048
|
+
{ project: thisProject, detail: { repo, kind: it2.kind, number: it2.number, prompt: textDigest(prompt) } },
|
|
83049
|
+
() => ctx.dispatcher.dispatch(request.payload, request.options),
|
|
83050
|
+
(result) => ({ thread: result.slug, detail: { sessionId: result.sessionId } })
|
|
83051
|
+
);
|
|
82537
83052
|
dispatched.push({ number: it2.number, kind: it2.kind, slug: res.slug });
|
|
82538
83053
|
} catch (e14) {
|
|
82539
83054
|
failed.push({ number: it2.number, kind: it2.kind, error: e14.message.slice(0, 120) });
|
|
@@ -82574,6 +83089,7 @@ var init_router5 = __esm({
|
|
|
82574
83089
|
init_claude_models();
|
|
82575
83090
|
init_claude_model_upgrade();
|
|
82576
83091
|
init_logging();
|
|
83092
|
+
init_audit();
|
|
82577
83093
|
init_codex();
|
|
82578
83094
|
init_quota();
|
|
82579
83095
|
init_auth_status();
|
|
@@ -82656,9 +83172,9 @@ var init_compression = __esm({
|
|
|
82656
83172
|
});
|
|
82657
83173
|
|
|
82658
83174
|
// packages/server/src/project-icon.ts
|
|
82659
|
-
import { readFileSync as
|
|
82660
|
-
import { homedir as
|
|
82661
|
-
import { basename as basename10, dirname as
|
|
83175
|
+
import { readFileSync as readFileSync32, readdirSync as readdirSync13, realpathSync as realpathSync13, statSync as statSync22 } from "node:fs";
|
|
83176
|
+
import { homedir as homedir19 } from "node:os";
|
|
83177
|
+
import { basename as basename10, dirname as dirname23, extname as extname3, join as join47, relative as relative2, sep as sep4 } from "node:path";
|
|
82662
83178
|
function normalizeStem(stem) {
|
|
82663
83179
|
const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
|
|
82664
83180
|
const normalized = sized.replace(VARIANT_SUFFIX, "");
|
|
@@ -82676,7 +83192,7 @@ function sizeScore(dimensions) {
|
|
|
82676
83192
|
return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
|
|
82677
83193
|
}
|
|
82678
83194
|
function under(root, relativeDirectory) {
|
|
82679
|
-
return relativeDirectory ?
|
|
83195
|
+
return relativeDirectory ? join47(root, relativeDirectory) : root;
|
|
82680
83196
|
}
|
|
82681
83197
|
function listFiles(directory) {
|
|
82682
83198
|
try {
|
|
@@ -82698,19 +83214,19 @@ function iconDirectories(root) {
|
|
|
82698
83214
|
for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
|
|
82699
83215
|
for (const host of HOST_DIRECTORIES) {
|
|
82700
83216
|
if (!children2.has(host)) continue;
|
|
82701
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
83217
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join47(root, host), asset));
|
|
82702
83218
|
}
|
|
82703
83219
|
for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
|
|
82704
83220
|
for (const container of WORKSPACE_CONTAINERS) {
|
|
82705
83221
|
if (!children2.has(container)) continue;
|
|
82706
83222
|
let members;
|
|
82707
83223
|
try {
|
|
82708
|
-
members = readdirSync13(
|
|
83224
|
+
members = readdirSync13(join47(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
82709
83225
|
} catch {
|
|
82710
83226
|
continue;
|
|
82711
83227
|
}
|
|
82712
83228
|
for (const member of members) {
|
|
82713
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
83229
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join47(root, container, member), asset));
|
|
82714
83230
|
}
|
|
82715
83231
|
}
|
|
82716
83232
|
return [...new Set(directories)];
|
|
@@ -82718,13 +83234,13 @@ function iconDirectories(root) {
|
|
|
82718
83234
|
function manifestIcons(manifestPath) {
|
|
82719
83235
|
let parsed;
|
|
82720
83236
|
try {
|
|
82721
|
-
parsed = JSON.parse(
|
|
83237
|
+
parsed = JSON.parse(readFileSync32(manifestPath, "utf8"));
|
|
82722
83238
|
} catch {
|
|
82723
83239
|
return [];
|
|
82724
83240
|
}
|
|
82725
83241
|
if (!Array.isArray(parsed?.icons)) return [];
|
|
82726
|
-
const directory =
|
|
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) =>
|
|
83242
|
+
const directory = dirname23(manifestPath);
|
|
83243
|
+
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) => join47(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
|
|
82728
83244
|
}
|
|
82729
83245
|
function projectIconCandidates(root) {
|
|
82730
83246
|
const projectStem = normalizeStem(basename10(root)).normalized;
|
|
@@ -82743,10 +83259,10 @@ function projectIconCandidates(root) {
|
|
|
82743
83259
|
for (const name of listFiles(directory)) {
|
|
82744
83260
|
const extension2 = extname3(name).toLowerCase();
|
|
82745
83261
|
if (MANIFEST_NAMES.includes(name.toLowerCase())) {
|
|
82746
|
-
for (const icon of manifestIcons(
|
|
83262
|
+
for (const icon of manifestIcons(join47(directory, name))) {
|
|
82747
83263
|
if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
|
|
82748
83264
|
fromManifest.add(icon);
|
|
82749
|
-
files.push({ path: icon, directory:
|
|
83265
|
+
files.push({ path: icon, directory: dirname23(icon) });
|
|
82750
83266
|
}
|
|
82751
83267
|
}
|
|
82752
83268
|
continue;
|
|
@@ -82754,7 +83270,7 @@ function projectIconCandidates(root) {
|
|
|
82754
83270
|
if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
|
|
82755
83271
|
const stem = name.slice(0, name.length - extension2.length);
|
|
82756
83272
|
if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
|
|
82757
|
-
files.push({ path:
|
|
83273
|
+
files.push({ path: join47(directory, name), directory });
|
|
82758
83274
|
if (files.length >= MAX_CANDIDATES) break;
|
|
82759
83275
|
}
|
|
82760
83276
|
}
|
|
@@ -82796,7 +83312,7 @@ function iconMediaType(path3) {
|
|
|
82796
83312
|
}
|
|
82797
83313
|
function resolveProjectIconResponse(id2, options = {}) {
|
|
82798
83314
|
if (!id2) return { status: 400 };
|
|
82799
|
-
const home = options.home ??
|
|
83315
|
+
const home = options.home ?? homedir19();
|
|
82800
83316
|
const entry = readRegistry(home).projects.find((project) => project.id === id2);
|
|
82801
83317
|
if (!entry) return { status: 404 };
|
|
82802
83318
|
const path3 = resolveProjectIcon(id2, (root) => detectProjectIcon(root)?.path, { home });
|
|
@@ -82806,7 +83322,7 @@ function resolveProjectIconResponse(id2, options = {}) {
|
|
|
82806
83322
|
let real;
|
|
82807
83323
|
try {
|
|
82808
83324
|
real = realpathSync13(path3);
|
|
82809
|
-
if (!
|
|
83325
|
+
if (!statSync22(real).isFile()) return { status: 404 };
|
|
82810
83326
|
} catch {
|
|
82811
83327
|
return { status: 404 };
|
|
82812
83328
|
}
|
|
@@ -82819,7 +83335,7 @@ function resolveProjectIconResponse(id2, options = {}) {
|
|
|
82819
83335
|
});
|
|
82820
83336
|
if (!roots.some((root) => real === root || real.startsWith(root + sep4))) return { status: 404 };
|
|
82821
83337
|
try {
|
|
82822
|
-
return { status: 200, contentType, body:
|
|
83338
|
+
return { status: 200, contentType, body: readFileSync32(real) };
|
|
82823
83339
|
} catch {
|
|
82824
83340
|
return { status: 404 };
|
|
82825
83341
|
}
|
|
@@ -82931,8 +83447,8 @@ var init_project_icon = __esm({
|
|
|
82931
83447
|
});
|
|
82932
83448
|
|
|
82933
83449
|
// packages/server/src/local-visualization.ts
|
|
82934
|
-
import { readdirSync as readdirSync14, readFileSync as
|
|
82935
|
-
import { join as
|
|
83450
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync33, realpathSync as realpathSync14, statSync as statSync23 } from "node:fs";
|
|
83451
|
+
import { join as join48, sep as sep5 } from "node:path";
|
|
82936
83452
|
function children(path3, pattern) {
|
|
82937
83453
|
try {
|
|
82938
83454
|
return readdirSync14(path3, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
|
|
@@ -82944,7 +83460,7 @@ function isUnder2(path3, root) {
|
|
|
82944
83460
|
return path3 === root || path3.startsWith(root.endsWith(sep5) ? root : root + sep5);
|
|
82945
83461
|
}
|
|
82946
83462
|
function resolveFragment(projectDir, sessionId, file) {
|
|
82947
|
-
const base =
|
|
83463
|
+
const base = join48(projectDir, ".codex", "visualizations");
|
|
82948
83464
|
let projectReal;
|
|
82949
83465
|
let baseReal;
|
|
82950
83466
|
try {
|
|
@@ -82955,15 +83471,15 @@ function resolveFragment(projectDir, sessionId, file) {
|
|
|
82955
83471
|
}
|
|
82956
83472
|
if (!isUnder2(baseReal, projectReal)) return null;
|
|
82957
83473
|
for (const year of children(base, YEAR_PART)) {
|
|
82958
|
-
const yearDir =
|
|
83474
|
+
const yearDir = join48(base, year);
|
|
82959
83475
|
for (const month of children(yearDir, DATE_PART)) {
|
|
82960
|
-
const monthDir =
|
|
83476
|
+
const monthDir = join48(yearDir, month);
|
|
82961
83477
|
for (const day of children(monthDir, DATE_PART)) {
|
|
82962
|
-
const sessionRoot =
|
|
82963
|
-
const candidate =
|
|
83478
|
+
const sessionRoot = join48(baseReal, year, month, day, sessionId);
|
|
83479
|
+
const candidate = join48(monthDir, day, sessionId, file);
|
|
82964
83480
|
try {
|
|
82965
83481
|
const real = realpathSync14(candidate);
|
|
82966
|
-
if (isUnder2(real, sessionRoot) &&
|
|
83482
|
+
if (isUnder2(real, sessionRoot) && statSync23(real).isFile()) return real;
|
|
82967
83483
|
} catch {
|
|
82968
83484
|
}
|
|
82969
83485
|
}
|
|
@@ -83048,9 +83564,9 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
|
|
|
83048
83564
|
if (!path3) return { status: 404 };
|
|
83049
83565
|
let fragment;
|
|
83050
83566
|
try {
|
|
83051
|
-
const size =
|
|
83567
|
+
const size = statSync23(path3).size;
|
|
83052
83568
|
if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
|
|
83053
|
-
fragment =
|
|
83569
|
+
fragment = readFileSync33(path3, "utf8");
|
|
83054
83570
|
} catch {
|
|
83055
83571
|
return { status: 404 };
|
|
83056
83572
|
}
|
|
@@ -83092,9 +83608,9 @@ var init_local_visualization = __esm({
|
|
|
83092
83608
|
});
|
|
83093
83609
|
|
|
83094
83610
|
// packages/server/src/app.ts
|
|
83095
|
-
import { mkdirSync as
|
|
83611
|
+
import { mkdirSync as mkdirSync25, writeFileSync as writeFileSync19 } from "node:fs";
|
|
83096
83612
|
import { Readable } from "node:stream";
|
|
83097
|
-
import { join as
|
|
83613
|
+
import { join as join49 } from "node:path";
|
|
83098
83614
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
83099
83615
|
function createApp(ctx, options = {}) {
|
|
83100
83616
|
const app = new Hono2();
|
|
@@ -83129,6 +83645,17 @@ function createApp(ctx, options = {}) {
|
|
|
83129
83645
|
c.header("x-frizz-boot", ctx.bootId);
|
|
83130
83646
|
await next();
|
|
83131
83647
|
});
|
|
83648
|
+
app.use(
|
|
83649
|
+
`${frizzRoute("/rpc")}/*`,
|
|
83650
|
+
(c, next) => withRequestOrigin(
|
|
83651
|
+
requestOriginFrom({
|
|
83652
|
+
caller: c.req.header(CALLER_HEADER),
|
|
83653
|
+
userAgent: c.req.header("user-agent"),
|
|
83654
|
+
socketRemote: c.env?.remoteAddress
|
|
83655
|
+
}),
|
|
83656
|
+
next
|
|
83657
|
+
)
|
|
83658
|
+
);
|
|
83132
83659
|
app.use(`${frizzRoute("/rpc")}/*`, async (c, next) => {
|
|
83133
83660
|
await next();
|
|
83134
83661
|
const encoding = negotiateEncoding(c.req.header("accept-encoding"));
|
|
@@ -83201,11 +83728,11 @@ function createApp(ctx, options = {}) {
|
|
|
83201
83728
|
if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
|
|
83202
83729
|
const ext = `.${attachmentExtension(name)}`;
|
|
83203
83730
|
const buf = Buffer.from(body.data, "base64");
|
|
83204
|
-
const dir =
|
|
83205
|
-
|
|
83731
|
+
const dir = join49(ctx.project.stateDir, "attachments");
|
|
83732
|
+
mkdirSync25(dir, { recursive: true });
|
|
83206
83733
|
const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
|
|
83207
|
-
const path3 =
|
|
83208
|
-
|
|
83734
|
+
const path3 = join49(dir, `${Date.now()}-${randomUUID18().slice(0, 8)}-${base}${ext}`);
|
|
83735
|
+
writeFileSync19(path3, buf);
|
|
83209
83736
|
return c.json({ path: path3 });
|
|
83210
83737
|
});
|
|
83211
83738
|
app.get(
|
|
@@ -83257,21 +83784,23 @@ var init_app = __esm({
|
|
|
83257
83784
|
init_local_image();
|
|
83258
83785
|
init_project_icon();
|
|
83259
83786
|
init_local_visualization();
|
|
83787
|
+
init_audit();
|
|
83260
83788
|
init_local_image();
|
|
83261
83789
|
init_local_visualization();
|
|
83262
83790
|
}
|
|
83263
83791
|
});
|
|
83264
83792
|
|
|
83265
83793
|
// packages/server/src/app-socket.ts
|
|
83266
|
-
import { createHash as
|
|
83794
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
83267
83795
|
function isWsPath(url) {
|
|
83268
83796
|
return (url ?? "").split("?")[0] === WS_PATH;
|
|
83269
83797
|
}
|
|
83270
|
-
function makeTranscriptReader(project, storage, backendFor, lifecycleFor, peerNameFor, ownerGone) {
|
|
83798
|
+
function makeTranscriptReader(project, storage, backendFor, lifecycleFor, peerNameFor, ownerGone, sessionPeerThread) {
|
|
83271
83799
|
return (slug) => {
|
|
83272
83800
|
const page = readLatestThreadTranscriptPage(project, storage, slug, backendFor, { editedFiles: false });
|
|
83273
83801
|
const named = peerNameFor ? projectTranscriptPeerNames(page.messages, (taskId) => peerNameFor(slug, taskId)) : page.messages;
|
|
83274
|
-
const
|
|
83802
|
+
const sent = sessionPeerThread ? projectTranscriptSessionPeers(named, sessionPeerThread) : named;
|
|
83803
|
+
const projected = lifecycleFor ? projectTranscriptAgentLifecycles(sent, (id2) => lifecycleFor(slug, id2)) : sent;
|
|
83275
83804
|
const messages = projectRetiredBackgroundOps(projected, retiredOpsFor(storage, slug), ownerGone?.(slug) ?? false);
|
|
83276
83805
|
return {
|
|
83277
83806
|
messages,
|
|
@@ -83467,7 +83996,7 @@ function createAppSocketServer(deps) {
|
|
|
83467
83996
|
sendEncoded(ws, frame, false);
|
|
83468
83997
|
}
|
|
83469
83998
|
function frameSignature(frame) {
|
|
83470
|
-
return
|
|
83999
|
+
return createHash17("sha256").update(frame.text).digest("base64url");
|
|
83471
84000
|
}
|
|
83472
84001
|
const globalReadTimes = [];
|
|
83473
84002
|
const originReadTimes = /* @__PURE__ */ new Map();
|
|
@@ -84024,6 +84553,7 @@ var init_app_socket = __esm({
|
|
|
84024
84553
|
"packages/server/src/app-socket.ts"() {
|
|
84025
84554
|
"use strict";
|
|
84026
84555
|
init_wrapper();
|
|
84556
|
+
init_session_peer();
|
|
84027
84557
|
init_src();
|
|
84028
84558
|
init_transcript();
|
|
84029
84559
|
init_local_origin();
|
|
@@ -84124,11 +84654,11 @@ var init_app_socket = __esm({
|
|
|
84124
84654
|
});
|
|
84125
84655
|
|
|
84126
84656
|
// packages/server/src/local-file-watch.ts
|
|
84127
|
-
import { statSync as
|
|
84128
|
-
import { basename as basename11, dirname as
|
|
84657
|
+
import { statSync as statSync24, watch } from "node:fs";
|
|
84658
|
+
import { basename as basename11, dirname as dirname24 } from "node:path";
|
|
84129
84659
|
function stampOf(path3) {
|
|
84130
84660
|
try {
|
|
84131
|
-
const s =
|
|
84661
|
+
const s = statSync24(path3, { bigint: true });
|
|
84132
84662
|
return `${s.ino}:${s.size}:${s.mtimeNs}`;
|
|
84133
84663
|
} catch {
|
|
84134
84664
|
return "gone";
|
|
@@ -84148,7 +84678,7 @@ function watchLocalFile(path3, onChange) {
|
|
|
84148
84678
|
let entry = entries.get(path3);
|
|
84149
84679
|
if (!entry) {
|
|
84150
84680
|
const name = basename11(path3);
|
|
84151
|
-
const watcher2 = watch(
|
|
84681
|
+
const watcher2 = watch(dirname24(path3), { persistent: false }, (_event, changed) => {
|
|
84152
84682
|
if (changed !== null && changed !== void 0 && changed.toString() !== name) return;
|
|
84153
84683
|
const current = entries.get(path3);
|
|
84154
84684
|
if (!current) return;
|
|
@@ -84184,10 +84714,10 @@ var init_local_file_watch = __esm({
|
|
|
84184
84714
|
});
|
|
84185
84715
|
|
|
84186
84716
|
// packages/server/src/boot-progress.ts
|
|
84187
|
-
import { mkdirSync as
|
|
84188
|
-
import { basename as basename12, dirname as
|
|
84717
|
+
import { mkdirSync as mkdirSync26, readFileSync as readFileSync34, renameSync as renameSync12, rmSync as rmSync13, writeFileSync as writeFileSync20 } from "node:fs";
|
|
84718
|
+
import { basename as basename12, dirname as dirname25, join as join50 } from "node:path";
|
|
84189
84719
|
function bootProgressPath(stateDir) {
|
|
84190
|
-
return
|
|
84720
|
+
return join50(stateDir, BOOT_PROGRESS_NAME);
|
|
84191
84721
|
}
|
|
84192
84722
|
function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
84193
84723
|
if (!stateDir) {
|
|
@@ -84207,11 +84737,11 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
84207
84737
|
lastAt = now;
|
|
84208
84738
|
step++;
|
|
84209
84739
|
try {
|
|
84210
|
-
|
|
84211
|
-
const temp =
|
|
84212
|
-
|
|
84740
|
+
mkdirSync26(dirname25(path3), { recursive: true, mode: 448 });
|
|
84741
|
+
const temp = join50(dirname25(path3), `.${basename12(path3)}.${process.pid}.tmp`);
|
|
84742
|
+
writeFileSync20(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
|
|
84213
84743
|
`, "utf8");
|
|
84214
|
-
|
|
84744
|
+
renameSync12(temp, path3);
|
|
84215
84745
|
} catch {
|
|
84216
84746
|
}
|
|
84217
84747
|
};
|
|
@@ -84234,13 +84764,13 @@ var init_boot_progress = __esm({
|
|
|
84234
84764
|
});
|
|
84235
84765
|
|
|
84236
84766
|
// packages/server/src/runtime-lease.ts
|
|
84237
|
-
import { existsSync as existsSync22, mkdirSync as
|
|
84238
|
-
import { dirname as
|
|
84767
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync27, readdirSync as readdirSync15, readFileSync as readFileSync35, unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "node:fs";
|
|
84768
|
+
import { dirname as dirname26, join as join51 } from "node:path";
|
|
84239
84769
|
function runtimeVersionDir(bin) {
|
|
84240
|
-
let dir =
|
|
84770
|
+
let dir = dirname26(bin);
|
|
84241
84771
|
for (let step = 0; step < MAX_ASCENT; step++) {
|
|
84242
|
-
if (existsSync22(
|
|
84243
|
-
const parent =
|
|
84772
|
+
if (existsSync22(join51(dir, PROVISIONED_MARKER))) return dir;
|
|
84773
|
+
const parent = dirname26(dir);
|
|
84244
84774
|
if (parent === dir) return void 0;
|
|
84245
84775
|
dir = parent;
|
|
84246
84776
|
}
|
|
@@ -84258,11 +84788,11 @@ function leaseRuntime(bin, role) {
|
|
|
84258
84788
|
const versionDir = runtimeVersionDir(bin);
|
|
84259
84789
|
if (!versionDir) return () => {
|
|
84260
84790
|
};
|
|
84261
|
-
const path3 =
|
|
84791
|
+
const path3 = join51(versionDir, LEASES_DIR, `${process.pid}.json`);
|
|
84262
84792
|
try {
|
|
84263
|
-
|
|
84793
|
+
mkdirSync27(dirname26(path3), { recursive: true });
|
|
84264
84794
|
const lease = { pid: process.pid, role, bin, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
84265
|
-
|
|
84795
|
+
writeFileSync21(path3, JSON.stringify(lease));
|
|
84266
84796
|
} catch {
|
|
84267
84797
|
return () => {
|
|
84268
84798
|
};
|
|
@@ -84275,7 +84805,7 @@ function leaseRuntime(bin, role) {
|
|
|
84275
84805
|
};
|
|
84276
84806
|
}
|
|
84277
84807
|
function liveRuntimeLeases(versionDir) {
|
|
84278
|
-
const dir =
|
|
84808
|
+
const dir = join51(versionDir, LEASES_DIR);
|
|
84279
84809
|
let names;
|
|
84280
84810
|
try {
|
|
84281
84811
|
names = readdirSync15(dir);
|
|
@@ -84285,10 +84815,10 @@ function liveRuntimeLeases(versionDir) {
|
|
|
84285
84815
|
const live = [];
|
|
84286
84816
|
for (const name of names) {
|
|
84287
84817
|
if (!name.endsWith(".json")) continue;
|
|
84288
|
-
const path3 =
|
|
84818
|
+
const path3 = join51(dir, name);
|
|
84289
84819
|
let lease;
|
|
84290
84820
|
try {
|
|
84291
|
-
lease = JSON.parse(
|
|
84821
|
+
lease = JSON.parse(readFileSync35(path3, "utf8"));
|
|
84292
84822
|
} catch {
|
|
84293
84823
|
continue;
|
|
84294
84824
|
}
|
|
@@ -84315,29 +84845,29 @@ var init_runtime_lease = __esm({
|
|
|
84315
84845
|
});
|
|
84316
84846
|
|
|
84317
84847
|
// packages/server/src/runtimes.ts
|
|
84318
|
-
import { createHash as
|
|
84848
|
+
import { createHash as createHash18 } from "node:crypto";
|
|
84319
84849
|
import {
|
|
84320
|
-
chmodSync as
|
|
84850
|
+
chmodSync as chmodSync5,
|
|
84321
84851
|
closeSync as closeSync18,
|
|
84322
84852
|
existsSync as existsSync23,
|
|
84323
|
-
mkdirSync as
|
|
84853
|
+
mkdirSync as mkdirSync28,
|
|
84324
84854
|
openSync as openSync19,
|
|
84325
|
-
readFileSync as
|
|
84855
|
+
readFileSync as readFileSync36,
|
|
84326
84856
|
readdirSync as readdirSync16,
|
|
84327
|
-
renameSync as
|
|
84857
|
+
renameSync as renameSync13,
|
|
84328
84858
|
rmSync as rmSync14,
|
|
84329
|
-
statSync as
|
|
84330
|
-
writeFileSync as
|
|
84859
|
+
statSync as statSync25,
|
|
84860
|
+
writeFileSync as writeFileSync22,
|
|
84331
84861
|
writeSync as writeSync3
|
|
84332
84862
|
} from "node:fs";
|
|
84333
|
-
import { dirname as
|
|
84863
|
+
import { dirname as dirname27, isAbsolute as isAbsolute10, join as join52, normalize, relative as relative3, sep as sep6 } from "node:path";
|
|
84334
84864
|
import { Readable as Readable2, Transform, Writable as Writable4 } from "node:stream";
|
|
84335
84865
|
import { pipeline } from "node:stream/promises";
|
|
84336
84866
|
import { createGunzip } from "node:zlib";
|
|
84337
84867
|
function runtimesRoot(env = process.env) {
|
|
84338
84868
|
const override = env[RUNTIMES_DIR_ENV];
|
|
84339
84869
|
if (override && isAbsolute10(override)) return override;
|
|
84340
|
-
return
|
|
84870
|
+
return join52(frizzRoots().cache, "runtimes");
|
|
84341
84871
|
}
|
|
84342
84872
|
function isMusl() {
|
|
84343
84873
|
if (process.platform !== "linux") return false;
|
|
@@ -84354,15 +84884,15 @@ function runtimeCoordinates(backend, platform3 = process.platform, arch = proces
|
|
|
84354
84884
|
return { pkg: "@openai/codex", packageVersion: `${CODEX_VERSION}-${platform3}-${arch}`, label: CODEX_VERSION, binary: `codex${exe2}` };
|
|
84355
84885
|
}
|
|
84356
84886
|
function provisionedBinary(backend, root, label) {
|
|
84357
|
-
const dir =
|
|
84887
|
+
const dir = join52(root, backend, label);
|
|
84358
84888
|
let marker;
|
|
84359
84889
|
try {
|
|
84360
|
-
marker = JSON.parse(
|
|
84890
|
+
marker = JSON.parse(readFileSync36(join52(dir, MARKER), "utf8"));
|
|
84361
84891
|
} catch {
|
|
84362
84892
|
return void 0;
|
|
84363
84893
|
}
|
|
84364
84894
|
if (typeof marker.binary !== "string" || marker.label !== label) return void 0;
|
|
84365
|
-
const bin =
|
|
84895
|
+
const bin = join52(dir, marker.binary);
|
|
84366
84896
|
return existsSync23(bin) ? bin : void 0;
|
|
84367
84897
|
}
|
|
84368
84898
|
function octal(buffer, offset, length) {
|
|
@@ -84377,17 +84907,17 @@ function safeEntryPath(dest, name) {
|
|
|
84377
84907
|
if (parts.length < 2) return void 0;
|
|
84378
84908
|
const rel = normalize(parts.slice(1).join(sep6));
|
|
84379
84909
|
if (isAbsolute10(rel) || rel === ".." || rel.startsWith(`..${sep6}`)) return void 0;
|
|
84380
|
-
const full =
|
|
84910
|
+
const full = join52(dest, rel);
|
|
84381
84911
|
const back = relative3(dest, full);
|
|
84382
84912
|
if (back.startsWith("..") || isAbsolute10(back)) return void 0;
|
|
84383
84913
|
return full;
|
|
84384
84914
|
}
|
|
84385
84915
|
function locateBinary(dir, backend, binary) {
|
|
84386
84916
|
if (backend === "claude") {
|
|
84387
|
-
const direct =
|
|
84917
|
+
const direct = join52(dir, binary);
|
|
84388
84918
|
return existsSync23(direct) ? direct : void 0;
|
|
84389
84919
|
}
|
|
84390
|
-
const vendor =
|
|
84920
|
+
const vendor = join52(dir, "vendor");
|
|
84391
84921
|
let triples;
|
|
84392
84922
|
try {
|
|
84393
84923
|
triples = readdirSync16(vendor);
|
|
@@ -84395,7 +84925,7 @@ function locateBinary(dir, backend, binary) {
|
|
|
84395
84925
|
return void 0;
|
|
84396
84926
|
}
|
|
84397
84927
|
for (const triple of triples) {
|
|
84398
|
-
const candidate =
|
|
84928
|
+
const candidate = join52(vendor, triple, "bin", binary);
|
|
84399
84929
|
if (existsSync23(candidate)) return candidate;
|
|
84400
84930
|
}
|
|
84401
84931
|
return void 0;
|
|
@@ -84411,12 +84941,12 @@ async function provisionRuntime(backend, options) {
|
|
|
84411
84941
|
const registry = options.registry ?? REGISTRY;
|
|
84412
84942
|
const progress = options.onProgress ?? (() => {
|
|
84413
84943
|
});
|
|
84414
|
-
const backendDir =
|
|
84415
|
-
const finalDir =
|
|
84416
|
-
const partial =
|
|
84417
|
-
|
|
84944
|
+
const backendDir = join52(root, backend);
|
|
84945
|
+
const finalDir = join52(backendDir, coordinates.label);
|
|
84946
|
+
const partial = join52(backendDir, `.partial-${coordinates.label}-${process.pid}`);
|
|
84947
|
+
mkdirSync28(backendDir, { recursive: true });
|
|
84418
84948
|
rmSync14(partial, { recursive: true, force: true });
|
|
84419
|
-
|
|
84949
|
+
mkdirSync28(partial);
|
|
84420
84950
|
try {
|
|
84421
84951
|
const manifestUrl = `${registry}/${coordinates.pkg.replace("/", "%2F")}/${coordinates.packageVersion}`;
|
|
84422
84952
|
progress(`resolving ${coordinates.pkg}@${coordinates.packageVersion}`);
|
|
@@ -84429,7 +84959,7 @@ async function provisionRuntime(backend, options) {
|
|
|
84429
84959
|
const response = await fetchImpl(tarball);
|
|
84430
84960
|
if (!response.ok || !response.body) throw new Error(`tarball download answered ${response.status}`);
|
|
84431
84961
|
const total = Number(response.headers.get("content-length") ?? 0);
|
|
84432
|
-
const hash =
|
|
84962
|
+
const hash = createHash18("sha512");
|
|
84433
84963
|
let seen = 0;
|
|
84434
84964
|
let lastReport = 0;
|
|
84435
84965
|
const hasher = new Transform({
|
|
@@ -84450,7 +84980,7 @@ async function provisionRuntime(backend, options) {
|
|
|
84450
84980
|
if (digest !== integrity) throw new Error(`integrity mismatch for ${tarball}: expected ${integrity}, got ${digest}`);
|
|
84451
84981
|
const bin = locateBinary(partial, backend, coordinates.binary);
|
|
84452
84982
|
if (!bin) throw new Error(`${coordinates.pkg}@${coordinates.packageVersion} unpacked without a ${coordinates.binary} binary`);
|
|
84453
|
-
if (process.platform !== "win32")
|
|
84983
|
+
if (process.platform !== "win32") chmodSync5(bin, 493);
|
|
84454
84984
|
const marker = {
|
|
84455
84985
|
backend,
|
|
84456
84986
|
label: coordinates.label,
|
|
@@ -84460,9 +84990,9 @@ async function provisionRuntime(backend, options) {
|
|
|
84460
84990
|
binary: relative3(partial, bin),
|
|
84461
84991
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
84462
84992
|
};
|
|
84463
|
-
|
|
84993
|
+
writeFileSync22(join52(partial, MARKER), `${JSON.stringify(marker, null, 2)}
|
|
84464
84994
|
`, "utf8");
|
|
84465
|
-
const rename2 = options.rename ??
|
|
84995
|
+
const rename2 = options.rename ?? renameSync13;
|
|
84466
84996
|
try {
|
|
84467
84997
|
for (let attempt = 1; ; attempt++) {
|
|
84468
84998
|
try {
|
|
@@ -84480,7 +85010,7 @@ async function provisionRuntime(backend, options) {
|
|
|
84480
85010
|
return { bin: theirs, label: coordinates.label, fetched: false };
|
|
84481
85011
|
}
|
|
84482
85012
|
progress("ready");
|
|
84483
|
-
return { bin:
|
|
85013
|
+
return { bin: join52(finalDir, marker.binary), label: coordinates.label, fetched: true };
|
|
84484
85014
|
} catch (err) {
|
|
84485
85015
|
rmSync14(partial, { recursive: true, force: true });
|
|
84486
85016
|
throw err;
|
|
@@ -84488,7 +85018,7 @@ async function provisionRuntime(backend, options) {
|
|
|
84488
85018
|
}
|
|
84489
85019
|
function sweepRuntimes(backend, root, keepLabel, now = Date.now(), deps = {}) {
|
|
84490
85020
|
const rm2 = deps.rm ?? defaultSweepRm;
|
|
84491
|
-
const backendDir =
|
|
85021
|
+
const backendDir = join52(root, backend);
|
|
84492
85022
|
let entries2;
|
|
84493
85023
|
try {
|
|
84494
85024
|
entries2 = readdirSync16(backendDir);
|
|
@@ -84498,10 +85028,10 @@ function sweepRuntimes(backend, root, keepLabel, now = Date.now(), deps = {}) {
|
|
|
84498
85028
|
const sweep = { removed: [], kept: [] };
|
|
84499
85029
|
for (const entry of entries2) {
|
|
84500
85030
|
if (entry === keepLabel) continue;
|
|
84501
|
-
const full =
|
|
85031
|
+
const full = join52(backendDir, entry);
|
|
84502
85032
|
if (entry.startsWith(".partial-")) {
|
|
84503
85033
|
try {
|
|
84504
|
-
if (now -
|
|
85034
|
+
if (now - statSync25(full).mtimeMs < 24 * 60 * 60 * 1e3) continue;
|
|
84505
85035
|
} catch {
|
|
84506
85036
|
continue;
|
|
84507
85037
|
}
|
|
@@ -84681,7 +85211,7 @@ var init_runtimes = __esm({
|
|
|
84681
85211
|
return;
|
|
84682
85212
|
case "5": {
|
|
84683
85213
|
const dir = safeEntryPath(this.dest, name);
|
|
84684
|
-
if (dir)
|
|
85214
|
+
if (dir) mkdirSync28(dir, { recursive: true });
|
|
84685
85215
|
return;
|
|
84686
85216
|
}
|
|
84687
85217
|
case "0":
|
|
@@ -84689,7 +85219,7 @@ var init_runtimes = __esm({
|
|
|
84689
85219
|
case "7": {
|
|
84690
85220
|
const file = safeEntryPath(this.dest, name);
|
|
84691
85221
|
if (!file) return;
|
|
84692
|
-
|
|
85222
|
+
mkdirSync28(dirname27(file), { recursive: true });
|
|
84693
85223
|
this.fd = openSync19(file, "w", octal(header, 100, 8) & 511 || 420);
|
|
84694
85224
|
this.written.push(file);
|
|
84695
85225
|
return;
|
|
@@ -84757,6 +85287,7 @@ function createTenantMap(options) {
|
|
|
84757
85287
|
log.info("tenants", `project ${project.name} (${project.id}) moved from ${already.project.dir} to ${project.dir}; reopening it there`);
|
|
84758
85288
|
await deactivate(project.id);
|
|
84759
85289
|
}
|
|
85290
|
+
refuseWorldWritableProject(project.dir);
|
|
84760
85291
|
const ctx = await options.createContext({ ...options.contextOptions, project });
|
|
84761
85292
|
open.set(project.id, { project, ctx, app: options.createApp?.(ctx) });
|
|
84762
85293
|
await options.startProducers?.(ctx);
|
|
@@ -84764,11 +85295,12 @@ function createTenantMap(options) {
|
|
|
84764
85295
|
} catch (error) {
|
|
84765
85296
|
report(project, error);
|
|
84766
85297
|
return void 0;
|
|
84767
|
-
} finally {
|
|
84768
|
-
opening.delete(project.id);
|
|
84769
85298
|
}
|
|
84770
85299
|
})();
|
|
84771
85300
|
opening.set(project.id, attempt);
|
|
85301
|
+
void attempt.then(() => {
|
|
85302
|
+
if (opening.get(project.id) === attempt) opening.delete(project.id);
|
|
85303
|
+
});
|
|
84772
85304
|
return attempt;
|
|
84773
85305
|
}
|
|
84774
85306
|
async function deactivate(projectId) {
|
|
@@ -84816,6 +85348,7 @@ var init_tenants = __esm({
|
|
|
84816
85348
|
"use strict";
|
|
84817
85349
|
init_context();
|
|
84818
85350
|
init_logging();
|
|
85351
|
+
init_project_root();
|
|
84819
85352
|
}
|
|
84820
85353
|
});
|
|
84821
85354
|
|
|
@@ -85269,18 +85802,18 @@ var init_legacy_project_db = __esm({
|
|
|
85269
85802
|
});
|
|
85270
85803
|
|
|
85271
85804
|
// packages/server/src/frizz-db.ts
|
|
85272
|
-
import { existsSync as existsSync24, mkdirSync as
|
|
85273
|
-
import { basename as basename13, dirname as
|
|
85805
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync29, readdirSync as readdirSync17, renameSync as renameSync14, statSync as statSync26 } from "node:fs";
|
|
85806
|
+
import { basename as basename13, dirname as dirname28, join as join53 } from "node:path";
|
|
85274
85807
|
function frizzDatabaseLocation(options) {
|
|
85275
85808
|
if (options.stateDir !== void 0) {
|
|
85276
|
-
const projectsDir =
|
|
85809
|
+
const projectsDir = dirname28(options.stateDir);
|
|
85277
85810
|
if (basename13(projectsDir) === "projects") {
|
|
85278
|
-
return { path: options.path ??
|
|
85811
|
+
return { path: options.path ?? join53(dirname28(projectsDir), "ui.db"), projectsDir };
|
|
85279
85812
|
}
|
|
85280
|
-
return { path: options.path ??
|
|
85813
|
+
return { path: options.path ?? join53(options.stateDir, "ui.db"), projectsDir: void 0 };
|
|
85281
85814
|
}
|
|
85282
85815
|
const data = options.home ? frizzPaths({ home: options.home }).data : frizzRoots().data;
|
|
85283
|
-
return { path: options.path ??
|
|
85816
|
+
return { path: options.path ?? join53(data, "ui.db"), projectsDir: join53(data, "projects") };
|
|
85284
85817
|
}
|
|
85285
85818
|
function ensureFrizzSchema(db2) {
|
|
85286
85819
|
db2.exec(`
|
|
@@ -85299,7 +85832,7 @@ function ensureFrizzSchema(db2) {
|
|
|
85299
85832
|
}
|
|
85300
85833
|
function openFrizzDatabase(options = {}) {
|
|
85301
85834
|
const { path: path3, projectsDir } = frizzDatabaseLocation(options);
|
|
85302
|
-
|
|
85835
|
+
mkdirSync29(dirname28(path3), { recursive: true });
|
|
85303
85836
|
const db2 = new sqlite_default(path3);
|
|
85304
85837
|
db2.pragma("busy_timeout = 5000");
|
|
85305
85838
|
db2.pragma("journal_mode = WAL");
|
|
@@ -85311,10 +85844,10 @@ function openFrizzDatabase(options = {}) {
|
|
|
85311
85844
|
);
|
|
85312
85845
|
for (const projectId of retiredLegacyProjectIds(projectsDir)) {
|
|
85313
85846
|
if (alreadyImported.has(projectId)) continue;
|
|
85314
|
-
const dir =
|
|
85847
|
+
const dir = join53(projectsDir, projectId);
|
|
85315
85848
|
try {
|
|
85316
|
-
|
|
85317
|
-
db2.prepare("INSERT INTO imported_project (project_id, source, rows, imported_at) VALUES (?, ?, 0, ?)").run(projectId,
|
|
85849
|
+
renameSync14(join53(dir, "ui.db.imported"), join53(dir, "ui.db"));
|
|
85850
|
+
db2.prepare("INSERT INTO imported_project (project_id, source, rows, imported_at) VALUES (?, ?, 0, ?)").run(projectId, join53(dir, "ui.db"), (/* @__PURE__ */ new Date()).toISOString());
|
|
85318
85851
|
alreadyImported.add(projectId);
|
|
85319
85852
|
log.info("frizz-db", `${projectId}: restored ui.db.imported to ui.db and recorded it as imported`);
|
|
85320
85853
|
} catch (error) {
|
|
@@ -85324,7 +85857,7 @@ function openFrizzDatabase(options = {}) {
|
|
|
85324
85857
|
}
|
|
85325
85858
|
for (const projectId of legacyProjectIds(projectsDir)) {
|
|
85326
85859
|
if (alreadyImported.has(projectId)) continue;
|
|
85327
|
-
const legacyPath =
|
|
85860
|
+
const legacyPath = join53(projectsDir, projectId, "ui.db");
|
|
85328
85861
|
try {
|
|
85329
85862
|
const rows = importLegacyProject(db2, projectId, legacyPath);
|
|
85330
85863
|
imported.push({ projectId, rows });
|
|
@@ -85357,7 +85890,7 @@ function projectIdsWithFile(projectsDir, file) {
|
|
|
85357
85890
|
if (!existsSync24(projectsDir)) return [];
|
|
85358
85891
|
return readdirSync17(projectsDir).filter((name) => {
|
|
85359
85892
|
try {
|
|
85360
|
-
return
|
|
85893
|
+
return statSync26(join53(projectsDir, name, file)).isFile();
|
|
85361
85894
|
} catch {
|
|
85362
85895
|
return false;
|
|
85363
85896
|
}
|
|
@@ -85367,7 +85900,7 @@ function legacyProjectIds(projectsDir) {
|
|
|
85367
85900
|
return projectIdsWithFile(projectsDir, "ui.db");
|
|
85368
85901
|
}
|
|
85369
85902
|
function retiredLegacyProjectIds(projectsDir) {
|
|
85370
|
-
return projectIdsWithFile(projectsDir, "ui.db.imported").filter((id2) => !existsSync24(
|
|
85903
|
+
return projectIdsWithFile(projectsDir, "ui.db.imported").filter((id2) => !existsSync24(join53(projectsDir, id2, "ui.db")));
|
|
85371
85904
|
}
|
|
85372
85905
|
function tableColumns(db2, schema, table) {
|
|
85373
85906
|
return db2.prepare(`PRAGMA ${schema}.table_info(${table})`).all().map((c) => c.name);
|
|
@@ -85522,8 +86055,8 @@ var init_tenant_prime = __esm({
|
|
|
85522
86055
|
|
|
85523
86056
|
// packages/server/src/project-teardown.ts
|
|
85524
86057
|
import { rmSync as rmSync15 } from "node:fs";
|
|
85525
|
-
import { homedir as
|
|
85526
|
-
import { dirname as
|
|
86058
|
+
import { homedir as homedir20 } from "node:os";
|
|
86059
|
+
import { dirname as dirname29, resolve as resolve11 } from "node:path";
|
|
85527
86060
|
async function stopProjectWorkers(ctx) {
|
|
85528
86061
|
let stopped = 0;
|
|
85529
86062
|
for (const row of ctx.storage.allSessions()) {
|
|
@@ -85538,12 +86071,12 @@ async function stopProjectWorkers(ctx) {
|
|
|
85538
86071
|
}
|
|
85539
86072
|
return stopped;
|
|
85540
86073
|
}
|
|
85541
|
-
function deleteProjectState(projectId, home =
|
|
86074
|
+
function deleteProjectState(projectId, home = homedir20()) {
|
|
85542
86075
|
const target = projectStateDir(projectId, home);
|
|
85543
86076
|
if (!/^[\w.-]+$/u.test(projectId) || projectId === "." || projectId === "..") {
|
|
85544
86077
|
throw new Error(`Refusing to delete state for a malformed project id: ${projectId}`);
|
|
85545
86078
|
}
|
|
85546
|
-
if (
|
|
86079
|
+
if (dirname29(resolve11(target)) !== resolve11(dirname29(projectStateDir("x", home)))) {
|
|
85547
86080
|
throw new Error(`Refusing to delete ${target} \u2014 it is not a project state directory`);
|
|
85548
86081
|
}
|
|
85549
86082
|
rmSync15(target, { recursive: true, force: true });
|
|
@@ -85572,11 +86105,11 @@ __export(index_exports, {
|
|
|
85572
86105
|
unknownProjectPage: () => unknownProjectPage
|
|
85573
86106
|
});
|
|
85574
86107
|
import { createServer } from "node:http";
|
|
85575
|
-
import { readFileSync as
|
|
85576
|
-
import { dirname as
|
|
86108
|
+
import { readFileSync as readFileSync37, existsSync as existsSync25, statSync as statSync27 } from "node:fs";
|
|
86109
|
+
import { dirname as dirname30, join as join54, resolve as resolve12, extname as extname4, posix as posix2, sep as sep7 } from "node:path";
|
|
85577
86110
|
function readServerAddressHolder(path3) {
|
|
85578
86111
|
try {
|
|
85579
|
-
const value = JSON.parse(
|
|
86112
|
+
const value = JSON.parse(readFileSync37(path3, "utf8"));
|
|
85580
86113
|
if (typeof value?.pid !== "number") return void 0;
|
|
85581
86114
|
return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
|
|
85582
86115
|
} catch {
|
|
@@ -85623,7 +86156,10 @@ async function pipeToApp(app, req, res, port2, controller) {
|
|
|
85623
86156
|
// @ts-expect-error duplex is required by node's fetch when streaming a request body
|
|
85624
86157
|
duplex: "half",
|
|
85625
86158
|
signal: controller.signal
|
|
85626
|
-
})
|
|
86159
|
+
}),
|
|
86160
|
+
// The peer this server actually accepted, for a request the launcher's proxy did not stamp — the
|
|
86161
|
+
// only place it is known once the request becomes a Web Request (app.ts, the audit attribution).
|
|
86162
|
+
{ remoteAddress: req.socket?.remoteAddress }
|
|
85627
86163
|
);
|
|
85628
86164
|
res.writeHead(response.status, Object.fromEntries(response.headers.entries()));
|
|
85629
86165
|
if (response.body) {
|
|
@@ -85701,12 +86237,12 @@ function staticIsFresh(req, etag, mtimeMs) {
|
|
|
85701
86237
|
}
|
|
85702
86238
|
function serveStatic(distDir, req, res) {
|
|
85703
86239
|
const rel = posix2.normalize((req.url ?? "/").split("?")[0].replace(/\\/g, "/")).replace(/^(\.\.[/\\])+/, "");
|
|
85704
|
-
let file =
|
|
85705
|
-
if (!file.startsWith(distDir + sep7)) file =
|
|
85706
|
-
if (!existsSync25(file)) file =
|
|
86240
|
+
let file = join54(distDir, rel === "/" ? "index.html" : rel);
|
|
86241
|
+
if (!file.startsWith(distDir + sep7)) file = join54(distDir, "index.html");
|
|
86242
|
+
if (!existsSync25(file)) file = join54(distDir, "index.html");
|
|
85707
86243
|
try {
|
|
85708
|
-
const stats =
|
|
85709
|
-
const cacheControl = file.startsWith(
|
|
86244
|
+
const stats = statSync27(file);
|
|
86245
|
+
const cacheControl = file.startsWith(join54(distDir, "assets") + sep7) ? STATIC_CACHE_IMMUTABLE : STATIC_CACHE_REVALIDATE;
|
|
85710
86246
|
const etag = `"${stats.size.toString(16)}-${Math.trunc(stats.mtimeMs).toString(16)}"`;
|
|
85711
86247
|
const headers = {
|
|
85712
86248
|
"content-type": MIME[extname4(file)] ?? "application/octet-stream",
|
|
@@ -85722,7 +86258,7 @@ function serveStatic(distDir, req, res) {
|
|
|
85722
86258
|
res.end();
|
|
85723
86259
|
return;
|
|
85724
86260
|
}
|
|
85725
|
-
let body =
|
|
86261
|
+
let body = readFileSync37(file);
|
|
85726
86262
|
const accept = req.headers["accept-encoding"];
|
|
85727
86263
|
const encoding = negotiateEncoding(Array.isArray(accept) ? accept.join(",") : accept);
|
|
85728
86264
|
if (encoding && shouldCompress(new Headers({ "content-type": headers["content-type"] }), body.byteLength)) {
|
|
@@ -85761,7 +86297,7 @@ async function startServer(opts = {}) {
|
|
|
85761
86297
|
`${candidate.name} is already being served by another Frizz (pid ${other}). Stop that one first \u2014 two servers on one board would fire its timers and recurring prompts twice.`
|
|
85762
86298
|
);
|
|
85763
86299
|
};
|
|
85764
|
-
const activeTenants = () => tenants.active().map(({ project: open, ctx: openCtx }) => ({ project: open, board: openCtx.board }));
|
|
86300
|
+
const activeTenants = () => tenants.active().map(({ project: open, ctx: openCtx }) => ({ project: open, board: openCtx.board, storage: openCtx.storage }));
|
|
85765
86301
|
const teardownProject = async (projectId, options) => {
|
|
85766
86302
|
if (projectId === project.id) return { closed: false, stoppedWorkers: 0 };
|
|
85767
86303
|
const open = tenants.get(projectId);
|
|
@@ -85841,7 +86377,8 @@ async function startServer(opts = {}) {
|
|
|
85841
86377
|
(slug, taskId) => c.tailer.subAgentByTaskId?.(slug, taskId),
|
|
85842
86378
|
// The /ws producer is the one the live UI actually renders, so a dead owner has to reach it
|
|
85843
86379
|
// too — projecting only the RPC is the exact half-fix the × already had to correct once.
|
|
85844
|
-
(slug) => c.tailer.ownerGone?.(slug) ?? false
|
|
86380
|
+
(slug) => c.tailer.ownerGone?.(slug) ?? false,
|
|
86381
|
+
c.sessionPeerThread
|
|
85845
86382
|
),
|
|
85846
86383
|
// A reader's live watch on the file it shows. Gated as the read is (one set of openable roots for
|
|
85847
86384
|
// both readers, plus the Markdown reader's canonical-extension check) and watched by CANONICAL
|
|
@@ -85979,7 +86516,7 @@ async function startServer(opts = {}) {
|
|
|
85979
86516
|
if (statusPath && statusIdentity) runtime.removeStatus(statusPath, statusIdentity);
|
|
85980
86517
|
if (statusPath && statusIdentity) {
|
|
85981
86518
|
try {
|
|
85982
|
-
runtime.removeStatus(serverAddressPathForStateDir(
|
|
86519
|
+
runtime.removeStatus(serverAddressPathForStateDir(dirname30(statusPath)), statusIdentity);
|
|
85983
86520
|
} catch {
|
|
85984
86521
|
}
|
|
85985
86522
|
}
|
|
@@ -86111,7 +86648,7 @@ async function startServer(opts = {}) {
|
|
|
86111
86648
|
}
|
|
86112
86649
|
statusPath = serverLockPathFor(ctx.project);
|
|
86113
86650
|
const webRoot = resolve12(import.meta.dirname, "..", "..", "web");
|
|
86114
|
-
const distDir = opts.webDistDir ? resolve12(opts.webDistDir) :
|
|
86651
|
+
const distDir = opts.webDistDir ? resolve12(opts.webDistDir) : join54(webRoot, "dist");
|
|
86115
86652
|
startupPhase = "Vite";
|
|
86116
86653
|
if (opts.dev) {
|
|
86117
86654
|
try {
|
|
@@ -86189,7 +86726,7 @@ async function startServer(opts = {}) {
|
|
|
86189
86726
|
if (vite) {
|
|
86190
86727
|
vite.middlewares(req, res, () => {
|
|
86191
86728
|
try {
|
|
86192
|
-
const html =
|
|
86729
|
+
const html = readFileSync37(join54(webRoot, "index.html"), "utf8");
|
|
86193
86730
|
void vite.transformIndexHtml(url, html).then((out) => {
|
|
86194
86731
|
res.writeHead(200, { "content-type": "text/html" });
|
|
86195
86732
|
res.end(out);
|
|
@@ -86395,7 +86932,7 @@ var init_index = __esm({
|
|
|
86395
86932
|
}
|
|
86396
86933
|
};
|
|
86397
86934
|
isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
|
|
86398
|
-
serverLockPathFor = (project) =>
|
|
86935
|
+
serverLockPathFor = (project) => join54(project.stateDir, "server.lock");
|
|
86399
86936
|
MIME = {
|
|
86400
86937
|
".html": "text/html",
|
|
86401
86938
|
".js": "text/javascript",
|
|
@@ -86418,64 +86955,17 @@ init_project();
|
|
|
86418
86955
|
init_project_launch();
|
|
86419
86956
|
init_shutdown();
|
|
86420
86957
|
init_logging();
|
|
86958
|
+
init_access_codes();
|
|
86421
86959
|
import { existsSync as existsSync26 } from "node:fs";
|
|
86422
|
-
import { join as
|
|
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
|
-
}
|
|
86960
|
+
import { join as join55 } from "node:path";
|
|
86473
86961
|
|
|
86474
86962
|
// packages/server/src/session-epoch-child.ts
|
|
86963
|
+
init_access_codes();
|
|
86475
86964
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
86476
|
-
import { join as
|
|
86965
|
+
import { join as join11 } from "node:path";
|
|
86477
86966
|
|
|
86478
86967
|
// packages/server/src/restart-supervisor.ts
|
|
86968
|
+
init_access_codes();
|
|
86479
86969
|
init_local_origin();
|
|
86480
86970
|
init_local_image();
|
|
86481
86971
|
|
|
@@ -86684,6 +87174,7 @@ var RECOVERY_SCRIPT = `
|
|
|
86684
87174
|
`.trim();
|
|
86685
87175
|
|
|
86686
87176
|
// packages/server/src/restart-supervisor.ts
|
|
87177
|
+
init_audit();
|
|
86687
87178
|
init_src();
|
|
86688
87179
|
var SUPERVISOR_CONTROL_PREFIX = "/_frizz/control";
|
|
86689
87180
|
var SUPERVISOR_RESTART_PATH = `${SUPERVISOR_CONTROL_PREFIX}/restart`;
|
|
@@ -86719,7 +87210,7 @@ async function signOutOlderSessionEpoch(options) {
|
|
|
86719
87210
|
}
|
|
86720
87211
|
function supervisorPort(stateDir, supervisorPid) {
|
|
86721
87212
|
try {
|
|
86722
|
-
const status = JSON.parse(readFileSync7(
|
|
87213
|
+
const status = JSON.parse(readFileSync7(join11(stateDir, "dev-supervisor.lock"), "utf8"));
|
|
86723
87214
|
if (status.pid !== supervisorPid) return void 0;
|
|
86724
87215
|
return Number.isInteger(status.port) && status.port > 0 && status.port <= 65535 ? status.port : void 0;
|
|
86725
87216
|
} catch {
|
|
@@ -86784,7 +87275,7 @@ try {
|
|
|
86784
87275
|
];
|
|
86785
87276
|
if (!existsSync26(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
|
|
86786
87277
|
for (const [name, directory, requiredFile] of required) {
|
|
86787
|
-
if (!directory || !existsSync26(
|
|
87278
|
+
if (!directory || !existsSync26(join55(directory, requiredFile)))
|
|
86788
87279
|
throw new Error(`stable artifact launch is missing verified ${name}`);
|
|
86789
87280
|
}
|
|
86790
87281
|
}
|