frizz 0.7.5 → 0.7.8
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/README.md +31 -53
- package/dist/dev-child.js +476 -303
- package/dist/frizz.js +13476 -6556
- package/package.json +5 -3
- package/runtime/cc-worker/DECISIONS.md +12 -0
- package/runtime/cc-worker/bin/frizz-mcp.mjs +3 -2
- package/web-dist/assets/{TerminalPane-Cyao7kTi.js → TerminalPane-ubcEP7X3.js} +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-D1U0Q_zY.js → abnfDiagram-VRR7QNED-0brfnieb.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-DksosNDW.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-CtUBwBcU.js → architectureDiagram-ZJ3FMSHR-Dji-XBdF.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-OzqrN18g.js → blockDiagram-677ZJIJ3-BQMyz3Q9.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-DgYAtD7L.js → c4Diagram-LMCZKHZV-BMNws0Oi.js} +1 -1
- package/web-dist/assets/channel-DqoPvfQz.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-CKwBruPa.js → chunk-32BRIVSS-CVv1ae7n.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-gvoNW_ar.js → chunk-52WLFC77-BYhPlKCT.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-EJ5BdmRQ.js → chunk-C7G6YPKG-Cn4HhNwb.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-DJQF-VwN.js → chunk-EX3LRPZG-P3ZYFC1W.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-CXBLvjvR.js → chunk-FWX5IMBZ-Ba3NpEQa.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-De3ULdBq.js → chunk-HOUHSVGY-BCWyMhwJ.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-aUbMdGsl.js → chunk-ICXQ74PX-DWAAqHL7.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-BLK44SUW.js → chunk-MOJQB5TN-pc5VJ4Nq.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-CQZ3zQ2q.js → chunk-OGEWGWER-DUxmbiuX.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-DcdN44K2.js → chunk-PUDLZKDR-DRdZWzxX.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-Db2ge7fW.js → chunk-Q4XR5HBZ-Bafzu7s-.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-D80jxcmB.js → chunk-V7JOEXUC-Bj0A8ftW.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-nDGsXZZE.js → chunk-VAUOI2AC-DBgVQKIO.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-BGXgLAsD.js → chunk-VR4S4FIN-DU-1KtuM.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-BbGEK50o.js → chunk-WYO6CB5R-DzVb3-Rj.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-CjEI23Vu.js → chunk-ZGVPDNZ5-BPKQvduj.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DwUs74RB.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DwUs74RB.js +1 -0
- package/web-dist/assets/{cynefin-VYW2F7L2-CR69iDgw.js → cynefin-VYW2F7L2-lo8PqVCk.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Le_FSC65.js → cynefinDiagram-TSTJHNR4-BtQLaDV0.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-CxAlFDI9.js → dagre-VKFMJZFB-BJ2-f-A0.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-BFMwv6Pj.js → diagram-FQU43EPY-CLM-8r74.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-mWAc5hJ0.js → diagram-G47NLZAW-CfuoJGpN.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-CC-QXuir.js → diagram-NH7WQ7WH-DfxxRwH8.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-Cqs5o39q.js → diagram-OA4YK3LP-D7knxZee.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-B9PF6IpG.js → diagram-WEI45ONY-C2WfMXWl.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-C1DkTGUE.js → ebnfDiagram-CCIWWBDH-DRSZ24tF.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-CbCG5w3K.js → erDiagram-Q63AITRT-DXe0OrbY.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-CUIjQ7kE.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-Dka-3F3n.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-CaywKz56.js → ganttDiagram-NO4QXBWP-wGqOgjvs.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-DhbijOBs.js → gitGraph-TEB2WS4Q-BygokG6y.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-DHngf1QZ.js → gitGraphDiagram-IHSO6WYX-CV1933_M.js} +1 -1
- package/web-dist/assets/index-CmrDpsD8.css +1 -0
- package/web-dist/assets/{index-CxwWndgM.js → index-DB1d3eMJ.js} +107 -102
- package/web-dist/assets/{info-DKCQHKI2-D2uo8Yq_.js → info-DKCQHKI2-DLavbzui.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-Bixn1mvJ.js → infoDiagram-FWYZ7A6U-Biouxd9G.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DG48ASOp.js → ishikawaDiagram-FXEZZL3T-DJxwwS3R.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-DpQOwYAS.js → journeyDiagram-5HDEW3XC-Clx_WkdW.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-Dph0AMZo.js → kanban-definition-HUTT4EX6-Bf7bX_96.js} +1 -1
- package/web-dist/assets/{line-hnYRfUMr.js → line-CV2v49IN.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-DdD3ClpS.js → mermaid-parser.core-BPsFhEi6.js} +3 -3
- package/web-dist/assets/{mermaid.core-C2DMq9ss.js → mermaid.core-0EWDNL_R.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-CirJBG-x.js → mindmap-definition-LN4V7U3C-C1y4yy3Z.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-kD-OtFAF.js → packet-7NZHBO7P-CpcpxruB.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-DGmi8fl-.js → pegDiagram-2B236MQR-CVlVP4cH.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-DpKplj-N.js → pie-RZYD4A2V-BcVPOhTZ.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-CW-zVLyR.js → pieDiagram-ENE6RG2P-DZv4Tfae.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-fxSaIvo2.js → quadrantDiagram-ABIIQ3AL-DOzS_U_a.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-BPu7ClHP.js → radar-I7S5WNFK-8YADxkdT.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-CoQXFYm6.js → railroad-3IZDKUUU-DzndPrRy.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-CCnWa6K9.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-jtVdzv7e.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-B8D6TyEe.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-Bqnz_3Bc.js → railroadDiagram-RFXS5EU6-CPJAH-r7.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-DJHMdBhh.js → requirementDiagram-TGXJPOKE-BVFJZfwl.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-BlxzmT-W.js → sankeyDiagram-HTMAVEWB-CUhvFPmE.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-BT7Rn1Uo.js → sequenceDiagram-DBY2YBRQ-Cy9CGhNq.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-CDoiFcke.js → stateDiagram-2N3HPSRC-CqOnmPLp.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DWKW-4qu.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-DtzTgSSP.js → swimlanes-5IMT3BWC-c_zBqkb9.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-DZKoB7ae.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-Dn63VmSO.js → timeline-definition-FHXFAJF6-y_QM62SK.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-DIfJIc9R.js → treeView-QDETBFTQ-T3y_1KXV.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-n9Fwqngl.js → treemap-6X3UGDF4-CzvqucqY.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-C1thEMxE.js → vennDiagram-L72KCM5P-6-HNOpN0.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-Dl6RiScD.js → wardley-OPB4EBWU-BrsaqsLL.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-DBelgTwB.js → wardleyDiagram-EHGQE667-Cr_rCzwd.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-DFGVnPLj.js → xychartDiagram-FW5EYKEG-BnX6ccx4.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-BS8x9TQa.js +0 -1
- package/web-dist/assets/channel-DHZV3ADN.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-Dcx3TDdU.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-Dcx3TDdU.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-DAhP7KCX.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-Be2iuqwq.js +0 -1
- package/web-dist/assets/index-C-3lsl4q.css +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-BiqkuXNr.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-CDaukY4Z.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-CsUPdvVL.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DiLnjG8k.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BqvWOcR2.js +0 -8
package/dist/dev-child.js
CHANGED
|
@@ -12905,6 +12905,16 @@ var init_receipt_bus = __esm({
|
|
|
12905
12905
|
}
|
|
12906
12906
|
});
|
|
12907
12907
|
|
|
12908
|
+
// packages/shared/src/relay-protocol.ts
|
|
12909
|
+
var RELAY_MAX_FRAME_BODY, RELAY_MAX_WS_CHUNK;
|
|
12910
|
+
var init_relay_protocol = __esm({
|
|
12911
|
+
"packages/shared/src/relay-protocol.ts"() {
|
|
12912
|
+
"use strict";
|
|
12913
|
+
RELAY_MAX_FRAME_BODY = 512 * 1024;
|
|
12914
|
+
RELAY_MAX_WS_CHUNK = 64 * 1024;
|
|
12915
|
+
}
|
|
12916
|
+
});
|
|
12917
|
+
|
|
12908
12918
|
// packages/shared/src/index.ts
|
|
12909
12919
|
function attachmentExtension(name) {
|
|
12910
12920
|
const m = /\.([a-zA-Z0-9]+)$/.exec(name.trim());
|
|
@@ -13267,6 +13277,7 @@ var init_src = __esm({
|
|
|
13267
13277
|
init_drainable_worker();
|
|
13268
13278
|
init_interactions();
|
|
13269
13279
|
init_receipt_bus();
|
|
13280
|
+
init_relay_protocol();
|
|
13270
13281
|
init_thread_slug();
|
|
13271
13282
|
ATTACHMENT_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "webp"];
|
|
13272
13283
|
ATTACHMENT_DOC_EXTENSIONS = [
|
|
@@ -19507,40 +19518,29 @@ var init_storage = __esm({
|
|
|
19507
19518
|
}
|
|
19508
19519
|
});
|
|
19509
19520
|
|
|
19510
|
-
// packages/server/src/
|
|
19521
|
+
// packages/server/src/machine-config.ts
|
|
19511
19522
|
import { closeSync as closeSync5, fsyncSync as fsyncSync5, mkdirSync as mkdirSync7, openSync as openSync6, readFileSync as readFileSync6, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
19512
19523
|
import { dirname as dirname6, join as join9 } from "node:path";
|
|
19513
|
-
function
|
|
19514
|
-
return join9(frizzPaths({ home }).data, "
|
|
19515
|
-
}
|
|
19516
|
-
function pickMachine(settings) {
|
|
19517
|
-
return Object.fromEntries(MACHINE_KEYS.map((key) => [key, settings[key]]));
|
|
19524
|
+
function machineConfigPath(home) {
|
|
19525
|
+
return join9(frizzPaths({ home }).data, "config.json");
|
|
19518
19526
|
}
|
|
19519
|
-
function
|
|
19527
|
+
function readAll(home) {
|
|
19520
19528
|
let raw2;
|
|
19521
19529
|
try {
|
|
19522
|
-
raw2 = JSON.parse(readFileSync6(
|
|
19530
|
+
raw2 = JSON.parse(readFileSync6(machineConfigPath(home), "utf8"));
|
|
19523
19531
|
} catch {
|
|
19524
19532
|
return {};
|
|
19525
19533
|
}
|
|
19526
|
-
|
|
19527
|
-
const parsed = Settings.partial().safeParse(raw2);
|
|
19528
|
-
if (!parsed.success) return {};
|
|
19529
|
-
return pickPresent(parsed.data);
|
|
19530
|
-
}
|
|
19531
|
-
function pickPresent(partial) {
|
|
19532
|
-
const out = {};
|
|
19533
|
-
for (const key of MACHINE_KEYS) if (partial[key] !== void 0) Object.assign(out, { [key]: partial[key] });
|
|
19534
|
-
return out;
|
|
19534
|
+
return raw2 && typeof raw2 === "object" && !Array.isArray(raw2) ? raw2 : {};
|
|
19535
19535
|
}
|
|
19536
|
-
function
|
|
19537
|
-
const path =
|
|
19536
|
+
function writeAll(home, all) {
|
|
19537
|
+
const path = machineConfigPath(home);
|
|
19538
19538
|
mkdirSync7(dirname6(path), { recursive: true });
|
|
19539
19539
|
const temp = `${path}.${process.pid}.tmp`;
|
|
19540
19540
|
let fd;
|
|
19541
19541
|
try {
|
|
19542
19542
|
fd = openSync6(temp, "w", 384);
|
|
19543
|
-
writeFileSync6(fd, `${JSON.stringify(
|
|
19543
|
+
writeFileSync6(fd, `${JSON.stringify(all, null, 2)}
|
|
19544
19544
|
`, "utf8");
|
|
19545
19545
|
fsyncSync5(fd);
|
|
19546
19546
|
closeSync5(fd);
|
|
@@ -19557,6 +19557,58 @@ function writeMachineSettings(next, home) {
|
|
|
19557
19557
|
}
|
|
19558
19558
|
}
|
|
19559
19559
|
}
|
|
19560
|
+
function readMachineConfig(home, key, schema) {
|
|
19561
|
+
const value = readAll(home)[key];
|
|
19562
|
+
if (value === void 0) return void 0;
|
|
19563
|
+
const parsed = schema.safeParse(value);
|
|
19564
|
+
return parsed.success ? parsed.data : void 0;
|
|
19565
|
+
}
|
|
19566
|
+
function writeMachineConfig(home, key, value) {
|
|
19567
|
+
writeAll(home, { ...readAll(home), [key]: value });
|
|
19568
|
+
}
|
|
19569
|
+
function deleteMachineConfig(home, key) {
|
|
19570
|
+
const all = readAll(home);
|
|
19571
|
+
if (!(key in all)) return;
|
|
19572
|
+
delete all[key];
|
|
19573
|
+
writeAll(home, all);
|
|
19574
|
+
}
|
|
19575
|
+
var init_machine_config = __esm({
|
|
19576
|
+
"packages/server/src/machine-config.ts"() {
|
|
19577
|
+
"use strict";
|
|
19578
|
+
init_frizz_paths();
|
|
19579
|
+
}
|
|
19580
|
+
});
|
|
19581
|
+
|
|
19582
|
+
// packages/server/src/settings.ts
|
|
19583
|
+
import { readFileSync as readFileSync7, rmSync as rmSync7 } from "node:fs";
|
|
19584
|
+
import { join as join10 } from "node:path";
|
|
19585
|
+
function legacyMachineSettingsPath(home) {
|
|
19586
|
+
return join10(frizzPaths({ home }).data, "settings.json");
|
|
19587
|
+
}
|
|
19588
|
+
function pickMachine(settings) {
|
|
19589
|
+
return Object.fromEntries(MACHINE_KEYS.map((key) => [key, settings[key]]));
|
|
19590
|
+
}
|
|
19591
|
+
function readMachineSettings(home) {
|
|
19592
|
+
const stored = readMachineConfig(home, SETTINGS_KEY, MachineSettingsRecord);
|
|
19593
|
+
if (stored) return pickPresent(stored);
|
|
19594
|
+
let raw2;
|
|
19595
|
+
try {
|
|
19596
|
+
raw2 = JSON.parse(readFileSync7(legacyMachineSettingsPath(home), "utf8"));
|
|
19597
|
+
} catch {
|
|
19598
|
+
return {};
|
|
19599
|
+
}
|
|
19600
|
+
if (!raw2 || typeof raw2 !== "object") return {};
|
|
19601
|
+
const parsed = MachineSettingsRecord.safeParse(raw2);
|
|
19602
|
+
return parsed.success ? pickPresent(parsed.data) : {};
|
|
19603
|
+
}
|
|
19604
|
+
function pickPresent(partial) {
|
|
19605
|
+
const out = {};
|
|
19606
|
+
for (const key of MACHINE_KEYS) if (partial[key] !== void 0) Object.assign(out, { [key]: partial[key] });
|
|
19607
|
+
return out;
|
|
19608
|
+
}
|
|
19609
|
+
function writeMachineSettings(next, home) {
|
|
19610
|
+
writeMachineConfig(home, SETTINGS_KEY, next);
|
|
19611
|
+
}
|
|
19560
19612
|
function getSettings(storage, home) {
|
|
19561
19613
|
const raw2 = storage.getSetting(SETTINGS_KEY);
|
|
19562
19614
|
const project = raw2 === void 0 ? defaultSettings() : Settings.safeParse({ ...defaultSettings(), ...raw2 }).data ?? defaultSettings();
|
|
@@ -19570,20 +19622,23 @@ function setSettings(storage, next, home) {
|
|
|
19570
19622
|
}
|
|
19571
19623
|
function resetSettings(storage, home) {
|
|
19572
19624
|
storage.deleteSetting(SETTINGS_KEY);
|
|
19625
|
+
deleteMachineConfig(home, SETTINGS_KEY);
|
|
19573
19626
|
try {
|
|
19574
|
-
|
|
19627
|
+
rmSync7(legacyMachineSettingsPath(home), { force: true });
|
|
19575
19628
|
} catch {
|
|
19576
19629
|
}
|
|
19577
19630
|
return defaultSettings();
|
|
19578
19631
|
}
|
|
19579
|
-
var SETTINGS_KEY, MACHINE_KEYS, defaultSettings;
|
|
19632
|
+
var SETTINGS_KEY, MACHINE_KEYS, MachineSettingsRecord, defaultSettings;
|
|
19580
19633
|
var init_settings = __esm({
|
|
19581
19634
|
"packages/server/src/settings.ts"() {
|
|
19582
19635
|
"use strict";
|
|
19583
19636
|
init_src();
|
|
19584
19637
|
init_frizz_paths();
|
|
19638
|
+
init_machine_config();
|
|
19585
19639
|
SETTINGS_KEY = "settings";
|
|
19586
19640
|
MACHINE_KEYS = ["font", "notifications", "localFileOpener", "projectRail"];
|
|
19641
|
+
MachineSettingsRecord = Settings.partial();
|
|
19587
19642
|
defaultSettings = () => ({
|
|
19588
19643
|
// `bypassPermissions` = claude's --dangerously-skip-permissions: a headless worker never stops on an
|
|
19589
19644
|
// approval card. Shipped default since 0.7.2 (maintainer 2026-08-24); the Settings "Permissions"
|
|
@@ -19603,9 +19658,78 @@ var init_settings = __esm({
|
|
|
19603
19658
|
}
|
|
19604
19659
|
});
|
|
19605
19660
|
|
|
19661
|
+
// packages/server/src/dispatch-preferences.ts
|
|
19662
|
+
function readMachineDispatchPreferences(home) {
|
|
19663
|
+
return readMachineConfig(home, MACHINE_KEY, DispatchPreferences);
|
|
19664
|
+
}
|
|
19665
|
+
function permissionFor(backend, mode) {
|
|
19666
|
+
if (backend === "codex") {
|
|
19667
|
+
if (mode === "plan" || mode === "bypassPermissions") return mode;
|
|
19668
|
+
return "default";
|
|
19669
|
+
}
|
|
19670
|
+
return mode === "plan" ? "auto" : mode;
|
|
19671
|
+
}
|
|
19672
|
+
function defaultDispatchPreferences(settings, codexModels = []) {
|
|
19673
|
+
const backend = settings.backend ?? (codexModels.some((model) => model.slug === settings.model) ? "codex" : "claude");
|
|
19674
|
+
const selected = {
|
|
19675
|
+
...settings.model ? { model: settings.model } : {},
|
|
19676
|
+
...settings.effort ? { effort: settings.effort } : {},
|
|
19677
|
+
permissionMode: permissionFor(backend, settings.permissionMode)
|
|
19678
|
+
};
|
|
19679
|
+
return {
|
|
19680
|
+
backend,
|
|
19681
|
+
claude: backend === "claude" ? selected : { permissionMode: "auto" },
|
|
19682
|
+
codex: backend === "codex" ? selected : { permissionMode: "default" }
|
|
19683
|
+
};
|
|
19684
|
+
}
|
|
19685
|
+
function getDispatchPreferences(storage, settings, home, codexModels = []) {
|
|
19686
|
+
const machine = readMachineDispatchPreferences(home);
|
|
19687
|
+
if (machine) return machine;
|
|
19688
|
+
const parsed = DispatchPreferences.safeParse(storage.getSetting(KEY));
|
|
19689
|
+
return parsed.success ? parsed.data : defaultDispatchPreferences(settings, codexModels);
|
|
19690
|
+
}
|
|
19691
|
+
function setDispatchPreference(storage, settings, home, update, codexModels = []) {
|
|
19692
|
+
const current = getDispatchPreferences(storage, settings, home, codexModels);
|
|
19693
|
+
let next;
|
|
19694
|
+
if (update.field === "backend") {
|
|
19695
|
+
next = { ...current, backend: update.value };
|
|
19696
|
+
} else if (update.field === "profile") {
|
|
19697
|
+
next = {
|
|
19698
|
+
...current,
|
|
19699
|
+
backend: update.backend,
|
|
19700
|
+
[update.backend]: {
|
|
19701
|
+
...current[update.backend],
|
|
19702
|
+
model: update.model,
|
|
19703
|
+
effort: update.effort
|
|
19704
|
+
}
|
|
19705
|
+
};
|
|
19706
|
+
} else {
|
|
19707
|
+
const profile = current[update.backend];
|
|
19708
|
+
next = {
|
|
19709
|
+
...current,
|
|
19710
|
+
...update.field === "model" ? { backend: update.backend } : {},
|
|
19711
|
+
[update.backend]: { ...profile, [update.field]: update.value }
|
|
19712
|
+
};
|
|
19713
|
+
}
|
|
19714
|
+
const validated = DispatchPreferences.parse(next);
|
|
19715
|
+
writeMachineConfig(home, MACHINE_KEY, validated);
|
|
19716
|
+
storage.setSetting(KEY, validated);
|
|
19717
|
+
return validated;
|
|
19718
|
+
}
|
|
19719
|
+
var KEY, MACHINE_KEY;
|
|
19720
|
+
var init_dispatch_preferences = __esm({
|
|
19721
|
+
"packages/server/src/dispatch-preferences.ts"() {
|
|
19722
|
+
"use strict";
|
|
19723
|
+
init_src();
|
|
19724
|
+
init_machine_config();
|
|
19725
|
+
KEY = "dispatch-preferences.v1";
|
|
19726
|
+
MACHINE_KEY = "dispatchPreferences";
|
|
19727
|
+
}
|
|
19728
|
+
});
|
|
19729
|
+
|
|
19606
19730
|
// packages/server/src/discover.ts
|
|
19607
19731
|
import { readdirSync as readdirSync3, statSync as statSync4, openSync as openSync7, readSync, closeSync as closeSync6 } from "node:fs";
|
|
19608
|
-
import { dirname as dirname7, join as
|
|
19732
|
+
import { dirname as dirname7, join as join11 } from "node:path";
|
|
19609
19733
|
function sentinelFor(sessionId) {
|
|
19610
19734
|
return `threads/${sessionId}/`;
|
|
19611
19735
|
}
|
|
@@ -19642,7 +19766,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
19642
19766
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
19643
19767
|
const id = name.slice(0, -".jsonl".length);
|
|
19644
19768
|
if (!id || id === sessionId || exclude?.has(id)) continue;
|
|
19645
|
-
const path =
|
|
19769
|
+
const path = join11(logDir, name);
|
|
19646
19770
|
let mtime;
|
|
19647
19771
|
try {
|
|
19648
19772
|
mtime = statSync4(path).mtimeMs;
|
|
@@ -19670,7 +19794,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
|
|
|
19670
19794
|
const name = `${sessionId}.jsonl`;
|
|
19671
19795
|
const better = (best2, dir) => {
|
|
19672
19796
|
if (dir === logDir) return best2;
|
|
19673
|
-
const at = mtimeOfNonEmpty(
|
|
19797
|
+
const at = mtimeOfNonEmpty(join11(dir, name));
|
|
19674
19798
|
if (at === void 0) return best2;
|
|
19675
19799
|
return !best2 || at > best2.mtimeMs ? { dir, mtimeMs: at } : best2;
|
|
19676
19800
|
};
|
|
@@ -19683,7 +19807,7 @@ function discoverTranscriptDir(logDir, sessionId, memo3 = strandedLogDirs) {
|
|
|
19683
19807
|
} catch {
|
|
19684
19808
|
return void 0;
|
|
19685
19809
|
}
|
|
19686
|
-
for (const entry of entries) best = better(best,
|
|
19810
|
+
for (const entry of entries) best = better(best, join11(dirname7(logDir), entry));
|
|
19687
19811
|
if (!best) return void 0;
|
|
19688
19812
|
memo3.add(best.dir);
|
|
19689
19813
|
return best.dir;
|
|
@@ -19701,11 +19825,11 @@ var init_discover = __esm({
|
|
|
19701
19825
|
});
|
|
19702
19826
|
|
|
19703
19827
|
// packages/server/src/session-files.ts
|
|
19704
|
-
import { lstatSync, rmSync as
|
|
19705
|
-
import { join as
|
|
19828
|
+
import { lstatSync, rmSync as rmSync8 } from "node:fs";
|
|
19829
|
+
import { join as join12 } from "node:path";
|
|
19706
19830
|
function systemPromptPath(sessionId) {
|
|
19707
19831
|
if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
|
|
19708
|
-
return
|
|
19832
|
+
return join12(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
|
|
19709
19833
|
}
|
|
19710
19834
|
function isDirectDirectory(path) {
|
|
19711
19835
|
try {
|
|
@@ -19725,9 +19849,9 @@ function pathAbsent(path) {
|
|
|
19725
19849
|
}
|
|
19726
19850
|
function unlinkDirectChild(parent, filename) {
|
|
19727
19851
|
if (!isDirectDirectory(parent)) return pathAbsent(parent);
|
|
19728
|
-
const child =
|
|
19852
|
+
const child = join12(parent, filename);
|
|
19729
19853
|
try {
|
|
19730
|
-
|
|
19854
|
+
rmSync8(child, { force: true });
|
|
19731
19855
|
} catch {
|
|
19732
19856
|
return false;
|
|
19733
19857
|
}
|
|
@@ -19735,14 +19859,14 @@ function unlinkDirectChild(parent, filename) {
|
|
|
19735
19859
|
}
|
|
19736
19860
|
function cleanupAdoptionSessionFiles(projectDir, sessionId) {
|
|
19737
19861
|
if (!SESSION_ID_RE.test(sessionId)) return false;
|
|
19738
|
-
const frizzDir =
|
|
19862
|
+
const frizzDir = join12(projectDir, ".frizz");
|
|
19739
19863
|
let clean = true;
|
|
19740
19864
|
if (isDirectDirectory(frizzDir)) {
|
|
19741
|
-
const threads =
|
|
19865
|
+
const threads = join12(frizzDir, "threads");
|
|
19742
19866
|
if (isDirectDirectory(threads)) {
|
|
19743
|
-
const child =
|
|
19867
|
+
const child = join12(threads, sessionId);
|
|
19744
19868
|
try {
|
|
19745
|
-
|
|
19869
|
+
rmSync8(child, { recursive: true, force: true });
|
|
19746
19870
|
} catch {
|
|
19747
19871
|
clean = false;
|
|
19748
19872
|
}
|
|
@@ -19992,10 +20116,10 @@ var init_adoption_recovery = __esm({
|
|
|
19992
20116
|
});
|
|
19993
20117
|
|
|
19994
20118
|
// packages/server/src/backend/codex-models.ts
|
|
19995
|
-
import { join as
|
|
19996
|
-
import { readFileSync as
|
|
20119
|
+
import { join as join13 } from "node:path";
|
|
20120
|
+
import { readFileSync as readFileSync8 } from "node:fs";
|
|
19997
20121
|
function cachePath(codexHome) {
|
|
19998
|
-
return
|
|
20122
|
+
return join13(codexHome, "models_cache.json");
|
|
19999
20123
|
}
|
|
20000
20124
|
function toCodexModel(raw2) {
|
|
20001
20125
|
if (!raw2 || typeof raw2 !== "object") return void 0;
|
|
@@ -20031,7 +20155,7 @@ function readCodexModels(codexHome = defaultCodexHome()) {
|
|
|
20031
20155
|
if (hit && now - hit.at < TTL_MS) return hit.models;
|
|
20032
20156
|
let models;
|
|
20033
20157
|
try {
|
|
20034
|
-
models = parseCodexModelsCache(
|
|
20158
|
+
models = parseCodexModelsCache(readFileSync8(path, "utf8"));
|
|
20035
20159
|
} catch {
|
|
20036
20160
|
models = CODEX_MODELS_FALLBACK;
|
|
20037
20161
|
}
|
|
@@ -20573,10 +20697,10 @@ var init_claude_agent_sdk_protocol = __esm({
|
|
|
20573
20697
|
});
|
|
20574
20698
|
|
|
20575
20699
|
// packages/server/src/backend/claude-broker-diagnostics.ts
|
|
20576
|
-
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, readFileSync as
|
|
20577
|
-
import { join as
|
|
20700
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, readFileSync as readFileSync9, renameSync as renameSync6, statSync as statSync5 } from "node:fs";
|
|
20701
|
+
import { join as join14 } from "node:path";
|
|
20578
20702
|
function claudeBrokerDiagnosticLogPath(stateDir, sessionId) {
|
|
20579
|
-
return
|
|
20703
|
+
return join14(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
|
|
20580
20704
|
}
|
|
20581
20705
|
function readClaudeBrokerExit(stateDir, sessionId, generation) {
|
|
20582
20706
|
if (!generation) return null;
|
|
@@ -20584,7 +20708,7 @@ function readClaudeBrokerExit(stateDir, sessionId, generation) {
|
|
|
20584
20708
|
for (const path of [`${claudeBrokerDiagnosticLogPath(stateDir, sessionId)}.1`, claudeBrokerDiagnosticLogPath(stateDir, sessionId)]) {
|
|
20585
20709
|
let text;
|
|
20586
20710
|
try {
|
|
20587
|
-
text =
|
|
20711
|
+
text = readFileSync9(path, "utf8");
|
|
20588
20712
|
} catch {
|
|
20589
20713
|
continue;
|
|
20590
20714
|
}
|
|
@@ -20648,10 +20772,10 @@ var init_detached_daemons = __esm({
|
|
|
20648
20772
|
});
|
|
20649
20773
|
|
|
20650
20774
|
// packages/server/src/backend/ipc-path.ts
|
|
20651
|
-
import { join as
|
|
20775
|
+
import { join as join15 } from "node:path";
|
|
20652
20776
|
function frizzIpcPath(name) {
|
|
20653
20777
|
if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
|
|
20654
|
-
return
|
|
20778
|
+
return join15(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
|
|
20655
20779
|
}
|
|
20656
20780
|
var init_ipc_path = __esm({
|
|
20657
20781
|
"packages/server/src/backend/ipc-path.ts"() {
|
|
@@ -20662,18 +20786,18 @@ var init_ipc_path = __esm({
|
|
|
20662
20786
|
// packages/server/src/backend/claude-broker-host.ts
|
|
20663
20787
|
import { spawn } from "node:child_process";
|
|
20664
20788
|
import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
|
|
20665
|
-
import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as
|
|
20666
|
-
import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as
|
|
20789
|
+
import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as readFileSync10, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
20790
|
+
import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as join16 } from "node:path";
|
|
20667
20791
|
function windowsShimTarget(shimPath) {
|
|
20668
20792
|
let body;
|
|
20669
20793
|
try {
|
|
20670
|
-
body =
|
|
20794
|
+
body = readFileSync10(shimPath, "utf8");
|
|
20671
20795
|
} catch {
|
|
20672
20796
|
return void 0;
|
|
20673
20797
|
}
|
|
20674
20798
|
const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
|
|
20675
20799
|
if (!target) return void 0;
|
|
20676
|
-
const full =
|
|
20800
|
+
const full = join16(dirname8(shimPath), target);
|
|
20677
20801
|
try {
|
|
20678
20802
|
accessSync(full, fsConstants.F_OK);
|
|
20679
20803
|
return full;
|
|
@@ -20694,17 +20818,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
20694
20818
|
for (const dir of searchPath(env).split(delimiter)) {
|
|
20695
20819
|
if (!dir) continue;
|
|
20696
20820
|
if (windows) {
|
|
20697
|
-
const exe =
|
|
20821
|
+
const exe = join16(dir, `${candidate}.exe`);
|
|
20698
20822
|
try {
|
|
20699
20823
|
accessSync(exe, fsConstants.F_OK);
|
|
20700
20824
|
return exe;
|
|
20701
20825
|
} catch {
|
|
20702
20826
|
}
|
|
20703
|
-
const viaShim = windowsShimTarget(
|
|
20827
|
+
const viaShim = windowsShimTarget(join16(dir, `${candidate}.cmd`));
|
|
20704
20828
|
if (viaShim) return viaShim;
|
|
20705
20829
|
continue;
|
|
20706
20830
|
}
|
|
20707
|
-
const full =
|
|
20831
|
+
const full = join16(dir, candidate);
|
|
20708
20832
|
try {
|
|
20709
20833
|
accessSync(full, fsConstants.X_OK);
|
|
20710
20834
|
return full;
|
|
@@ -20719,11 +20843,11 @@ function claudeBrokerSocketPath(stateDir, sessionId) {
|
|
|
20719
20843
|
}
|
|
20720
20844
|
function claudeBrokerRecordPath(stateDir, sessionId) {
|
|
20721
20845
|
const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
20722
|
-
return
|
|
20846
|
+
return join16(stateDir, "claude-broker", `${key}.json`);
|
|
20723
20847
|
}
|
|
20724
20848
|
function claudeBrokerRetirementPath(stateDir, sessionId) {
|
|
20725
20849
|
const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
20726
|
-
return
|
|
20850
|
+
return join16(stateDir, "claude-broker", `${key}.retired`);
|
|
20727
20851
|
}
|
|
20728
20852
|
function markBrokerRetired(stateDir, sessionId, reason, generation) {
|
|
20729
20853
|
const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
|
|
@@ -20738,7 +20862,7 @@ function takeBrokerRetirement(stateDir, sessionId) {
|
|
|
20738
20862
|
const path = claudeBrokerRetirementPath(stateDir, sessionId);
|
|
20739
20863
|
let mark = null;
|
|
20740
20864
|
try {
|
|
20741
|
-
const parsed = JSON.parse(
|
|
20865
|
+
const parsed = JSON.parse(readFileSync10(path, "utf8"));
|
|
20742
20866
|
if (typeof parsed?.at === "string" && typeof parsed.generation === "string" && typeof parsed.reason === "string") {
|
|
20743
20867
|
mark = { at: parsed.at, generation: parsed.generation, reason: parsed.reason };
|
|
20744
20868
|
}
|
|
@@ -20760,7 +20884,7 @@ function pidAlive(pid) {
|
|
|
20760
20884
|
}
|
|
20761
20885
|
function readBrokerRecord(recordPath2) {
|
|
20762
20886
|
try {
|
|
20763
|
-
return JSON.parse(
|
|
20887
|
+
return JSON.parse(readFileSync10(recordPath2, "utf8"));
|
|
20764
20888
|
} catch {
|
|
20765
20889
|
return null;
|
|
20766
20890
|
}
|
|
@@ -20790,7 +20914,7 @@ function liveBrokerRecord(recordPath2) {
|
|
|
20790
20914
|
return null;
|
|
20791
20915
|
}
|
|
20792
20916
|
function liveBrokerRecords(stateDir) {
|
|
20793
|
-
const dir =
|
|
20917
|
+
const dir = join16(stateDir, "claude-broker");
|
|
20794
20918
|
let names;
|
|
20795
20919
|
try {
|
|
20796
20920
|
names = readdirSync4(dir);
|
|
@@ -20800,7 +20924,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
20800
20924
|
const out = [];
|
|
20801
20925
|
for (const name of names) {
|
|
20802
20926
|
if (!name.endsWith(".json")) continue;
|
|
20803
|
-
const record = liveBrokerRecord(
|
|
20927
|
+
const record = liveBrokerRecord(join16(dir, name));
|
|
20804
20928
|
if (record) out.push(record);
|
|
20805
20929
|
}
|
|
20806
20930
|
return out;
|
|
@@ -21608,15 +21732,15 @@ var init_completion_relay = __esm({
|
|
|
21608
21732
|
|
|
21609
21733
|
// packages/server/src/tail-cache.ts
|
|
21610
21734
|
import { createHash as createHash6 } from "node:crypto";
|
|
21611
|
-
import { closeSync as closeSync8, openSync as openSync9, readFileSync as
|
|
21612
|
-
import { join as
|
|
21735
|
+
import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync11, readSync as readSync3, statSync as statSync7 } from "node:fs";
|
|
21736
|
+
import { join as join17 } from "node:path";
|
|
21613
21737
|
function foldSchemaDigest(dir = import.meta.dirname) {
|
|
21614
21738
|
if (foldSchemaMemo) return foldSchemaMemo;
|
|
21615
21739
|
const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
|
|
21616
21740
|
let read = 0;
|
|
21617
21741
|
for (const name of FOLD_SOURCES) {
|
|
21618
21742
|
try {
|
|
21619
|
-
hash.update(name).update("\0").update(
|
|
21743
|
+
hash.update(name).update("\0").update(readFileSync11(join17(dir, name)));
|
|
21620
21744
|
read++;
|
|
21621
21745
|
} catch {
|
|
21622
21746
|
hash.update(name).update("\0missing\0");
|
|
@@ -21812,9 +21936,9 @@ var init_tail_cache = __esm({
|
|
|
21812
21936
|
});
|
|
21813
21937
|
|
|
21814
21938
|
// packages/server/src/tailer.ts
|
|
21815
|
-
import { statSync as statSync8, openSync as openSync10, readSync as readSync4, closeSync as closeSync9, readdirSync as readdirSync5, realpathSync as realpathSync5, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as
|
|
21939
|
+
import { statSync as statSync8, openSync as openSync10, readSync as readSync4, closeSync as closeSync9, readdirSync as readdirSync5, realpathSync as realpathSync5, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as readFileSync12, existsSync as existsSync5 } from "node:fs";
|
|
21816
21940
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
21817
|
-
import { basename as basename4, join as
|
|
21941
|
+
import { basename as basename4, join as join18 } from "node:path";
|
|
21818
21942
|
import { homedir as homedir7 } from "node:os";
|
|
21819
21943
|
function probeShellAlive(outputFile) {
|
|
21820
21944
|
if (!existsSync5(outputFile)) return void 0;
|
|
@@ -22076,7 +22200,7 @@ function launchTaskId(text) {
|
|
|
22076
22200
|
function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
22077
22201
|
let names;
|
|
22078
22202
|
try {
|
|
22079
|
-
names = readdirSync5(
|
|
22203
|
+
names = readdirSync5(join18(sessionDir, "subagents"));
|
|
22080
22204
|
} catch {
|
|
22081
22205
|
return [];
|
|
22082
22206
|
}
|
|
@@ -22087,7 +22211,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
22087
22211
|
if (!agentId) continue;
|
|
22088
22212
|
let parsed;
|
|
22089
22213
|
try {
|
|
22090
|
-
parsed = JSON.parse(
|
|
22214
|
+
parsed = JSON.parse(readFileSync12(join18(sessionDir, "subagents", name), "utf8"));
|
|
22091
22215
|
} catch {
|
|
22092
22216
|
continue;
|
|
22093
22217
|
}
|
|
@@ -22101,7 +22225,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
22101
22225
|
agentType: text(meta.agentType),
|
|
22102
22226
|
parentAgentId: text(meta.parentAgentId),
|
|
22103
22227
|
spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
|
|
22104
|
-
spawnedAtMs: mtimeMs(
|
|
22228
|
+
spawnedAtMs: mtimeMs(join18(sessionDir, "subagents", name))
|
|
22105
22229
|
});
|
|
22106
22230
|
}
|
|
22107
22231
|
return out;
|
|
@@ -22581,13 +22705,13 @@ function defaultMtimeMs(path) {
|
|
|
22581
22705
|
}
|
|
22582
22706
|
}
|
|
22583
22707
|
function defaultLogDir(project) {
|
|
22584
|
-
return
|
|
22708
|
+
return join18(homedir7(), ".claude", "projects", project.cwdSlug);
|
|
22585
22709
|
}
|
|
22586
22710
|
function defaultReadPermMarker(project) {
|
|
22587
22711
|
if (!project.stateDir) return () => void 0;
|
|
22588
22712
|
return (slug) => {
|
|
22589
22713
|
try {
|
|
22590
|
-
const parsed = JSON.parse(
|
|
22714
|
+
const parsed = JSON.parse(readFileSync12(permMarkerPath(project, slug), "utf8"));
|
|
22591
22715
|
return isPermMarker(parsed) ? parsed : void 0;
|
|
22592
22716
|
} catch {
|
|
22593
22717
|
return void 0;
|
|
@@ -22713,7 +22837,7 @@ function createTailer(deps) {
|
|
|
22713
22837
|
return paneDead(row.slug);
|
|
22714
22838
|
}
|
|
22715
22839
|
const defaultBackend = {
|
|
22716
|
-
transcriptPath: (sessionId) =>
|
|
22840
|
+
transcriptPath: (sessionId) => join18(logDir, `${sessionId}.jsonl`),
|
|
22717
22841
|
foldLine: (state, line) => {
|
|
22718
22842
|
const rec = parseLine(line);
|
|
22719
22843
|
if (rec) applyRecord(state, rec);
|
|
@@ -22838,7 +22962,7 @@ ${ask}`;
|
|
|
22838
22962
|
return state.path.replace(/\.jsonl$/, "");
|
|
22839
22963
|
}
|
|
22840
22964
|
function descendantSidecars(state) {
|
|
22841
|
-
const at = mtimeMs(
|
|
22965
|
+
const at = mtimeMs(join18(sessionDirOf(state), "subagents"));
|
|
22842
22966
|
const cached2 = descendantIndex.get(state.slug);
|
|
22843
22967
|
if (cached2 && cached2.at === at) return cached2.all;
|
|
22844
22968
|
const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
|
|
@@ -22852,7 +22976,7 @@ ${ask}`;
|
|
|
22852
22976
|
return descendantIndex.get(state.slug)?.byToolUse.get(id);
|
|
22853
22977
|
}
|
|
22854
22978
|
function descendantTranscript(state, meta) {
|
|
22855
|
-
return
|
|
22979
|
+
return join18(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
|
|
22856
22980
|
}
|
|
22857
22981
|
function subAgentDescendantTasks(slug, id) {
|
|
22858
22982
|
const state = states.get(slug);
|
|
@@ -23166,7 +23290,7 @@ ${ask}`;
|
|
|
23166
23290
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
23167
23291
|
const id = name.slice(0, -".jsonl".length);
|
|
23168
23292
|
if (!id || registered.has(id)) continue;
|
|
23169
|
-
const path =
|
|
23293
|
+
const path = join18(logDir, name);
|
|
23170
23294
|
let mtime;
|
|
23171
23295
|
try {
|
|
23172
23296
|
mtime = statSync8(path).mtimeMs;
|
|
@@ -23438,7 +23562,7 @@ ${ask}`;
|
|
|
23438
23562
|
);
|
|
23439
23563
|
try {
|
|
23440
23564
|
mkdirSync10(stallLogDir, { recursive: true });
|
|
23441
|
-
writeFileSync8(
|
|
23565
|
+
writeFileSync8(join18(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
|
|
23442
23566
|
captured_at: ${new Date(now()).toISOString()}
|
|
23443
23567
|
|
|
23444
23568
|
${detail}
|
|
@@ -23466,7 +23590,7 @@ ${detail}
|
|
|
23466
23590
|
state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
|
|
23467
23591
|
const strandedDir = discoverTranscriptDir(logDir, row.session_id);
|
|
23468
23592
|
if (strandedDir) {
|
|
23469
|
-
state.path =
|
|
23593
|
+
state.path = join18(strandedDir, `${row.session_id}.jsonl`);
|
|
23470
23594
|
state.offset = 0;
|
|
23471
23595
|
state.partial = "";
|
|
23472
23596
|
state.primed = false;
|
|
@@ -23489,7 +23613,7 @@ ${detail}
|
|
|
23489
23613
|
committed = false;
|
|
23490
23614
|
}
|
|
23491
23615
|
if (!committed) return false;
|
|
23492
|
-
state.path =
|
|
23616
|
+
state.path = join18(logDir, `${found}.jsonl`);
|
|
23493
23617
|
state.offset = 0;
|
|
23494
23618
|
state.partial = "";
|
|
23495
23619
|
state.primed = false;
|
|
@@ -23535,7 +23659,7 @@ ${detail}
|
|
|
23535
23659
|
let state = states.get(row.slug);
|
|
23536
23660
|
const runtimeGeneration = row.runtime_generation ?? 0;
|
|
23537
23661
|
if (!state || state.sessionId !== row.session_id || state.nativeSessionId !== nativeId || state.runtimeGeneration !== runtimeGeneration) {
|
|
23538
|
-
const path = backend.transcriptPath(nativeId) ??
|
|
23662
|
+
const path = backend.transcriptPath(nativeId) ?? join18(logDir, `${nativeId}.jsonl`);
|
|
23539
23663
|
state = newTailState(row.slug, row.session_id, path, false, nativeId, runtimeGeneration);
|
|
23540
23664
|
state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
|
|
23541
23665
|
hydrateFromCache(state, row, nativeId);
|
|
@@ -23984,14 +24108,14 @@ var init_tailer = __esm({
|
|
|
23984
24108
|
});
|
|
23985
24109
|
|
|
23986
24110
|
// packages/server/src/backend/codex.ts
|
|
23987
|
-
import { join as
|
|
24111
|
+
import { join as join19 } from "node:path";
|
|
23988
24112
|
import { homedir as homedir8 } from "node:os";
|
|
23989
|
-
import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as
|
|
24113
|
+
import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync13, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
|
|
23990
24114
|
function defaultCodexHome() {
|
|
23991
|
-
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME :
|
|
24115
|
+
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join19(homedir8(), ".codex");
|
|
23992
24116
|
}
|
|
23993
24117
|
function sessionsDir(codexHome) {
|
|
23994
|
-
return
|
|
24118
|
+
return join19(codexHome, "sessions");
|
|
23995
24119
|
}
|
|
23996
24120
|
function codexSandbox(mode) {
|
|
23997
24121
|
switch (mode) {
|
|
@@ -24372,17 +24496,17 @@ function collectRollouts(dir, out, budget) {
|
|
|
24372
24496
|
const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).sort(descByName);
|
|
24373
24497
|
for (const d of dirs) {
|
|
24374
24498
|
if (budget.n <= 0) return;
|
|
24375
|
-
collectRollouts(
|
|
24499
|
+
collectRollouts(join19(dir, d.name), out, budget);
|
|
24376
24500
|
}
|
|
24377
24501
|
for (const f of files) {
|
|
24378
24502
|
if (budget.n <= 0) return;
|
|
24379
24503
|
let mtimeMs;
|
|
24380
24504
|
try {
|
|
24381
|
-
mtimeMs = statSync9(
|
|
24505
|
+
mtimeMs = statSync9(join19(dir, f.name)).mtimeMs;
|
|
24382
24506
|
} catch {
|
|
24383
24507
|
continue;
|
|
24384
24508
|
}
|
|
24385
|
-
out.push({ path:
|
|
24509
|
+
out.push({ path: join19(dir, f.name), mtimeMs });
|
|
24386
24510
|
budget.n--;
|
|
24387
24511
|
}
|
|
24388
24512
|
}
|
|
@@ -24426,9 +24550,9 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
|
|
|
24426
24550
|
const out = /* @__PURE__ */ new Map();
|
|
24427
24551
|
let raw2;
|
|
24428
24552
|
try {
|
|
24429
|
-
const path =
|
|
24553
|
+
const path = join19(codexHome, "session_index.jsonl");
|
|
24430
24554
|
if (statSync9(path).size > SESSION_INDEX_MAX_BYTES) return out;
|
|
24431
|
-
raw2 =
|
|
24555
|
+
raw2 = readFileSync13(path, "utf8");
|
|
24432
24556
|
} catch {
|
|
24433
24557
|
return out;
|
|
24434
24558
|
}
|
|
@@ -28464,16 +28588,16 @@ var init_wrapper = __esm({
|
|
|
28464
28588
|
|
|
28465
28589
|
// packages/server/src/worker-plugin-dir.ts
|
|
28466
28590
|
import { existsSync as existsSync6 } from "node:fs";
|
|
28467
|
-
import { dirname as dirname9, join as
|
|
28591
|
+
import { dirname as dirname9, join as join20 } from "node:path";
|
|
28468
28592
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
28469
28593
|
function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
|
|
28470
28594
|
const override = env.FRIZZ_WORKER_PLUGIN_DIR;
|
|
28471
|
-
if (override && existsSync6(
|
|
28595
|
+
if (override && existsSync6(join20(override, ".claude-plugin", "plugin.json")))
|
|
28472
28596
|
return override;
|
|
28473
28597
|
let current = dirname9(fileURLToPath2(moduleUrl));
|
|
28474
28598
|
for (; ; ) {
|
|
28475
|
-
const candidate =
|
|
28476
|
-
if (existsSync6(
|
|
28599
|
+
const candidate = join20(current, "cc-worker");
|
|
28600
|
+
if (existsSync6(join20(candidate, ".claude-plugin", "plugin.json"))) return candidate;
|
|
28477
28601
|
const parent = dirname9(current);
|
|
28478
28602
|
if (parent === current) return void 0;
|
|
28479
28603
|
current = parent;
|
|
@@ -28487,7 +28611,7 @@ var init_worker_plugin_dir = __esm({
|
|
|
28487
28611
|
|
|
28488
28612
|
// packages/server/src/backend/types.ts
|
|
28489
28613
|
import { existsSync as existsSync7 } from "node:fs";
|
|
28490
|
-
import { join as
|
|
28614
|
+
import { join as join21 } from "node:path";
|
|
28491
28615
|
function frizzMcpEnv(mcp) {
|
|
28492
28616
|
return {
|
|
28493
28617
|
FRIZZ_STATE_DIR: mcp.stateDir,
|
|
@@ -28511,7 +28635,7 @@ function chromeDevtoolsMcpMount() {
|
|
|
28511
28635
|
function resolveBrowserMcpScript(moduleUrl = import.meta.url, env = process.env) {
|
|
28512
28636
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
28513
28637
|
if (!pluginDir) return void 0;
|
|
28514
|
-
const scriptPath =
|
|
28638
|
+
const scriptPath = join21(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
|
|
28515
28639
|
return existsSync7(scriptPath) ? scriptPath : void 0;
|
|
28516
28640
|
}
|
|
28517
28641
|
function workerCap(name, lifted, env) {
|
|
@@ -28609,15 +28733,15 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
28609
28733
|
import { connect } from "node:net";
|
|
28610
28734
|
import { Agent as HttpAgent } from "node:http";
|
|
28611
28735
|
import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
|
|
28612
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as
|
|
28613
|
-
import { join as
|
|
28736
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
|
|
28737
|
+
import { join as join22 } from "node:path";
|
|
28614
28738
|
import { PassThrough, Writable } from "node:stream";
|
|
28615
28739
|
import { StringDecoder } from "node:string_decoder";
|
|
28616
28740
|
function nativeDir(stateDir) {
|
|
28617
|
-
return
|
|
28741
|
+
return join22(stateDir, "codex-app-server-native");
|
|
28618
28742
|
}
|
|
28619
28743
|
function nativeRecordPath(stateDir, projectId) {
|
|
28620
|
-
return
|
|
28744
|
+
return join22(nativeDir(stateDir), `${projectId}.json`);
|
|
28621
28745
|
}
|
|
28622
28746
|
function nativeListenSocketPath(stateDir, projectId) {
|
|
28623
28747
|
const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
@@ -28633,7 +28757,7 @@ function pidAlive2(pid) {
|
|
|
28633
28757
|
}
|
|
28634
28758
|
function readNativeRecord(stateDir, projectId) {
|
|
28635
28759
|
try {
|
|
28636
|
-
const value = JSON.parse(
|
|
28760
|
+
const value = JSON.parse(readFileSync14(nativeRecordPath(stateDir, projectId), "utf8"));
|
|
28637
28761
|
if (typeof value.listenerPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
28638
28762
|
return {
|
|
28639
28763
|
projectId,
|
|
@@ -28881,15 +29005,15 @@ var init_codex_app_server_native = __esm({
|
|
|
28881
29005
|
import { spawn as spawn3, spawnSync } from "node:child_process";
|
|
28882
29006
|
import { createConnection } from "node:net";
|
|
28883
29007
|
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
28884
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as
|
|
28885
|
-
import { join as
|
|
29008
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync15, unlinkSync as unlinkSync3 } from "node:fs";
|
|
29009
|
+
import { join as join23 } from "node:path";
|
|
28886
29010
|
import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
|
|
28887
29011
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
28888
29012
|
function daemonDir(stateDir) {
|
|
28889
|
-
return
|
|
29013
|
+
return join23(stateDir, "codex-app-server");
|
|
28890
29014
|
}
|
|
28891
29015
|
function recordPath(stateDir, projectId) {
|
|
28892
|
-
return
|
|
29016
|
+
return join23(daemonDir(stateDir), `${projectId}.json`);
|
|
28893
29017
|
}
|
|
28894
29018
|
function codexAppServerSocketPath(stateDir, projectId) {
|
|
28895
29019
|
const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
@@ -28905,7 +29029,7 @@ function pidAlive3(pid) {
|
|
|
28905
29029
|
}
|
|
28906
29030
|
function readDaemonRecord(stateDir, projectId) {
|
|
28907
29031
|
try {
|
|
28908
|
-
const value = JSON.parse(
|
|
29032
|
+
const value = JSON.parse(readFileSync15(recordPath(stateDir, projectId), "utf8"));
|
|
28909
29033
|
if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
28910
29034
|
return {
|
|
28911
29035
|
projectId,
|
|
@@ -28921,7 +29045,7 @@ function readDaemonRecord(stateDir, projectId) {
|
|
|
28921
29045
|
}
|
|
28922
29046
|
function readDaemonExitBreadcrumb(stateDir, projectId) {
|
|
28923
29047
|
try {
|
|
28924
|
-
const value = JSON.parse(
|
|
29048
|
+
const value = JSON.parse(readFileSync15(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
|
|
28925
29049
|
if (typeof value.generation !== "string" || typeof value.reason !== "string") return null;
|
|
28926
29050
|
return {
|
|
28927
29051
|
generation: value.generation,
|
|
@@ -32117,11 +32241,11 @@ var init_codex_app_server = __esm({
|
|
|
32117
32241
|
});
|
|
32118
32242
|
|
|
32119
32243
|
// packages/server/src/backend/codex-quota.ts
|
|
32120
|
-
import { join as
|
|
32244
|
+
import { join as join24 } from "node:path";
|
|
32121
32245
|
import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
|
|
32122
32246
|
import { spawn as spawn4 } from "node:child_process";
|
|
32123
32247
|
function sessionsDir2(codexHome) {
|
|
32124
|
-
return
|
|
32248
|
+
return join24(codexHome, "sessions");
|
|
32125
32249
|
}
|
|
32126
32250
|
function newestRollouts(dir, out, budget) {
|
|
32127
32251
|
if (budget.n <= 0) return;
|
|
@@ -32135,11 +32259,11 @@ function newestRollouts(dir, out, budget) {
|
|
|
32135
32259
|
const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
|
|
32136
32260
|
for (const d of dirs) {
|
|
32137
32261
|
if (budget.n <= 0) return;
|
|
32138
|
-
newestRollouts(
|
|
32262
|
+
newestRollouts(join24(dir, d), out, budget);
|
|
32139
32263
|
}
|
|
32140
32264
|
for (const f of files) {
|
|
32141
32265
|
if (budget.n <= 0) return;
|
|
32142
|
-
out.push(
|
|
32266
|
+
out.push(join24(dir, f));
|
|
32143
32267
|
budget.n--;
|
|
32144
32268
|
}
|
|
32145
32269
|
}
|
|
@@ -32339,7 +32463,7 @@ var init_codex_quota = __esm({
|
|
|
32339
32463
|
});
|
|
32340
32464
|
|
|
32341
32465
|
// packages/server/src/backend/claude-quota.ts
|
|
32342
|
-
import { join as
|
|
32466
|
+
import { join as join25 } from "node:path";
|
|
32343
32467
|
import { homedir as homedir9, platform } from "node:os";
|
|
32344
32468
|
import { createHash as createHash10 } from "node:crypto";
|
|
32345
32469
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -32347,7 +32471,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
32347
32471
|
import { promisify as promisify2 } from "node:util";
|
|
32348
32472
|
function claudeConfigDir() {
|
|
32349
32473
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32350
|
-
return override && override.trim() ? override :
|
|
32474
|
+
return override && override.trim() ? override : join25(homedir9(), ".claude");
|
|
32351
32475
|
}
|
|
32352
32476
|
function tokenFromCredentialsJson(raw2) {
|
|
32353
32477
|
let doc;
|
|
@@ -32376,7 +32500,7 @@ async function readKeychainToken() {
|
|
|
32376
32500
|
}
|
|
32377
32501
|
async function readAccessToken(configDir) {
|
|
32378
32502
|
try {
|
|
32379
|
-
const fromFile = tokenFromCredentialsJson(await readFile(
|
|
32503
|
+
const fromFile = tokenFromCredentialsJson(await readFile(join25(configDir, ".credentials.json"), "utf8"));
|
|
32380
32504
|
if (fromFile) return fromFile;
|
|
32381
32505
|
} catch {
|
|
32382
32506
|
}
|
|
@@ -32445,8 +32569,8 @@ function parseClaudeUsage(body, planType) {
|
|
|
32445
32569
|
function cachePaths(cacheDir, configDir) {
|
|
32446
32570
|
const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
|
|
32447
32571
|
return {
|
|
32448
|
-
data:
|
|
32449
|
-
lock:
|
|
32572
|
+
data: join25(cacheDir, `claude-${profile}.json`),
|
|
32573
|
+
lock: join25(cacheDir, `claude-${profile}.lock`)
|
|
32450
32574
|
};
|
|
32451
32575
|
}
|
|
32452
32576
|
async function readShared(path) {
|
|
@@ -32642,7 +32766,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
|
|
|
32642
32766
|
async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
32643
32767
|
const now = (deps.now ?? Date.now)();
|
|
32644
32768
|
const configDir = claudeConfigDir();
|
|
32645
|
-
const cacheDir = deps.cacheDir ??
|
|
32769
|
+
const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
|
|
32646
32770
|
try {
|
|
32647
32771
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
32648
32772
|
} catch {
|
|
@@ -32653,7 +32777,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
|
32653
32777
|
async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
|
|
32654
32778
|
const now = (deps.now ?? Date.now)();
|
|
32655
32779
|
const configDir = claudeConfigDir();
|
|
32656
|
-
const cacheDir = deps.cacheDir ??
|
|
32780
|
+
const cacheDir = deps.cacheDir ?? join25(frizzRoots().cache, "quota-cache");
|
|
32657
32781
|
const paths = cachePaths(cacheDir, configDir);
|
|
32658
32782
|
try {
|
|
32659
32783
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
@@ -32813,7 +32937,7 @@ var init_quota = __esm({
|
|
|
32813
32937
|
// packages/server/src/frizz.ts
|
|
32814
32938
|
import { execFile as execFile3 } from "node:child_process";
|
|
32815
32939
|
import { lstatSync as lstatSync2, realpathSync as realpathSync6 } from "node:fs";
|
|
32816
|
-
import { basename as basename5, dirname as dirname10, join as
|
|
32940
|
+
import { basename as basename5, dirname as dirname10, join as join26, resolve as resolve4 } from "node:path";
|
|
32817
32941
|
import { promisify as promisify3 } from "node:util";
|
|
32818
32942
|
function frizzScriptsDir() {
|
|
32819
32943
|
if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
|
|
@@ -32822,7 +32946,7 @@ function frizzScriptsDir() {
|
|
|
32822
32946
|
function directFrizzRoot(projectDir) {
|
|
32823
32947
|
try {
|
|
32824
32948
|
const projectRoot = realpathSync6(projectDir);
|
|
32825
|
-
const path =
|
|
32949
|
+
const path = join26(projectRoot, ".frizz");
|
|
32826
32950
|
const stat2 = lstatSync2(path);
|
|
32827
32951
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
32828
32952
|
const real = realpathSync6(path);
|
|
@@ -32836,7 +32960,7 @@ function frizzDirExists(projectDir) {
|
|
|
32836
32960
|
}
|
|
32837
32961
|
async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
32838
32962
|
if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
|
|
32839
|
-
const { stdout } = await execFileP("node", [
|
|
32963
|
+
const { stdout } = await execFileP("node", [join26(scriptsDir, "index.mjs"), "--json"], {
|
|
32840
32964
|
cwd: projectDir,
|
|
32841
32965
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
|
|
32842
32966
|
maxBuffer: 32 * 1024 * 1024
|
|
@@ -32861,7 +32985,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
|
32861
32985
|
};
|
|
32862
32986
|
}
|
|
32863
32987
|
async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
|
|
32864
|
-
await execFileP("node", [
|
|
32988
|
+
await execFileP("node", [join26(scriptsDir, "thread-update.mjs"), slug, ...args], {
|
|
32865
32989
|
cwd: projectDir,
|
|
32866
32990
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
|
|
32867
32991
|
});
|
|
@@ -34746,19 +34870,19 @@ var init_claude_agent_broker_bridge = __esm({
|
|
|
34746
34870
|
});
|
|
34747
34871
|
|
|
34748
34872
|
// packages/server/src/backend/auth-status.ts
|
|
34749
|
-
import { join as
|
|
34873
|
+
import { join as join27 } from "node:path";
|
|
34750
34874
|
import { homedir as homedir11, platform as platform2 } from "node:os";
|
|
34751
|
-
import { readFileSync as
|
|
34875
|
+
import { readFileSync as readFileSync16, statSync as statSync11 } from "node:fs";
|
|
34752
34876
|
import { execFile as execFile4 } from "node:child_process";
|
|
34753
34877
|
import { promisify as promisify4 } from "node:util";
|
|
34754
34878
|
function claudeConfigDir2() {
|
|
34755
34879
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
34756
|
-
return override && override.trim() ? override :
|
|
34880
|
+
return override && override.trim() ? override : join27(homedir11(), ".claude");
|
|
34757
34881
|
}
|
|
34758
34882
|
function claudeFileState(configDir) {
|
|
34759
34883
|
let raw2;
|
|
34760
34884
|
try {
|
|
34761
|
-
raw2 =
|
|
34885
|
+
raw2 = readFileSync16(join27(configDir, ".credentials.json"), "utf8");
|
|
34762
34886
|
} catch (err) {
|
|
34763
34887
|
return err.code === "ENOENT" ? "absent" : "error";
|
|
34764
34888
|
}
|
|
@@ -34791,7 +34915,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
34791
34915
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
|
|
34792
34916
|
let raw2;
|
|
34793
34917
|
try {
|
|
34794
|
-
raw2 =
|
|
34918
|
+
raw2 = readFileSync16(join27(codexHome, "auth.json"), "utf8");
|
|
34795
34919
|
} catch (err) {
|
|
34796
34920
|
return err.code === "ENOENT" ? "signed-out" : "unknown";
|
|
34797
34921
|
}
|
|
@@ -34856,7 +34980,7 @@ function asEmail(value) {
|
|
|
34856
34980
|
}
|
|
34857
34981
|
function claudeAccountFile() {
|
|
34858
34982
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
34859
|
-
return override && override.trim() ?
|
|
34983
|
+
return override && override.trim() ? join27(override, ".claude.json") : join27(homedir11(), ".claude.json");
|
|
34860
34984
|
}
|
|
34861
34985
|
function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
34862
34986
|
let stat2;
|
|
@@ -34869,7 +34993,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
|
34869
34993
|
if (memo3 && memo3.path === path && memo3.mtimeMs === stat2.mtimeMs && memo3.size === stat2.size) return memo3.email;
|
|
34870
34994
|
let email;
|
|
34871
34995
|
try {
|
|
34872
|
-
const doc = JSON.parse(
|
|
34996
|
+
const doc = JSON.parse(readFileSync16(path, "utf8"));
|
|
34873
34997
|
email = asEmail(doc?.oauthAccount?.emailAddress);
|
|
34874
34998
|
} catch {
|
|
34875
34999
|
email = void 0;
|
|
@@ -34880,7 +35004,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
|
34880
35004
|
function readCodexAccountEmail(codexHome = defaultCodexHome()) {
|
|
34881
35005
|
let doc;
|
|
34882
35006
|
try {
|
|
34883
|
-
doc = JSON.parse(
|
|
35007
|
+
doc = JSON.parse(readFileSync16(join27(codexHome, "auth.json"), "utf8"));
|
|
34884
35008
|
} catch {
|
|
34885
35009
|
return void 0;
|
|
34886
35010
|
}
|
|
@@ -34948,8 +35072,8 @@ var init_auth_status = __esm({
|
|
|
34948
35072
|
});
|
|
34949
35073
|
|
|
34950
35074
|
// packages/server/src/dispatch.ts
|
|
34951
|
-
import { closeSync as closeSync12, constants, existsSync as existsSync10, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as
|
|
34952
|
-
import { basename as basename6, join as
|
|
35075
|
+
import { closeSync as closeSync12, constants, existsSync as existsSync10, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync17, realpathSync as realpathSync7, statSync as statSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync9 } from "node:fs";
|
|
35076
|
+
import { basename as basename6, join as join28, dirname as dirname11 } from "node:path";
|
|
34953
35077
|
import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
|
|
34954
35078
|
function fallbackTitle(prompt) {
|
|
34955
35079
|
const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
|
|
@@ -34968,7 +35092,7 @@ function fallbackTitle(prompt) {
|
|
|
34968
35092
|
}
|
|
34969
35093
|
function resolveSlug(frizzDir, base, taken) {
|
|
34970
35094
|
base = ThreadSlug.parse(base);
|
|
34971
|
-
const isTaken = (slug) => existsSync10(
|
|
35095
|
+
const isTaken = (slug) => existsSync10(join28(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
|
|
34972
35096
|
if (!isTaken(base)) return base;
|
|
34973
35097
|
for (let n = 2; ; n++) {
|
|
34974
35098
|
const suffix = `-${n}`;
|
|
@@ -34985,12 +35109,12 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
34985
35109
|
if (!parsed.success) return null;
|
|
34986
35110
|
try {
|
|
34987
35111
|
const projectRoot = realpathSync7(projectDir);
|
|
34988
|
-
const frizzPath =
|
|
35112
|
+
const frizzPath = join28(projectRoot, ".frizz");
|
|
34989
35113
|
const frizzStat = lstatSync3(frizzPath);
|
|
34990
35114
|
if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
|
|
34991
35115
|
const realFrizz = realpathSync7(frizzPath);
|
|
34992
35116
|
if (dirname11(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
|
|
34993
|
-
const path =
|
|
35117
|
+
const path = join28(realFrizz, `${parsed.data}.md`);
|
|
34994
35118
|
const before = lstatSync3(path);
|
|
34995
35119
|
if (!before.isFile() || before.isSymbolicLink()) return null;
|
|
34996
35120
|
const realPath = realpathSync7(path);
|
|
@@ -35001,7 +35125,7 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
35001
35125
|
const fd = openSync13(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
35002
35126
|
try {
|
|
35003
35127
|
openedBefore = fstatSync2(fd);
|
|
35004
|
-
contents =
|
|
35128
|
+
contents = readFileSync17(fd);
|
|
35005
35129
|
openedAfter = fstatSync2(fd);
|
|
35006
35130
|
} finally {
|
|
35007
35131
|
closeSync12(fd);
|
|
@@ -35034,7 +35158,7 @@ function boardAuthorizesAdoption(board, slug) {
|
|
|
35034
35158
|
return !board.errorItems.some((item) => item.file === `${slug}.md`);
|
|
35035
35159
|
}
|
|
35036
35160
|
function ensureSafeDirectDirectory(parent, name) {
|
|
35037
|
-
const path =
|
|
35161
|
+
const path = join28(parent, name);
|
|
35038
35162
|
try {
|
|
35039
35163
|
mkdirSync13(path);
|
|
35040
35164
|
} catch (error) {
|
|
@@ -35064,8 +35188,8 @@ function loadWorkerPrompt(kind = "claude") {
|
|
|
35064
35188
|
function monitorScriptsDir() {
|
|
35065
35189
|
const plugin = workerPluginDir();
|
|
35066
35190
|
if (!plugin) return void 0;
|
|
35067
|
-
const dir =
|
|
35068
|
-
return existsSync10(
|
|
35191
|
+
const dir = join28(plugin, "skills", "gh", "scripts");
|
|
35192
|
+
return existsSync10(join28(dir, "ci-watch.mjs")) ? dir : void 0;
|
|
35069
35193
|
}
|
|
35070
35194
|
function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
35071
35195
|
if (!hookScript || !sessionId) return {};
|
|
@@ -35077,7 +35201,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
35077
35201
|
}
|
|
35078
35202
|
]
|
|
35079
35203
|
});
|
|
35080
|
-
const bashBackgroundHook =
|
|
35204
|
+
const bashBackgroundHook = join28(dirname11(hookScript), "bash-background.mjs");
|
|
35081
35205
|
return {
|
|
35082
35206
|
bypass_hook_trust: true,
|
|
35083
35207
|
hooks: {
|
|
@@ -35103,7 +35227,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
35103
35227
|
}
|
|
35104
35228
|
function scratchpadHookScript() {
|
|
35105
35229
|
const plugin = workerPluginDir();
|
|
35106
|
-
return plugin ?
|
|
35230
|
+
return plugin ? join28(plugin, "hooks", "scratchpad.mjs") : void 0;
|
|
35107
35231
|
}
|
|
35108
35232
|
function composePrompt(sessionId, prompt, kind = "claude") {
|
|
35109
35233
|
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.";
|
|
@@ -35119,12 +35243,12 @@ function scratchpadOrientation(sessionId, kind = "claude") {
|
|
|
35119
35243
|
return `SCRATCH DIRECTORY: .frizz/threads/${sessionId}/ \u2014 yours, free-form, as many files as you like, and nothing is expected in it. A single direct task usually needs none; writing notes is never a substitute for doing the work. On a long effort write the doc you would want if you lost your context (${children2}), then arm mcp__frizz__recurring_prompt with post_compaction: true and a prompt LINKING that file \u2014 frizz hands the link back when your context is compacted. Nothing in this directory is read automatically.`;
|
|
35120
35244
|
}
|
|
35121
35245
|
function frizzConfigBlock(projectDir) {
|
|
35122
|
-
const path =
|
|
35246
|
+
const path = join28(projectDir, "FRIZZ.md");
|
|
35123
35247
|
let body;
|
|
35124
35248
|
try {
|
|
35125
35249
|
const st = statSync12(path);
|
|
35126
35250
|
if (!st.isFile() || st.size > FRIZZ_MD_MAX_BYTES) return "";
|
|
35127
|
-
body =
|
|
35251
|
+
body = readFileSync17(path, "utf8").trim();
|
|
35128
35252
|
} catch {
|
|
35129
35253
|
return "";
|
|
35130
35254
|
}
|
|
@@ -35159,7 +35283,7 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
|
|
|
35159
35283
|
const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
|
|
35160
35284
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
35161
35285
|
if (!pluginDir) return void 0;
|
|
35162
|
-
const scriptPath =
|
|
35286
|
+
const scriptPath = join28(pluginDir, "bin", FRIZZ_MCP.script);
|
|
35163
35287
|
if (!existsSync10(scriptPath)) return void 0;
|
|
35164
35288
|
return {
|
|
35165
35289
|
scriptPath,
|
|
@@ -35242,12 +35366,12 @@ function buildClaudeResumeCommand(opts) {
|
|
|
35242
35366
|
}
|
|
35243
35367
|
function createDispatcher(deps) {
|
|
35244
35368
|
const readBoardSource = deps.readBoard ?? readBoard;
|
|
35245
|
-
const frizzDir =
|
|
35369
|
+
const frizzDir = join28(deps.project.dir, ".frizz");
|
|
35246
35370
|
const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
|
|
35247
35371
|
function cleanupPrewrites(built) {
|
|
35248
35372
|
for (const path of new Set(built.prewrite.map((file) => file.path))) {
|
|
35249
35373
|
try {
|
|
35250
|
-
|
|
35374
|
+
rmSync9(path, { force: true });
|
|
35251
35375
|
} catch {
|
|
35252
35376
|
}
|
|
35253
35377
|
}
|
|
@@ -35255,7 +35379,7 @@ function createDispatcher(deps) {
|
|
|
35255
35379
|
function cleanupDispatchFiles(scratchRel, built, sessionId) {
|
|
35256
35380
|
cleanupPrewrites(built);
|
|
35257
35381
|
try {
|
|
35258
|
-
|
|
35382
|
+
rmSync9(join28(deps.project.dir, scratchRel), { force: true, recursive: true });
|
|
35259
35383
|
} catch {
|
|
35260
35384
|
}
|
|
35261
35385
|
cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
|
|
@@ -35688,7 +35812,7 @@ import {
|
|
|
35688
35812
|
watch as fsWatch
|
|
35689
35813
|
} from "node:fs";
|
|
35690
35814
|
import { homedir as homedir12 } from "node:os";
|
|
35691
|
-
import { join as
|
|
35815
|
+
import { join as join29 } from "node:path";
|
|
35692
35816
|
import watcher from "@parcel/watcher";
|
|
35693
35817
|
function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
|
|
35694
35818
|
if (!liveness) return false;
|
|
@@ -35873,7 +35997,7 @@ function hasFreshDelivery(row, processGone) {
|
|
|
35873
35997
|
if (processGone) return false;
|
|
35874
35998
|
return parseDeliveryLedger(row.delivery_ledger).some((d) => d.state === "pending" || d.state === "enqueued" || d.state === "delivered");
|
|
35875
35999
|
}
|
|
35876
|
-
function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, nowMs = Date.now(), limitPause = void 0, excuseLiveOwnWork = true, deliveryProcessGone = false, github = {}, registeredPrWatches = /* @__PURE__ */ new Set()) {
|
|
36000
|
+
function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, nowMs = Date.now(), limitPause = void 0, excuseLiveOwnWork = true, deliveryProcessGone = false, github = {}, registeredPrWatches = /* @__PURE__ */ new Set(), armedTimerIds = /* @__PURE__ */ new Set()) {
|
|
35877
36001
|
if (futureSnooze(row, nowMs)) return false;
|
|
35878
36002
|
if (hasActionableInteraction) return true;
|
|
35879
36003
|
if (runtime === "perm-prompt") return true;
|
|
@@ -35888,7 +36012,7 @@ function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, no
|
|
|
35888
36012
|
if (excuseLiveOwnWork && runtime !== "exited" && hasLiveBackgroundWork(tele) && !tele?.lastFence) return false;
|
|
35889
36013
|
if (excuseLiveOwnWork && runtime !== "exited" && hasDeclaredBackgroundPark(tele, nowMs)) return false;
|
|
35890
36014
|
if (excuseLiveOwnWork && runtime !== "exited" && heldByRunningChecks(tele, github, registeredPrWatches)) return false;
|
|
35891
|
-
if (runtime !== "exited" && hasLiveOwnWork(tele) && tele?.lastFence?.kind !== "done") return !bgSnoozeArmed(row);
|
|
36015
|
+
if (runtime !== "exited" && (hasLiveOwnWork(tele) || hasParkedTimerWatch(tele, armedTimerIds)) && tele?.lastFence?.kind !== "done") return !bgSnoozeArmed(row);
|
|
35892
36016
|
if (tele?.lastFence?.kind === "done") return true;
|
|
35893
36017
|
return true;
|
|
35894
36018
|
}
|
|
@@ -35899,7 +36023,7 @@ function deriveAwaitingBackground(row, tele, runtime, hasActionableInteraction =
|
|
|
35899
36023
|
if (tele?.lastFence?.kind === "awaiting" && !hasParkedPrWatch(tele) && !hasDeclaredBackgroundPark(tele, nowMs) && // A TIMER PARK IS THE SAME EXCEPTION AGAIN (2026-08-24): its fence has no park action either, so
|
|
35900
36024
|
// suppressing this card left the wait stated nowhere but the fence's own machinery footer.
|
|
35901
36025
|
!hasParkedTimerWatch(tele, armedTimerIds)) return false;
|
|
35902
|
-
return deriveNeedsYou({ ...row, bg_snooze_rested_at: null }, tele, runtime, hasActionableInteraction, nowMs, limitPause, false, deliveryProcessGone);
|
|
36026
|
+
return deriveNeedsYou({ ...row, bg_snooze_rested_at: null }, tele, runtime, hasActionableInteraction, nowMs, limitPause, false, deliveryProcessGone, {}, /* @__PURE__ */ new Set(), armedTimerIds);
|
|
35903
36027
|
}
|
|
35904
36028
|
function resolveSessionProfile(row, tele) {
|
|
35905
36029
|
const persistedModel = row.model?.trim() || void 0;
|
|
@@ -36005,7 +36129,7 @@ function sessionThreadView(projectDir, storage, row, tele, registeredLegacyTermi
|
|
|
36005
36129
|
const state = effectiveSessionState(row, registeredLegacyTerminal);
|
|
36006
36130
|
const archived = state === "archived";
|
|
36007
36131
|
const limitPause = resolveLimitPause(row, tele, nowMs);
|
|
36008
|
-
const needsYou = archived ? false : deriveNeedsYou(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, true, deliveryProcessGone, github, registeredPrWatches);
|
|
36132
|
+
const needsYou = archived ? false : deriveNeedsYou(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, true, deliveryProcessGone, github, registeredPrWatches, armedTimerIds);
|
|
36009
36133
|
const awaitingBackground = archived ? false : deriveAwaitingBackground(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, deliveryProcessGone, github, registeredPrWatches, armedTimerIds);
|
|
36010
36134
|
const crashed = runtime === "exited" && (tele?.turn === "in-flight" || hasLiveBackgroundWork(tele) || headlessLostWork);
|
|
36011
36135
|
const snoozedUntil = futureSnooze(row, nowMs);
|
|
@@ -36373,7 +36497,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
36373
36497
|
if (parcelSub || stopped) return Promise.resolve();
|
|
36374
36498
|
if (watchSetup) return watchSetup;
|
|
36375
36499
|
const setup = (async () => {
|
|
36376
|
-
const next = await subscribe(
|
|
36500
|
+
const next = await subscribe(join29(project.dir, ".frizz"), () => scheduleRebuild());
|
|
36377
36501
|
if (stopped) {
|
|
36378
36502
|
await next.unsubscribe();
|
|
36379
36503
|
return;
|
|
@@ -36491,7 +36615,8 @@ function delivery(row) {
|
|
|
36491
36615
|
createdAt: row.created_at,
|
|
36492
36616
|
updatedAt: row.updated_at,
|
|
36493
36617
|
deliveredAt: row.delivered_at,
|
|
36494
|
-
terminalAt: row.terminal_at
|
|
36618
|
+
terminalAt: row.terminal_at,
|
|
36619
|
+
sentAt: row.sent_at ?? null
|
|
36495
36620
|
};
|
|
36496
36621
|
}
|
|
36497
36622
|
function createWakeDeliveryStore(db) {
|
|
@@ -36514,11 +36639,14 @@ function createWakeDeliveryStore(db) {
|
|
|
36514
36639
|
updated_at INTEGER NOT NULL,
|
|
36515
36640
|
delivered_at INTEGER,
|
|
36516
36641
|
terminal_at INTEGER,
|
|
36642
|
+
sent_at INTEGER,
|
|
36517
36643
|
UNIQUE(thread_slug, session_id, fence_id)
|
|
36518
36644
|
);
|
|
36519
36645
|
CREATE INDEX IF NOT EXISTS wake_delivery_due
|
|
36520
36646
|
ON wake_delivery(state, next_attempt_at, created_at);
|
|
36521
36647
|
`);
|
|
36648
|
+
const columns = db.prepare("PRAGMA table_info(wake_delivery)").all();
|
|
36649
|
+
if (!columns.some((c) => c.name === "sent_at")) db.exec("ALTER TABLE wake_delivery ADD COLUMN sent_at INTEGER");
|
|
36522
36650
|
const byId = db.prepare("SELECT * FROM wake_delivery WHERE id = ?");
|
|
36523
36651
|
const all = db.prepare("SELECT * FROM wake_delivery ORDER BY created_at, id");
|
|
36524
36652
|
const open = db.prepare(
|
|
@@ -36555,7 +36683,7 @@ function createWakeDeliveryStore(db) {
|
|
|
36555
36683
|
const claimStmt = db.prepare(`
|
|
36556
36684
|
UPDATE wake_delivery SET
|
|
36557
36685
|
state = 'leased', attempts = attempts + 1, lease_owner = @owner, lease_until = @leaseUntil,
|
|
36558
|
-
last_error = NULL, updated_at = @now
|
|
36686
|
+
last_error = NULL, sent_at = NULL, updated_at = @now
|
|
36559
36687
|
WHERE id = @id AND state = 'pending' AND next_attempt_at <= @now AND attempts < @maxAttempts
|
|
36560
36688
|
`);
|
|
36561
36689
|
const deferFailureStmt = db.prepare(`
|
|
@@ -36563,6 +36691,11 @@ function createWakeDeliveryStore(db) {
|
|
|
36563
36691
|
lease_until = @retryAt, last_error = @error, updated_at = @now
|
|
36564
36692
|
WHERE id = @id AND state = 'leased' AND lease_owner = @owner
|
|
36565
36693
|
`);
|
|
36694
|
+
const markSentStmt = db.prepare(`
|
|
36695
|
+
UPDATE wake_delivery SET
|
|
36696
|
+
sent_at = @now, lease_until = @confirmUntil, last_error = NULL, updated_at = @now
|
|
36697
|
+
WHERE id = @id AND state = 'leased' AND lease_owner = @owner
|
|
36698
|
+
`);
|
|
36566
36699
|
const recoverExpiredStmt = db.prepare(`
|
|
36567
36700
|
UPDATE wake_delivery SET
|
|
36568
36701
|
state = CASE WHEN attempts >= @maxAttempts THEN 'exhausted' ELSE 'pending' END,
|
|
@@ -36631,6 +36764,7 @@ function createWakeDeliveryStore(db) {
|
|
|
36631
36764
|
return row ? delivery(row) : void 0;
|
|
36632
36765
|
},
|
|
36633
36766
|
acknowledge: (id, owner, now) => acknowledgeStmt.run({ id, owner, now }).changes === 1,
|
|
36767
|
+
markSent: (id, owner, now, confirmUntil) => markSentStmt.run({ id, owner, now, confirmUntil }).changes === 1,
|
|
36634
36768
|
confirm: (id, now) => confirmStmt.run({ id, now }).changes === 1,
|
|
36635
36769
|
supersede: (id, now, reason) => supersedeStmt.run({ id, now, reason: reason.slice(0, 500) }).changes === 1
|
|
36636
36770
|
};
|
|
@@ -37183,6 +37317,28 @@ function isTimerFenceId(fenceId) {
|
|
|
37183
37317
|
function timerIdOf(fenceId) {
|
|
37184
37318
|
return fenceId.slice(TIMER_FENCE_PREFIX.length + 1);
|
|
37185
37319
|
}
|
|
37320
|
+
function conciseGhError(err) {
|
|
37321
|
+
const code = err?.code;
|
|
37322
|
+
if (code === "ENOENT") return "the `gh` CLI is not installed on the PATH of the process Frizz runs as";
|
|
37323
|
+
if (err?.killed || code === "ETIMEDOUT") return "`gh` did not answer within 15s";
|
|
37324
|
+
const stderr = typeof err?.stderr === "string" ? err.stderr : "";
|
|
37325
|
+
const line = stderr.trim().split(/\r?\n/).map((l) => l.trim()).find((l) => l.length > 0);
|
|
37326
|
+
if (line) return line.slice(0, 300);
|
|
37327
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
37328
|
+
return message.trim().split(/\r?\n/, 1)[0]?.slice(0, 300) || "unknown error";
|
|
37329
|
+
}
|
|
37330
|
+
async function probePrReadable(ref) {
|
|
37331
|
+
try {
|
|
37332
|
+
await execFileAsync4(
|
|
37333
|
+
"gh",
|
|
37334
|
+
["pr", "view", String(ref.number), "--repo", `${ref.owner}/${ref.repo}`, "--json", "state"],
|
|
37335
|
+
{ timeout: 15e3, maxBuffer: 1e6, env: { ...process.env, GH_PAGER: "cat", GH_PROMPT_DISABLED: "1" } }
|
|
37336
|
+
);
|
|
37337
|
+
return { ok: true };
|
|
37338
|
+
} catch (err) {
|
|
37339
|
+
return { ok: false, reason: conciseGhError(err) };
|
|
37340
|
+
}
|
|
37341
|
+
}
|
|
37186
37342
|
async function defaultFetchPr(ref) {
|
|
37187
37343
|
try {
|
|
37188
37344
|
const { stdout } = await execFileAsync4(
|
|
@@ -37209,8 +37365,8 @@ async function defaultFetchPr(ref) {
|
|
|
37209
37365
|
reviewDecision: typeof j.reviewDecision === "string" ? j.reviewDecision : void 0,
|
|
37210
37366
|
workflowRuns
|
|
37211
37367
|
};
|
|
37212
|
-
} catch {
|
|
37213
|
-
|
|
37368
|
+
} catch (err) {
|
|
37369
|
+
throw new Error(conciseGhError(err));
|
|
37214
37370
|
}
|
|
37215
37371
|
}
|
|
37216
37372
|
function createScheduler(deps) {
|
|
@@ -37223,6 +37379,7 @@ function createScheduler(deps) {
|
|
|
37223
37379
|
const retryBaseMs = Math.max(1, deps.retryBaseMs ?? 5e3);
|
|
37224
37380
|
const retryMaxMs = Math.max(retryBaseMs, deps.retryMaxMs ?? 5 * 6e4);
|
|
37225
37381
|
const maxDeliveryAttempts = Math.max(1, deps.maxDeliveryAttempts ?? 6);
|
|
37382
|
+
const confirmGraceMs = Math.max(1, deps.confirmGraceMs ?? 6e4);
|
|
37226
37383
|
const deliveryBatchSize = Math.max(0, deps.deliveryBatchSize ?? 50);
|
|
37227
37384
|
const deliveryOwner = randomUUID14();
|
|
37228
37385
|
const outbox = createWakeDeliveryStore(deps.storage.db);
|
|
@@ -37352,6 +37509,23 @@ function createScheduler(deps) {
|
|
|
37352
37509
|
log3(`waker: GitHub review check failed for ${key} (${slug}) [${result.failure.kind}] \u2014 ${result.failure.message}${suppressed}`);
|
|
37353
37510
|
reviewFailures.set(key, { signature, loggedAt: at, suppressed: 0 });
|
|
37354
37511
|
}
|
|
37512
|
+
const statusFailures = /* @__PURE__ */ new Map();
|
|
37513
|
+
function recordStatusFailure(key, message, at) {
|
|
37514
|
+
const prior = statusFailures.get(key);
|
|
37515
|
+
if (prior?.signature === message && at - prior.loggedAt < 15 * 6e4) {
|
|
37516
|
+
prior.suppressed++;
|
|
37517
|
+
return;
|
|
37518
|
+
}
|
|
37519
|
+
const suppressed = prior?.suppressed ? ` (${prior.suppressed} identical repeats suppressed)` : "";
|
|
37520
|
+
log3(`waker: PR status check failed for ${key} \u2014 ${message}${suppressed}; CI and merge wakes cannot fire until \`gh\` can read it`);
|
|
37521
|
+
statusFailures.set(key, { signature: message, loggedAt: at, suppressed: 0 });
|
|
37522
|
+
}
|
|
37523
|
+
function recordStatusSuccess(key) {
|
|
37524
|
+
const prior = statusFailures.get(key);
|
|
37525
|
+
if (!prior) return;
|
|
37526
|
+
statusFailures.delete(key);
|
|
37527
|
+
log3(`waker: PR status check recovered for ${key}${prior.suppressed ? `; ${prior.suppressed} identical repeats were suppressed` : ""}`);
|
|
37528
|
+
}
|
|
37355
37529
|
function recordReviewSuccess(key, slug) {
|
|
37356
37530
|
const prior = reviewFailures.get(key);
|
|
37357
37531
|
if (!prior) return;
|
|
@@ -37696,9 +37870,10 @@ ${clock}`;
|
|
|
37696
37870
|
if (pr) {
|
|
37697
37871
|
status.set(key, githubWatchStatus(pr, new Date(nowMs).toISOString()));
|
|
37698
37872
|
publishGithubStatus(key, pr, nowMs);
|
|
37873
|
+
recordStatusSuccess(key);
|
|
37699
37874
|
}
|
|
37700
37875
|
} catch (err) {
|
|
37701
|
-
|
|
37876
|
+
recordStatusFailure(key, err instanceof Error ? err.message : String(err), nowMs);
|
|
37702
37877
|
}
|
|
37703
37878
|
try {
|
|
37704
37879
|
const result = normalizeReviewResult(await fetchGithubReview(ref));
|
|
@@ -37992,6 +38167,38 @@ ${clock}`;
|
|
|
37992
38167
|
continue;
|
|
37993
38168
|
}
|
|
37994
38169
|
if (item.state !== "leased" || item.leaseUntil === null || item.leaseUntil > nowMs) continue;
|
|
38170
|
+
if (item.sentAt !== null) {
|
|
38171
|
+
const runtime = deps.wakeRuntimeState?.(item.slug, item.sessionId) ?? "unknown";
|
|
38172
|
+
if (runtime !== "dead") {
|
|
38173
|
+
if (outbox.confirm(item.id, nowMs)) {
|
|
38174
|
+
settleSnooze(item);
|
|
38175
|
+
settleSchedulePrompt(item);
|
|
38176
|
+
settleRestPrompt(item);
|
|
38177
|
+
settleCompactPrompt(item);
|
|
38178
|
+
settleTimer(item);
|
|
38179
|
+
settleSignoffNudge(item);
|
|
38180
|
+
log3(`waker: delivered ${item.slug} \u2014 ${item.reason}${item.attempts > 1 ? ` (on attempt ${item.attempts})` : ""}`);
|
|
38181
|
+
}
|
|
38182
|
+
continue;
|
|
38183
|
+
}
|
|
38184
|
+
if (context !== "current-idle") continue;
|
|
38185
|
+
const recovered2 = outbox.recoverExpired(
|
|
38186
|
+
item.id,
|
|
38187
|
+
nowMs,
|
|
38188
|
+
nowMs + retryDelay(item.attempts),
|
|
38189
|
+
maxDeliveryAttempts,
|
|
38190
|
+
"the worker's process died before it read this wake"
|
|
38191
|
+
);
|
|
38192
|
+
if (!recovered2) continue;
|
|
38193
|
+
if (recovered2.state === "exhausted") {
|
|
38194
|
+
settleSnooze(item);
|
|
38195
|
+
settleTimer(item);
|
|
38196
|
+
log3(`waker: delivery EXHAUSTED for ${item.slug} after ${recovered2.attempts} attempts \u2014 ${recovered2.lastError ?? "unknown error"}`);
|
|
38197
|
+
} else {
|
|
38198
|
+
log3(`waker: wake LOST for ${item.slug} \u2014 ${item.reason}: the worker's process died before it read it; sending again (attempt ${item.attempts} of ${maxDeliveryAttempts} spent)`);
|
|
38199
|
+
}
|
|
38200
|
+
continue;
|
|
38201
|
+
}
|
|
37995
38202
|
if (context !== "current-idle") continue;
|
|
37996
38203
|
const recovered = outbox.recoverExpired(
|
|
37997
38204
|
item.id,
|
|
@@ -38061,6 +38268,15 @@ ${clock}`;
|
|
|
38061
38268
|
log3(`waker: delivery FAILED for ${item.slug} (attempt ${item.attempts} of ${maxDeliveryAttempts}): ${message}`);
|
|
38062
38269
|
continue;
|
|
38063
38270
|
}
|
|
38271
|
+
const runtime = deps.wakeRuntimeState?.(item.slug, item.sessionId) ?? "unknown";
|
|
38272
|
+
if (runtime !== "unknown") {
|
|
38273
|
+
const sentAt = now();
|
|
38274
|
+
if (outbox.markSent(item.id, deliveryOwner, sentAt, sentAt + confirmGraceMs)) {
|
|
38275
|
+
log3(`waker: sent ${item.slug} \u2014 ${item.reason}; confirming within ${Math.round(confirmGraceMs / 1e3)}s`);
|
|
38276
|
+
checkpoint("after-delivery", item);
|
|
38277
|
+
continue;
|
|
38278
|
+
}
|
|
38279
|
+
}
|
|
38064
38280
|
const retried = item.attempts > 1 ? ` (on attempt ${item.attempts})` : "";
|
|
38065
38281
|
log3(`waker: delivered ${item.slug} \u2014 ${item.reason}${retried}`);
|
|
38066
38282
|
checkpoint("after-delivery", item);
|
|
@@ -38307,7 +38523,7 @@ var init_resume = __esm({
|
|
|
38307
38523
|
});
|
|
38308
38524
|
|
|
38309
38525
|
// packages/server/src/backend/claude.ts
|
|
38310
|
-
import { join as
|
|
38526
|
+
import { join as join30 } from "node:path";
|
|
38311
38527
|
function toolResultText2(content) {
|
|
38312
38528
|
if (typeof content === "string") return content;
|
|
38313
38529
|
if (!Array.isArray(content)) return "";
|
|
@@ -38396,7 +38612,7 @@ function createClaudeBackend(opts) {
|
|
|
38396
38612
|
return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
|
|
38397
38613
|
},
|
|
38398
38614
|
transcriptPath(sessionId) {
|
|
38399
|
-
return
|
|
38615
|
+
return join30(opts.logDir, `${sessionId}.jsonl`);
|
|
38400
38616
|
},
|
|
38401
38617
|
parseLine(line) {
|
|
38402
38618
|
return parseClaudeLine(line);
|
|
@@ -38566,12 +38782,12 @@ var init_login_utility = __esm({
|
|
|
38566
38782
|
|
|
38567
38783
|
// packages/server/src/backend/codex-app-server-diagnostics.ts
|
|
38568
38784
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync14, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
|
|
38569
|
-
import { join as
|
|
38785
|
+
import { join as join31 } from "node:path";
|
|
38570
38786
|
function codexDiagnosticLogPath(stateDir, projectId) {
|
|
38571
|
-
return
|
|
38787
|
+
return join31(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
|
|
38572
38788
|
}
|
|
38573
38789
|
function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
|
|
38574
|
-
const dir =
|
|
38790
|
+
const dir = join31(stateDir, "codex-app-server");
|
|
38575
38791
|
const path = codexDiagnosticLogPath(stateDir, projectId);
|
|
38576
38792
|
let ensured = false;
|
|
38577
38793
|
return (event) => {
|
|
@@ -38603,7 +38819,7 @@ var init_codex_app_server_diagnostics = __esm({
|
|
|
38603
38819
|
import { execFile as execFile7 } from "node:child_process";
|
|
38604
38820
|
import { readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
|
|
38605
38821
|
import { connect as connectSocket } from "node:net";
|
|
38606
|
-
import { join as
|
|
38822
|
+
import { join as join32 } from "node:path";
|
|
38607
38823
|
function parseLsofSocketNames(stdout) {
|
|
38608
38824
|
const referenced = /* @__PURE__ */ new Set();
|
|
38609
38825
|
for (const line of stdout.split("\n")) {
|
|
@@ -38620,7 +38836,7 @@ function sweepStaleSockets(options, deps = {}) {
|
|
|
38620
38836
|
const keep = new Set(options.keep ?? []);
|
|
38621
38837
|
let candidates;
|
|
38622
38838
|
try {
|
|
38623
|
-
candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) =>
|
|
38839
|
+
candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join32(options.dir, name)).filter((path) => !keep.has(path));
|
|
38624
38840
|
} catch {
|
|
38625
38841
|
return;
|
|
38626
38842
|
}
|
|
@@ -38670,7 +38886,7 @@ var init_stale_socket_sweep = __esm({
|
|
|
38670
38886
|
|
|
38671
38887
|
// packages/server/src/orphan-reaper.ts
|
|
38672
38888
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
38673
|
-
import { readFileSync as
|
|
38889
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
38674
38890
|
import { dirname as dirname12 } from "node:path";
|
|
38675
38891
|
function firstTokenBasename(command) {
|
|
38676
38892
|
const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
|
|
@@ -38937,7 +39153,7 @@ var init_orphan_reaper = __esm({
|
|
|
38937
39153
|
defaultExec = (file, args) => execFileSync5(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 });
|
|
38938
39154
|
defaultReadEnv = (pid) => {
|
|
38939
39155
|
try {
|
|
38940
|
-
return
|
|
39156
|
+
return readFileSync18(`/proc/${pid}/environ`, "utf8");
|
|
38941
39157
|
} catch {
|
|
38942
39158
|
return null;
|
|
38943
39159
|
}
|
|
@@ -39084,7 +39300,7 @@ var init_thread_hibernation = __esm({
|
|
|
39084
39300
|
});
|
|
39085
39301
|
|
|
39086
39302
|
// packages/server/src/context.ts
|
|
39087
|
-
import { join as
|
|
39303
|
+
import { join as join33 } from "node:path";
|
|
39088
39304
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
39089
39305
|
import { homedir as homedir13 } from "node:os";
|
|
39090
39306
|
function reconcileSessions(storage) {
|
|
@@ -39242,7 +39458,7 @@ async function createContext(opts = {}) {
|
|
|
39242
39458
|
function createContextUnchecked(opts, resources) {
|
|
39243
39459
|
const home = opts.home ?? homedir13();
|
|
39244
39460
|
const project = opts.project ?? resolveProject();
|
|
39245
|
-
const dbPath =
|
|
39461
|
+
const dbPath = join33(project.stateDir, "ui.db");
|
|
39246
39462
|
const storage = createStorage(dbPath);
|
|
39247
39463
|
resources.storage = storage;
|
|
39248
39464
|
const bus = new Bus();
|
|
@@ -39484,6 +39700,15 @@ function createContextUnchecked(opts, resources) {
|
|
|
39484
39700
|
// instant for a weekly limit, whose message text carries a clock but no date; readQuota memoizes,
|
|
39485
39701
|
// so consulting it per tick costs a live request only every few minutes.
|
|
39486
39702
|
readQuota,
|
|
39703
|
+
// The only runtime that can answer is the broker: its daemon record is on disk while the daemon
|
|
39704
|
+
// lives and is unlinked when it dies (liveBrokerRecords checks the pid), so "did the process that
|
|
39705
|
+
// took this wake survive" is one directory read. Codex and any row whose session moved on answer
|
|
39706
|
+
// "unknown", which keeps their wakes on the delivered-on-return path they always had.
|
|
39707
|
+
wakeRuntimeState: (slug, sessionId) => {
|
|
39708
|
+
const row = storage.getSession(slug);
|
|
39709
|
+
if (!row || row.session_id !== sessionId || row.backend !== "claude" || row.claude_runtime !== "broker" || !claudeBroker) return "unknown";
|
|
39710
|
+
return liveBrokerRecords(project.stateDir).some((r) => r.sessionId === sessionId) ? "alive" : "dead";
|
|
39711
|
+
},
|
|
39487
39712
|
resume: (slug, message, deliveryId) => {
|
|
39488
39713
|
const deliveryMessage = `${message}
|
|
39489
39714
|
|
|
@@ -39565,11 +39790,14 @@ ${wakeDeliveryToken(deliveryId)}`;
|
|
|
39565
39790
|
tailer,
|
|
39566
39791
|
dispatcher,
|
|
39567
39792
|
scheduler,
|
|
39793
|
+
probePr: probePrReadable,
|
|
39568
39794
|
stopSubscriptions,
|
|
39569
39795
|
backendFor,
|
|
39570
39796
|
getSettings: () => getSettings(storage, home),
|
|
39571
39797
|
setSettings: (s) => setSettings(storage, s, home),
|
|
39572
39798
|
resetSettings: () => resetSettings(storage, home),
|
|
39799
|
+
getDispatchPreferences: (codexModels) => getDispatchPreferences(storage, getSettings(storage, home), home, codexModels),
|
|
39800
|
+
setDispatchPreference: (update, codexModels) => setDispatchPreference(storage, getSettings(storage, home), home, update, codexModels),
|
|
39573
39801
|
activeTenants: opts.activeTenants,
|
|
39574
39802
|
claudeBin: opts.claudeBin,
|
|
39575
39803
|
codexBin: opts.codexBin,
|
|
@@ -39585,6 +39813,7 @@ var init_context = __esm({
|
|
|
39585
39813
|
init_project();
|
|
39586
39814
|
init_storage();
|
|
39587
39815
|
init_settings();
|
|
39816
|
+
init_dispatch_preferences();
|
|
39588
39817
|
init_quota();
|
|
39589
39818
|
init_claude_quota();
|
|
39590
39819
|
init_board();
|
|
@@ -42270,7 +42499,7 @@ var init_server = __esm({
|
|
|
42270
42499
|
});
|
|
42271
42500
|
|
|
42272
42501
|
// packages/server/src/repair.ts
|
|
42273
|
-
import { existsSync as existsSync12, readFileSync as
|
|
42502
|
+
import { existsSync as existsSync12, readFileSync as readFileSync19, writeFileSync as writeFileSync11 } from "node:fs";
|
|
42274
42503
|
import { basename as basename7, dirname as dirname13, resolve as resolve6 } from "node:path";
|
|
42275
42504
|
function quoteValue(v) {
|
|
42276
42505
|
if (/^[\w./#:+-]+$/.test(v)) return v;
|
|
@@ -42286,7 +42515,7 @@ function repairThreadFile(frizzDir, file) {
|
|
|
42286
42515
|
if (dirname13(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
|
|
42287
42516
|
if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
|
|
42288
42517
|
if (!existsSync12(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
|
|
42289
|
-
const content =
|
|
42518
|
+
const content = readFileSync19(abs, "utf8");
|
|
42290
42519
|
const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
|
|
42291
42520
|
if (firstLine2?.trim() === "---") {
|
|
42292
42521
|
throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
|
|
@@ -42319,7 +42548,7 @@ var init_repair = __esm({
|
|
|
42319
42548
|
});
|
|
42320
42549
|
|
|
42321
42550
|
// cc-worker/hooks/bash-background.mjs
|
|
42322
|
-
import { readFileSync as
|
|
42551
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
42323
42552
|
import { basename as basename8 } from "node:path";
|
|
42324
42553
|
import { pathToFileURL } from "node:url";
|
|
42325
42554
|
function emit(obj) {
|
|
@@ -42468,7 +42697,7 @@ var init_bash_background = __esm({
|
|
|
42468
42697
|
if (isDirectHookExecution(process.argv[1], import.meta.url)) {
|
|
42469
42698
|
try {
|
|
42470
42699
|
const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
|
|
42471
|
-
emit(evaluateBashBackgroundHook(JSON.parse(
|
|
42700
|
+
emit(evaluateBashBackgroundHook(JSON.parse(readFileSync20(0, "utf8")), env));
|
|
42472
42701
|
} catch {
|
|
42473
42702
|
emit({});
|
|
42474
42703
|
}
|
|
@@ -42477,10 +42706,10 @@ var init_bash_background = __esm({
|
|
|
42477
42706
|
});
|
|
42478
42707
|
|
|
42479
42708
|
// packages/server/src/transcript.ts
|
|
42480
|
-
import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as
|
|
42709
|
+
import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync21, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
42481
42710
|
import { createHash as createHash13 } from "node:crypto";
|
|
42482
42711
|
import { StringDecoder as StringDecoder4 } from "node:string_decoder";
|
|
42483
|
-
import { join as
|
|
42712
|
+
import { join as join34 } from "node:path";
|
|
42484
42713
|
import { homedir as homedir14 } from "node:os";
|
|
42485
42714
|
function formatTokens(n) {
|
|
42486
42715
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
@@ -43030,14 +43259,14 @@ function pruneScreenshotCache() {
|
|
|
43030
43259
|
if (entries.length <= SCREENSHOT_CACHE_MAX) return;
|
|
43031
43260
|
const byMtime = entries.map((n) => {
|
|
43032
43261
|
try {
|
|
43033
|
-
return { n, m: statSync14(
|
|
43262
|
+
return { n, m: statSync14(join34(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
|
|
43034
43263
|
} catch {
|
|
43035
43264
|
return { n, m: 0 };
|
|
43036
43265
|
}
|
|
43037
43266
|
}).sort((a, b) => b.m - a.m);
|
|
43038
43267
|
for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
|
|
43039
43268
|
try {
|
|
43040
|
-
unlinkSync5(
|
|
43269
|
+
unlinkSync5(join34(SCREENSHOT_CACHE_DIR, n));
|
|
43041
43270
|
} catch {
|
|
43042
43271
|
}
|
|
43043
43272
|
}
|
|
@@ -43067,14 +43296,14 @@ function persistBase64Image(mediaType, data, idKey) {
|
|
|
43067
43296
|
const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
|
|
43068
43297
|
if (!ext || !data) return void 0;
|
|
43069
43298
|
const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
43070
|
-
const path =
|
|
43299
|
+
const path = join34(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
|
|
43071
43300
|
try {
|
|
43072
43301
|
if (existsSync13(path)) return path;
|
|
43073
43302
|
if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
|
|
43074
43303
|
const buf = Buffer.from(data, "base64");
|
|
43075
43304
|
if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
|
|
43076
43305
|
mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
43077
|
-
const tmp =
|
|
43306
|
+
const tmp = join34(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
43078
43307
|
writeFileSync12(tmp, buf);
|
|
43079
43308
|
renameSync9(tmp, path);
|
|
43080
43309
|
pruneScreenshotCache();
|
|
@@ -43089,14 +43318,14 @@ function persistSentFile(srcPath, idKey) {
|
|
|
43089
43318
|
const outExt = ext === "jpeg" ? "jpg" : ext;
|
|
43090
43319
|
try {
|
|
43091
43320
|
const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
43092
|
-
const dest =
|
|
43321
|
+
const dest = join34(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
|
|
43093
43322
|
if (existsSync13(dest)) return dest;
|
|
43094
43323
|
const size = statSync14(srcPath).size;
|
|
43095
43324
|
if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
|
|
43096
|
-
const buf =
|
|
43325
|
+
const buf = readFileSync21(srcPath);
|
|
43097
43326
|
if (!looksLikeImage(buf, outExt)) return void 0;
|
|
43098
43327
|
mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
43099
|
-
const tmp =
|
|
43328
|
+
const tmp = join34(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
43100
43329
|
writeFileSync12(tmp, buf);
|
|
43101
43330
|
renameSync9(tmp, dest);
|
|
43102
43331
|
pruneScreenshotCache();
|
|
@@ -43513,7 +43742,7 @@ function readTranscript(project, sessionId) {
|
|
|
43513
43742
|
}
|
|
43514
43743
|
function verifyIncrementalParse(path, identityPrefix, incremental) {
|
|
43515
43744
|
try {
|
|
43516
|
-
const fresh = parseTranscript(
|
|
43745
|
+
const fresh = parseTranscript(readFileSync21(path, "utf8"), identityPrefix);
|
|
43517
43746
|
const a = JSON.stringify(incremental);
|
|
43518
43747
|
const b = JSON.stringify(fresh);
|
|
43519
43748
|
if (a !== b) {
|
|
@@ -43533,16 +43762,16 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
|
|
|
43533
43762
|
}
|
|
43534
43763
|
}
|
|
43535
43764
|
function logDirOf(project) {
|
|
43536
|
-
return
|
|
43765
|
+
return join34(homedir14(), ".claude", "projects", project.cwdSlug);
|
|
43537
43766
|
}
|
|
43538
43767
|
function resolveTranscriptPath(project, sessionId) {
|
|
43539
|
-
const path =
|
|
43768
|
+
const path = join34(logDirOf(project), `${sessionId}.jsonl`);
|
|
43540
43769
|
try {
|
|
43541
43770
|
if (statSync14(path).size > 0) return path;
|
|
43542
43771
|
} catch {
|
|
43543
43772
|
}
|
|
43544
43773
|
const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
|
|
43545
|
-
return stranded ?
|
|
43774
|
+
return stranded ? join34(stranded, `${sessionId}.jsonl`) : path;
|
|
43546
43775
|
}
|
|
43547
43776
|
function projectCodexTranscript(raw2, identityPrefix = "codex") {
|
|
43548
43777
|
const out = [];
|
|
@@ -44745,7 +44974,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
|
|
|
44745
44974
|
}
|
|
44746
44975
|
function readCodexTranscriptFile(absPath, nativeId = absPath) {
|
|
44747
44976
|
try {
|
|
44748
|
-
return parseCodexTranscript(
|
|
44977
|
+
return parseCodexTranscript(readFileSync21(absPath, "utf8"), `codex:${nativeId}`);
|
|
44749
44978
|
} catch {
|
|
44750
44979
|
return [];
|
|
44751
44980
|
}
|
|
@@ -44843,7 +45072,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
|
|
|
44843
45072
|
function readTranscriptFile(absPath) {
|
|
44844
45073
|
try {
|
|
44845
45074
|
const pathKey = createHash13("sha256").update(absPath).digest("base64url").slice(0, 16);
|
|
44846
|
-
return parseTranscript(
|
|
45075
|
+
return parseTranscript(readFileSync21(absPath, "utf8"), `claude-file:${pathKey}`);
|
|
44847
45076
|
} catch {
|
|
44848
45077
|
return [];
|
|
44849
45078
|
}
|
|
@@ -44940,9 +45169,9 @@ var init_open_external = __esm({
|
|
|
44940
45169
|
|
|
44941
45170
|
// packages/server/src/local-file.ts
|
|
44942
45171
|
import { spawn as spawn6 } from "node:child_process";
|
|
44943
|
-
import { readFileSync as
|
|
45172
|
+
import { readFileSync as readFileSync22, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
|
|
44944
45173
|
import { homedir as homedir15 } from "node:os";
|
|
44945
|
-
import { isAbsolute as isAbsolute3, join as
|
|
45174
|
+
import { isAbsolute as isAbsolute3, join as join35, resolve as resolve7, sep } from "node:path";
|
|
44946
45175
|
function isUnder(real, root) {
|
|
44947
45176
|
let rootReal;
|
|
44948
45177
|
try {
|
|
@@ -44972,7 +45201,7 @@ function resolveLocalFile(rawPath, roots) {
|
|
|
44972
45201
|
function resolveOpenableFile(raw2, projectDir, roots, home = homedir15()) {
|
|
44973
45202
|
const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
|
|
44974
45203
|
if (!trimmed) return null;
|
|
44975
|
-
const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ?
|
|
45204
|
+
const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join35(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
|
|
44976
45205
|
try {
|
|
44977
45206
|
return resolveLocalFile(abs, roots);
|
|
44978
45207
|
} catch {
|
|
@@ -44983,7 +45212,7 @@ function readLocalMarkdown(rawPath, roots) {
|
|
|
44983
45212
|
if (!MARKDOWN_FILE_EXT.test(rawPath.trim())) throw new Error("Local file is not a Markdown file");
|
|
44984
45213
|
const path = resolveLocalFile(rawPath, roots);
|
|
44985
45214
|
if (!MARKDOWN_FILE_EXT.test(path)) throw new Error("Local file is not a Markdown file");
|
|
44986
|
-
const bytes =
|
|
45215
|
+
const bytes = readFileSync22(path);
|
|
44987
45216
|
if (bytes.length <= MARKDOWN_READ_LIMIT) return { path, markdown: bytes.toString("utf8"), truncated: false };
|
|
44988
45217
|
const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
|
|
44989
45218
|
const lastBreak = head.lastIndexOf(10);
|
|
@@ -45004,7 +45233,7 @@ var MARKDOWN_FILE_EXT, MARKDOWN_READ_LIMIT;
|
|
|
45004
45233
|
var init_local_file = __esm({
|
|
45005
45234
|
"packages/server/src/local-file.ts"() {
|
|
45006
45235
|
"use strict";
|
|
45007
|
-
MARKDOWN_FILE_EXT = /\.(?:md|markdown)$/i;
|
|
45236
|
+
MARKDOWN_FILE_EXT = /\.(?:md|mdx|markdown)$/i;
|
|
45008
45237
|
MARKDOWN_READ_LIMIT = 1024 * 1024;
|
|
45009
45238
|
}
|
|
45010
45239
|
});
|
|
@@ -45330,67 +45559,6 @@ var init_account_actions = __esm({
|
|
|
45330
45559
|
}
|
|
45331
45560
|
});
|
|
45332
45561
|
|
|
45333
|
-
// packages/server/src/dispatch-preferences.ts
|
|
45334
|
-
function permissionFor(backend, mode) {
|
|
45335
|
-
if (backend === "codex") {
|
|
45336
|
-
if (mode === "plan" || mode === "bypassPermissions") return mode;
|
|
45337
|
-
return "default";
|
|
45338
|
-
}
|
|
45339
|
-
return mode === "plan" ? "auto" : mode;
|
|
45340
|
-
}
|
|
45341
|
-
function defaultDispatchPreferences(settings, codexModels = []) {
|
|
45342
|
-
const backend = settings.backend ?? (codexModels.some((model) => model.slug === settings.model) ? "codex" : "claude");
|
|
45343
|
-
const selected = {
|
|
45344
|
-
...settings.model ? { model: settings.model } : {},
|
|
45345
|
-
...settings.effort ? { effort: settings.effort } : {},
|
|
45346
|
-
permissionMode: permissionFor(backend, settings.permissionMode)
|
|
45347
|
-
};
|
|
45348
|
-
return {
|
|
45349
|
-
backend,
|
|
45350
|
-
claude: backend === "claude" ? selected : { permissionMode: "auto" },
|
|
45351
|
-
codex: backend === "codex" ? selected : { permissionMode: "default" }
|
|
45352
|
-
};
|
|
45353
|
-
}
|
|
45354
|
-
function getDispatchPreferences(storage, settings, codexModels = []) {
|
|
45355
|
-
const parsed = DispatchPreferences.safeParse(storage.getSetting(KEY));
|
|
45356
|
-
return parsed.success ? parsed.data : defaultDispatchPreferences(settings, codexModels);
|
|
45357
|
-
}
|
|
45358
|
-
function setDispatchPreference(storage, settings, update, codexModels = []) {
|
|
45359
|
-
const current = getDispatchPreferences(storage, settings, codexModels);
|
|
45360
|
-
let next;
|
|
45361
|
-
if (update.field === "backend") {
|
|
45362
|
-
next = { ...current, backend: update.value };
|
|
45363
|
-
} else if (update.field === "profile") {
|
|
45364
|
-
next = {
|
|
45365
|
-
...current,
|
|
45366
|
-
backend: update.backend,
|
|
45367
|
-
[update.backend]: {
|
|
45368
|
-
...current[update.backend],
|
|
45369
|
-
model: update.model,
|
|
45370
|
-
effort: update.effort
|
|
45371
|
-
}
|
|
45372
|
-
};
|
|
45373
|
-
} else {
|
|
45374
|
-
const profile = current[update.backend];
|
|
45375
|
-
next = {
|
|
45376
|
-
...current,
|
|
45377
|
-
...update.field === "model" ? { backend: update.backend } : {},
|
|
45378
|
-
[update.backend]: { ...profile, [update.field]: update.value }
|
|
45379
|
-
};
|
|
45380
|
-
}
|
|
45381
|
-
const validated = DispatchPreferences.parse(next);
|
|
45382
|
-
storage.setSetting(KEY, validated);
|
|
45383
|
-
return validated;
|
|
45384
|
-
}
|
|
45385
|
-
var KEY;
|
|
45386
|
-
var init_dispatch_preferences = __esm({
|
|
45387
|
-
"packages/server/src/dispatch-preferences.ts"() {
|
|
45388
|
-
"use strict";
|
|
45389
|
-
init_src();
|
|
45390
|
-
KEY = "dispatch-preferences.v1";
|
|
45391
|
-
}
|
|
45392
|
-
});
|
|
45393
|
-
|
|
45394
45562
|
// packages/server/src/external-terminal.ts
|
|
45395
45563
|
function shellQuote(value) {
|
|
45396
45564
|
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
@@ -45743,11 +45911,11 @@ var init_directory_picker = __esm({
|
|
|
45743
45911
|
});
|
|
45744
45912
|
|
|
45745
45913
|
// packages/server/src/router.ts
|
|
45746
|
-
import { readFileSync as
|
|
45747
|
-
import { join as
|
|
45914
|
+
import { readFileSync as readFileSync23, statSync as statSync17 } from "node:fs";
|
|
45915
|
+
import { join as join36, resolve as resolve8 } from "node:path";
|
|
45748
45916
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
45749
45917
|
import { basename as basename9, dirname as dirname14 } from "node:path";
|
|
45750
|
-
import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as
|
|
45918
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "node:fs";
|
|
45751
45919
|
import { homedir as homedir16 } from "node:os";
|
|
45752
45920
|
function validateGithubDispatchProfile(input) {
|
|
45753
45921
|
validateThreadProfile(input.backend, input.model, input.effort);
|
|
@@ -45907,7 +46075,7 @@ function projectCard(entry, stale) {
|
|
|
45907
46075
|
function addProjectAtPath(input) {
|
|
45908
46076
|
const typed = input.trim();
|
|
45909
46077
|
if (!typed) throw new Error("Enter a folder path.");
|
|
45910
|
-
const expanded = typed === "~" || typed.startsWith("~/") ?
|
|
46078
|
+
const expanded = typed === "~" || typed.startsWith("~/") ? join36(homedir16(), typed.slice(1)) : typed;
|
|
45911
46079
|
const absolute = resolve8(expanded);
|
|
45912
46080
|
let stats;
|
|
45913
46081
|
try {
|
|
@@ -45938,12 +46106,12 @@ function storeProjectIcon(id, name, bytes) {
|
|
|
45938
46106
|
mkdirSync16(dirname14(path), { recursive: true });
|
|
45939
46107
|
writeFileSync13(path, bytes);
|
|
45940
46108
|
if (!imageDimensions(path)) {
|
|
45941
|
-
|
|
46109
|
+
rmSync10(path, { force: true });
|
|
45942
46110
|
throw new Error("That file does not look like an image Frizz can draw.");
|
|
45943
46111
|
}
|
|
45944
46112
|
for (const stale of PROJECT_ICON_EXTENSIONS) {
|
|
45945
46113
|
const other = customIconPath(id, `.${stale}`);
|
|
45946
|
-
if (other !== path)
|
|
46114
|
+
if (other !== path) rmSync10(other, { force: true });
|
|
45947
46115
|
}
|
|
45948
46116
|
const updated = setProjectIcon(id, path);
|
|
45949
46117
|
if (!updated) throw new Error("No such project.");
|
|
@@ -45952,7 +46120,7 @@ function storeProjectIcon(id, name, bytes) {
|
|
|
45952
46120
|
function setProjectIconFromFile(id, file) {
|
|
45953
46121
|
let bytes;
|
|
45954
46122
|
try {
|
|
45955
|
-
bytes =
|
|
46123
|
+
bytes = readFileSync23(file);
|
|
45956
46124
|
} catch {
|
|
45957
46125
|
throw new Error("That file could not be read.");
|
|
45958
46126
|
}
|
|
@@ -45960,7 +46128,7 @@ function setProjectIconFromFile(id, file) {
|
|
|
45960
46128
|
return storeProjectIcon(id, file, bytes);
|
|
45961
46129
|
}
|
|
45962
46130
|
function createRouter(ctx) {
|
|
45963
|
-
const frizzDir =
|
|
46131
|
+
const frizzDir = join36(ctx.project.dir, ".frizz");
|
|
45964
46132
|
const openRoots = openableFileRoots(ctx.project);
|
|
45965
46133
|
function isAutoTitledSession(slug) {
|
|
45966
46134
|
return ctx.storage.getSession(slug)?.title_auto === 1;
|
|
@@ -47094,6 +47262,12 @@ ${gapNote}` : input.message;
|
|
|
47094
47262
|
if (forMs === null) {
|
|
47095
47263
|
throw new Error(`\`for: ${input.for}\` is not a duration \u2014 give one like \`30m\`, \`2h\` or \`3d\` (max 24h)`);
|
|
47096
47264
|
}
|
|
47265
|
+
const probe = await ctx.probePr(ref);
|
|
47266
|
+
if (!probe.ok) {
|
|
47267
|
+
throw new Error(
|
|
47268
|
+
`\`${target}\` cannot be watched \u2014 the server's \`gh\` could not read it: ${probe.reason}. Frizz polls with the \`gh\` of the process it runs as, not yours: check \`gh auth status\` there and that the repo is reachable, then register again. If GitHub itself was briefly down, registering again in a minute is enough.`
|
|
47269
|
+
);
|
|
47270
|
+
}
|
|
47097
47271
|
const now = Date.now();
|
|
47098
47272
|
const id = `prw_${randomUUID16().replace(/-/g, "").slice(0, 12)}`;
|
|
47099
47273
|
ctx.storage.armPrWatch({ id, slug: input.slug, owner: ref.owner, repo: ref.repo, number: ref.number, createdAtMs: now, expiresAtMs: now + forMs });
|
|
@@ -47561,7 +47735,7 @@ ${gapNote}` : input.message;
|
|
|
47561
47735
|
output: ProjectCard,
|
|
47562
47736
|
handler: async ({ input }) => {
|
|
47563
47737
|
for (const extension2 of PROJECT_ICON_EXTENSIONS) {
|
|
47564
|
-
|
|
47738
|
+
rmSync10(customIconPath(input.id, `.${extension2}`), { force: true });
|
|
47565
47739
|
}
|
|
47566
47740
|
const updated = clearProjectIcon(input.id);
|
|
47567
47741
|
if (!updated) throw new Error("No such project.");
|
|
@@ -47615,7 +47789,7 @@ ${gapNote}` : input.message;
|
|
|
47615
47789
|
for (const entry of listProjects()) {
|
|
47616
47790
|
if (entry.stale) continue;
|
|
47617
47791
|
try {
|
|
47618
|
-
const db = new sqlite_default(
|
|
47792
|
+
const db = new sqlite_default(join36(projectStateDir(entry.id), "ui.db"), { readonly: true });
|
|
47619
47793
|
try {
|
|
47620
47794
|
const hit = db.prepare("SELECT 1 FROM session WHERE slug = ? LIMIT 1").get(input.slug);
|
|
47621
47795
|
if (hit) found.push({ projectSlug: entry.slug, projectName: entry.name ?? entry.slug });
|
|
@@ -47645,12 +47819,12 @@ ${gapNote}` : input.message;
|
|
|
47645
47819
|
}),
|
|
47646
47820
|
dispatchPreferencesGet: query({
|
|
47647
47821
|
output: DispatchPreferences,
|
|
47648
|
-
handler: async () =>
|
|
47822
|
+
handler: async () => ctx.getDispatchPreferences(readCodexModels())
|
|
47649
47823
|
}),
|
|
47650
47824
|
dispatchPreferenceSet: mutation({
|
|
47651
47825
|
input: SetDispatchPreferenceInput,
|
|
47652
47826
|
output: DispatchPreferences,
|
|
47653
|
-
handler: async ({ input }) =>
|
|
47827
|
+
handler: async ({ input }) => ctx.setDispatchPreference(input, readCodexModels())
|
|
47654
47828
|
}),
|
|
47655
47829
|
// The shipped GitHub batch-dispatch prompt template (single source of truth: server/github.ts).
|
|
47656
47830
|
// The Settings UI reads it to prefill the editor and to power "reset to default"; an empty/unset
|
|
@@ -47761,7 +47935,6 @@ var init_router5 = __esm({
|
|
|
47761
47935
|
init_thread_profiles();
|
|
47762
47936
|
init_adoption_recovery();
|
|
47763
47937
|
init_awaiting();
|
|
47764
|
-
init_dispatch_preferences();
|
|
47765
47938
|
init_storage();
|
|
47766
47939
|
init_external_terminal();
|
|
47767
47940
|
init_background_shell_output();
|
|
@@ -47972,7 +48145,7 @@ var init_compression = __esm({
|
|
|
47972
48145
|
});
|
|
47973
48146
|
|
|
47974
48147
|
// packages/server/src/local-image.ts
|
|
47975
|
-
import { readFileSync as
|
|
48148
|
+
import { readFileSync as readFileSync24, realpathSync as realpathSync9, statSync as statSync18 } from "node:fs";
|
|
47976
48149
|
import { extname as extname2, isAbsolute as isAbsolute4 } from "node:path";
|
|
47977
48150
|
function resolveLocalImage(rawPath) {
|
|
47978
48151
|
if (!rawPath || !isAbsolute4(rawPath)) return { status: 400 };
|
|
@@ -47986,7 +48159,7 @@ function resolveLocalImage(rawPath) {
|
|
|
47986
48159
|
}
|
|
47987
48160
|
try {
|
|
47988
48161
|
if (!statSync18(real).isFile()) return { status: 404 };
|
|
47989
|
-
return { status: 200, contentType, body:
|
|
48162
|
+
return { status: 200, contentType, body: readFileSync24(real) };
|
|
47990
48163
|
} catch {
|
|
47991
48164
|
return { status: 404 };
|
|
47992
48165
|
}
|
|
@@ -48006,9 +48179,9 @@ var init_local_image = __esm({
|
|
|
48006
48179
|
});
|
|
48007
48180
|
|
|
48008
48181
|
// packages/server/src/project-icon.ts
|
|
48009
|
-
import { readFileSync as
|
|
48182
|
+
import { readFileSync as readFileSync25, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
|
|
48010
48183
|
import { homedir as homedir17 } from "node:os";
|
|
48011
|
-
import { basename as basename10, dirname as dirname15, extname as extname3, join as
|
|
48184
|
+
import { basename as basename10, dirname as dirname15, extname as extname3, join as join37, relative, sep as sep2 } from "node:path";
|
|
48012
48185
|
function normalizeStem(stem) {
|
|
48013
48186
|
const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
|
|
48014
48187
|
const normalized = sized.replace(VARIANT_SUFFIX, "");
|
|
@@ -48026,7 +48199,7 @@ function sizeScore(dimensions) {
|
|
|
48026
48199
|
return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
|
|
48027
48200
|
}
|
|
48028
48201
|
function under(root, relativeDirectory) {
|
|
48029
|
-
return relativeDirectory ?
|
|
48202
|
+
return relativeDirectory ? join37(root, relativeDirectory) : root;
|
|
48030
48203
|
}
|
|
48031
48204
|
function listFiles(directory) {
|
|
48032
48205
|
try {
|
|
@@ -48048,19 +48221,19 @@ function iconDirectories(root) {
|
|
|
48048
48221
|
for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
|
|
48049
48222
|
for (const host of HOST_DIRECTORIES) {
|
|
48050
48223
|
if (!children2.has(host)) continue;
|
|
48051
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
48224
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join37(root, host), asset));
|
|
48052
48225
|
}
|
|
48053
48226
|
for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
|
|
48054
48227
|
for (const container of WORKSPACE_CONTAINERS) {
|
|
48055
48228
|
if (!children2.has(container)) continue;
|
|
48056
48229
|
let members;
|
|
48057
48230
|
try {
|
|
48058
|
-
members = readdirSync10(
|
|
48231
|
+
members = readdirSync10(join37(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
48059
48232
|
} catch {
|
|
48060
48233
|
continue;
|
|
48061
48234
|
}
|
|
48062
48235
|
for (const member of members) {
|
|
48063
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
48236
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join37(root, container, member), asset));
|
|
48064
48237
|
}
|
|
48065
48238
|
}
|
|
48066
48239
|
return [...new Set(directories)];
|
|
@@ -48068,13 +48241,13 @@ function iconDirectories(root) {
|
|
|
48068
48241
|
function manifestIcons(manifestPath) {
|
|
48069
48242
|
let parsed;
|
|
48070
48243
|
try {
|
|
48071
|
-
parsed = JSON.parse(
|
|
48244
|
+
parsed = JSON.parse(readFileSync25(manifestPath, "utf8"));
|
|
48072
48245
|
} catch {
|
|
48073
48246
|
return [];
|
|
48074
48247
|
}
|
|
48075
48248
|
if (!Array.isArray(parsed?.icons)) return [];
|
|
48076
48249
|
const directory = dirname15(manifestPath);
|
|
48077
|
-
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) =>
|
|
48250
|
+
return parsed.icons.map((icon) => typeof icon?.src === "string" ? icon.src : void 0).filter((src) => !!src && !/^(https?:)?\/\//u.test(src) && !src.startsWith("data:")).map((src) => join37(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
|
|
48078
48251
|
}
|
|
48079
48252
|
function projectIconCandidates(root) {
|
|
48080
48253
|
const projectStem = normalizeStem(basename10(root)).normalized;
|
|
@@ -48093,7 +48266,7 @@ function projectIconCandidates(root) {
|
|
|
48093
48266
|
for (const name of listFiles(directory)) {
|
|
48094
48267
|
const extension2 = extname3(name).toLowerCase();
|
|
48095
48268
|
if (MANIFEST_NAMES.includes(name.toLowerCase())) {
|
|
48096
|
-
for (const icon of manifestIcons(
|
|
48269
|
+
for (const icon of manifestIcons(join37(directory, name))) {
|
|
48097
48270
|
if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
|
|
48098
48271
|
fromManifest.add(icon);
|
|
48099
48272
|
files.push({ path: icon, directory: dirname15(icon) });
|
|
@@ -48104,7 +48277,7 @@ function projectIconCandidates(root) {
|
|
|
48104
48277
|
if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
|
|
48105
48278
|
const stem = name.slice(0, name.length - extension2.length);
|
|
48106
48279
|
if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
|
|
48107
|
-
files.push({ path:
|
|
48280
|
+
files.push({ path: join37(directory, name), directory });
|
|
48108
48281
|
if (files.length >= MAX_CANDIDATES) break;
|
|
48109
48282
|
}
|
|
48110
48283
|
}
|
|
@@ -48169,7 +48342,7 @@ function resolveProjectIconResponse(id, options = {}) {
|
|
|
48169
48342
|
});
|
|
48170
48343
|
if (!roots.some((root) => real === root || real.startsWith(root + sep2))) return { status: 404 };
|
|
48171
48344
|
try {
|
|
48172
|
-
return { status: 200, contentType, body:
|
|
48345
|
+
return { status: 200, contentType, body: readFileSync25(real) };
|
|
48173
48346
|
} catch {
|
|
48174
48347
|
return { status: 404 };
|
|
48175
48348
|
}
|
|
@@ -48281,8 +48454,8 @@ var init_project_icon = __esm({
|
|
|
48281
48454
|
});
|
|
48282
48455
|
|
|
48283
48456
|
// packages/server/src/local-visualization.ts
|
|
48284
|
-
import { readdirSync as readdirSync11, readFileSync as
|
|
48285
|
-
import { join as
|
|
48457
|
+
import { readdirSync as readdirSync11, readFileSync as readFileSync26, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
|
|
48458
|
+
import { join as join38, sep as sep3 } from "node:path";
|
|
48286
48459
|
function children(path, pattern) {
|
|
48287
48460
|
try {
|
|
48288
48461
|
return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
|
|
@@ -48294,7 +48467,7 @@ function isUnder2(path, root) {
|
|
|
48294
48467
|
return path === root || path.startsWith(root.endsWith(sep3) ? root : root + sep3);
|
|
48295
48468
|
}
|
|
48296
48469
|
function resolveFragment(projectDir, sessionId, file) {
|
|
48297
|
-
const base =
|
|
48470
|
+
const base = join38(projectDir, ".codex", "visualizations");
|
|
48298
48471
|
let projectReal;
|
|
48299
48472
|
let baseReal;
|
|
48300
48473
|
try {
|
|
@@ -48305,12 +48478,12 @@ function resolveFragment(projectDir, sessionId, file) {
|
|
|
48305
48478
|
}
|
|
48306
48479
|
if (!isUnder2(baseReal, projectReal)) return null;
|
|
48307
48480
|
for (const year of children(base, YEAR_PART)) {
|
|
48308
|
-
const yearDir =
|
|
48481
|
+
const yearDir = join38(base, year);
|
|
48309
48482
|
for (const month of children(yearDir, DATE_PART)) {
|
|
48310
|
-
const monthDir =
|
|
48483
|
+
const monthDir = join38(yearDir, month);
|
|
48311
48484
|
for (const day of children(monthDir, DATE_PART)) {
|
|
48312
|
-
const sessionRoot =
|
|
48313
|
-
const candidate =
|
|
48485
|
+
const sessionRoot = join38(baseReal, year, month, day, sessionId);
|
|
48486
|
+
const candidate = join38(monthDir, day, sessionId, file);
|
|
48314
48487
|
try {
|
|
48315
48488
|
const real = realpathSync11(candidate);
|
|
48316
48489
|
if (isUnder2(real, sessionRoot) && statSync20(real).isFile()) return real;
|
|
@@ -48396,7 +48569,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
|
|
|
48396
48569
|
try {
|
|
48397
48570
|
const size = statSync20(path).size;
|
|
48398
48571
|
if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
|
|
48399
|
-
fragment =
|
|
48572
|
+
fragment = readFileSync26(path, "utf8");
|
|
48400
48573
|
} catch {
|
|
48401
48574
|
return { status: 404 };
|
|
48402
48575
|
}
|
|
@@ -48439,7 +48612,7 @@ var init_local_visualization = __esm({
|
|
|
48439
48612
|
|
|
48440
48613
|
// packages/server/src/app.ts
|
|
48441
48614
|
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync14 } from "node:fs";
|
|
48442
|
-
import { join as
|
|
48615
|
+
import { join as join39 } from "node:path";
|
|
48443
48616
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
48444
48617
|
function createApp(ctx, options = {}) {
|
|
48445
48618
|
const app = new Hono2();
|
|
@@ -48543,10 +48716,10 @@ function createApp(ctx, options = {}) {
|
|
|
48543
48716
|
if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
|
|
48544
48717
|
const ext = `.${attachmentExtension(name)}`;
|
|
48545
48718
|
const buf = Buffer.from(body.data, "base64");
|
|
48546
|
-
const dir =
|
|
48719
|
+
const dir = join39(ctx.project.stateDir, "attachments");
|
|
48547
48720
|
mkdirSync17(dir, { recursive: true });
|
|
48548
48721
|
const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
|
|
48549
|
-
const path =
|
|
48722
|
+
const path = join39(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
|
|
48550
48723
|
writeFileSync14(path, buf);
|
|
48551
48724
|
return c.json({ path });
|
|
48552
48725
|
});
|
|
@@ -49785,10 +49958,10 @@ var init_app_socket = __esm({
|
|
|
49785
49958
|
});
|
|
49786
49959
|
|
|
49787
49960
|
// packages/server/src/boot-progress.ts
|
|
49788
|
-
import { mkdirSync as mkdirSync18, readFileSync as
|
|
49789
|
-
import { basename as basename11, dirname as dirname16, join as
|
|
49961
|
+
import { mkdirSync as mkdirSync18, readFileSync as readFileSync27, renameSync as renameSync10, rmSync as rmSync11, writeFileSync as writeFileSync15 } from "node:fs";
|
|
49962
|
+
import { basename as basename11, dirname as dirname16, join as join40 } from "node:path";
|
|
49790
49963
|
function bootProgressPath(stateDir) {
|
|
49791
|
-
return
|
|
49964
|
+
return join40(stateDir, BOOT_PROGRESS_NAME);
|
|
49792
49965
|
}
|
|
49793
49966
|
function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
49794
49967
|
if (!stateDir) {
|
|
@@ -49809,7 +49982,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
49809
49982
|
step++;
|
|
49810
49983
|
try {
|
|
49811
49984
|
mkdirSync18(dirname16(path), { recursive: true, mode: 448 });
|
|
49812
|
-
const temp =
|
|
49985
|
+
const temp = join40(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
|
|
49813
49986
|
writeFileSync15(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
|
|
49814
49987
|
`, "utf8");
|
|
49815
49988
|
renameSync10(temp, path);
|
|
@@ -49819,7 +49992,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
49819
49992
|
return Object.assign(write, {
|
|
49820
49993
|
done: () => {
|
|
49821
49994
|
try {
|
|
49822
|
-
|
|
49995
|
+
rmSync11(path, { force: true });
|
|
49823
49996
|
} catch {
|
|
49824
49997
|
}
|
|
49825
49998
|
}
|
|
@@ -49926,11 +50099,11 @@ __export(index_exports, {
|
|
|
49926
50099
|
unknownProjectPage: () => unknownProjectPage
|
|
49927
50100
|
});
|
|
49928
50101
|
import { createServer } from "node:http";
|
|
49929
|
-
import { readFileSync as
|
|
49930
|
-
import { dirname as dirname17, join as
|
|
50102
|
+
import { readFileSync as readFileSync28, existsSync as existsSync15 } from "node:fs";
|
|
50103
|
+
import { dirname as dirname17, join as join41, resolve as resolve9, extname as extname4, normalize } from "node:path";
|
|
49931
50104
|
function readServerAddressHolder(path) {
|
|
49932
50105
|
try {
|
|
49933
|
-
const value = JSON.parse(
|
|
50106
|
+
const value = JSON.parse(readFileSync28(path, "utf8"));
|
|
49934
50107
|
if (typeof value?.pid !== "number") return void 0;
|
|
49935
50108
|
return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
|
|
49936
50109
|
} catch {
|
|
@@ -50030,11 +50203,11 @@ function createShutdownSignalHandler(options) {
|
|
|
50030
50203
|
}
|
|
50031
50204
|
function serveStatic(distDir, req, res) {
|
|
50032
50205
|
const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
|
|
50033
|
-
let file =
|
|
50034
|
-
if (!file.startsWith(distDir)) file =
|
|
50035
|
-
if (!existsSync15(file)) file =
|
|
50206
|
+
let file = join41(distDir, rel === "/" ? "index.html" : rel);
|
|
50207
|
+
if (!file.startsWith(distDir)) file = join41(distDir, "index.html");
|
|
50208
|
+
if (!existsSync15(file)) file = join41(distDir, "index.html");
|
|
50036
50209
|
try {
|
|
50037
|
-
const body =
|
|
50210
|
+
const body = readFileSync28(file);
|
|
50038
50211
|
res.writeHead(200, { "content-type": MIME[extname4(file)] ?? "application/octet-stream" });
|
|
50039
50212
|
res.end(body);
|
|
50040
50213
|
} catch {
|
|
@@ -50383,7 +50556,7 @@ async function startServer(opts = {}) {
|
|
|
50383
50556
|
}
|
|
50384
50557
|
statusPath = serverLockPathFor(ctx.project);
|
|
50385
50558
|
const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
|
|
50386
|
-
const distDir = opts.webDistDir ? resolve9(opts.webDistDir) :
|
|
50559
|
+
const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join41(webRoot, "dist");
|
|
50387
50560
|
startupPhase = "Vite";
|
|
50388
50561
|
if (opts.dev) {
|
|
50389
50562
|
try {
|
|
@@ -50459,7 +50632,7 @@ async function startServer(opts = {}) {
|
|
|
50459
50632
|
if (vite) {
|
|
50460
50633
|
vite.middlewares(req, res, () => {
|
|
50461
50634
|
try {
|
|
50462
|
-
const html =
|
|
50635
|
+
const html = readFileSync28(join41(webRoot, "index.html"), "utf8");
|
|
50463
50636
|
void vite.transformIndexHtml(url, html).then((out) => {
|
|
50464
50637
|
res.writeHead(200, { "content-type": "text/html" });
|
|
50465
50638
|
res.end(out);
|
|
@@ -50651,7 +50824,7 @@ var init_index = __esm({
|
|
|
50651
50824
|
}
|
|
50652
50825
|
};
|
|
50653
50826
|
isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
|
|
50654
|
-
serverLockPathFor = (project) =>
|
|
50827
|
+
serverLockPathFor = (project) => join41(project.stateDir, "server.lock");
|
|
50655
50828
|
MIME = {
|
|
50656
50829
|
".html": "text/html",
|
|
50657
50830
|
".js": "text/javascript",
|
|
@@ -50670,7 +50843,7 @@ init_project_launch();
|
|
|
50670
50843
|
init_shutdown();
|
|
50671
50844
|
init_logging();
|
|
50672
50845
|
import { existsSync as existsSync16 } from "node:fs";
|
|
50673
|
-
import { join as
|
|
50846
|
+
import { join as join42 } from "node:path";
|
|
50674
50847
|
process.on("uncaughtException", (error) => {
|
|
50675
50848
|
log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
|
|
50676
50849
|
process.exit(1);
|
|
@@ -50710,7 +50883,7 @@ try {
|
|
|
50710
50883
|
];
|
|
50711
50884
|
if (!existsSync16(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
|
|
50712
50885
|
for (const [name, directory, requiredFile] of required) {
|
|
50713
|
-
if (!directory || !existsSync16(
|
|
50886
|
+
if (!directory || !existsSync16(join42(directory, requiredFile)))
|
|
50714
50887
|
throw new Error(`stable artifact launch is missing verified ${name}`);
|
|
50715
50888
|
}
|
|
50716
50889
|
}
|