frizz-server 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude-agent-broker.js +35911 -0
- package/dist/codex-app-server-daemon.js +423 -0
- package/dist/dev-child.js +56233 -0
- package/package.json +34 -0
- package/runtime/board/agent-bindings.mjs +287 -0
- package/runtime/board/agent-liveness.mjs +367 -0
- package/runtime/board/agent-status.mjs +178 -0
- package/runtime/board/config.mjs +993 -0
- package/runtime/board/decisions.mjs +97 -0
- package/runtime/board/index.mjs +704 -0
- package/runtime/board/notify-shared.mjs +90 -0
- package/runtime/board/notify.mjs +81 -0
- package/runtime/board/ownership.mjs +120 -0
- package/runtime/board/rest-detect.mjs +213 -0
- package/runtime/board/thread-excerpt.mjs +162 -0
- package/runtime/board/thread-update.mjs +289 -0
- package/runtime/cc-worker/.claude-plugin/plugin.json +10 -0
- package/runtime/cc-worker/DECISIONS.md +1172 -0
- package/runtime/cc-worker/LICENSE +21 -0
- package/runtime/cc-worker/agents/high.md +7 -0
- package/runtime/cc-worker/agents/low.md +7 -0
- package/runtime/cc-worker/agents/max.md +7 -0
- package/runtime/cc-worker/agents/medium.md +7 -0
- package/runtime/cc-worker/agents/xhigh.md +7 -0
- package/runtime/cc-worker/bin/frizz +17 -0
- package/runtime/cc-worker/bin/frizz-mcp.mjs +1612 -0
- package/runtime/cc-worker/bin/frizz-update +18 -0
- package/runtime/cc-worker/hooks/agent-bind.mjs +40 -0
- package/runtime/cc-worker/hooks/agent-dispatch.mjs +121 -0
- package/runtime/cc-worker/hooks/bash-background.d.mts +6 -0
- package/runtime/cc-worker/hooks/bash-background.mjs +247 -0
- package/runtime/cc-worker/hooks/deny-ask.mjs +39 -0
- package/runtime/cc-worker/hooks/deny-plan.mjs +62 -0
- package/runtime/cc-worker/hooks/hooks.json +102 -0
- package/runtime/cc-worker/hooks/perm-policy.mjs +211 -0
- package/runtime/cc-worker/hooks/scratchpad.mjs +417 -0
- package/runtime/cc-worker/hooks/session-seed.mjs +107 -0
- package/runtime/cc-worker/scripts/frizz/agent-bindings.mjs +9 -0
- package/runtime/cc-worker/scripts/frizz/config.mjs +12 -0
- package/runtime/cc-worker/skills/gh/SKILL.md +141 -0
- package/runtime/cc-worker/skills/gh/scripts/ci-watch.mjs +60 -0
- package/runtime/cc-worker/skills/gh/scripts/github-watch.mjs +130 -0
- package/runtime/cc-worker/skills/gh/scripts/review-watch.mjs +54 -0
- package/web-dist/apple-touch-icon.png +0 -0
- package/web-dist/assets/TerminalPane-DyLvW_rQ.js +7 -0
- package/web-dist/assets/abnfDiagram-VRR7QNED-DIPgkiM8.js +1 -0
- package/web-dist/assets/arc-BSyeo0Gb.js +1 -0
- package/web-dist/assets/architecture-TIHT7OUA-B8qUD5-C.js +1 -0
- package/web-dist/assets/architectureDiagram-ZJ3FMSHR-DBAKToiy.js +36 -0
- package/web-dist/assets/array-BifhSqXX.js +1 -0
- package/web-dist/assets/blockDiagram-677ZJIJ3-Ba0xt8st.js +132 -0
- package/web-dist/assets/c4Diagram-LMCZKHZV-DFham1h_.js +10 -0
- package/web-dist/assets/channel-5l10tOPT.js +1 -0
- package/web-dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/web-dist/assets/chunk-32BRIVSS-Bl-817K-.js +1 -0
- package/web-dist/assets/chunk-52WLFC77-DBLTDz2W.js +10 -0
- package/web-dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/web-dist/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- package/web-dist/assets/chunk-C7G6YPKG-ClL6Ebv8.js +1 -0
- package/web-dist/assets/chunk-EX3LRPZG--3vJLCZP.js +231 -0
- package/web-dist/assets/chunk-FWX5IMBZ-DMOdhcCP.js +2 -0
- package/web-dist/assets/chunk-HOUHSVGY-DkgTGLCa.js +1 -0
- package/web-dist/assets/chunk-ICXQ74PX-7X6iir1H.js +2 -0
- package/web-dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/web-dist/assets/chunk-KEIR6QF5-BfrZ3jm6.js +161 -0
- package/web-dist/assets/chunk-MOJQB5TN-OpO5flE4.js +88 -0
- package/web-dist/assets/chunk-OGEWGWER-BbAMAzTZ.js +1 -0
- package/web-dist/assets/chunk-PUDLZKDR-avcvDgZl.js +156 -0
- package/web-dist/assets/chunk-Q4XR5HBZ-BaiGN1cd.js +70 -0
- package/web-dist/assets/chunk-RYQCIY6F-Cu_KplZW.js +1 -0
- package/web-dist/assets/chunk-V7JOEXUC-CKVakdOJ.js +206 -0
- package/web-dist/assets/chunk-VAUOI2AC-DzG-rM3_.js +1 -0
- package/web-dist/assets/chunk-VR4S4FIN-t3j3HHQF.js +1 -0
- package/web-dist/assets/chunk-WYO6CB5R-SnP0NDTw.js +127 -0
- package/web-dist/assets/chunk-XXDRQBXY-DYlTP5J-.js +1 -0
- package/web-dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/web-dist/assets/chunk-ZGVPDNZ5-pXn3giwS.js +62 -0
- package/web-dist/assets/chunk-ZIRB5QZD-C6fEPe3t.js +32 -0
- package/web-dist/assets/classDiagram-OUVF2IWQ-vIfzHupB.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-vIfzHupB.js +1 -0
- package/web-dist/assets/cose-bilkent-JH36ORCC-BUIsLrGc.js +1 -0
- package/web-dist/assets/cynefin-VYW2F7L2-C4qNLMkm.js +1 -0
- package/web-dist/assets/cynefinDiagram-TSTJHNR4-2vzWUUfl.js +62 -0
- package/web-dist/assets/cytoscape.esm-B3I8pqwA.js +321 -0
- package/web-dist/assets/dagre-CXRCoUWR.js +1 -0
- package/web-dist/assets/dagre-VKFMJZFB-DUdNHEM9.js +4 -0
- package/web-dist/assets/defaultLocale-C8Fc0cco.js +1 -0
- package/web-dist/assets/diagram-FQU43EPY-C_EHNL09.js +3 -0
- package/web-dist/assets/diagram-G47NLZAW-DOt98NB-.js +24 -0
- package/web-dist/assets/diagram-NH7WQ7WH-uIgVP9iZ.js +24 -0
- package/web-dist/assets/diagram-OA4YK3LP-CGWe4oxq.js +30 -0
- package/web-dist/assets/diagram-WEI45ONY-C-5f7o9T.js +41 -0
- package/web-dist/assets/dist-DoH_9pyS.js +1 -0
- package/web-dist/assets/ebnfDiagram-CCIWWBDH-DoSFLtL-.js +1 -0
- package/web-dist/assets/erDiagram-Q63AITRT-DsCLMzEE.js +85 -0
- package/web-dist/assets/eventmodeling-45OFAUF4-D7GQYhiK.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-CR371xZs.js +1 -0
- package/web-dist/assets/ganttDiagram-NO4QXBWP-D8UNGcBR.js +292 -0
- package/web-dist/assets/gitGraph-TEB2WS4Q-mC-XQzTE.js +1 -0
- package/web-dist/assets/gitGraphDiagram-IHSO6WYX-CkpPggS7.js +106 -0
- package/web-dist/assets/graphlib-B8gBHxth.js +1 -0
- package/web-dist/assets/index-CT6k_A5y.css +1 -0
- package/web-dist/assets/index-Dmo0zJc8.js +319 -0
- package/web-dist/assets/info-DKCQHKI2-Drg-xVbr.js +1 -0
- package/web-dist/assets/infoDiagram-FWYZ7A6U-CsGMTGpl.js +2 -0
- package/web-dist/assets/init-D6jRqBbL.js +1 -0
- package/web-dist/assets/ishikawaDiagram-FXEZZL3T-DNgGBlL6.js +70 -0
- package/web-dist/assets/journeyDiagram-5HDEW3XC-BFN2bObi.js +139 -0
- package/web-dist/assets/kanban-definition-HUTT4EX6-BnDPclXf.js +89 -0
- package/web-dist/assets/katex-CddkPoXu.js +257 -0
- package/web-dist/assets/line-DmLw74JM.js +1 -0
- package/web-dist/assets/linear-z2V0wJk9.js +1 -0
- package/web-dist/assets/map-DsCK-0Cs.js +1 -0
- package/web-dist/assets/mermaid-parser.core-DGJk39E-.js +7 -0
- package/web-dist/assets/mermaid.core-8aee8nsf.js +11 -0
- package/web-dist/assets/mindmap-definition-LN4V7U3C-CGWK_Qbm.js +96 -0
- package/web-dist/assets/ordinal-hYBb2elL.js +1 -0
- package/web-dist/assets/packet-7NZHBO7P-C5HYQyS5.js +1 -0
- package/web-dist/assets/path-BWPyau1x.js +1 -0
- package/web-dist/assets/pegDiagram-2B236MQR-WiQm887Q.js +1 -0
- package/web-dist/assets/pie-RZYD4A2V-DKBNMtMn.js +1 -0
- package/web-dist/assets/pieDiagram-ENE6RG2P-F1A8_3DO.js +39 -0
- package/web-dist/assets/quadrantDiagram-ABIIQ3AL-bf6a3f_f.js +7 -0
- package/web-dist/assets/radar-I7S5WNFK-AOKDUn-C.js +1 -0
- package/web-dist/assets/railroad-3IZDKUUU-DNHhkFAC.js +1 -0
- package/web-dist/assets/railroad-abnf-AHOZXSZD-DOXbu4iv.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-C1oE2RHD.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-B4GD-bq-.js +1 -0
- package/web-dist/assets/railroadDiagram-RFXS5EU6-Be52T90z.js +1 -0
- package/web-dist/assets/requirementDiagram-TGXJPOKE-BqdMvEGK.js +84 -0
- package/web-dist/assets/rolldown-runtime-Bh1tDfsg.js +1 -0
- package/web-dist/assets/rough.esm-CSKSodPl.js +1 -0
- package/web-dist/assets/sankeyDiagram-HTMAVEWB-BP3X6Ofp.js +40 -0
- package/web-dist/assets/sequenceDiagram-DBY2YBRQ-yDHhaUzc.js +162 -0
- package/web-dist/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- package/web-dist/assets/src-C4XfhTaE.js +1 -0
- package/web-dist/assets/stateDiagram-2N3HPSRC-xvctsgCU.js +1 -0
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-xFk0N3Cq.js +1 -0
- package/web-dist/assets/swimlanes-5IMT3BWC-DZMLgrjk.js +2 -0
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BoWrxkxy.js +8 -0
- package/web-dist/assets/timeline-definition-FHXFAJF6-n8sU0qlT.js +120 -0
- package/web-dist/assets/treeView-QDETBFTQ-Su8KloaY.js +1 -0
- package/web-dist/assets/treemap-6X3UGDF4-CNgRuVWf.js +1 -0
- package/web-dist/assets/vennDiagram-L72KCM5P-B5I9YxaY.js +34 -0
- package/web-dist/assets/wardley-OPB4EBWU-khMe_Wbq.js +1 -0
- package/web-dist/assets/wardleyDiagram-EHGQE667-d8LsqhTO.js +78 -0
- package/web-dist/assets/xychartDiagram-FW5EYKEG-b0CH_-wy.js +7 -0
- package/web-dist/favicon-16.png +0 -0
- package/web-dist/favicon-32.png +0 -0
- package/web-dist/favicon.svg +34 -0
- package/web-dist/icon-192.png +0 -0
- package/web-dist/icon-512.png +0 -0
- package/web-dist/icon-maskable-512.png +0 -0
- package/web-dist/index.html +44 -0
- package/web-dist/manifest.webmanifest +16 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { createRequire as __frizzCreateRequire } from "node:module"; const require = __frizzCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// packages/server/src/backend/codex-app-server-daemon.ts
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
import { createServer } from "node:net";
|
|
6
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7
|
+
import { dirname as dirname2 } from "node:path";
|
|
8
|
+
import { StringDecoder } from "node:string_decoder";
|
|
9
|
+
|
|
10
|
+
// packages/server/src/backend/stale-socket-sweep.ts
|
|
11
|
+
import { execFile } from "node:child_process";
|
|
12
|
+
import { readdirSync, unlinkSync } from "node:fs";
|
|
13
|
+
import { connect as connectSocket } from "node:net";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
function parseLsofSocketNames(stdout) {
|
|
16
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
17
|
+
for (const line of stdout.split("\n")) {
|
|
18
|
+
if (!line.startsWith("n/")) continue;
|
|
19
|
+
const raw = line.slice(1);
|
|
20
|
+
referenced.add(raw);
|
|
21
|
+
const meta = raw.indexOf(" type=");
|
|
22
|
+
if (meta > 0) referenced.add(raw.slice(0, meta));
|
|
23
|
+
}
|
|
24
|
+
return referenced;
|
|
25
|
+
}
|
|
26
|
+
var defaultListReferenced = (prefix, done) => {
|
|
27
|
+
execFile("lsof", ["-U", "-F", "n"], { timeout: 3e4, maxBuffer: 16 * 1024 * 1024 }, (error, stdout) => {
|
|
28
|
+
if (!stdout) return done(null);
|
|
29
|
+
if (error && !stdout.includes(prefix)) return done(null);
|
|
30
|
+
done(parseLsofSocketNames(stdout));
|
|
31
|
+
}).unref?.();
|
|
32
|
+
};
|
|
33
|
+
var defaultProbe = (path, verdict) => {
|
|
34
|
+
const probe = connectSocket(path);
|
|
35
|
+
probe.unref?.();
|
|
36
|
+
probe.on("connect", () => {
|
|
37
|
+
probe.destroy();
|
|
38
|
+
verdict(false);
|
|
39
|
+
});
|
|
40
|
+
probe.on("error", (error) => {
|
|
41
|
+
probe.destroy();
|
|
42
|
+
verdict(error.code === "ECONNREFUSED" || error.code === "ENOENT");
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
function sweepStaleSockets(options, deps = {}) {
|
|
46
|
+
if (process.platform === "win32") return;
|
|
47
|
+
const keep = new Set(options.keep ?? []);
|
|
48
|
+
let candidates;
|
|
49
|
+
try {
|
|
50
|
+
candidates = (deps.readdir ?? readdirSync)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join(options.dir, name)).filter((path) => !keep.has(path));
|
|
51
|
+
} catch {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (candidates.length === 0) return;
|
|
55
|
+
const probe = deps.probe ?? defaultProbe;
|
|
56
|
+
const unlink = deps.unlink ?? ((path) => {
|
|
57
|
+
try {
|
|
58
|
+
unlinkSync(path);
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
(deps.listReferenced ?? defaultListReferenced)(options.prefix, (referenced) => {
|
|
63
|
+
if (!referenced) return;
|
|
64
|
+
for (const path of candidates) {
|
|
65
|
+
if (referenced.has(path)) continue;
|
|
66
|
+
probe(path, (dead) => {
|
|
67
|
+
if (dead) unlink(path);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// packages/server/src/runtime-lease.ts
|
|
74
|
+
import { existsSync, mkdirSync, readdirSync as readdirSync2, readFileSync, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
|
|
75
|
+
import { dirname, join as join2 } from "node:path";
|
|
76
|
+
var PROVISIONED_MARKER = "provisioned.json";
|
|
77
|
+
var LEASES_DIR = ".leases";
|
|
78
|
+
var MAX_ASCENT = 6;
|
|
79
|
+
function runtimeVersionDir(bin) {
|
|
80
|
+
let dir = dirname(bin);
|
|
81
|
+
for (let step = 0; step < MAX_ASCENT; step++) {
|
|
82
|
+
if (existsSync(join2(dir, PROVISIONED_MARKER))) return dir;
|
|
83
|
+
const parent = dirname(dir);
|
|
84
|
+
if (parent === dir) return void 0;
|
|
85
|
+
dir = parent;
|
|
86
|
+
}
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
function leaseRuntime(bin, role) {
|
|
90
|
+
const versionDir = runtimeVersionDir(bin);
|
|
91
|
+
if (!versionDir) return () => {
|
|
92
|
+
};
|
|
93
|
+
const path = join2(versionDir, LEASES_DIR, `${process.pid}.json`);
|
|
94
|
+
try {
|
|
95
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
96
|
+
const lease = { pid: process.pid, role, bin, at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
97
|
+
writeFileSync(path, JSON.stringify(lease));
|
|
98
|
+
} catch {
|
|
99
|
+
return () => {
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return () => {
|
|
103
|
+
try {
|
|
104
|
+
unlinkSync2(path);
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// packages/server/src/backend/codex-app-server-daemon.ts
|
|
111
|
+
var MAX_QUEUED_LINES = 2e4;
|
|
112
|
+
var MAX_QUEUED_BYTES = 64 * 1024 * 1024;
|
|
113
|
+
var MAX_LINE_BYTES = 8 * 1024 * 1024;
|
|
114
|
+
var IDLE_EXIT_MS = 6 * 60 * 60 * 1e3;
|
|
115
|
+
var HANDSHAKE_TIMEOUT_MS = 3e4;
|
|
116
|
+
var REACHABILITY_CHECK_MS = 3e4;
|
|
117
|
+
var REACHABILITY_STRIKES = 2;
|
|
118
|
+
function readConfig() {
|
|
119
|
+
const raw = process.env.FRIZZ_CODEX_APP_SERVER_DAEMON;
|
|
120
|
+
if (!raw) throw new Error("codex app-server daemon started without FRIZZ_CODEX_APP_SERVER_DAEMON");
|
|
121
|
+
const config = JSON.parse(raw);
|
|
122
|
+
if (!config.socketPath || !config.recordPath || !config.codexBin || !config.generation) {
|
|
123
|
+
throw new Error("codex app-server daemon config is incomplete");
|
|
124
|
+
}
|
|
125
|
+
return config;
|
|
126
|
+
}
|
|
127
|
+
function lineReader(onLine, onOverflow) {
|
|
128
|
+
const decoder = new StringDecoder("utf8");
|
|
129
|
+
let buffer = "";
|
|
130
|
+
let overflowed = false;
|
|
131
|
+
return (chunk) => {
|
|
132
|
+
buffer += decoder.write(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
133
|
+
for (; ; ) {
|
|
134
|
+
const index = buffer.indexOf("\n");
|
|
135
|
+
if (index < 0) break;
|
|
136
|
+
const line = buffer.slice(0, index);
|
|
137
|
+
buffer = buffer.slice(index + 1);
|
|
138
|
+
if (overflowed) {
|
|
139
|
+
overflowed = false;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (Buffer.byteLength(line) > MAX_LINE_BYTES) {
|
|
143
|
+
onOverflow();
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const trimmed = line.trim();
|
|
147
|
+
if (trimmed) onLine(trimmed);
|
|
148
|
+
}
|
|
149
|
+
if (Buffer.byteLength(buffer) > MAX_LINE_BYTES) {
|
|
150
|
+
buffer = "";
|
|
151
|
+
if (!overflowed) onOverflow();
|
|
152
|
+
overflowed = true;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function main() {
|
|
157
|
+
const config = readConfig();
|
|
158
|
+
const releaseRuntimeLease = leaseRuntime(config.codexBin, "codex-app-server");
|
|
159
|
+
const child = spawn(config.codexBin, config.appServerArgs ?? ["app-server", "--stdio"], {
|
|
160
|
+
cwd: config.cwd,
|
|
161
|
+
env: config.env,
|
|
162
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
163
|
+
// This daemon is forked `detached`, which on Windows is DETACHED_PROCESS: it owns NO console. A
|
|
164
|
+
// console-less parent starting a console-subsystem exe (codex.exe) without CREATE_NO_WINDOW gets
|
|
165
|
+
// a fresh, VISIBLE console allocated for it — a black `codex.exe` window on every Codex dispatch,
|
|
166
|
+
// and closing it killed the app-server and every Codex thread in the project (Windows audit
|
|
167
|
+
// 2026-09-11, finding 4; the same mechanism PR #32 found for the update successor). The Claude
|
|
168
|
+
// side was safe only because the SDK passes windowsHide in its own spawn.
|
|
169
|
+
windowsHide: true
|
|
170
|
+
});
|
|
171
|
+
let client = null;
|
|
172
|
+
let queuedLines = [];
|
|
173
|
+
let queuedBytes = 0;
|
|
174
|
+
let dropped = 0;
|
|
175
|
+
let idleTimer = null;
|
|
176
|
+
let published = false;
|
|
177
|
+
const recordOwner = () => {
|
|
178
|
+
try {
|
|
179
|
+
const value = JSON.parse(readFileSync2(config.recordPath, "utf8"));
|
|
180
|
+
return typeof value.daemonPid === "number" ? value.daemonPid : null;
|
|
181
|
+
} catch {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const cleanup = () => {
|
|
186
|
+
try {
|
|
187
|
+
client?.destroy();
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
const owner = recordOwner();
|
|
191
|
+
if (owner === process.pid) {
|
|
192
|
+
try {
|
|
193
|
+
unlinkSync3(config.recordPath);
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (published && owner !== null && owner !== process.pid) return;
|
|
198
|
+
if (published && process.platform !== "win32") {
|
|
199
|
+
try {
|
|
200
|
+
unlinkSync3(config.socketPath);
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const writeExitBreadcrumb = (reason) => {
|
|
206
|
+
try {
|
|
207
|
+
writeFileSync2(`${config.recordPath}.exit`, JSON.stringify({
|
|
208
|
+
projectId: config.projectId,
|
|
209
|
+
generation: config.generation,
|
|
210
|
+
daemonPid: process.pid,
|
|
211
|
+
childPid: child.pid ?? null,
|
|
212
|
+
reason,
|
|
213
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
214
|
+
}));
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const die = (code, reason) => {
|
|
219
|
+
writeExitBreadcrumb(reason);
|
|
220
|
+
releaseRuntimeLease();
|
|
221
|
+
cleanup();
|
|
222
|
+
process.exit(code);
|
|
223
|
+
};
|
|
224
|
+
const armIdleExit = () => {
|
|
225
|
+
if (idleTimer) clearTimeout(idleTimer);
|
|
226
|
+
idleTimer = setTimeout(() => {
|
|
227
|
+
try {
|
|
228
|
+
child.kill("SIGTERM");
|
|
229
|
+
} catch {
|
|
230
|
+
}
|
|
231
|
+
;
|
|
232
|
+
die(0, "idle-timeout");
|
|
233
|
+
}, IDLE_EXIT_MS);
|
|
234
|
+
idleTimer.unref?.();
|
|
235
|
+
};
|
|
236
|
+
let unreachableStrikes = 0;
|
|
237
|
+
const checkReachable = () => {
|
|
238
|
+
if (client) {
|
|
239
|
+
unreachableStrikes = 0;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (recordOwner() === process.pid) {
|
|
243
|
+
unreachableStrikes = 0;
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (++unreachableStrikes < REACHABILITY_STRIKES) return;
|
|
247
|
+
try {
|
|
248
|
+
child.kill("SIGTERM");
|
|
249
|
+
} catch {
|
|
250
|
+
}
|
|
251
|
+
die(0, "self-collected-record-reassigned");
|
|
252
|
+
};
|
|
253
|
+
const toClient = (line) => {
|
|
254
|
+
if (client) {
|
|
255
|
+
try {
|
|
256
|
+
client.write(`${line}
|
|
257
|
+
`);
|
|
258
|
+
return;
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (queuedLines.length >= MAX_QUEUED_LINES || queuedBytes >= MAX_QUEUED_BYTES) {
|
|
263
|
+
dropped++;
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
queuedLines.push(line);
|
|
267
|
+
queuedBytes += Buffer.byteLength(line) + 1;
|
|
268
|
+
};
|
|
269
|
+
const control = (payload) => JSON.stringify({ frizz: 1, ...payload });
|
|
270
|
+
const HANDSHAKE_ID = -1;
|
|
271
|
+
let initializeResult;
|
|
272
|
+
let handshakeDone = false;
|
|
273
|
+
const pendingFromClient = /* @__PURE__ */ new Map();
|
|
274
|
+
let nextDaemonId = 1e6;
|
|
275
|
+
const toServer = (message) => {
|
|
276
|
+
try {
|
|
277
|
+
child.stdin.write(`${JSON.stringify(message)}
|
|
278
|
+
`);
|
|
279
|
+
} catch {
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
const readServerLine = (line) => {
|
|
283
|
+
let message;
|
|
284
|
+
try {
|
|
285
|
+
message = JSON.parse(line);
|
|
286
|
+
} catch {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (!handshakeDone && message.id === HANDSHAKE_ID) {
|
|
290
|
+
if (message.error) die(3, "handshake-rejected");
|
|
291
|
+
initializeResult = message.result;
|
|
292
|
+
handshakeDone = true;
|
|
293
|
+
toServer({ method: "initialized" });
|
|
294
|
+
startListening();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (message.id !== void 0 && message.method === void 0 && typeof message.id === "number") {
|
|
298
|
+
const clientId = pendingFromClient.get(message.id);
|
|
299
|
+
if (clientId !== void 0) {
|
|
300
|
+
pendingFromClient.delete(message.id);
|
|
301
|
+
toClient(JSON.stringify({ ...message, id: clientId }));
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
toClient(line);
|
|
306
|
+
};
|
|
307
|
+
const readClientLine = (line) => {
|
|
308
|
+
let message;
|
|
309
|
+
try {
|
|
310
|
+
message = JSON.parse(line);
|
|
311
|
+
} catch {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (message.method === "initialize") {
|
|
315
|
+
if (message.id !== void 0) toClient(JSON.stringify({ id: message.id, result: initializeResult }));
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (message.method === "initialized") return;
|
|
319
|
+
if (message.id !== void 0 && message.method !== void 0) {
|
|
320
|
+
const daemonId = nextDaemonId++;
|
|
321
|
+
pendingFromClient.set(daemonId, message.id);
|
|
322
|
+
toServer({ ...message, id: daemonId });
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
toServer(message);
|
|
326
|
+
};
|
|
327
|
+
const writeRecord = () => {
|
|
328
|
+
writeFileSync2(config.recordPath, JSON.stringify({
|
|
329
|
+
projectId: config.projectId,
|
|
330
|
+
generation: config.generation,
|
|
331
|
+
daemonPid: process.pid,
|
|
332
|
+
childPid: child.pid,
|
|
333
|
+
socketPath: config.socketPath,
|
|
334
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
335
|
+
...config.authAccountId ? { authAccountId: config.authAccountId } : {}
|
|
336
|
+
}));
|
|
337
|
+
};
|
|
338
|
+
const server = createServer((sock) => {
|
|
339
|
+
if (client) {
|
|
340
|
+
try {
|
|
341
|
+
client.destroy();
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
client = sock;
|
|
346
|
+
if (idleTimer) {
|
|
347
|
+
clearTimeout(idleTimer);
|
|
348
|
+
idleTimer = null;
|
|
349
|
+
}
|
|
350
|
+
sock.setNoDelay(true);
|
|
351
|
+
try {
|
|
352
|
+
sock.write(`${control({ hello: 1, generation: config.generation, childPid: child.pid, droppedWhileDetached: dropped })}
|
|
353
|
+
`);
|
|
354
|
+
for (const line of queuedLines) sock.write(`${line}
|
|
355
|
+
`);
|
|
356
|
+
} catch {
|
|
357
|
+
}
|
|
358
|
+
queuedLines = [];
|
|
359
|
+
queuedBytes = 0;
|
|
360
|
+
dropped = 0;
|
|
361
|
+
sock.on("data", lineReader((line) => {
|
|
362
|
+
if (!sock.destroyed) readClientLine(line);
|
|
363
|
+
}, () => sock.destroy()));
|
|
364
|
+
const drop = () => {
|
|
365
|
+
if (client !== sock) return;
|
|
366
|
+
client = null;
|
|
367
|
+
armIdleExit();
|
|
368
|
+
};
|
|
369
|
+
sock.on("close", drop);
|
|
370
|
+
sock.on("error", drop);
|
|
371
|
+
});
|
|
372
|
+
const sweepOwnFamily = () => sweepStaleSockets({ dir: dirname2(config.socketPath), prefix: "frizz-codex-", keep: [config.socketPath] });
|
|
373
|
+
const startListening = () => {
|
|
374
|
+
if (process.platform !== "win32" && existsSync2(config.socketPath)) {
|
|
375
|
+
try {
|
|
376
|
+
unlinkSync3(config.socketPath);
|
|
377
|
+
} catch {
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
server.on("error", () => die(6, "socket-listen-error"));
|
|
381
|
+
server.listen(config.socketPath, () => {
|
|
382
|
+
published = true;
|
|
383
|
+
writeRecord();
|
|
384
|
+
armIdleExit();
|
|
385
|
+
const reachability = setInterval(checkReachable, config.reachabilityCheckMs ?? REACHABILITY_CHECK_MS);
|
|
386
|
+
reachability.unref?.();
|
|
387
|
+
setTimeout(sweepOwnFamily, 5e3).unref?.();
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
child.stdout.on("data", lineReader(readServerLine, () => {
|
|
391
|
+
dropped++;
|
|
392
|
+
const lostClient = client;
|
|
393
|
+
client = null;
|
|
394
|
+
lostClient?.destroy();
|
|
395
|
+
armIdleExit();
|
|
396
|
+
}));
|
|
397
|
+
child.stderr.resume();
|
|
398
|
+
child.on("exit", (code, signal) => die(0, signal ? `app-server-killed-${signal}` : `app-server-exited-code-${code ?? "null"}`));
|
|
399
|
+
child.on("error", () => die(4, "app-server-spawn-error"));
|
|
400
|
+
toServer({ id: HANDSHAKE_ID, method: "initialize", params: { clientInfo: config.clientInfo, capabilities: config.capabilities } });
|
|
401
|
+
const handshakeTimer = setTimeout(() => {
|
|
402
|
+
if (!handshakeDone) {
|
|
403
|
+
try {
|
|
404
|
+
child.kill("SIGTERM");
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
;
|
|
408
|
+
die(5, "handshake-timeout");
|
|
409
|
+
}
|
|
410
|
+
}, HANDSHAKE_TIMEOUT_MS);
|
|
411
|
+
handshakeTimer.unref?.();
|
|
412
|
+
for (const signal of ["SIGTERM", "SIGINT", "SIGHUP"]) {
|
|
413
|
+
process.on(signal, () => {
|
|
414
|
+
try {
|
|
415
|
+
child.kill("SIGTERM");
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
;
|
|
419
|
+
die(0, `signal-${signal}`);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
main();
|