frizz 0.7.0 → 0.7.2
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 +1 -1
- package/dist/claude-agent-broker.js +9 -3
- package/dist/codex-app-server-daemon.js +12 -3
- package/dist/dev-child.js +387 -209
- package/dist/frizz.js +36 -4
- package/package.json +2 -2
- package/web-dist/assets/{TerminalPane-DW91LtY6.js → TerminalPane-K-DhxpCR.js} +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-Cz9pKsnx.js → abnfDiagram-VRR7QNED-D1qyMYic.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-DhCDPuB9.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-Cx1Inab9.js → architectureDiagram-ZJ3FMSHR-B7OHBGs-.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-Dkow3KWq.js → blockDiagram-677ZJIJ3-BOkbWfnO.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-D54f0v8B.js → c4Diagram-LMCZKHZV-DcfWo37Z.js} +1 -1
- package/web-dist/assets/channel-C0ssx150.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-5HfLNqOq.js → chunk-32BRIVSS-DG_MDBh7.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-CoVH-jjk.js → chunk-52WLFC77-HgYoNFkS.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-w41h00On.js → chunk-C7G6YPKG-Dfpg508V.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-BC_Frphy.js → chunk-EX3LRPZG-zaEux9Wm.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-DLZVUhWr.js → chunk-FWX5IMBZ-CpSICFGT.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-DCl7dozs.js → chunk-HOUHSVGY-CSwYs-ck.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-I8bc3hpu.js → chunk-ICXQ74PX-CkRfiAJk.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-D1tbS5-A.js → chunk-MOJQB5TN-DFtJBynx.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-CLa17J5_.js → chunk-OGEWGWER-B1ST2fth.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-DcYIQuxf.js → chunk-PUDLZKDR-B7ABSn_A.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-DGHqsWli.js → chunk-Q4XR5HBZ-CivO3j1P.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-DdVYI4tg.js → chunk-V7JOEXUC-BaM6_dmG.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-Dn_uoDoN.js → chunk-VAUOI2AC-BY3O_FOQ.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-AM_J_EWt.js → chunk-VR4S4FIN-BIV_iEar.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-BldKUlC0.js → chunk-WYO6CB5R-CUi65Li4.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-Oh85mcuX.js → chunk-ZGVPDNZ5-Dg0vMfMN.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DGsI7bj0.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DGsI7bj0.js +1 -0
- package/web-dist/assets/{cynefin-VYW2F7L2-5lF8kTLT.js → cynefin-VYW2F7L2-DWJeaT_t.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-_otwu953.js → cynefinDiagram-TSTJHNR4-ClaGZDTr.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-DxX5d4Jp.js → dagre-VKFMJZFB-C0pp3Xyc.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-JkCl7NEC.js → diagram-FQU43EPY-SSBAJs6v.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-ETwnVi8G.js → diagram-G47NLZAW-3GFBBF81.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-DZXKHMOv.js → diagram-NH7WQ7WH-DqYwuzE7.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP--Yt9Hbcy.js → diagram-OA4YK3LP-K6M4KioM.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-BXUskT8t.js → diagram-WEI45ONY-ByTNMmJD.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-C7E1X1Dl.js → ebnfDiagram-CCIWWBDH-Bl6rAFTA.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-DOfGp1t7.js → erDiagram-Q63AITRT-BGWlKkvA.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-CwE_bxam.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-BY0J247Q.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-P5HZV3uF.js → ganttDiagram-NO4QXBWP-C5eEoPLo.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-CsJYjOme.js → gitGraph-TEB2WS4Q-BNmphrH5.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-BNyrduBc.js → gitGraphDiagram-IHSO6WYX-zHU_D41b.js} +1 -1
- package/web-dist/assets/index-C-3lsl4q.css +1 -0
- package/web-dist/assets/{index-CYVVF_ZU.js → index-Kzg-vTmI.js} +114 -114
- package/web-dist/assets/{info-DKCQHKI2-WzpT_dbU.js → info-DKCQHKI2-BfD-7Xcw.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-CA_SxvAY.js → infoDiagram-FWYZ7A6U-CR3bcaik.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-DXMy0GH9.js → ishikawaDiagram-FXEZZL3T-VtEgUbJP.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-Bwmn4bNv.js → journeyDiagram-5HDEW3XC-DZ3fGB6L.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-D265Z0Fg.js → kanban-definition-HUTT4EX6-ChfTvN7D.js} +1 -1
- package/web-dist/assets/{line-DNn_Towe.js → line-B6kig2Co.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-3CrMhKoT.js → mermaid-parser.core-jyk1DbDV.js} +3 -3
- package/web-dist/assets/{mermaid.core-DfCFu8_x.js → mermaid.core-C5yyeZnx.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-CQ5g8Qrh.js → mindmap-definition-LN4V7U3C-BcXFy-N9.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-CRDQ5t5W.js → packet-7NZHBO7P-BXfwnw74.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-B0XFyb7d.js → pegDiagram-2B236MQR-BCD3YN2p.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-DqjiBFGO.js → pie-RZYD4A2V-AinCQhe4.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-C41GJ3-U.js → pieDiagram-ENE6RG2P-D91RCAtQ.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-9cF0WJaM.js → quadrantDiagram-ABIIQ3AL-CiOs81pa.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-S1F7Z4Kj.js → radar-I7S5WNFK-PjwSEfhJ.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-da9Pjcp1.js → railroad-3IZDKUUU-De7aPcv6.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-BdaR6aMg.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-BQ1i-m_V.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-Bz7gY9Z5.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-CkXBDByE.js → railroadDiagram-RFXS5EU6-Ba5vfAy2.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-CL9Famg0.js → requirementDiagram-TGXJPOKE-cl6D_V6r.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-LyB-A0pD.js → sankeyDiagram-HTMAVEWB-BiL7lO9N.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DXfA9UDM.js → sequenceDiagram-DBY2YBRQ-DWwMnGgF.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-DgxMkPRv.js → stateDiagram-2N3HPSRC-DyDSg9bX.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DdKoRulX.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-TvRb3Iib.js → swimlanes-5IMT3BWC-DXcDUTKt.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-e28nOYgP.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-BBvC3bzZ.js → timeline-definition-FHXFAJF6-BmhB--di.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-CvCYIkJk.js → treeView-QDETBFTQ-uZOu6XJp.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-Bj60PrS0.js → treemap-6X3UGDF4-vvG-U9_8.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-CLuLJiNi.js → vennDiagram-L72KCM5P-1w9D4erz.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-C4tNB2Mi.js → wardley-OPB4EBWU-BJKEDRlS.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-D_bno6Pc.js → wardleyDiagram-EHGQE667-BZuQjgMm.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-CklFVNTA.js → xychartDiagram-FW5EYKEG-BuCgSm0a.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-pEHgxrgQ.js +0 -1
- package/web-dist/assets/channel-DmtoXjBB.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-CUGsPtaX.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-CUGsPtaX.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-D47al60X.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-Cfew-ywI.js +0 -1
- package/web-dist/assets/index-CjEngYN7.css +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-cPb8e4yf.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-BdArTI_P.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-cRtFMlRA.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BVl1T6pD.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-CaBRomjp.js +0 -8
package/dist/dev-child.js
CHANGED
|
@@ -50,8 +50,14 @@ function xdg(env, name) {
|
|
|
50
50
|
const value = env[name];
|
|
51
51
|
return value && (value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value)) ? value : void 0;
|
|
52
52
|
}
|
|
53
|
+
function insideHome(child, home) {
|
|
54
|
+
const norm = (value) => value.replace(/[\\/]+$/u, "").replaceAll("\\", "/").toLowerCase();
|
|
55
|
+
const parent = norm(home);
|
|
56
|
+
const inner = norm(child);
|
|
57
|
+
return inner === parent || inner.startsWith(`${parent}/`);
|
|
58
|
+
}
|
|
53
59
|
function windowsRoots(env, home) {
|
|
54
|
-
const local = env.LOCALAPPDATA
|
|
60
|
+
const local = env.LOCALAPPDATA && insideHome(env.LOCALAPPDATA, home) ? env.LOCALAPPDATA : join(home, "AppData", "Local");
|
|
55
61
|
const base = join(local, "Frizz");
|
|
56
62
|
return {
|
|
57
63
|
data: join(base, "Data"),
|
|
@@ -475,7 +481,7 @@ function readGitWorktreeProjectId(worktree) {
|
|
|
475
481
|
);
|
|
476
482
|
}
|
|
477
483
|
function syncGitConfigPath(path) {
|
|
478
|
-
const fd = openSync(path, "r");
|
|
484
|
+
const fd = openSync(path, process.platform === "win32" ? "r+" : "r");
|
|
479
485
|
try {
|
|
480
486
|
fsyncSync(fd);
|
|
481
487
|
} finally {
|
|
@@ -12702,6 +12708,16 @@ var init_interactions = __esm({
|
|
|
12702
12708
|
}
|
|
12703
12709
|
});
|
|
12704
12710
|
|
|
12711
|
+
// packages/shared/src/claim.ts
|
|
12712
|
+
var CLAIM_MAX_AGE_MS, CLAIM_LEASE_MS;
|
|
12713
|
+
var init_claim = __esm({
|
|
12714
|
+
"packages/shared/src/claim.ts"() {
|
|
12715
|
+
"use strict";
|
|
12716
|
+
CLAIM_MAX_AGE_MS = 5 * 6e4;
|
|
12717
|
+
CLAIM_LEASE_MS = 30 * 24 * 60 * 6e4;
|
|
12718
|
+
}
|
|
12719
|
+
});
|
|
12720
|
+
|
|
12705
12721
|
// packages/shared/src/code-fences.ts
|
|
12706
12722
|
function fencedInteriors(text) {
|
|
12707
12723
|
const out = [];
|
|
@@ -13062,6 +13078,9 @@ function prWatchExpiredWakeMessage(ref) {
|
|
|
13062
13078
|
|
|
13063
13079
|
If you still care about it, register it again with \`mcp__frizz__watch_pr\` and a fresh \`for:\`. If you do not, and it was the only thing you were waiting on, end in a proper terminal state instead of parking on it again.`;
|
|
13064
13080
|
}
|
|
13081
|
+
function queuedThread(t) {
|
|
13082
|
+
return t.kind === "session" && t.foreign !== true && t.needsYou === true && t.state !== "archived";
|
|
13083
|
+
}
|
|
13065
13084
|
function formatElapsed(ms) {
|
|
13066
13085
|
if (!Number.isFinite(ms) || ms < 0) return "an unknown time";
|
|
13067
13086
|
const s = Math.floor(ms / 1e3);
|
|
@@ -13208,6 +13227,7 @@ var init_src = __esm({
|
|
|
13208
13227
|
init_zod();
|
|
13209
13228
|
init_interactions();
|
|
13210
13229
|
init_thread_slug();
|
|
13230
|
+
init_claim();
|
|
13211
13231
|
init_code_fences();
|
|
13212
13232
|
init_delta();
|
|
13213
13233
|
init_drainable_worker();
|
|
@@ -14026,8 +14046,8 @@ var init_src = __esm({
|
|
|
14026
14046
|
PermissionMode = external_exports.enum(["auto", "default", "acceptEdits", "plan", "bypassPermissions"]);
|
|
14027
14047
|
LocalFileOpener = external_exports.enum(["system", "cursor", "vscode", "finder", "copy"]);
|
|
14028
14048
|
Settings = external_exports.object({
|
|
14029
|
-
// The mode NEW Claude workers launch in. Settings surfaces exactly two of them — `
|
|
14030
|
-
//
|
|
14049
|
+
// The mode NEW Claude workers launch in. Settings surfaces exactly two of them — `bypassPermissions`
|
|
14050
|
+
// (--dangerously-skip-permissions, the shipped default since 0.7.2) and `auto` — because those are the only two
|
|
14031
14051
|
// an unattended worker can actually run in; the server's workerDispatchPermission enforces that same
|
|
14032
14052
|
// floor, so a restrictive value left here by an older build cannot reach a spawn.
|
|
14033
14053
|
permissionMode: PermissionMode,
|
|
@@ -19531,11 +19551,13 @@ var init_settings = __esm({
|
|
|
19531
19551
|
SETTINGS_KEY = "settings";
|
|
19532
19552
|
MACHINE_KEYS = ["font", "notifications", "localFileOpener", "projectRail"];
|
|
19533
19553
|
defaultSettings = () => ({
|
|
19534
|
-
// `
|
|
19535
|
-
// card.
|
|
19536
|
-
// control can
|
|
19537
|
-
//
|
|
19538
|
-
|
|
19554
|
+
// `bypassPermissions` = claude's --dangerously-skip-permissions: a headless worker never stops on an
|
|
19555
|
+
// approval card. Shipped default since 0.7.2 (maintainer 2026-08-24); the Settings "Permissions"
|
|
19556
|
+
// (under Claude) control can lower it to `auto` — the CLI's classifier mode, where risky actions
|
|
19557
|
+
// still surface an approval card in the thread. Those are the only two values a headless worker can
|
|
19558
|
+
// run in: the dispatch floor (WORKER_DISPATCH_PERMISSION) stays `auto`, and workerDispatchPermission
|
|
19559
|
+
// honors exactly one deviation from it, which is this one.
|
|
19560
|
+
permissionMode: "bypassPermissions",
|
|
19539
19561
|
model: void 0,
|
|
19540
19562
|
effort: void 0,
|
|
19541
19563
|
notifications: true,
|
|
@@ -20591,11 +20613,23 @@ var init_detached_daemons = __esm({
|
|
|
20591
20613
|
}
|
|
20592
20614
|
});
|
|
20593
20615
|
|
|
20616
|
+
// packages/server/src/backend/ipc-path.ts
|
|
20617
|
+
import { join as join13 } from "node:path";
|
|
20618
|
+
function frizzIpcPath(name) {
|
|
20619
|
+
if (process.platform === "win32") return `\\\\.\\pipe\\${name}`;
|
|
20620
|
+
return join13(process.env.TMPDIR ?? "/tmp", `${name}.sock`);
|
|
20621
|
+
}
|
|
20622
|
+
var init_ipc_path = __esm({
|
|
20623
|
+
"packages/server/src/backend/ipc-path.ts"() {
|
|
20624
|
+
"use strict";
|
|
20625
|
+
}
|
|
20626
|
+
});
|
|
20627
|
+
|
|
20594
20628
|
// packages/server/src/backend/claude-broker-host.ts
|
|
20595
20629
|
import { spawn } from "node:child_process";
|
|
20596
20630
|
import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
|
|
20597
20631
|
import { accessSync, constants as fsConstants, mkdirSync as mkdirSync9, readFileSync as readFileSync9, readdirSync as readdirSync4, unlinkSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
20598
|
-
import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as
|
|
20632
|
+
import { delimiter, dirname as dirname8, isAbsolute as isAbsolute2, join as join14 } from "node:path";
|
|
20599
20633
|
function windowsShimTarget(shimPath) {
|
|
20600
20634
|
let body;
|
|
20601
20635
|
try {
|
|
@@ -20605,7 +20639,7 @@ function windowsShimTarget(shimPath) {
|
|
|
20605
20639
|
}
|
|
20606
20640
|
const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
|
|
20607
20641
|
if (!target) return void 0;
|
|
20608
|
-
const full =
|
|
20642
|
+
const full = join14(dirname8(shimPath), target);
|
|
20609
20643
|
try {
|
|
20610
20644
|
accessSync(full, fsConstants.F_OK);
|
|
20611
20645
|
return full;
|
|
@@ -20620,17 +20654,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
20620
20654
|
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
20621
20655
|
if (!dir) continue;
|
|
20622
20656
|
if (windows) {
|
|
20623
|
-
const exe =
|
|
20657
|
+
const exe = join14(dir, `${candidate}.exe`);
|
|
20624
20658
|
try {
|
|
20625
20659
|
accessSync(exe, fsConstants.F_OK);
|
|
20626
20660
|
return exe;
|
|
20627
20661
|
} catch {
|
|
20628
20662
|
}
|
|
20629
|
-
const viaShim = windowsShimTarget(
|
|
20663
|
+
const viaShim = windowsShimTarget(join14(dir, `${candidate}.cmd`));
|
|
20630
20664
|
if (viaShim) return viaShim;
|
|
20631
20665
|
continue;
|
|
20632
20666
|
}
|
|
20633
|
-
const full =
|
|
20667
|
+
const full = join14(dir, candidate);
|
|
20634
20668
|
try {
|
|
20635
20669
|
accessSync(full, fsConstants.X_OK);
|
|
20636
20670
|
return full;
|
|
@@ -20641,16 +20675,15 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
20641
20675
|
}
|
|
20642
20676
|
function claudeBrokerSocketPath(stateDir, sessionId) {
|
|
20643
20677
|
const key = createHash5("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
|
|
20644
|
-
|
|
20645
|
-
return join13(process.env.TMPDIR ?? "/tmp", `frizz-claude-${key}.sock`);
|
|
20678
|
+
return frizzIpcPath(`frizz-claude-${key}`);
|
|
20646
20679
|
}
|
|
20647
20680
|
function claudeBrokerRecordPath(stateDir, sessionId) {
|
|
20648
20681
|
const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
20649
|
-
return
|
|
20682
|
+
return join14(stateDir, "claude-broker", `${key}.json`);
|
|
20650
20683
|
}
|
|
20651
20684
|
function claudeBrokerRetirementPath(stateDir, sessionId) {
|
|
20652
20685
|
const key = createHash5("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
20653
|
-
return
|
|
20686
|
+
return join14(stateDir, "claude-broker", `${key}.retired`);
|
|
20654
20687
|
}
|
|
20655
20688
|
function markBrokerRetired(stateDir, sessionId, reason, generation) {
|
|
20656
20689
|
const mark = { at: (/* @__PURE__ */ new Date()).toISOString(), generation, reason };
|
|
@@ -20717,7 +20750,7 @@ function liveBrokerRecord(recordPath2) {
|
|
|
20717
20750
|
return null;
|
|
20718
20751
|
}
|
|
20719
20752
|
function liveBrokerRecords(stateDir) {
|
|
20720
|
-
const dir =
|
|
20753
|
+
const dir = join14(stateDir, "claude-broker");
|
|
20721
20754
|
let names;
|
|
20722
20755
|
try {
|
|
20723
20756
|
names = readdirSync4(dir);
|
|
@@ -20727,7 +20760,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
20727
20760
|
const out = [];
|
|
20728
20761
|
for (const name of names) {
|
|
20729
20762
|
if (!name.endsWith(".json")) continue;
|
|
20730
|
-
const record = liveBrokerRecord(
|
|
20763
|
+
const record = liveBrokerRecord(join14(dir, name));
|
|
20731
20764
|
if (record) out.push(record);
|
|
20732
20765
|
}
|
|
20733
20766
|
return out;
|
|
@@ -20807,6 +20840,7 @@ var init_claude_broker_host = __esm({
|
|
|
20807
20840
|
"use strict";
|
|
20808
20841
|
init_detached_daemons();
|
|
20809
20842
|
init_claude_broker_diagnostics();
|
|
20843
|
+
init_ipc_path();
|
|
20810
20844
|
WINDOWS_SHIM_TARGET = /^\s*"%dp0%\\(.+?)"/mu;
|
|
20811
20845
|
}
|
|
20812
20846
|
});
|
|
@@ -20916,6 +20950,21 @@ function retireOutstandingDeliveries(storage, slug) {
|
|
|
20916
20950
|
storage.setDeliveryLedger(slug, serializeDeliveryLedger(next));
|
|
20917
20951
|
return items.length - next.length;
|
|
20918
20952
|
}
|
|
20953
|
+
function deliverOutstandingDeliveries(storage, slug) {
|
|
20954
|
+
const row = storage.getSession(slug);
|
|
20955
|
+
if (!row) return 0;
|
|
20956
|
+
const items = parseDeliveryLedger(row.delivery_ledger);
|
|
20957
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
20958
|
+
let moved = 0;
|
|
20959
|
+
const next = items.map((item) => {
|
|
20960
|
+
if (item.state !== "pending" && item.state !== "enqueued") return item;
|
|
20961
|
+
moved++;
|
|
20962
|
+
return { ...item, state: "delivered", updatedAt: at };
|
|
20963
|
+
});
|
|
20964
|
+
if (!moved) return 0;
|
|
20965
|
+
storage.setDeliveryLedger(slug, serializeDeliveryLedger(next));
|
|
20966
|
+
return moved;
|
|
20967
|
+
}
|
|
20919
20968
|
function deliveryItem(storage, slug, id) {
|
|
20920
20969
|
const row = storage.getSession(slug);
|
|
20921
20970
|
if (!row) return null;
|
|
@@ -21520,14 +21569,14 @@ var init_completion_relay = __esm({
|
|
|
21520
21569
|
// packages/server/src/tail-cache.ts
|
|
21521
21570
|
import { createHash as createHash6 } from "node:crypto";
|
|
21522
21571
|
import { closeSync as closeSync8, openSync as openSync9, readFileSync as readFileSync10, readSync as readSync3, statSync as statSync7 } from "node:fs";
|
|
21523
|
-
import { join as
|
|
21572
|
+
import { join as join15 } from "node:path";
|
|
21524
21573
|
function foldSchemaDigest(dir = import.meta.dirname) {
|
|
21525
21574
|
if (foldSchemaMemo) return foldSchemaMemo;
|
|
21526
21575
|
const hash = createHash6("sha256").update("frizz-tail-state-v1\0");
|
|
21527
21576
|
let read = 0;
|
|
21528
21577
|
for (const name of FOLD_SOURCES) {
|
|
21529
21578
|
try {
|
|
21530
|
-
hash.update(name).update("\0").update(readFileSync10(
|
|
21579
|
+
hash.update(name).update("\0").update(readFileSync10(join15(dir, name)));
|
|
21531
21580
|
read++;
|
|
21532
21581
|
} catch {
|
|
21533
21582
|
hash.update(name).update("\0missing\0");
|
|
@@ -21725,7 +21774,7 @@ var init_tail_cache = __esm({
|
|
|
21725
21774
|
// packages/server/src/tailer.ts
|
|
21726
21775
|
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 readFileSync11, existsSync as existsSync5 } from "node:fs";
|
|
21727
21776
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
21728
|
-
import { basename as basename4, join as
|
|
21777
|
+
import { basename as basename4, join as join16 } from "node:path";
|
|
21729
21778
|
import { homedir as homedir7 } from "node:os";
|
|
21730
21779
|
function probeShellAlive(outputFile) {
|
|
21731
21780
|
if (!existsSync5(outputFile)) return void 0;
|
|
@@ -21987,7 +22036,7 @@ function launchTaskId(text) {
|
|
|
21987
22036
|
function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
21988
22037
|
let names;
|
|
21989
22038
|
try {
|
|
21990
|
-
names = readdirSync5(
|
|
22039
|
+
names = readdirSync5(join16(sessionDir, "subagents"));
|
|
21991
22040
|
} catch {
|
|
21992
22041
|
return [];
|
|
21993
22042
|
}
|
|
@@ -21998,7 +22047,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
21998
22047
|
if (!agentId) continue;
|
|
21999
22048
|
let parsed;
|
|
22000
22049
|
try {
|
|
22001
|
-
parsed = JSON.parse(readFileSync11(
|
|
22050
|
+
parsed = JSON.parse(readFileSync11(join16(sessionDir, "subagents", name), "utf8"));
|
|
22002
22051
|
} catch {
|
|
22003
22052
|
continue;
|
|
22004
22053
|
}
|
|
@@ -22012,7 +22061,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
22012
22061
|
agentType: text(meta.agentType),
|
|
22013
22062
|
parentAgentId: text(meta.parentAgentId),
|
|
22014
22063
|
spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
|
|
22015
|
-
spawnedAtMs: mtimeMs(
|
|
22064
|
+
spawnedAtMs: mtimeMs(join16(sessionDir, "subagents", name))
|
|
22016
22065
|
});
|
|
22017
22066
|
}
|
|
22018
22067
|
return out;
|
|
@@ -22492,7 +22541,7 @@ function defaultMtimeMs(path) {
|
|
|
22492
22541
|
}
|
|
22493
22542
|
}
|
|
22494
22543
|
function defaultLogDir(project) {
|
|
22495
|
-
return
|
|
22544
|
+
return join16(homedir7(), ".claude", "projects", project.cwdSlug);
|
|
22496
22545
|
}
|
|
22497
22546
|
function defaultReadPermMarker(project) {
|
|
22498
22547
|
if (!project.stateDir) return () => void 0;
|
|
@@ -22623,7 +22672,7 @@ function createTailer(deps) {
|
|
|
22623
22672
|
return paneDead(row.slug);
|
|
22624
22673
|
}
|
|
22625
22674
|
const defaultBackend = {
|
|
22626
|
-
transcriptPath: (sessionId) =>
|
|
22675
|
+
transcriptPath: (sessionId) => join16(logDir, `${sessionId}.jsonl`),
|
|
22627
22676
|
foldLine: (state, line) => {
|
|
22628
22677
|
const rec = parseLine(line);
|
|
22629
22678
|
if (rec) applyRecord(state, rec);
|
|
@@ -22748,7 +22797,7 @@ ${ask}`;
|
|
|
22748
22797
|
return state.path.replace(/\.jsonl$/, "");
|
|
22749
22798
|
}
|
|
22750
22799
|
function descendantSidecars(state) {
|
|
22751
|
-
const at = mtimeMs(
|
|
22800
|
+
const at = mtimeMs(join16(sessionDirOf(state), "subagents"));
|
|
22752
22801
|
const cached2 = descendantIndex.get(state.slug);
|
|
22753
22802
|
if (cached2 && cached2.at === at) return cached2.all;
|
|
22754
22803
|
const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
|
|
@@ -22762,7 +22811,7 @@ ${ask}`;
|
|
|
22762
22811
|
return descendantIndex.get(state.slug)?.byToolUse.get(id);
|
|
22763
22812
|
}
|
|
22764
22813
|
function descendantTranscript(state, meta) {
|
|
22765
|
-
return
|
|
22814
|
+
return join16(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
|
|
22766
22815
|
}
|
|
22767
22816
|
function subAgentDescendantTasks(slug, id) {
|
|
22768
22817
|
const state = states.get(slug);
|
|
@@ -23076,7 +23125,7 @@ ${ask}`;
|
|
|
23076
23125
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
23077
23126
|
const id = name.slice(0, -".jsonl".length);
|
|
23078
23127
|
if (!id || registered.has(id)) continue;
|
|
23079
|
-
const path =
|
|
23128
|
+
const path = join16(logDir, name);
|
|
23080
23129
|
let mtime;
|
|
23081
23130
|
try {
|
|
23082
23131
|
mtime = statSync8(path).mtimeMs;
|
|
@@ -23348,7 +23397,7 @@ ${ask}`;
|
|
|
23348
23397
|
);
|
|
23349
23398
|
try {
|
|
23350
23399
|
mkdirSync10(stallLogDir, { recursive: true });
|
|
23351
|
-
writeFileSync8(
|
|
23400
|
+
writeFileSync8(join16(stallLogDir, `${row.slug}.stall.log`), `session_id: ${row.session_id}
|
|
23352
23401
|
captured_at: ${new Date(now()).toISOString()}
|
|
23353
23402
|
|
|
23354
23403
|
${detail}
|
|
@@ -23376,7 +23425,7 @@ ${detail}
|
|
|
23376
23425
|
state.nextDiscoverMs = nowMs + DISCOVER_RETRY_MS;
|
|
23377
23426
|
const strandedDir = discoverTranscriptDir(logDir, row.session_id);
|
|
23378
23427
|
if (strandedDir) {
|
|
23379
|
-
state.path =
|
|
23428
|
+
state.path = join16(strandedDir, `${row.session_id}.jsonl`);
|
|
23380
23429
|
state.offset = 0;
|
|
23381
23430
|
state.partial = "";
|
|
23382
23431
|
state.primed = false;
|
|
@@ -23399,7 +23448,7 @@ ${detail}
|
|
|
23399
23448
|
committed = false;
|
|
23400
23449
|
}
|
|
23401
23450
|
if (!committed) return false;
|
|
23402
|
-
state.path =
|
|
23451
|
+
state.path = join16(logDir, `${found}.jsonl`);
|
|
23403
23452
|
state.offset = 0;
|
|
23404
23453
|
state.partial = "";
|
|
23405
23454
|
state.primed = false;
|
|
@@ -23445,7 +23494,7 @@ ${detail}
|
|
|
23445
23494
|
let state = states.get(row.slug);
|
|
23446
23495
|
const runtimeGeneration = row.runtime_generation ?? 0;
|
|
23447
23496
|
if (!state || state.sessionId !== row.session_id || state.nativeSessionId !== nativeId || state.runtimeGeneration !== runtimeGeneration) {
|
|
23448
|
-
const path = backend.transcriptPath(nativeId) ??
|
|
23497
|
+
const path = backend.transcriptPath(nativeId) ?? join16(logDir, `${nativeId}.jsonl`);
|
|
23449
23498
|
state = newTailState(row.slug, row.session_id, path, false, nativeId, runtimeGeneration);
|
|
23450
23499
|
state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
|
|
23451
23500
|
hydrateFromCache(state, row, nativeId);
|
|
@@ -23894,14 +23943,14 @@ var init_tailer = __esm({
|
|
|
23894
23943
|
});
|
|
23895
23944
|
|
|
23896
23945
|
// packages/server/src/backend/codex.ts
|
|
23897
|
-
import { join as
|
|
23946
|
+
import { join as join17 } from "node:path";
|
|
23898
23947
|
import { homedir as homedir8 } from "node:os";
|
|
23899
23948
|
import { readdirSync as readdirSync6, statSync as statSync9, readFileSync as readFileSync12, openSync as openSync11, readSync as readSync5, closeSync as closeSync10 } from "node:fs";
|
|
23900
23949
|
function defaultCodexHome() {
|
|
23901
|
-
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME :
|
|
23950
|
+
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join17(homedir8(), ".codex");
|
|
23902
23951
|
}
|
|
23903
23952
|
function sessionsDir(codexHome) {
|
|
23904
|
-
return
|
|
23953
|
+
return join17(codexHome, "sessions");
|
|
23905
23954
|
}
|
|
23906
23955
|
function codexSandbox(mode) {
|
|
23907
23956
|
switch (mode) {
|
|
@@ -24282,17 +24331,17 @@ function collectRollouts(dir, out, budget) {
|
|
|
24282
24331
|
const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).sort(descByName);
|
|
24283
24332
|
for (const d of dirs) {
|
|
24284
24333
|
if (budget.n <= 0) return;
|
|
24285
|
-
collectRollouts(
|
|
24334
|
+
collectRollouts(join17(dir, d.name), out, budget);
|
|
24286
24335
|
}
|
|
24287
24336
|
for (const f of files) {
|
|
24288
24337
|
if (budget.n <= 0) return;
|
|
24289
24338
|
let mtimeMs;
|
|
24290
24339
|
try {
|
|
24291
|
-
mtimeMs = statSync9(
|
|
24340
|
+
mtimeMs = statSync9(join17(dir, f.name)).mtimeMs;
|
|
24292
24341
|
} catch {
|
|
24293
24342
|
continue;
|
|
24294
24343
|
}
|
|
24295
|
-
out.push({ path:
|
|
24344
|
+
out.push({ path: join17(dir, f.name), mtimeMs });
|
|
24296
24345
|
budget.n--;
|
|
24297
24346
|
}
|
|
24298
24347
|
}
|
|
@@ -24336,7 +24385,7 @@ function readCodexThreadNames(codexHome = defaultCodexHome()) {
|
|
|
24336
24385
|
const out = /* @__PURE__ */ new Map();
|
|
24337
24386
|
let raw2;
|
|
24338
24387
|
try {
|
|
24339
|
-
const path =
|
|
24388
|
+
const path = join17(codexHome, "session_index.jsonl");
|
|
24340
24389
|
if (statSync9(path).size > SESSION_INDEX_MAX_BYTES) return out;
|
|
24341
24390
|
raw2 = readFileSync12(path, "utf8");
|
|
24342
24391
|
} catch {
|
|
@@ -28374,16 +28423,16 @@ var init_wrapper = __esm({
|
|
|
28374
28423
|
|
|
28375
28424
|
// packages/server/src/worker-plugin-dir.ts
|
|
28376
28425
|
import { existsSync as existsSync6 } from "node:fs";
|
|
28377
|
-
import { dirname as dirname9, join as
|
|
28426
|
+
import { dirname as dirname9, join as join18 } from "node:path";
|
|
28378
28427
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
28379
28428
|
function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
|
|
28380
28429
|
const override = env.FRIZZ_WORKER_PLUGIN_DIR;
|
|
28381
|
-
if (override && existsSync6(
|
|
28430
|
+
if (override && existsSync6(join18(override, ".claude-plugin", "plugin.json")))
|
|
28382
28431
|
return override;
|
|
28383
28432
|
let current = dirname9(fileURLToPath2(moduleUrl));
|
|
28384
28433
|
for (; ; ) {
|
|
28385
|
-
const candidate =
|
|
28386
|
-
if (existsSync6(
|
|
28434
|
+
const candidate = join18(current, "cc-worker");
|
|
28435
|
+
if (existsSync6(join18(candidate, ".claude-plugin", "plugin.json"))) return candidate;
|
|
28387
28436
|
const parent = dirname9(current);
|
|
28388
28437
|
if (parent === current) return void 0;
|
|
28389
28438
|
current = parent;
|
|
@@ -28397,7 +28446,7 @@ var init_worker_plugin_dir = __esm({
|
|
|
28397
28446
|
|
|
28398
28447
|
// packages/server/src/backend/types.ts
|
|
28399
28448
|
import { existsSync as existsSync7 } from "node:fs";
|
|
28400
|
-
import { join as
|
|
28449
|
+
import { join as join19 } from "node:path";
|
|
28401
28450
|
function frizzMcpEnv(mcp) {
|
|
28402
28451
|
return {
|
|
28403
28452
|
FRIZZ_STATE_DIR: mcp.stateDir,
|
|
@@ -28421,7 +28470,7 @@ function chromeDevtoolsMcpMount() {
|
|
|
28421
28470
|
function resolveBrowserMcpScript(moduleUrl = import.meta.url, env = process.env) {
|
|
28422
28471
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
28423
28472
|
if (!pluginDir) return void 0;
|
|
28424
|
-
const scriptPath =
|
|
28473
|
+
const scriptPath = join19(pluginDir, "bin", CHROME_DEVTOOLS_MCP.script);
|
|
28425
28474
|
return existsSync7(scriptPath) ? scriptPath : void 0;
|
|
28426
28475
|
}
|
|
28427
28476
|
function workerCap(name, lifted, env) {
|
|
@@ -28517,21 +28566,21 @@ var init_codex_mcp = __esm({
|
|
|
28517
28566
|
// packages/server/src/backend/codex-app-server-native.ts
|
|
28518
28567
|
import { spawn as spawn2 } from "node:child_process";
|
|
28519
28568
|
import { connect } from "node:net";
|
|
28569
|
+
import { Agent as HttpAgent } from "node:http";
|
|
28520
28570
|
import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
|
|
28521
28571
|
import { existsSync as existsSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync13, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
|
|
28522
|
-
import { join as
|
|
28572
|
+
import { join as join20 } from "node:path";
|
|
28523
28573
|
import { PassThrough, Writable } from "node:stream";
|
|
28524
28574
|
import { StringDecoder } from "node:string_decoder";
|
|
28525
28575
|
function nativeDir(stateDir) {
|
|
28526
|
-
return
|
|
28576
|
+
return join20(stateDir, "codex-app-server-native");
|
|
28527
28577
|
}
|
|
28528
28578
|
function nativeRecordPath(stateDir, projectId) {
|
|
28529
|
-
return
|
|
28579
|
+
return join20(nativeDir(stateDir), `${projectId}.json`);
|
|
28530
28580
|
}
|
|
28531
28581
|
function nativeListenSocketPath(stateDir, projectId) {
|
|
28532
28582
|
const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
28533
|
-
|
|
28534
|
-
return join19(process.env.TMPDIR ?? "/tmp", `frizz-codex-native-${key}.sock`);
|
|
28583
|
+
return frizzIpcPath(`frizz-codex-native-${key}`);
|
|
28535
28584
|
}
|
|
28536
28585
|
function pidAlive2(pid) {
|
|
28537
28586
|
try {
|
|
@@ -28608,9 +28657,18 @@ function socketAccepting(socketPath) {
|
|
|
28608
28657
|
setTimeout(() => done(false), 2e3).unref?.();
|
|
28609
28658
|
});
|
|
28610
28659
|
}
|
|
28660
|
+
function ipcWebSocket(endpoint) {
|
|
28661
|
+
if (process.platform !== "win32") return new import_websocket.default(`ws+unix://${endpoint}:/`, { perMessageDeflate: false });
|
|
28662
|
+
class PipeAgent extends HttpAgent {
|
|
28663
|
+
createConnection() {
|
|
28664
|
+
return connect(endpoint);
|
|
28665
|
+
}
|
|
28666
|
+
}
|
|
28667
|
+
return new import_websocket.default("ws://localhost/", { agent: new PipeAgent(), perMessageDeflate: false });
|
|
28668
|
+
}
|
|
28611
28669
|
function attach(record, timeoutMs) {
|
|
28612
28670
|
return new Promise((resolve10, reject) => {
|
|
28613
|
-
const socket =
|
|
28671
|
+
const socket = ipcWebSocket(record.socketPath);
|
|
28614
28672
|
const stdout = new PassThrough();
|
|
28615
28673
|
const stderr = new PassThrough();
|
|
28616
28674
|
const listeners = { exit: [], error: [] };
|
|
@@ -28727,6 +28785,7 @@ var init_codex_app_server_native = __esm({
|
|
|
28727
28785
|
"packages/server/src/backend/codex-app-server-native.ts"() {
|
|
28728
28786
|
"use strict";
|
|
28729
28787
|
init_wrapper();
|
|
28788
|
+
init_ipc_path();
|
|
28730
28789
|
init_codex_mcp();
|
|
28731
28790
|
init_logging();
|
|
28732
28791
|
PRESUMED_LOSSY_REJOIN = 1;
|
|
@@ -28778,23 +28837,22 @@ var init_codex_app_server_native = __esm({
|
|
|
28778
28837
|
});
|
|
28779
28838
|
|
|
28780
28839
|
// packages/server/src/backend/codex-app-server-host.ts
|
|
28781
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
28840
|
+
import { spawn as spawn3, spawnSync } from "node:child_process";
|
|
28782
28841
|
import { createConnection } from "node:net";
|
|
28783
28842
|
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
28784
28843
|
import { existsSync as existsSync9, mkdirSync as mkdirSync12, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "node:fs";
|
|
28785
|
-
import { join as
|
|
28844
|
+
import { join as join21 } from "node:path";
|
|
28786
28845
|
import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
|
|
28787
28846
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
28788
28847
|
function daemonDir(stateDir) {
|
|
28789
|
-
return
|
|
28848
|
+
return join21(stateDir, "codex-app-server");
|
|
28790
28849
|
}
|
|
28791
28850
|
function recordPath(stateDir, projectId) {
|
|
28792
|
-
return
|
|
28851
|
+
return join21(daemonDir(stateDir), `${projectId}.json`);
|
|
28793
28852
|
}
|
|
28794
28853
|
function codexAppServerSocketPath(stateDir, projectId) {
|
|
28795
28854
|
const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
28796
|
-
|
|
28797
|
-
return join20(process.env.TMPDIR ?? "/tmp", `frizz-codex-${key}.sock`);
|
|
28855
|
+
return frizzIpcPath(`frizz-codex-${key}`);
|
|
28798
28856
|
}
|
|
28799
28857
|
function pidAlive3(pid) {
|
|
28800
28858
|
try {
|
|
@@ -28845,13 +28903,26 @@ function liveDaemonRecord(stateDir, projectId) {
|
|
|
28845
28903
|
}
|
|
28846
28904
|
return null;
|
|
28847
28905
|
}
|
|
28906
|
+
function endDaemonTree(pid, signal) {
|
|
28907
|
+
if (process.platform !== "win32") {
|
|
28908
|
+
try {
|
|
28909
|
+
process.kill(pid, signal);
|
|
28910
|
+
} catch {
|
|
28911
|
+
}
|
|
28912
|
+
return;
|
|
28913
|
+
}
|
|
28914
|
+
const killed = spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore", windowsHide: true });
|
|
28915
|
+
if (killed.error || killed.status !== 0) {
|
|
28916
|
+
try {
|
|
28917
|
+
process.kill(pid, signal);
|
|
28918
|
+
} catch {
|
|
28919
|
+
}
|
|
28920
|
+
}
|
|
28921
|
+
}
|
|
28848
28922
|
function killCodexAppServerDaemon(stateDir, projectId) {
|
|
28849
28923
|
const record = liveDaemonRecord(stateDir, projectId);
|
|
28850
28924
|
if (!record) return;
|
|
28851
|
-
|
|
28852
|
-
process.kill(record.daemonPid, "SIGTERM");
|
|
28853
|
-
} catch {
|
|
28854
|
-
}
|
|
28925
|
+
endDaemonTree(record.daemonPid, "SIGTERM");
|
|
28855
28926
|
try {
|
|
28856
28927
|
unlinkSync3(recordPath(stateDir, projectId));
|
|
28857
28928
|
} catch {
|
|
@@ -28867,10 +28938,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
28867
28938
|
await new Promise((resolve10) => setTimeout(resolve10, 25));
|
|
28868
28939
|
}
|
|
28869
28940
|
if (pidAlive3(record.daemonPid)) {
|
|
28870
|
-
|
|
28871
|
-
process.kill(record.daemonPid, "SIGKILL");
|
|
28872
|
-
} catch {
|
|
28873
|
-
}
|
|
28941
|
+
endDaemonTree(record.daemonPid, "SIGKILL");
|
|
28874
28942
|
while (pidAlive3(record.daemonPid) && Date.now() < deadline + 2e3) {
|
|
28875
28943
|
await new Promise((resolve10) => setTimeout(resolve10, 25));
|
|
28876
28944
|
}
|
|
@@ -29017,6 +29085,14 @@ function inProcessCodexAppServer(options) {
|
|
|
29017
29085
|
env: options.env,
|
|
29018
29086
|
stdio: ["pipe", "pipe", "pipe"]
|
|
29019
29087
|
});
|
|
29088
|
+
const kill = child.kill.bind(child);
|
|
29089
|
+
child.kill = ((signal) => {
|
|
29090
|
+
try {
|
|
29091
|
+
return kill(signal);
|
|
29092
|
+
} catch {
|
|
29093
|
+
return false;
|
|
29094
|
+
}
|
|
29095
|
+
});
|
|
29020
29096
|
return { process: child, generation: randomUUID10(), reattached: false, daemonPid: process.pid, droppedWhileDetached: 0 };
|
|
29021
29097
|
}
|
|
29022
29098
|
function directChildHost(spawnChild, generationId = randomUUID10) {
|
|
@@ -29034,6 +29110,7 @@ var init_codex_app_server_host = __esm({
|
|
|
29034
29110
|
"use strict";
|
|
29035
29111
|
init_detached_daemons();
|
|
29036
29112
|
init_codex_app_server_native();
|
|
29113
|
+
init_ipc_path();
|
|
29037
29114
|
init_codex_mcp();
|
|
29038
29115
|
init_logging();
|
|
29039
29116
|
daemonEntry = () => resolveDetachedDaemonEntry(import.meta.url, "codex-app-server-daemon");
|
|
@@ -31999,11 +32076,11 @@ var init_codex_app_server = __esm({
|
|
|
31999
32076
|
});
|
|
32000
32077
|
|
|
32001
32078
|
// packages/server/src/backend/codex-quota.ts
|
|
32002
|
-
import { join as
|
|
32079
|
+
import { join as join22 } from "node:path";
|
|
32003
32080
|
import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync12, readSync as readSync6, fstatSync, closeSync as closeSync11 } from "node:fs";
|
|
32004
32081
|
import { spawn as spawn4 } from "node:child_process";
|
|
32005
32082
|
function sessionsDir2(codexHome) {
|
|
32006
|
-
return
|
|
32083
|
+
return join22(codexHome, "sessions");
|
|
32007
32084
|
}
|
|
32008
32085
|
function newestRollouts(dir, out, budget) {
|
|
32009
32086
|
if (budget.n <= 0) return;
|
|
@@ -32017,11 +32094,11 @@ function newestRollouts(dir, out, budget) {
|
|
|
32017
32094
|
const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
|
|
32018
32095
|
for (const d of dirs) {
|
|
32019
32096
|
if (budget.n <= 0) return;
|
|
32020
|
-
newestRollouts(
|
|
32097
|
+
newestRollouts(join22(dir, d), out, budget);
|
|
32021
32098
|
}
|
|
32022
32099
|
for (const f of files) {
|
|
32023
32100
|
if (budget.n <= 0) return;
|
|
32024
|
-
out.push(
|
|
32101
|
+
out.push(join22(dir, f));
|
|
32025
32102
|
budget.n--;
|
|
32026
32103
|
}
|
|
32027
32104
|
}
|
|
@@ -32221,7 +32298,7 @@ var init_codex_quota = __esm({
|
|
|
32221
32298
|
});
|
|
32222
32299
|
|
|
32223
32300
|
// packages/server/src/backend/claude-quota.ts
|
|
32224
|
-
import { join as
|
|
32301
|
+
import { join as join23 } from "node:path";
|
|
32225
32302
|
import { homedir as homedir9, platform } from "node:os";
|
|
32226
32303
|
import { createHash as createHash10 } from "node:crypto";
|
|
32227
32304
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -32229,7 +32306,7 @@ import { execFile as execFile2 } from "node:child_process";
|
|
|
32229
32306
|
import { promisify as promisify2 } from "node:util";
|
|
32230
32307
|
function claudeConfigDir() {
|
|
32231
32308
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
32232
|
-
return override && override.trim() ? override :
|
|
32309
|
+
return override && override.trim() ? override : join23(homedir9(), ".claude");
|
|
32233
32310
|
}
|
|
32234
32311
|
function tokenFromCredentialsJson(raw2) {
|
|
32235
32312
|
let doc;
|
|
@@ -32258,7 +32335,7 @@ async function readKeychainToken() {
|
|
|
32258
32335
|
}
|
|
32259
32336
|
async function readAccessToken(configDir) {
|
|
32260
32337
|
try {
|
|
32261
|
-
const fromFile = tokenFromCredentialsJson(await readFile(
|
|
32338
|
+
const fromFile = tokenFromCredentialsJson(await readFile(join23(configDir, ".credentials.json"), "utf8"));
|
|
32262
32339
|
if (fromFile) return fromFile;
|
|
32263
32340
|
} catch {
|
|
32264
32341
|
}
|
|
@@ -32327,8 +32404,8 @@ function parseClaudeUsage(body, planType) {
|
|
|
32327
32404
|
function cachePaths(cacheDir, configDir) {
|
|
32328
32405
|
const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
|
|
32329
32406
|
return {
|
|
32330
|
-
data:
|
|
32331
|
-
lock:
|
|
32407
|
+
data: join23(cacheDir, `claude-${profile}.json`),
|
|
32408
|
+
lock: join23(cacheDir, `claude-${profile}.lock`)
|
|
32332
32409
|
};
|
|
32333
32410
|
}
|
|
32334
32411
|
async function readShared(path) {
|
|
@@ -32520,7 +32597,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
|
|
|
32520
32597
|
async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
32521
32598
|
const now = (deps.now ?? Date.now)();
|
|
32522
32599
|
const configDir = claudeConfigDir();
|
|
32523
|
-
const cacheDir = deps.cacheDir ??
|
|
32600
|
+
const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
|
|
32524
32601
|
try {
|
|
32525
32602
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
32526
32603
|
} catch {
|
|
@@ -32531,7 +32608,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
|
32531
32608
|
async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
|
|
32532
32609
|
const now = (deps.now ?? Date.now)();
|
|
32533
32610
|
const configDir = claudeConfigDir();
|
|
32534
|
-
const cacheDir = deps.cacheDir ??
|
|
32611
|
+
const cacheDir = deps.cacheDir ?? join23(frizzRoots().cache, "quota-cache");
|
|
32535
32612
|
const paths = cachePaths(cacheDir, configDir);
|
|
32536
32613
|
try {
|
|
32537
32614
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
@@ -32690,7 +32767,7 @@ var init_quota = __esm({
|
|
|
32690
32767
|
// packages/server/src/frizz.ts
|
|
32691
32768
|
import { execFile as execFile3 } from "node:child_process";
|
|
32692
32769
|
import { lstatSync as lstatSync2, realpathSync as realpathSync6 } from "node:fs";
|
|
32693
|
-
import { basename as basename5, dirname as dirname10, join as
|
|
32770
|
+
import { basename as basename5, dirname as dirname10, join as join24, resolve as resolve4 } from "node:path";
|
|
32694
32771
|
import { promisify as promisify3 } from "node:util";
|
|
32695
32772
|
function frizzScriptsDir() {
|
|
32696
32773
|
if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
|
|
@@ -32699,7 +32776,7 @@ function frizzScriptsDir() {
|
|
|
32699
32776
|
function directFrizzRoot(projectDir) {
|
|
32700
32777
|
try {
|
|
32701
32778
|
const projectRoot = realpathSync6(projectDir);
|
|
32702
|
-
const path =
|
|
32779
|
+
const path = join24(projectRoot, ".frizz");
|
|
32703
32780
|
const stat2 = lstatSync2(path);
|
|
32704
32781
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
32705
32782
|
const real = realpathSync6(path);
|
|
@@ -32713,7 +32790,7 @@ function frizzDirExists(projectDir) {
|
|
|
32713
32790
|
}
|
|
32714
32791
|
async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
32715
32792
|
if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
|
|
32716
|
-
const { stdout } = await execFileP("node", [
|
|
32793
|
+
const { stdout } = await execFileP("node", [join24(scriptsDir, "index.mjs"), "--json"], {
|
|
32717
32794
|
cwd: projectDir,
|
|
32718
32795
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
|
|
32719
32796
|
maxBuffer: 32 * 1024 * 1024
|
|
@@ -32738,7 +32815,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
|
32738
32815
|
};
|
|
32739
32816
|
}
|
|
32740
32817
|
async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
|
|
32741
|
-
await execFileP("node", [
|
|
32818
|
+
await execFileP("node", [join24(scriptsDir, "thread-update.mjs"), slug, ...args], {
|
|
32742
32819
|
cwd: projectDir,
|
|
32743
32820
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
|
|
32744
32821
|
});
|
|
@@ -34623,19 +34700,19 @@ var init_claude_agent_broker_bridge = __esm({
|
|
|
34623
34700
|
});
|
|
34624
34701
|
|
|
34625
34702
|
// packages/server/src/backend/auth-status.ts
|
|
34626
|
-
import { join as
|
|
34703
|
+
import { join as join25 } from "node:path";
|
|
34627
34704
|
import { homedir as homedir11, platform as platform2 } from "node:os";
|
|
34628
34705
|
import { readFileSync as readFileSync15, statSync as statSync11 } from "node:fs";
|
|
34629
34706
|
import { execFile as execFile4 } from "node:child_process";
|
|
34630
34707
|
import { promisify as promisify4 } from "node:util";
|
|
34631
34708
|
function claudeConfigDir2() {
|
|
34632
34709
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
34633
|
-
return override && override.trim() ? override :
|
|
34710
|
+
return override && override.trim() ? override : join25(homedir11(), ".claude");
|
|
34634
34711
|
}
|
|
34635
34712
|
function claudeFileState(configDir) {
|
|
34636
34713
|
let raw2;
|
|
34637
34714
|
try {
|
|
34638
|
-
raw2 = readFileSync15(
|
|
34715
|
+
raw2 = readFileSync15(join25(configDir, ".credentials.json"), "utf8");
|
|
34639
34716
|
} catch (err) {
|
|
34640
34717
|
return err.code === "ENOENT" ? "absent" : "error";
|
|
34641
34718
|
}
|
|
@@ -34668,7 +34745,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
34668
34745
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
|
|
34669
34746
|
let raw2;
|
|
34670
34747
|
try {
|
|
34671
|
-
raw2 = readFileSync15(
|
|
34748
|
+
raw2 = readFileSync15(join25(codexHome, "auth.json"), "utf8");
|
|
34672
34749
|
} catch (err) {
|
|
34673
34750
|
return err.code === "ENOENT" ? "signed-out" : "unknown";
|
|
34674
34751
|
}
|
|
@@ -34733,7 +34810,7 @@ function asEmail(value) {
|
|
|
34733
34810
|
}
|
|
34734
34811
|
function claudeAccountFile() {
|
|
34735
34812
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
34736
|
-
return override && override.trim() ?
|
|
34813
|
+
return override && override.trim() ? join25(override, ".claude.json") : join25(homedir11(), ".claude.json");
|
|
34737
34814
|
}
|
|
34738
34815
|
function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
34739
34816
|
let stat2;
|
|
@@ -34757,7 +34834,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
|
34757
34834
|
function readCodexAccountEmail(codexHome = defaultCodexHome()) {
|
|
34758
34835
|
let doc;
|
|
34759
34836
|
try {
|
|
34760
|
-
doc = JSON.parse(readFileSync15(
|
|
34837
|
+
doc = JSON.parse(readFileSync15(join25(codexHome, "auth.json"), "utf8"));
|
|
34761
34838
|
} catch {
|
|
34762
34839
|
return void 0;
|
|
34763
34840
|
}
|
|
@@ -34825,7 +34902,7 @@ var init_auth_status = __esm({
|
|
|
34825
34902
|
|
|
34826
34903
|
// packages/server/src/dispatch.ts
|
|
34827
34904
|
import { closeSync as closeSync12, constants, existsSync as existsSync10, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync16, realpathSync as realpathSync7, statSync as statSync12, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync8 } from "node:fs";
|
|
34828
|
-
import { basename as basename6, join as
|
|
34905
|
+
import { basename as basename6, join as join26, dirname as dirname11 } from "node:path";
|
|
34829
34906
|
import { createHash as createHash11, randomUUID as randomUUID13 } from "node:crypto";
|
|
34830
34907
|
function fallbackTitle(prompt) {
|
|
34831
34908
|
const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
|
|
@@ -34844,7 +34921,7 @@ function fallbackTitle(prompt) {
|
|
|
34844
34921
|
}
|
|
34845
34922
|
function resolveSlug(frizzDir, base, taken) {
|
|
34846
34923
|
base = ThreadSlug.parse(base);
|
|
34847
|
-
const isTaken = (slug) => existsSync10(
|
|
34924
|
+
const isTaken = (slug) => existsSync10(join26(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
|
|
34848
34925
|
if (!isTaken(base)) return base;
|
|
34849
34926
|
for (let n = 2; ; n++) {
|
|
34850
34927
|
const suffix = `-${n}`;
|
|
@@ -34861,12 +34938,12 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
34861
34938
|
if (!parsed.success) return null;
|
|
34862
34939
|
try {
|
|
34863
34940
|
const projectRoot = realpathSync7(projectDir);
|
|
34864
|
-
const frizzPath =
|
|
34941
|
+
const frizzPath = join26(projectRoot, ".frizz");
|
|
34865
34942
|
const frizzStat = lstatSync3(frizzPath);
|
|
34866
34943
|
if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
|
|
34867
34944
|
const realFrizz = realpathSync7(frizzPath);
|
|
34868
34945
|
if (dirname11(realFrizz) !== projectRoot || basename6(realFrizz) !== ".frizz") return null;
|
|
34869
|
-
const path =
|
|
34946
|
+
const path = join26(realFrizz, `${parsed.data}.md`);
|
|
34870
34947
|
const before = lstatSync3(path);
|
|
34871
34948
|
if (!before.isFile() || before.isSymbolicLink()) return null;
|
|
34872
34949
|
const realPath = realpathSync7(path);
|
|
@@ -34910,7 +34987,7 @@ function boardAuthorizesAdoption(board, slug) {
|
|
|
34910
34987
|
return !board.errorItems.some((item) => item.file === `${slug}.md`);
|
|
34911
34988
|
}
|
|
34912
34989
|
function ensureSafeDirectDirectory(parent, name) {
|
|
34913
|
-
const path =
|
|
34990
|
+
const path = join26(parent, name);
|
|
34914
34991
|
try {
|
|
34915
34992
|
mkdirSync13(path);
|
|
34916
34993
|
} catch (error) {
|
|
@@ -34940,8 +35017,8 @@ function loadWorkerPrompt(kind = "claude") {
|
|
|
34940
35017
|
function monitorScriptsDir() {
|
|
34941
35018
|
const plugin = workerPluginDir();
|
|
34942
35019
|
if (!plugin) return void 0;
|
|
34943
|
-
const dir =
|
|
34944
|
-
return existsSync10(
|
|
35020
|
+
const dir = join26(plugin, "skills", "gh", "scripts");
|
|
35021
|
+
return existsSync10(join26(dir, "ci-watch.mjs")) ? dir : void 0;
|
|
34945
35022
|
}
|
|
34946
35023
|
function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
34947
35024
|
if (!hookScript || !sessionId) return {};
|
|
@@ -34953,7 +35030,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
34953
35030
|
}
|
|
34954
35031
|
]
|
|
34955
35032
|
});
|
|
34956
|
-
const bashBackgroundHook =
|
|
35033
|
+
const bashBackgroundHook = join26(dirname11(hookScript), "bash-background.mjs");
|
|
34957
35034
|
return {
|
|
34958
35035
|
bypass_hook_trust: true,
|
|
34959
35036
|
hooks: {
|
|
@@ -34979,7 +35056,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
34979
35056
|
}
|
|
34980
35057
|
function scratchpadHookScript() {
|
|
34981
35058
|
const plugin = workerPluginDir();
|
|
34982
|
-
return plugin ?
|
|
35059
|
+
return plugin ? join26(plugin, "hooks", "scratchpad.mjs") : void 0;
|
|
34983
35060
|
}
|
|
34984
35061
|
function composePrompt(sessionId, prompt, kind = "claude") {
|
|
34985
35062
|
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.";
|
|
@@ -34995,7 +35072,7 @@ function scratchpadOrientation(sessionId, kind = "claude") {
|
|
|
34995
35072
|
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.`;
|
|
34996
35073
|
}
|
|
34997
35074
|
function frizzConfigBlock(projectDir) {
|
|
34998
|
-
const path =
|
|
35075
|
+
const path = join26(projectDir, "FRIZZ.md");
|
|
34999
35076
|
let body;
|
|
35000
35077
|
try {
|
|
35001
35078
|
const st = statSync12(path);
|
|
@@ -35035,7 +35112,7 @@ function resolveFrizzMcp(target, moduleUrl = import.meta.url, env = process.env,
|
|
|
35035
35112
|
const { stateDir, serverLock, projectId } = typeof target === "string" ? { stateDir: target } : target;
|
|
35036
35113
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
35037
35114
|
if (!pluginDir) return void 0;
|
|
35038
|
-
const scriptPath =
|
|
35115
|
+
const scriptPath = join26(pluginDir, "bin", FRIZZ_MCP.script);
|
|
35039
35116
|
if (!existsSync10(scriptPath)) return void 0;
|
|
35040
35117
|
return {
|
|
35041
35118
|
scriptPath,
|
|
@@ -35118,7 +35195,7 @@ function buildClaudeResumeCommand(opts) {
|
|
|
35118
35195
|
}
|
|
35119
35196
|
function createDispatcher(deps) {
|
|
35120
35197
|
const readBoardSource = deps.readBoard ?? readBoard;
|
|
35121
|
-
const frizzDir =
|
|
35198
|
+
const frizzDir = join26(deps.project.dir, ".frizz");
|
|
35122
35199
|
const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
|
|
35123
35200
|
function cleanupPrewrites(built) {
|
|
35124
35201
|
for (const path of new Set(built.prewrite.map((file) => file.path))) {
|
|
@@ -35131,7 +35208,7 @@ function createDispatcher(deps) {
|
|
|
35131
35208
|
function cleanupDispatchFiles(scratchRel, built, sessionId) {
|
|
35132
35209
|
cleanupPrewrites(built);
|
|
35133
35210
|
try {
|
|
35134
|
-
rmSync8(
|
|
35211
|
+
rmSync8(join26(deps.project.dir, scratchRel), { force: true, recursive: true });
|
|
35135
35212
|
} catch {
|
|
35136
35213
|
}
|
|
35137
35214
|
cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
|
|
@@ -35564,7 +35641,7 @@ import {
|
|
|
35564
35641
|
watch as fsWatch
|
|
35565
35642
|
} from "node:fs";
|
|
35566
35643
|
import { homedir as homedir12 } from "node:os";
|
|
35567
|
-
import { join as
|
|
35644
|
+
import { join as join27 } from "node:path";
|
|
35568
35645
|
import watcher from "@parcel/watcher";
|
|
35569
35646
|
function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
|
|
35570
35647
|
if (!liveness) return false;
|
|
@@ -36249,7 +36326,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
36249
36326
|
if (parcelSub || stopped) return Promise.resolve();
|
|
36250
36327
|
if (watchSetup) return watchSetup;
|
|
36251
36328
|
const setup = (async () => {
|
|
36252
|
-
const next = await subscribe(
|
|
36329
|
+
const next = await subscribe(join27(project.dir, ".frizz"), () => scheduleRebuild());
|
|
36253
36330
|
if (stopped) {
|
|
36254
36331
|
await next.unsubscribe();
|
|
36255
36332
|
return;
|
|
@@ -38183,7 +38260,7 @@ var init_resume = __esm({
|
|
|
38183
38260
|
});
|
|
38184
38261
|
|
|
38185
38262
|
// packages/server/src/backend/claude.ts
|
|
38186
|
-
import { join as
|
|
38263
|
+
import { join as join28 } from "node:path";
|
|
38187
38264
|
function toolResultText2(content) {
|
|
38188
38265
|
if (typeof content === "string") return content;
|
|
38189
38266
|
if (!Array.isArray(content)) return "";
|
|
@@ -38272,7 +38349,7 @@ function createClaudeBackend(opts) {
|
|
|
38272
38349
|
return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
|
|
38273
38350
|
},
|
|
38274
38351
|
transcriptPath(sessionId) {
|
|
38275
|
-
return
|
|
38352
|
+
return join28(opts.logDir, `${sessionId}.jsonl`);
|
|
38276
38353
|
},
|
|
38277
38354
|
parseLine(line) {
|
|
38278
38355
|
return parseClaudeLine(line);
|
|
@@ -38442,12 +38519,12 @@ var init_login_utility = __esm({
|
|
|
38442
38519
|
|
|
38443
38520
|
// packages/server/src/backend/codex-app-server-diagnostics.ts
|
|
38444
38521
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync14, renameSync as renameSync8, statSync as statSync13 } from "node:fs";
|
|
38445
|
-
import { join as
|
|
38522
|
+
import { join as join29 } from "node:path";
|
|
38446
38523
|
function codexDiagnosticLogPath(stateDir, projectId) {
|
|
38447
|
-
return
|
|
38524
|
+
return join29(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
|
|
38448
38525
|
}
|
|
38449
38526
|
function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
|
|
38450
|
-
const dir =
|
|
38527
|
+
const dir = join29(stateDir, "codex-app-server");
|
|
38451
38528
|
const path = codexDiagnosticLogPath(stateDir, projectId);
|
|
38452
38529
|
let ensured = false;
|
|
38453
38530
|
return (event) => {
|
|
@@ -38479,13 +38556,24 @@ var init_codex_app_server_diagnostics = __esm({
|
|
|
38479
38556
|
import { execFile as execFile7 } from "node:child_process";
|
|
38480
38557
|
import { readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
|
|
38481
38558
|
import { connect as connectSocket } from "node:net";
|
|
38482
|
-
import { join as
|
|
38559
|
+
import { join as join30 } from "node:path";
|
|
38560
|
+
function parseLsofSocketNames(stdout) {
|
|
38561
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
38562
|
+
for (const line of stdout.split("\n")) {
|
|
38563
|
+
if (!line.startsWith("n/")) continue;
|
|
38564
|
+
const raw2 = line.slice(1);
|
|
38565
|
+
referenced.add(raw2);
|
|
38566
|
+
const meta = raw2.indexOf(" type=");
|
|
38567
|
+
if (meta > 0) referenced.add(raw2.slice(0, meta));
|
|
38568
|
+
}
|
|
38569
|
+
return referenced;
|
|
38570
|
+
}
|
|
38483
38571
|
function sweepStaleSockets(options, deps = {}) {
|
|
38484
38572
|
if (process.platform === "win32") return;
|
|
38485
38573
|
const keep = new Set(options.keep ?? []);
|
|
38486
38574
|
let candidates;
|
|
38487
38575
|
try {
|
|
38488
|
-
candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) =>
|
|
38576
|
+
candidates = (deps.readdir ?? readdirSync8)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join30(options.dir, name)).filter((path) => !keep.has(path));
|
|
38489
38577
|
} catch {
|
|
38490
38578
|
return;
|
|
38491
38579
|
}
|
|
@@ -38515,9 +38603,7 @@ var init_stale_socket_sweep = __esm({
|
|
|
38515
38603
|
execFile7("lsof", ["-U", "-F", "n"], { timeout: 3e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
|
|
38516
38604
|
if (!stdout) return done(null);
|
|
38517
38605
|
if (error && !stdout.includes(prefix)) return done(null);
|
|
38518
|
-
|
|
38519
|
-
for (const line of stdout.split("\n")) if (line.startsWith("n/")) referenced.add(line.slice(1));
|
|
38520
|
-
done(referenced);
|
|
38606
|
+
done(parseLsofSocketNames(stdout));
|
|
38521
38607
|
}).unref?.();
|
|
38522
38608
|
};
|
|
38523
38609
|
defaultProbe = (path, verdict) => {
|
|
@@ -38537,6 +38623,7 @@ var init_stale_socket_sweep = __esm({
|
|
|
38537
38623
|
|
|
38538
38624
|
// packages/server/src/orphan-reaper.ts
|
|
38539
38625
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
38626
|
+
import { readFileSync as readFileSync17 } from "node:fs";
|
|
38540
38627
|
import { dirname as dirname12 } from "node:path";
|
|
38541
38628
|
function firstTokenBasename(command) {
|
|
38542
38629
|
const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
|
|
@@ -38636,8 +38723,8 @@ function parseEtimeMs(etime) {
|
|
|
38636
38723
|
else return 0;
|
|
38637
38724
|
return (((days * 24 + h) * 60 + m) * 60 + s) * 1e3;
|
|
38638
38725
|
}
|
|
38639
|
-
function enumerateProcs(exec = defaultExec) {
|
|
38640
|
-
const base = exec("ps", ["-
|
|
38726
|
+
function enumerateProcs(exec = defaultExec, opts = {}) {
|
|
38727
|
+
const base = exec("ps", ["-Aww", "-o", "pid=,ppid=,etime=,command="]);
|
|
38641
38728
|
const rows = [];
|
|
38642
38729
|
const byPid = /* @__PURE__ */ new Map();
|
|
38643
38730
|
const pids = [];
|
|
@@ -38653,6 +38740,21 @@ function enumerateProcs(exec = defaultExec) {
|
|
|
38653
38740
|
pids.push(pid);
|
|
38654
38741
|
}
|
|
38655
38742
|
if (!pids.length) return rows;
|
|
38743
|
+
if ((opts.platform ?? process.platform) === "linux") {
|
|
38744
|
+
const readEnv = opts.readEnv ?? defaultReadEnv;
|
|
38745
|
+
for (const row of rows) {
|
|
38746
|
+
const environ = readEnv(row.pid);
|
|
38747
|
+
if (environ === null) continue;
|
|
38748
|
+
for (const entry of environ.split("\0")) {
|
|
38749
|
+
const m = entry.match(/^FRIZZ_THREAD=([A-Za-z0-9._-]+)$/);
|
|
38750
|
+
if (m) {
|
|
38751
|
+
row.slug = m[1];
|
|
38752
|
+
break;
|
|
38753
|
+
}
|
|
38754
|
+
}
|
|
38755
|
+
}
|
|
38756
|
+
return rows;
|
|
38757
|
+
}
|
|
38656
38758
|
let text;
|
|
38657
38759
|
try {
|
|
38658
38760
|
text = exec("ps", ["-Eww", "-o", "pid=,command=", "-p", pids.join(",")]);
|
|
@@ -38728,7 +38830,7 @@ function sweepOrphansOnce(deps = {}) {
|
|
|
38728
38830
|
const minAgeMs = deps.minAgeMs ?? ORPHAN_MIN_AGE_MS;
|
|
38729
38831
|
let rows;
|
|
38730
38832
|
try {
|
|
38731
|
-
rows = enumerateProcs(exec);
|
|
38833
|
+
rows = enumerateProcs(exec, { platform: deps.platform, readEnv: deps.readEnv });
|
|
38732
38834
|
} catch {
|
|
38733
38835
|
return { reaped: 0, deadSlugs: [], liveSlugs: [] };
|
|
38734
38836
|
}
|
|
@@ -38776,7 +38878,7 @@ function startOrphanReaper(deps = {}) {
|
|
|
38776
38878
|
clearInterval(socketTimer);
|
|
38777
38879
|
};
|
|
38778
38880
|
}
|
|
38779
|
-
var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, defaultExec, defaultKill, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX;
|
|
38881
|
+
var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, defaultExec, defaultReadEnv, defaultKill, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX;
|
|
38780
38882
|
var init_orphan_reaper = __esm({
|
|
38781
38883
|
"packages/server/src/orphan-reaper.ts"() {
|
|
38782
38884
|
"use strict";
|
|
@@ -38786,6 +38888,13 @@ var init_orphan_reaper = __esm({
|
|
|
38786
38888
|
ORPHAN_MIN_AGE_MS = 12e4;
|
|
38787
38889
|
SLUG_RE = /FRIZZ_THREAD=([A-Za-z0-9._-]+)/;
|
|
38788
38890
|
defaultExec = (file, args) => execFileSync5(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 });
|
|
38891
|
+
defaultReadEnv = (pid) => {
|
|
38892
|
+
try {
|
|
38893
|
+
return readFileSync17(`/proc/${pid}/environ`, "utf8");
|
|
38894
|
+
} catch {
|
|
38895
|
+
return null;
|
|
38896
|
+
}
|
|
38897
|
+
};
|
|
38789
38898
|
defaultKill = (pid) => {
|
|
38790
38899
|
try {
|
|
38791
38900
|
process.kill(pid, "SIGKILL");
|
|
@@ -38928,7 +39037,7 @@ var init_thread_hibernation = __esm({
|
|
|
38928
39037
|
});
|
|
38929
39038
|
|
|
38930
39039
|
// packages/server/src/context.ts
|
|
38931
|
-
import { join as
|
|
39040
|
+
import { join as join31 } from "node:path";
|
|
38932
39041
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
38933
39042
|
import { homedir as homedir13 } from "node:os";
|
|
38934
39043
|
function reconcileSessions(storage) {
|
|
@@ -39086,7 +39195,7 @@ async function createContext(opts = {}) {
|
|
|
39086
39195
|
function createContextUnchecked(opts, resources) {
|
|
39087
39196
|
const home = opts.home ?? homedir13();
|
|
39088
39197
|
const project = opts.project ?? resolveProject();
|
|
39089
|
-
const dbPath =
|
|
39198
|
+
const dbPath = join31(project.stateDir, "ui.db");
|
|
39090
39199
|
const storage = createStorage(dbPath);
|
|
39091
39200
|
resources.storage = storage;
|
|
39092
39201
|
const bus = new Bus();
|
|
@@ -39414,6 +39523,7 @@ ${wakeDeliveryToken(deliveryId)}`;
|
|
|
39414
39523
|
getSettings: () => getSettings(storage, home),
|
|
39415
39524
|
setSettings: (s) => setSettings(storage, s, home),
|
|
39416
39525
|
resetSettings: () => resetSettings(storage, home),
|
|
39526
|
+
activeTenants: opts.activeTenants,
|
|
39417
39527
|
claudeBin: opts.claudeBin,
|
|
39418
39528
|
codexBin: opts.codexBin,
|
|
39419
39529
|
loginUtility: createLoginUtility({ claudeBin: opts.claudeBin, codexBin: opts.codexBin, cwd: project.dir })
|
|
@@ -42113,7 +42223,7 @@ var init_server = __esm({
|
|
|
42113
42223
|
});
|
|
42114
42224
|
|
|
42115
42225
|
// packages/server/src/repair.ts
|
|
42116
|
-
import { existsSync as existsSync12, readFileSync as
|
|
42226
|
+
import { existsSync as existsSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "node:fs";
|
|
42117
42227
|
import { basename as basename7, dirname as dirname13, resolve as resolve6 } from "node:path";
|
|
42118
42228
|
function quoteValue(v) {
|
|
42119
42229
|
if (/^[\w./#:+-]+$/.test(v)) return v;
|
|
@@ -42129,7 +42239,7 @@ function repairThreadFile(frizzDir, file) {
|
|
|
42129
42239
|
if (dirname13(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
|
|
42130
42240
|
if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
|
|
42131
42241
|
if (!existsSync12(abs)) throw new RepairError(`no thread file to repair: ${basename7(abs)}`);
|
|
42132
|
-
const content =
|
|
42242
|
+
const content = readFileSync18(abs, "utf8");
|
|
42133
42243
|
const firstLine2 = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
|
|
42134
42244
|
if (firstLine2?.trim() === "---") {
|
|
42135
42245
|
throw new RepairError(`${basename7(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
|
|
@@ -42162,7 +42272,7 @@ var init_repair = __esm({
|
|
|
42162
42272
|
});
|
|
42163
42273
|
|
|
42164
42274
|
// cc-worker/hooks/bash-background.mjs
|
|
42165
|
-
import { readFileSync as
|
|
42275
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
42166
42276
|
import { basename as basename8 } from "node:path";
|
|
42167
42277
|
import { pathToFileURL } from "node:url";
|
|
42168
42278
|
function emit(obj) {
|
|
@@ -42311,7 +42421,7 @@ var init_bash_background = __esm({
|
|
|
42311
42421
|
if (isDirectHookExecution(process.argv[1], import.meta.url)) {
|
|
42312
42422
|
try {
|
|
42313
42423
|
const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
|
|
42314
|
-
emit(evaluateBashBackgroundHook(JSON.parse(
|
|
42424
|
+
emit(evaluateBashBackgroundHook(JSON.parse(readFileSync19(0, "utf8")), env));
|
|
42315
42425
|
} catch {
|
|
42316
42426
|
emit({});
|
|
42317
42427
|
}
|
|
@@ -42320,10 +42430,10 @@ var init_bash_background = __esm({
|
|
|
42320
42430
|
});
|
|
42321
42431
|
|
|
42322
42432
|
// packages/server/src/transcript.ts
|
|
42323
|
-
import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as
|
|
42433
|
+
import { closeSync as closeSync13, existsSync as existsSync13, fstatSync as fstatSync3, mkdirSync as mkdirSync15, openSync as openSync14, readdirSync as readdirSync9, readFileSync as readFileSync20, readSync as readSync7, renameSync as renameSync9, statSync as statSync14, unlinkSync as unlinkSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
42324
42434
|
import { createHash as createHash13 } from "node:crypto";
|
|
42325
42435
|
import { StringDecoder as StringDecoder4 } from "node:string_decoder";
|
|
42326
|
-
import { join as
|
|
42436
|
+
import { join as join32 } from "node:path";
|
|
42327
42437
|
import { homedir as homedir14 } from "node:os";
|
|
42328
42438
|
function formatTokens(n) {
|
|
42329
42439
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
@@ -42428,17 +42538,28 @@ function pushToolPart(m, call) {
|
|
|
42428
42538
|
else m.parts.push({ kind: "tools", tools: [call] });
|
|
42429
42539
|
}
|
|
42430
42540
|
function coalescedQueuedKeys(deliveredText, pendingKeys) {
|
|
42431
|
-
|
|
42432
|
-
|
|
42433
|
-
|
|
42434
|
-
|
|
42435
|
-
|
|
42436
|
-
|
|
42437
|
-
if (
|
|
42438
|
-
|
|
42439
|
-
cursor
|
|
42440
|
-
|
|
42441
|
-
|
|
42541
|
+
if (!deliveredText) return [];
|
|
42542
|
+
const keys = [...pendingKeys];
|
|
42543
|
+
const dead = /* @__PURE__ */ new Set();
|
|
42544
|
+
const walk = (cursor, index) => {
|
|
42545
|
+
if (index >= keys.length) return null;
|
|
42546
|
+
const state = cursor * (keys.length + 1) + index;
|
|
42547
|
+
if (dead.has(state)) return null;
|
|
42548
|
+
const key = keys[index];
|
|
42549
|
+
if (key && deliveredText.startsWith(key, cursor)) {
|
|
42550
|
+
const next = cursor + key.length;
|
|
42551
|
+
if (next === deliveredText.length) return [key];
|
|
42552
|
+
if (deliveredText.startsWith("\n", next)) {
|
|
42553
|
+
const rest = walk(next + 1, index + 1);
|
|
42554
|
+
if (rest) return [key, ...rest];
|
|
42555
|
+
}
|
|
42556
|
+
}
|
|
42557
|
+
const skipped = walk(cursor, index + 1);
|
|
42558
|
+
if (skipped) return skipped;
|
|
42559
|
+
dead.add(state);
|
|
42560
|
+
return null;
|
|
42561
|
+
};
|
|
42562
|
+
return walk(0, 0) ?? [];
|
|
42442
42563
|
}
|
|
42443
42564
|
function commandEnvelopeQueuedKey(deliveredText) {
|
|
42444
42565
|
const name = COMMAND_NAME_RE.exec(deliveredText)?.[1]?.trim();
|
|
@@ -42862,14 +42983,14 @@ function pruneScreenshotCache() {
|
|
|
42862
42983
|
if (entries.length <= SCREENSHOT_CACHE_MAX) return;
|
|
42863
42984
|
const byMtime = entries.map((n) => {
|
|
42864
42985
|
try {
|
|
42865
|
-
return { n, m: statSync14(
|
|
42986
|
+
return { n, m: statSync14(join32(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
|
|
42866
42987
|
} catch {
|
|
42867
42988
|
return { n, m: 0 };
|
|
42868
42989
|
}
|
|
42869
42990
|
}).sort((a, b) => b.m - a.m);
|
|
42870
42991
|
for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
|
|
42871
42992
|
try {
|
|
42872
|
-
unlinkSync5(
|
|
42993
|
+
unlinkSync5(join32(SCREENSHOT_CACHE_DIR, n));
|
|
42873
42994
|
} catch {
|
|
42874
42995
|
}
|
|
42875
42996
|
}
|
|
@@ -42899,14 +43020,14 @@ function persistBase64Image(mediaType, data, idKey) {
|
|
|
42899
43020
|
const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
|
|
42900
43021
|
if (!ext || !data) return void 0;
|
|
42901
43022
|
const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
42902
|
-
const path =
|
|
43023
|
+
const path = join32(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
|
|
42903
43024
|
try {
|
|
42904
43025
|
if (existsSync13(path)) return path;
|
|
42905
43026
|
if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
|
|
42906
43027
|
const buf = Buffer.from(data, "base64");
|
|
42907
43028
|
if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
|
|
42908
43029
|
mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
42909
|
-
const tmp =
|
|
43030
|
+
const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
42910
43031
|
writeFileSync12(tmp, buf);
|
|
42911
43032
|
renameSync9(tmp, path);
|
|
42912
43033
|
pruneScreenshotCache();
|
|
@@ -42921,14 +43042,14 @@ function persistSentFile(srcPath, idKey) {
|
|
|
42921
43042
|
const outExt = ext === "jpeg" ? "jpg" : ext;
|
|
42922
43043
|
try {
|
|
42923
43044
|
const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
42924
|
-
const dest =
|
|
43045
|
+
const dest = join32(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
|
|
42925
43046
|
if (existsSync13(dest)) return dest;
|
|
42926
43047
|
const size = statSync14(srcPath).size;
|
|
42927
43048
|
if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
|
|
42928
|
-
const buf =
|
|
43049
|
+
const buf = readFileSync20(srcPath);
|
|
42929
43050
|
if (!looksLikeImage(buf, outExt)) return void 0;
|
|
42930
43051
|
mkdirSync15(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
42931
|
-
const tmp =
|
|
43052
|
+
const tmp = join32(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
42932
43053
|
writeFileSync12(tmp, buf);
|
|
42933
43054
|
renameSync9(tmp, dest);
|
|
42934
43055
|
pruneScreenshotCache();
|
|
@@ -43345,7 +43466,7 @@ function readTranscript(project, sessionId) {
|
|
|
43345
43466
|
}
|
|
43346
43467
|
function verifyIncrementalParse(path, identityPrefix, incremental) {
|
|
43347
43468
|
try {
|
|
43348
|
-
const fresh = parseTranscript(
|
|
43469
|
+
const fresh = parseTranscript(readFileSync20(path, "utf8"), identityPrefix);
|
|
43349
43470
|
const a = JSON.stringify(incremental);
|
|
43350
43471
|
const b = JSON.stringify(fresh);
|
|
43351
43472
|
if (a !== b) {
|
|
@@ -43365,16 +43486,16 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
|
|
|
43365
43486
|
}
|
|
43366
43487
|
}
|
|
43367
43488
|
function logDirOf(project) {
|
|
43368
|
-
return
|
|
43489
|
+
return join32(homedir14(), ".claude", "projects", project.cwdSlug);
|
|
43369
43490
|
}
|
|
43370
43491
|
function resolveTranscriptPath(project, sessionId) {
|
|
43371
|
-
const path =
|
|
43492
|
+
const path = join32(logDirOf(project), `${sessionId}.jsonl`);
|
|
43372
43493
|
try {
|
|
43373
43494
|
if (statSync14(path).size > 0) return path;
|
|
43374
43495
|
} catch {
|
|
43375
43496
|
}
|
|
43376
43497
|
const stranded = discoverTranscriptDir(logDirOf(project), sessionId);
|
|
43377
|
-
return stranded ?
|
|
43498
|
+
return stranded ? join32(stranded, `${sessionId}.jsonl`) : path;
|
|
43378
43499
|
}
|
|
43379
43500
|
function projectCodexTranscript(raw2, identityPrefix = "codex") {
|
|
43380
43501
|
const out = [];
|
|
@@ -44577,7 +44698,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
|
|
|
44577
44698
|
}
|
|
44578
44699
|
function readCodexTranscriptFile(absPath, nativeId = absPath) {
|
|
44579
44700
|
try {
|
|
44580
|
-
return parseCodexTranscript(
|
|
44701
|
+
return parseCodexTranscript(readFileSync20(absPath, "utf8"), `codex:${nativeId}`);
|
|
44581
44702
|
} catch {
|
|
44582
44703
|
return [];
|
|
44583
44704
|
}
|
|
@@ -44671,7 +44792,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
|
|
|
44671
44792
|
function readTranscriptFile(absPath) {
|
|
44672
44793
|
try {
|
|
44673
44794
|
const pathKey = createHash13("sha256").update(absPath).digest("base64url").slice(0, 16);
|
|
44674
|
-
return parseTranscript(
|
|
44795
|
+
return parseTranscript(readFileSync20(absPath, "utf8"), `claude-file:${pathKey}`);
|
|
44675
44796
|
} catch {
|
|
44676
44797
|
return [];
|
|
44677
44798
|
}
|
|
@@ -44768,9 +44889,9 @@ var init_open_external = __esm({
|
|
|
44768
44889
|
|
|
44769
44890
|
// packages/server/src/local-file.ts
|
|
44770
44891
|
import { spawn as spawn6 } from "node:child_process";
|
|
44771
|
-
import { readFileSync as
|
|
44892
|
+
import { readFileSync as readFileSync21, realpathSync as realpathSync8, statSync as statSync15 } from "node:fs";
|
|
44772
44893
|
import { homedir as homedir15 } from "node:os";
|
|
44773
|
-
import { isAbsolute as isAbsolute3, join as
|
|
44894
|
+
import { isAbsolute as isAbsolute3, join as join33, resolve as resolve7, sep } from "node:path";
|
|
44774
44895
|
function isUnder(real, root) {
|
|
44775
44896
|
let rootReal;
|
|
44776
44897
|
try {
|
|
@@ -44800,7 +44921,7 @@ function resolveLocalFile(rawPath, roots) {
|
|
|
44800
44921
|
function resolveOpenableFile(raw2, projectDir, roots, home = homedir15()) {
|
|
44801
44922
|
const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
|
|
44802
44923
|
if (!trimmed) return null;
|
|
44803
|
-
const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ?
|
|
44924
|
+
const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join33(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve7(projectDir, trimmed);
|
|
44804
44925
|
try {
|
|
44805
44926
|
return resolveLocalFile(abs, roots);
|
|
44806
44927
|
} catch {
|
|
@@ -44811,7 +44932,7 @@ function readLocalMarkdown(rawPath, roots) {
|
|
|
44811
44932
|
if (!MARKDOWN_FILE_EXT.test(rawPath.trim())) throw new Error("Local file is not a Markdown file");
|
|
44812
44933
|
const path = resolveLocalFile(rawPath, roots);
|
|
44813
44934
|
if (!MARKDOWN_FILE_EXT.test(path)) throw new Error("Local file is not a Markdown file");
|
|
44814
|
-
const bytes =
|
|
44935
|
+
const bytes = readFileSync21(path);
|
|
44815
44936
|
if (bytes.length <= MARKDOWN_READ_LIMIT) return { path, markdown: bytes.toString("utf8"), truncated: false };
|
|
44816
44937
|
const head = bytes.subarray(0, MARKDOWN_READ_LIMIT);
|
|
44817
44938
|
const lastBreak = head.lastIndexOf(10);
|
|
@@ -45257,6 +45378,17 @@ function readBackgroundShellOutput(path, maxBytes = OUTPUT_TAIL_BYTES) {
|
|
|
45257
45378
|
if (fd !== void 0) closeSync14(fd);
|
|
45258
45379
|
}
|
|
45259
45380
|
}
|
|
45381
|
+
function readHead2(fd, length) {
|
|
45382
|
+
if (length <= 0) return "";
|
|
45383
|
+
const buffer = Buffer.alloc(length);
|
|
45384
|
+
let read = 0;
|
|
45385
|
+
while (read < length) {
|
|
45386
|
+
const count = readSync8(fd, buffer, read, length - read, read);
|
|
45387
|
+
if (count === 0) break;
|
|
45388
|
+
read += count;
|
|
45389
|
+
}
|
|
45390
|
+
return buffer.subarray(0, read).toString("latin1");
|
|
45391
|
+
}
|
|
45260
45392
|
function backgroundShellLineCount(path) {
|
|
45261
45393
|
let fd;
|
|
45262
45394
|
try {
|
|
@@ -45264,9 +45396,21 @@ function backgroundShellLineCount(path) {
|
|
|
45264
45396
|
const stat2 = fstatSync4(fd);
|
|
45265
45397
|
const size = stat2.size;
|
|
45266
45398
|
let state = scans.get(path);
|
|
45267
|
-
if (state && (state.bytes > size || state.ino !== stat2.ino)) state = void 0;
|
|
45399
|
+
if (state && (state.bytes > size || state.ino !== stat2.ino || state.birthtimeMs !== stat2.birthtimeMs)) state = void 0;
|
|
45400
|
+
if (state && state.fingerprint !== readHead2(fd, state.fingerprint.length)) state = void 0;
|
|
45268
45401
|
if (state?.overflowed) return void 0;
|
|
45269
|
-
if (!state)
|
|
45402
|
+
if (!state) {
|
|
45403
|
+
state = {
|
|
45404
|
+
ino: stat2.ino,
|
|
45405
|
+
birthtimeMs: stat2.birthtimeMs,
|
|
45406
|
+
fingerprint: readHead2(fd, Math.min(FINGERPRINT_BYTES, size)),
|
|
45407
|
+
bytes: 0,
|
|
45408
|
+
breaks: 0,
|
|
45409
|
+
pendingCR: false,
|
|
45410
|
+
trailing: false,
|
|
45411
|
+
overflowed: false
|
|
45412
|
+
};
|
|
45413
|
+
}
|
|
45270
45414
|
if (size - state.bytes > SCAN_CEILING_BYTES) {
|
|
45271
45415
|
scans.set(path, { ...state, overflowed: true });
|
|
45272
45416
|
return void 0;
|
|
@@ -45302,7 +45446,7 @@ function backgroundShellLineCount(path) {
|
|
|
45302
45446
|
if (fd !== void 0) closeSync14(fd);
|
|
45303
45447
|
}
|
|
45304
45448
|
}
|
|
45305
|
-
var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, ANSI_ESCAPE_RE, scans;
|
|
45449
|
+
var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, FINGERPRINT_BYTES, ANSI_ESCAPE_RE, scans;
|
|
45306
45450
|
var init_background_shell_output = __esm({
|
|
45307
45451
|
"packages/server/src/background-shell-output.ts"() {
|
|
45308
45452
|
"use strict";
|
|
@@ -45310,6 +45454,7 @@ var init_background_shell_output = __esm({
|
|
|
45310
45454
|
SCAN_CHUNK_BYTES = 256 * 1024;
|
|
45311
45455
|
SCAN_CEILING_BYTES = 128 * 1024 * 1024;
|
|
45312
45456
|
SCAN_CACHE_LIMIT = 512;
|
|
45457
|
+
FINGERPRINT_BYTES = 64;
|
|
45313
45458
|
ANSI_ESCAPE_RE = /\x1b(?:\][^\x07]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~])/g;
|
|
45314
45459
|
scans = /* @__PURE__ */ new Map();
|
|
45315
45460
|
}
|
|
@@ -45318,7 +45463,7 @@ var init_background_shell_output = __esm({
|
|
|
45318
45463
|
// packages/server/src/image-header.ts
|
|
45319
45464
|
import { closeSync as closeSync15, openSync as openSync16, readSync as readSync9, statSync as statSync16 } from "node:fs";
|
|
45320
45465
|
import { extname } from "node:path";
|
|
45321
|
-
function
|
|
45466
|
+
function readHead3(path, budget) {
|
|
45322
45467
|
let fd;
|
|
45323
45468
|
try {
|
|
45324
45469
|
const size = statSync16(path).size;
|
|
@@ -45426,7 +45571,7 @@ function svg(head) {
|
|
|
45426
45571
|
}
|
|
45427
45572
|
function svgDeclaresColour(path) {
|
|
45428
45573
|
if (extname(path).toLowerCase() !== ".svg") return void 0;
|
|
45429
|
-
const head =
|
|
45574
|
+
const head = readHead3(path, 512 * 1024);
|
|
45430
45575
|
if (!head) return void 0;
|
|
45431
45576
|
const source = head.toString("utf8");
|
|
45432
45577
|
if (!/<svg\b/iu.test(source)) return void 0;
|
|
@@ -45439,7 +45584,7 @@ function svgDeclaresColour(path) {
|
|
|
45439
45584
|
function imageDimensions(path) {
|
|
45440
45585
|
const extension2 = extname(path).toLowerCase();
|
|
45441
45586
|
const budget = extension2 === ".jpg" || extension2 === ".jpeg" ? JPEG_SCAN_BYTES : HEAD_BYTES2;
|
|
45442
|
-
const head =
|
|
45587
|
+
const head = readHead3(path, budget);
|
|
45443
45588
|
if (!head) return void 0;
|
|
45444
45589
|
return png(head) ?? gif(head) ?? webp(head) ?? ico(head) ?? jpeg(head) ?? svg(head);
|
|
45445
45590
|
}
|
|
@@ -45547,8 +45692,8 @@ var init_directory_picker = __esm({
|
|
|
45547
45692
|
});
|
|
45548
45693
|
|
|
45549
45694
|
// packages/server/src/router.ts
|
|
45550
|
-
import { readFileSync as
|
|
45551
|
-
import { join as
|
|
45695
|
+
import { readFileSync as readFileSync22, statSync as statSync17 } from "node:fs";
|
|
45696
|
+
import { join as join34, resolve as resolve8 } from "node:path";
|
|
45552
45697
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
45553
45698
|
import { basename as basename9, dirname as dirname14 } from "node:path";
|
|
45554
45699
|
import { existsSync as existsSync14, mkdirSync as mkdirSync16, rmSync as rmSync9, writeFileSync as writeFileSync13 } from "node:fs";
|
|
@@ -45711,7 +45856,7 @@ function projectCard(entry, stale) {
|
|
|
45711
45856
|
function addProjectAtPath(input) {
|
|
45712
45857
|
const typed = input.trim();
|
|
45713
45858
|
if (!typed) throw new Error("Enter a folder path.");
|
|
45714
|
-
const expanded = typed === "~" || typed.startsWith("~/") ?
|
|
45859
|
+
const expanded = typed === "~" || typed.startsWith("~/") ? join34(homedir16(), typed.slice(1)) : typed;
|
|
45715
45860
|
const absolute = resolve8(expanded);
|
|
45716
45861
|
let stats;
|
|
45717
45862
|
try {
|
|
@@ -45756,7 +45901,7 @@ function storeProjectIcon(id, name, bytes) {
|
|
|
45756
45901
|
function setProjectIconFromFile(id, file) {
|
|
45757
45902
|
let bytes;
|
|
45758
45903
|
try {
|
|
45759
|
-
bytes =
|
|
45904
|
+
bytes = readFileSync22(file);
|
|
45760
45905
|
} catch {
|
|
45761
45906
|
throw new Error("That file could not be read.");
|
|
45762
45907
|
}
|
|
@@ -45764,7 +45909,7 @@ function setProjectIconFromFile(id, file) {
|
|
|
45764
45909
|
return storeProjectIcon(id, file, bytes);
|
|
45765
45910
|
}
|
|
45766
45911
|
function createRouter(ctx) {
|
|
45767
|
-
const frizzDir =
|
|
45912
|
+
const frizzDir = join34(ctx.project.dir, ".frizz");
|
|
45768
45913
|
const openRoots = openableFileRoots(ctx.project);
|
|
45769
45914
|
function isAutoTitledSession(slug) {
|
|
45770
45915
|
return ctx.storage.getSession(slug)?.title_auto === 1;
|
|
@@ -46396,15 +46541,16 @@ ${gapNote}` : input.message;
|
|
|
46396
46541
|
)
|
|
46397
46542
|
});
|
|
46398
46543
|
if (input.freshProcess) retireOutstandingDeliveries(ctx.storage, input.slug);
|
|
46399
|
-
|
|
46544
|
+
const preempted = input.interrupt === true && bridge.interruptTurn({ threadSlug: input.slug, sessionId: row.session_id });
|
|
46400
46545
|
if (input.deliveryId) {
|
|
46401
46546
|
appendDelivery(ctx.storage, input.slug, {
|
|
46402
46547
|
id: input.deliveryId,
|
|
46403
46548
|
text: input.message,
|
|
46404
46549
|
state: midTurn && input.freshProcess !== true ? "enqueued" : "delivered"
|
|
46405
46550
|
});
|
|
46406
|
-
ctx.transcriptChange.emit([input.slug]);
|
|
46407
46551
|
}
|
|
46552
|
+
if (preempted) deliverOutstandingDeliveries(ctx.storage, input.slug);
|
|
46553
|
+
if (input.deliveryId || preempted) ctx.transcriptChange.emit([input.slug]);
|
|
46408
46554
|
ctx.board.refresh();
|
|
46409
46555
|
return;
|
|
46410
46556
|
}
|
|
@@ -46490,6 +46636,7 @@ ${gapNote}` : input.message;
|
|
|
46490
46636
|
if (!bridge.interruptTurn({ threadSlug: input.slug, sessionId: row.session_id })) {
|
|
46491
46637
|
return { interrupted: false, reason: "Nothing to interrupt \u2014 this thread has no turn running" };
|
|
46492
46638
|
}
|
|
46639
|
+
if (deliverOutstandingDeliveries(ctx.storage, input.slug)) ctx.transcriptChange.emit([input.slug]);
|
|
46493
46640
|
return { interrupted: true };
|
|
46494
46641
|
}
|
|
46495
46642
|
}),
|
|
@@ -47267,6 +47414,35 @@ ${gapNote}` : input.message;
|
|
|
47267
47414
|
output: external_exports.array(ProjectCard),
|
|
47268
47415
|
handler: async () => listProjects().map((entry) => projectCard(entry, entry.stale))
|
|
47269
47416
|
}),
|
|
47417
|
+
/**
|
|
47418
|
+
* How many threads are in each project's queue, keyed by project id — the rail's badges.
|
|
47419
|
+
*
|
|
47420
|
+
* MACHINE-WIDE, answered from the boards this process has OPEN. A queue count is a board fact:
|
|
47421
|
+
* `needsYou` is derived from the tailer's live view of each session, so a project nobody has
|
|
47422
|
+
* opened since boot has no honest count, and it is left out rather than guessed at or opened for
|
|
47423
|
+
* the purpose (activating a project to badge it is exactly the cost lazy activation exists to
|
|
47424
|
+
* avoid — see tenants.ts). Absent ⇒ no badge; the project the operator is looking at is always
|
|
47425
|
+
* present, and the client draws THAT one from its own live board anyway.
|
|
47426
|
+
*
|
|
47427
|
+
* Kept OFF `projectsList` on purpose: that list is one registry-file read, cheap enough to be the
|
|
47428
|
+
* home page with forty projects, and this is a walk over live boards. The cached snapshot makes
|
|
47429
|
+
* it cheap too — but cheap-and-polled is a different budget from cheap-and-once.
|
|
47430
|
+
*/
|
|
47431
|
+
projectsQueueCounts: query({
|
|
47432
|
+
output: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()),
|
|
47433
|
+
handler: async () => {
|
|
47434
|
+
const counts = {};
|
|
47435
|
+
const open = ctx.activeTenants?.() ?? [{ project: ctx.project, board: ctx.board }];
|
|
47436
|
+
for (const { project, board } of open) {
|
|
47437
|
+
try {
|
|
47438
|
+
const { threads } = await board.snapshot();
|
|
47439
|
+
counts[project.id] = threads.filter(queuedThread).length;
|
|
47440
|
+
} catch {
|
|
47441
|
+
}
|
|
47442
|
+
}
|
|
47443
|
+
return counts;
|
|
47444
|
+
}
|
|
47445
|
+
}),
|
|
47270
47446
|
/**
|
|
47271
47447
|
* Pin the rail's order.
|
|
47272
47448
|
*
|
|
@@ -47388,7 +47564,7 @@ ${gapNote}` : input.message;
|
|
|
47388
47564
|
for (const entry of listProjects()) {
|
|
47389
47565
|
if (entry.stale) continue;
|
|
47390
47566
|
try {
|
|
47391
|
-
const db = new sqlite_default(
|
|
47567
|
+
const db = new sqlite_default(join34(projectStateDir(entry.id), "ui.db"), { readonly: true });
|
|
47392
47568
|
try {
|
|
47393
47569
|
const hit = db.prepare("SELECT 1 FROM session WHERE slug = ? LIMIT 1").get(input.slug);
|
|
47394
47570
|
if (hit) found.push({ projectSlug: entry.slug, projectName: entry.name ?? entry.slug });
|
|
@@ -47745,7 +47921,7 @@ var init_compression = __esm({
|
|
|
47745
47921
|
});
|
|
47746
47922
|
|
|
47747
47923
|
// packages/server/src/local-image.ts
|
|
47748
|
-
import { readFileSync as
|
|
47924
|
+
import { readFileSync as readFileSync23, realpathSync as realpathSync9, statSync as statSync18 } from "node:fs";
|
|
47749
47925
|
import { extname as extname2, isAbsolute as isAbsolute4 } from "node:path";
|
|
47750
47926
|
function resolveLocalImage(rawPath) {
|
|
47751
47927
|
if (!rawPath || !isAbsolute4(rawPath)) return { status: 400 };
|
|
@@ -47759,7 +47935,7 @@ function resolveLocalImage(rawPath) {
|
|
|
47759
47935
|
}
|
|
47760
47936
|
try {
|
|
47761
47937
|
if (!statSync18(real).isFile()) return { status: 404 };
|
|
47762
|
-
return { status: 200, contentType, body:
|
|
47938
|
+
return { status: 200, contentType, body: readFileSync23(real) };
|
|
47763
47939
|
} catch {
|
|
47764
47940
|
return { status: 404 };
|
|
47765
47941
|
}
|
|
@@ -47779,9 +47955,9 @@ var init_local_image = __esm({
|
|
|
47779
47955
|
});
|
|
47780
47956
|
|
|
47781
47957
|
// packages/server/src/project-icon.ts
|
|
47782
|
-
import { readFileSync as
|
|
47958
|
+
import { readFileSync as readFileSync24, readdirSync as readdirSync10, realpathSync as realpathSync10, statSync as statSync19 } from "node:fs";
|
|
47783
47959
|
import { homedir as homedir17 } from "node:os";
|
|
47784
|
-
import { basename as basename10, dirname as dirname15, extname as extname3, join as
|
|
47960
|
+
import { basename as basename10, dirname as dirname15, extname as extname3, join as join35, relative, sep as sep2 } from "node:path";
|
|
47785
47961
|
function normalizeStem(stem) {
|
|
47786
47962
|
const sized = stem.toLowerCase().replace(/[@-]\d+(\.\d+)?x(\d+)?$/u, "").replace(/[-_]\d{2,4}$/u, "");
|
|
47787
47963
|
const normalized = sized.replace(VARIANT_SUFFIX, "");
|
|
@@ -47799,7 +47975,7 @@ function sizeScore(dimensions) {
|
|
|
47799
47975
|
return Math.max(0, Math.min(40, Math.round(Math.log2(edge / 24) * 8)));
|
|
47800
47976
|
}
|
|
47801
47977
|
function under(root, relativeDirectory) {
|
|
47802
|
-
return relativeDirectory ?
|
|
47978
|
+
return relativeDirectory ? join35(root, relativeDirectory) : root;
|
|
47803
47979
|
}
|
|
47804
47980
|
function listFiles(directory) {
|
|
47805
47981
|
try {
|
|
@@ -47821,19 +47997,19 @@ function iconDirectories(root) {
|
|
|
47821
47997
|
for (const asset of ASSET_DIRECTORIES) directories.push(under(root, asset));
|
|
47822
47998
|
for (const host of HOST_DIRECTORIES) {
|
|
47823
47999
|
if (!children2.has(host)) continue;
|
|
47824
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
48000
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join35(root, host), asset));
|
|
47825
48001
|
}
|
|
47826
48002
|
for (const extra of EXTRA_DIRECTORIES) directories.push(under(root, extra));
|
|
47827
48003
|
for (const container of WORKSPACE_CONTAINERS) {
|
|
47828
48004
|
if (!children2.has(container)) continue;
|
|
47829
48005
|
let members;
|
|
47830
48006
|
try {
|
|
47831
|
-
members = readdirSync10(
|
|
48007
|
+
members = readdirSync10(join35(root, container), { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
47832
48008
|
} catch {
|
|
47833
48009
|
continue;
|
|
47834
48010
|
}
|
|
47835
48011
|
for (const member of members) {
|
|
47836
|
-
for (const asset of ASSET_DIRECTORIES) directories.push(under(
|
|
48012
|
+
for (const asset of ASSET_DIRECTORIES) directories.push(under(join35(root, container, member), asset));
|
|
47837
48013
|
}
|
|
47838
48014
|
}
|
|
47839
48015
|
return [...new Set(directories)];
|
|
@@ -47841,13 +48017,13 @@ function iconDirectories(root) {
|
|
|
47841
48017
|
function manifestIcons(manifestPath) {
|
|
47842
48018
|
let parsed;
|
|
47843
48019
|
try {
|
|
47844
|
-
parsed = JSON.parse(
|
|
48020
|
+
parsed = JSON.parse(readFileSync24(manifestPath, "utf8"));
|
|
47845
48021
|
} catch {
|
|
47846
48022
|
return [];
|
|
47847
48023
|
}
|
|
47848
48024
|
if (!Array.isArray(parsed?.icons)) return [];
|
|
47849
48025
|
const directory = dirname15(manifestPath);
|
|
47850
|
-
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) =>
|
|
48026
|
+
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) => join35(directory, src.replace(/[?#].*$/u, "").replace(/^\//u, "")));
|
|
47851
48027
|
}
|
|
47852
48028
|
function projectIconCandidates(root) {
|
|
47853
48029
|
const projectStem = normalizeStem(basename10(root)).normalized;
|
|
@@ -47866,7 +48042,7 @@ function projectIconCandidates(root) {
|
|
|
47866
48042
|
for (const name of listFiles(directory)) {
|
|
47867
48043
|
const extension2 = extname3(name).toLowerCase();
|
|
47868
48044
|
if (MANIFEST_NAMES.includes(name.toLowerCase())) {
|
|
47869
|
-
for (const icon of manifestIcons(
|
|
48045
|
+
for (const icon of manifestIcons(join35(directory, name))) {
|
|
47870
48046
|
if (MEASURABLE_IMAGE_EXTENSIONS.has(extname3(icon).toLowerCase())) {
|
|
47871
48047
|
fromManifest.add(icon);
|
|
47872
48048
|
files.push({ path: icon, directory: dirname15(icon) });
|
|
@@ -47877,7 +48053,7 @@ function projectIconCandidates(root) {
|
|
|
47877
48053
|
if (!MEASURABLE_IMAGE_EXTENSIONS.has(extension2)) continue;
|
|
47878
48054
|
const stem = name.slice(0, name.length - extension2.length);
|
|
47879
48055
|
if (normalizeStem(stem).normalized === "favicon") iconHomes.add(directory);
|
|
47880
|
-
files.push({ path:
|
|
48056
|
+
files.push({ path: join35(directory, name), directory });
|
|
47881
48057
|
if (files.length >= MAX_CANDIDATES) break;
|
|
47882
48058
|
}
|
|
47883
48059
|
}
|
|
@@ -47942,7 +48118,7 @@ function resolveProjectIconResponse(id, options = {}) {
|
|
|
47942
48118
|
});
|
|
47943
48119
|
if (!roots.some((root) => real === root || real.startsWith(root + sep2))) return { status: 404 };
|
|
47944
48120
|
try {
|
|
47945
|
-
return { status: 200, contentType, body:
|
|
48121
|
+
return { status: 200, contentType, body: readFileSync24(real) };
|
|
47946
48122
|
} catch {
|
|
47947
48123
|
return { status: 404 };
|
|
47948
48124
|
}
|
|
@@ -48054,8 +48230,8 @@ var init_project_icon = __esm({
|
|
|
48054
48230
|
});
|
|
48055
48231
|
|
|
48056
48232
|
// packages/server/src/local-visualization.ts
|
|
48057
|
-
import { readdirSync as readdirSync11, readFileSync as
|
|
48058
|
-
import { join as
|
|
48233
|
+
import { readdirSync as readdirSync11, readFileSync as readFileSync25, realpathSync as realpathSync11, statSync as statSync20 } from "node:fs";
|
|
48234
|
+
import { join as join36, sep as sep3 } from "node:path";
|
|
48059
48235
|
function children(path, pattern) {
|
|
48060
48236
|
try {
|
|
48061
48237
|
return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
|
|
@@ -48067,7 +48243,7 @@ function isUnder2(path, root) {
|
|
|
48067
48243
|
return path === root || path.startsWith(root.endsWith(sep3) ? root : root + sep3);
|
|
48068
48244
|
}
|
|
48069
48245
|
function resolveFragment(projectDir, sessionId, file) {
|
|
48070
|
-
const base =
|
|
48246
|
+
const base = join36(projectDir, ".codex", "visualizations");
|
|
48071
48247
|
let projectReal;
|
|
48072
48248
|
let baseReal;
|
|
48073
48249
|
try {
|
|
@@ -48078,12 +48254,12 @@ function resolveFragment(projectDir, sessionId, file) {
|
|
|
48078
48254
|
}
|
|
48079
48255
|
if (!isUnder2(baseReal, projectReal)) return null;
|
|
48080
48256
|
for (const year of children(base, YEAR_PART)) {
|
|
48081
|
-
const yearDir =
|
|
48257
|
+
const yearDir = join36(base, year);
|
|
48082
48258
|
for (const month of children(yearDir, DATE_PART)) {
|
|
48083
|
-
const monthDir =
|
|
48259
|
+
const monthDir = join36(yearDir, month);
|
|
48084
48260
|
for (const day of children(monthDir, DATE_PART)) {
|
|
48085
|
-
const sessionRoot =
|
|
48086
|
-
const candidate =
|
|
48261
|
+
const sessionRoot = join36(baseReal, year, month, day, sessionId);
|
|
48262
|
+
const candidate = join36(monthDir, day, sessionId, file);
|
|
48087
48263
|
try {
|
|
48088
48264
|
const real = realpathSync11(candidate);
|
|
48089
48265
|
if (isUnder2(real, sessionRoot) && statSync20(real).isFile()) return real;
|
|
@@ -48169,7 +48345,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
|
|
|
48169
48345
|
try {
|
|
48170
48346
|
const size = statSync20(path).size;
|
|
48171
48347
|
if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
|
|
48172
|
-
fragment =
|
|
48348
|
+
fragment = readFileSync25(path, "utf8");
|
|
48173
48349
|
} catch {
|
|
48174
48350
|
return { status: 404 };
|
|
48175
48351
|
}
|
|
@@ -48212,7 +48388,7 @@ var init_local_visualization = __esm({
|
|
|
48212
48388
|
|
|
48213
48389
|
// packages/server/src/app.ts
|
|
48214
48390
|
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync14 } from "node:fs";
|
|
48215
|
-
import { join as
|
|
48391
|
+
import { join as join37 } from "node:path";
|
|
48216
48392
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
48217
48393
|
function createApp(ctx, options = {}) {
|
|
48218
48394
|
const app = new Hono2();
|
|
@@ -48316,10 +48492,10 @@ function createApp(ctx, options = {}) {
|
|
|
48316
48492
|
if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
|
|
48317
48493
|
const ext = `.${attachmentExtension(name)}`;
|
|
48318
48494
|
const buf = Buffer.from(body.data, "base64");
|
|
48319
|
-
const dir =
|
|
48495
|
+
const dir = join37(ctx.project.stateDir, "attachments");
|
|
48320
48496
|
mkdirSync17(dir, { recursive: true });
|
|
48321
48497
|
const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
|
|
48322
|
-
const path =
|
|
48498
|
+
const path = join37(dir, `${Date.now()}-${randomUUID17().slice(0, 8)}-${base}${ext}`);
|
|
48323
48499
|
writeFileSync14(path, buf);
|
|
48324
48500
|
return c.json({ path });
|
|
48325
48501
|
});
|
|
@@ -49558,10 +49734,10 @@ var init_app_socket = __esm({
|
|
|
49558
49734
|
});
|
|
49559
49735
|
|
|
49560
49736
|
// packages/server/src/boot-progress.ts
|
|
49561
|
-
import { mkdirSync as mkdirSync18, readFileSync as
|
|
49562
|
-
import { basename as basename11, dirname as dirname16, join as
|
|
49737
|
+
import { mkdirSync as mkdirSync18, readFileSync as readFileSync26, renameSync as renameSync10, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "node:fs";
|
|
49738
|
+
import { basename as basename11, dirname as dirname16, join as join38 } from "node:path";
|
|
49563
49739
|
function bootProgressPath(stateDir) {
|
|
49564
|
-
return
|
|
49740
|
+
return join38(stateDir, BOOT_PROGRESS_NAME);
|
|
49565
49741
|
}
|
|
49566
49742
|
function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
49567
49743
|
if (!stateDir) {
|
|
@@ -49582,7 +49758,7 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
49582
49758
|
step++;
|
|
49583
49759
|
try {
|
|
49584
49760
|
mkdirSync18(dirname16(path), { recursive: true, mode: 448 });
|
|
49585
|
-
const temp =
|
|
49761
|
+
const temp = join38(dirname16(path), `.${basename11(path)}.${process.pid}.tmp`);
|
|
49586
49762
|
writeFileSync15(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
|
|
49587
49763
|
`, "utf8");
|
|
49588
49764
|
renameSync10(temp, path);
|
|
@@ -49699,11 +49875,11 @@ __export(index_exports, {
|
|
|
49699
49875
|
unknownProjectPage: () => unknownProjectPage
|
|
49700
49876
|
});
|
|
49701
49877
|
import { createServer } from "node:http";
|
|
49702
|
-
import { readFileSync as
|
|
49703
|
-
import { dirname as dirname17, join as
|
|
49878
|
+
import { readFileSync as readFileSync27, existsSync as existsSync15 } from "node:fs";
|
|
49879
|
+
import { dirname as dirname17, join as join39, resolve as resolve9, extname as extname4, normalize } from "node:path";
|
|
49704
49880
|
function readServerAddressHolder(path) {
|
|
49705
49881
|
try {
|
|
49706
|
-
const value = JSON.parse(
|
|
49882
|
+
const value = JSON.parse(readFileSync27(path, "utf8"));
|
|
49707
49883
|
if (typeof value?.pid !== "number") return void 0;
|
|
49708
49884
|
return { pid: value.pid, port: typeof value.port === "number" ? value.port : -1 };
|
|
49709
49885
|
} catch {
|
|
@@ -49803,11 +49979,11 @@ function createShutdownSignalHandler(options) {
|
|
|
49803
49979
|
}
|
|
49804
49980
|
function serveStatic(distDir, req, res) {
|
|
49805
49981
|
const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
|
|
49806
|
-
let file =
|
|
49807
|
-
if (!file.startsWith(distDir)) file =
|
|
49808
|
-
if (!existsSync15(file)) file =
|
|
49982
|
+
let file = join39(distDir, rel === "/" ? "index.html" : rel);
|
|
49983
|
+
if (!file.startsWith(distDir)) file = join39(distDir, "index.html");
|
|
49984
|
+
if (!existsSync15(file)) file = join39(distDir, "index.html");
|
|
49809
49985
|
try {
|
|
49810
|
-
const body =
|
|
49986
|
+
const body = readFileSync27(file);
|
|
49811
49987
|
res.writeHead(200, { "content-type": MIME[extname4(file)] ?? "application/octet-stream" });
|
|
49812
49988
|
res.end(body);
|
|
49813
49989
|
} catch {
|
|
@@ -49836,6 +50012,7 @@ async function startServer(opts = {}) {
|
|
|
49836
50012
|
`${candidate.name} is already being served by another Frizz (pid ${other}). Stop that one first \u2014 two servers on one board would fire its timers and recurring prompts twice.`
|
|
49837
50013
|
);
|
|
49838
50014
|
};
|
|
50015
|
+
const activeTenants = () => tenants.active().map(({ project: open, ctx: openCtx }) => ({ project: open, board: openCtx.board }));
|
|
49839
50016
|
const tenants = createTenantMap({
|
|
49840
50017
|
createContext: (contextOptions) => {
|
|
49841
50018
|
if (contextOptions.project) assertNotServedElsewhere(contextOptions.project);
|
|
@@ -49843,7 +50020,7 @@ async function startServer(opts = {}) {
|
|
|
49843
50020
|
},
|
|
49844
50021
|
// serverLockPath is the LAUNCHING project's: it is the only `server.lock` this process publishes
|
|
49845
50022
|
// (see "status publication"), so it is the only file a tenant's worker can read the port out of.
|
|
49846
|
-
contextOptions: { claudeBin: opts.claudeBin, serverLockPath: serverLockPathFor(project) },
|
|
50023
|
+
contextOptions: { claudeBin: opts.claudeBin, serverLockPath: serverLockPathFor(project), activeTenants },
|
|
49847
50024
|
// Each project's app carries ITS OWN owner proof, so /health stays honest per project rather than
|
|
49848
50025
|
// answering for whichever one happened to launch the server. The transports are per project for a
|
|
49849
50026
|
// blunter reason: a socket is a live feed of ONE board, so sharing the launcher's would push its
|
|
@@ -50102,6 +50279,7 @@ async function startServer(opts = {}) {
|
|
|
50102
50279
|
claudeBin: opts.claudeBin,
|
|
50103
50280
|
project,
|
|
50104
50281
|
serverLockPath: serverLockPathFor(project),
|
|
50282
|
+
activeTenants,
|
|
50105
50283
|
startup: {
|
|
50106
50284
|
afterPhase: (p) => {
|
|
50107
50285
|
bootProgress(`context: ${p}`);
|
|
@@ -50154,7 +50332,7 @@ async function startServer(opts = {}) {
|
|
|
50154
50332
|
}
|
|
50155
50333
|
statusPath = serverLockPathFor(ctx.project);
|
|
50156
50334
|
const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
|
|
50157
|
-
const distDir = opts.webDistDir ? resolve9(opts.webDistDir) :
|
|
50335
|
+
const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join39(webRoot, "dist");
|
|
50158
50336
|
startupPhase = "Vite";
|
|
50159
50337
|
if (opts.dev) {
|
|
50160
50338
|
try {
|
|
@@ -50230,7 +50408,7 @@ async function startServer(opts = {}) {
|
|
|
50230
50408
|
if (vite) {
|
|
50231
50409
|
vite.middlewares(req, res, () => {
|
|
50232
50410
|
try {
|
|
50233
|
-
const html =
|
|
50411
|
+
const html = readFileSync27(join39(webRoot, "index.html"), "utf8");
|
|
50234
50412
|
void vite.transformIndexHtml(url, html).then((out) => {
|
|
50235
50413
|
res.writeHead(200, { "content-type": "text/html" });
|
|
50236
50414
|
res.end(out);
|
|
@@ -50422,7 +50600,7 @@ var init_index = __esm({
|
|
|
50422
50600
|
}
|
|
50423
50601
|
};
|
|
50424
50602
|
isApiUrl = (url) => url === FRIZZ_ROUTE_PREFIX || url.startsWith(`${FRIZZ_ROUTE_PREFIX}/`);
|
|
50425
|
-
serverLockPathFor = (project) =>
|
|
50603
|
+
serverLockPathFor = (project) => join39(project.stateDir, "server.lock");
|
|
50426
50604
|
MIME = {
|
|
50427
50605
|
".html": "text/html",
|
|
50428
50606
|
".js": "text/javascript",
|
|
@@ -50441,7 +50619,7 @@ init_project_launch();
|
|
|
50441
50619
|
init_shutdown();
|
|
50442
50620
|
init_logging();
|
|
50443
50621
|
import { existsSync as existsSync16 } from "node:fs";
|
|
50444
|
-
import { join as
|
|
50622
|
+
import { join as join40 } from "node:path";
|
|
50445
50623
|
process.on("uncaughtException", (error) => {
|
|
50446
50624
|
log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
|
|
50447
50625
|
process.exit(1);
|
|
@@ -50481,7 +50659,7 @@ try {
|
|
|
50481
50659
|
];
|
|
50482
50660
|
if (!existsSync16(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
|
|
50483
50661
|
for (const [name, directory, requiredFile] of required) {
|
|
50484
|
-
if (!directory || !existsSync16(
|
|
50662
|
+
if (!directory || !existsSync16(join40(directory, requiredFile)))
|
|
50485
50663
|
throw new Error(`stable artifact launch is missing verified ${name}`);
|
|
50486
50664
|
}
|
|
50487
50665
|
}
|