frizz-server 0.15.4 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev-child.js +259 -93
- package/package.json +1 -1
- package/runtime/cc-worker/bin/frizz-mcp.mjs +21 -2
- package/web-dist/assets/{abnfDiagram-VRR7QNED-BxfU2ky7.js → abnfDiagram-VRR7QNED-CbqOYv6J.js} +1 -1
- package/web-dist/assets/{arc-CgErjH1d.js → arc-C7pirKdF.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-Bd5iF22L.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-DFARVJoN.js → architectureDiagram-ZJ3FMSHR-GSvfiia8.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-BS3Cwm7J.js → blockDiagram-677ZJIJ3-CEoI_nEr.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-Ib3IHrEi.js → c4Diagram-LMCZKHZV-Db0N8ZKZ.js} +1 -1
- package/web-dist/assets/channel-Bagqh84I.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-ByRx6NUK.js → chunk-32BRIVSS-DT3immeA.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-hjwNAryc.js → chunk-52WLFC77-D3HCw3CA.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-C6Ad4Bd0.js → chunk-C7G6YPKG-DW27d4eB.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-CQVUaGoV.js → chunk-EX3LRPZG-OPZph9SR.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-CZTMmNQk.js → chunk-FWX5IMBZ-Bm9FHMa7.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-C6BUv_ws.js → chunk-HOUHSVGY-BTOEnIzu.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-oh3XyLFV.js → chunk-ICXQ74PX-zs-5RXZE.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-Bp7LUwam.js → chunk-MOJQB5TN-DOsCoW_N.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-sAmFDKFT.js → chunk-OGEWGWER-BZIl0Yj7.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-DlN32NhF.js → chunk-PUDLZKDR-5eWMPQZ0.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-DEjynXCt.js → chunk-Q4XR5HBZ-BtHztk0F.js} +1 -1
- package/web-dist/assets/{chunk-RYQCIY6F-CZehtcWj.js → chunk-RYQCIY6F-DlTYPhZ8.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-DMBTmrLA.js → chunk-V7JOEXUC-YalOqDL7.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-pLTcMAXA.js → chunk-VAUOI2AC-M_2D8Gwk.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-B31zgsto.js → chunk-VR4S4FIN-HZPLNG7A.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-BYr0TKte.js → chunk-WYO6CB5R-gtQVqXEb.js} +1 -1
- package/web-dist/assets/{chunk-XXDRQBXY-DezATMt-.js → chunk-XXDRQBXY-CsAuYtU4.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-BZRpC7D4.js → chunk-ZGVPDNZ5-DtcuYy6F.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DXPARKeI.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DXPARKeI.js +1 -0
- package/web-dist/assets/{cose-bilkent-JH36ORCC-DCj8LJT7.js → cose-bilkent-JH36ORCC-DN8G4z--.js} +1 -1
- package/web-dist/assets/{cynefin-VYW2F7L2-BdtJMX-t.js → cynefin-VYW2F7L2-DmE5ulRO.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-CmCMm_Wq.js → cynefinDiagram-TSTJHNR4-D_EVG7EI.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-DjAmUhWm.js → dagre-VKFMJZFB-B7qpCNzR.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-0jj1-eWC.js → diagram-FQU43EPY-XJ39UoQP.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-CwnRmOlr.js → diagram-G47NLZAW-CU3wW01X.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-CeATVwIZ.js → diagram-NH7WQ7WH-Cb2jmTDE.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-yi-rZaxR.js → diagram-OA4YK3LP-Du53ln1W.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-DGA41j7G.js → diagram-WEI45ONY-EYSYIJXB.js} +1 -1
- package/web-dist/assets/{dist-ClPP980o.js → dist-Coq6Bx6Y.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-BQ0eK7BV.js → ebnfDiagram-CCIWWBDH-Bq4LpJn6.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-BNjpwgDH.js → erDiagram-Q63AITRT-Beo30eeI.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-DmLge5-D.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-rndT3Z05.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-C4na1dCg.js → ganttDiagram-NO4QXBWP-BBC4eUEO.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-r5HbDgDu.js → gitGraph-TEB2WS4Q-DEGavvzP.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-Ezyr9l2F.js → gitGraphDiagram-IHSO6WYX-CULHtc5i.js} +1 -1
- package/web-dist/assets/index-BtlZUVLY.css +2 -0
- package/web-dist/assets/{index-AuO_Psrz.js → index-Cxroyxuc.js} +57 -54
- package/web-dist/assets/{info-DKCQHKI2-DW4lo23y.js → info-DKCQHKI2-B2Njf2Cf.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-CXiyOu2-.js → infoDiagram-FWYZ7A6U-Ca0ZciuC.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-CpMuWt_7.js → ishikawaDiagram-FXEZZL3T-CPsNqnqs.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-BkPeIp41.js → journeyDiagram-5HDEW3XC-C0DA07RV.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-BV_9FKSZ.js → kanban-definition-HUTT4EX6-CXXam7zc.js} +1 -1
- package/web-dist/assets/{line-oIX8MMfl.js → line-B6ofc5bQ.js} +1 -1
- package/web-dist/assets/{linear-DNK_UIsk.js → linear-CLBVhrVv.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-KXhY4GxP.js → mermaid-parser.core-CcEAp6DX.js} +3 -3
- package/web-dist/assets/{mermaid.core-h9KNJFJJ.js → mermaid.core-CC-fPRQ3.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-DVEffHYP.js → mindmap-definition-LN4V7U3C-DxmJXxM1.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-DXFLYz0v.js → packet-7NZHBO7P-CvlFg_io.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-Bpf2-lwS.js → pegDiagram-2B236MQR-Bgwx28BQ.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-CRzNTyT_.js → pie-RZYD4A2V-DAMTNQcW.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-5OxjOvPl.js → pieDiagram-ENE6RG2P-DfTw_3mN.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-DmYfnHMg.js → quadrantDiagram-ABIIQ3AL-COTsv2Kc.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-WOiYkQ_h.js → radar-I7S5WNFK-DQRMGMPS.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-DQqlel4-.js → railroad-3IZDKUUU-z3gzfpLJ.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-CPdyVixb.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-CW9g40ih.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-BisCRXMy.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-Dy-QXMYm.js → railroadDiagram-RFXS5EU6-cyqSv0hl.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-DqiaxdLf.js → requirementDiagram-TGXJPOKE-BECiaDhq.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-CALQykld.js → sankeyDiagram-HTMAVEWB-BQvf8K8I.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-CkcHqhEB.js → sequenceDiagram-DBY2YBRQ-BLQoSIOd.js} +1 -1
- package/web-dist/assets/{src-mutgQtwo.js → src-ClqzeqlV.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-BiNElNmG.js → stateDiagram-2N3HPSRC-DWOZvXE6.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BlGBJ8Sv.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-CJe_K-xH.js → swimlanes-5IMT3BWC-D_OgCclp.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-CJ5vUUEc.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-_n-XbLIo.js → timeline-definition-FHXFAJF6-CzFA213Q.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-G53LKf3k.js → treeView-QDETBFTQ-VAA4e9vM.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-GinzV1R9.js → treemap-6X3UGDF4-BoLIw2ix.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-BpbLkzpA.js → vennDiagram-L72KCM5P-C5flYkCp.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-7cfRg4gk.js → wardley-OPB4EBWU-DqRI-fT7.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-BtkHWBJy.js → wardleyDiagram-EHGQE667-Pp4ADVTI.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-DqHJvx14.js → xychartDiagram-FW5EYKEG-BAGoibt3.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-Tn4efhzP.js +0 -1
- package/web-dist/assets/channel-4H014B-1.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-8JajOrhY.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-8JajOrhY.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-BGxDGBm7.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-BOD8PP2C.js +0 -1
- package/web-dist/assets/index-BSl6rM3u.css +0 -2
- package/web-dist/assets/railroad-abnf-AHOZXSZD-EtMjMxgl.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-f-9Oguw0.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-DyJccj3F.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-4cGI50SD.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-B9sjhf80.js +0 -8
package/dist/dev-child.js
CHANGED
|
@@ -14782,6 +14782,11 @@ ${ANSWER_CONTINUATION_INDENT}`);
|
|
|
14782
14782
|
* same card and the swap is invisible. Absent whenever there is nothing in flight, which is almost
|
|
14783
14783
|
* always — it exists for the seconds between the human sending and the worker being handed it. */
|
|
14784
14784
|
answersInFlight: external_exports.string().optional(),
|
|
14785
|
+
/** The human's message — a follow-up or a registered answer — is on its way to the worker and the turn
|
|
14786
|
+
* has not started yet (board.deriveDeliveryInFlight). The queue has already let the thread go; this
|
|
14787
|
+
* tells the rail to draw it as working in every tab, not only the one that sent it (web
|
|
14788
|
+
* lib/steering.ts). Absent otherwise. */
|
|
14789
|
+
deliveryInFlight: external_exports.boolean().optional(),
|
|
14785
14790
|
// ISO8601 of the newest REAL user interaction (answer/steer/dispatch) — the chronological listing
|
|
14786
14791
|
// sort key. Optional; the listing falls back to spawnedAt when absent (a dispatch IS an interaction).
|
|
14787
14792
|
lastUserAt: external_exports.string().optional(),
|
|
@@ -23755,6 +23760,7 @@ var init_tail_cache = __esm({
|
|
|
23755
23760
|
// packages/server/src/tailer.ts
|
|
23756
23761
|
import { statSync as statSync8, openSync as openSync10, readSync as readSync4, closeSync as closeSync9, readdirSync as readdirSync5, realpathSync as realpathSync5, mkdirSync as mkdirSync10, writeFileSync as writeFileSync8, readFileSync as readFileSync12, existsSync as existsSync5 } from "node:fs";
|
|
23757
23762
|
import { execFile as execFile2 } from "node:child_process";
|
|
23763
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
23758
23764
|
import { promisify as promisify2 } from "node:util";
|
|
23759
23765
|
import { basename as basename4, join as join18, win32 } from "node:path";
|
|
23760
23766
|
import { homedir as homedir7 } from "node:os";
|
|
@@ -23991,7 +23997,7 @@ function trackDispatches(state, rec) {
|
|
|
23991
23997
|
state.subAgents.set(id, { kind: "agent", toolUseId: id, label: desc ?? "sub-agent", startedAt, subagentType, outputFile });
|
|
23992
23998
|
} else if (b.name === "Bash" && input.run_in_background === true || b.name === "Monitor") {
|
|
23993
23999
|
const command = typeof input.command === "string" ? input.command : previous?.command;
|
|
23994
|
-
state.subAgents.set(id, { kind: "shell", toolUseId: id, label: desc ?? shellSummary(input.command), startedAt, command, outputFile, taskId: previous?.taskId });
|
|
24000
|
+
state.subAgents.set(id, { kind: "shell", toolUseId: id, label: desc ?? shellSummary(input.command), startedAt, command, outputFile, taskId: previous?.taskId, ...b.name === "Monitor" ? { monitor: true } : {} });
|
|
23995
24001
|
} else if (b.name === "Bash") {
|
|
23996
24002
|
const pending = state.pendingShells ??= /* @__PURE__ */ new Map();
|
|
23997
24003
|
pending.set(id, { label: desc ?? shellSummary(input.command), command: typeof input.command === "string" ? input.command : void 0, startedAt });
|
|
@@ -24062,6 +24068,22 @@ function findLiveByTaskId(state, taskId) {
|
|
|
24062
24068
|
for (const e14 of state.subAgents.values()) if (e14.taskId === taskId) return e14;
|
|
24063
24069
|
return void 0;
|
|
24064
24070
|
}
|
|
24071
|
+
function knowsDirectOp(state, taskId) {
|
|
24072
|
+
if (findLiveByTaskId(state, taskId)) return true;
|
|
24073
|
+
for (const r of state.retiredSubAgents.values()) if (r.taskId === taskId) return true;
|
|
24074
|
+
for (const r of state.retiredShells.values()) if (r.taskId === taskId) return true;
|
|
24075
|
+
return false;
|
|
24076
|
+
}
|
|
24077
|
+
function rememberFoldedTerminal(state, taskId, fingerprint) {
|
|
24078
|
+
const seen = state.foldedTerminals ??= /* @__PURE__ */ new Map();
|
|
24079
|
+
seen.delete(taskId);
|
|
24080
|
+
seen.set(taskId, fingerprint);
|
|
24081
|
+
while (seen.size > FOLDED_TERMINALS_MAX) {
|
|
24082
|
+
const oldest = seen.keys().next().value;
|
|
24083
|
+
if (oldest === void 0) break;
|
|
24084
|
+
seen.delete(oldest);
|
|
24085
|
+
}
|
|
24086
|
+
}
|
|
24065
24087
|
function launchOutputFile(state, text2) {
|
|
24066
24088
|
const m = text2.match(/output_file:\s*(\S+)/) ?? text2.match(/Output is being written to:\s*(\S+)/);
|
|
24067
24089
|
if (m) return m[1].replace(/\.$/, "");
|
|
@@ -24227,14 +24249,21 @@ function trackCompletions(state, rec) {
|
|
|
24227
24249
|
const monitorTimedOut = block.includes("<event>[Monitor timed out");
|
|
24228
24250
|
const terminal = status === "completed" || status === "failed" || status === "killed" ? status : status === "stopped" || monitorTimedOut ? "killed" : void 0;
|
|
24229
24251
|
if (!terminal) continue;
|
|
24252
|
+
const fingerprint = createHash7("sha1").update(block).digest("hex").slice(0, 16);
|
|
24253
|
+
const repeatOf = /* @__PURE__ */ new Set();
|
|
24254
|
+
for (const id of blockTaskIds(block)) {
|
|
24255
|
+
if (state.foldedTerminals?.get(id) === fingerprint) repeatOf.add(id);
|
|
24256
|
+
else if (knowsDirectOp(state, id)) rememberFoldedTerminal(state, id, fingerprint);
|
|
24257
|
+
}
|
|
24230
24258
|
const doomed = /* @__PURE__ */ new Set();
|
|
24231
24259
|
for (const m of block.matchAll(/<tool-use-id>([^<]*)<\/tool-use-id>/g)) {
|
|
24232
24260
|
const entry = state.subAgents.get(m[1]);
|
|
24233
|
-
if (entry) doomed.add(entry);
|
|
24261
|
+
if (entry && !(entry.taskId && repeatOf.has(entry.taskId))) doomed.add(entry);
|
|
24234
24262
|
}
|
|
24235
24263
|
const stampedAt = typeof rec.timestamp === "string" ? Date.parse(rec.timestamp) : Number.NaN;
|
|
24236
24264
|
for (const m of block.matchAll(/<task-id>([^<]*)<\/task-id>/g)) {
|
|
24237
24265
|
if (m[1].startsWith("__orphan_summary__")) continue;
|
|
24266
|
+
if (repeatOf.has(m[1])) continue;
|
|
24238
24267
|
const entry = findLiveByTaskId(state, m[1]);
|
|
24239
24268
|
if (entry) doomed.add(entry);
|
|
24240
24269
|
else if (Number.isFinite(stampedAt)) recordDescendantTerminal(state, m[1], stampedAt);
|
|
@@ -24814,7 +24843,7 @@ function createTailer(deps) {
|
|
|
24814
24843
|
if (e14.kind !== "shell") continue;
|
|
24815
24844
|
const lastActivityAt = entryLastActivity(state, e14);
|
|
24816
24845
|
const shellState = shellIsGone(e14) ? "stale" : "running";
|
|
24817
|
-
out.push({ label: e14.label, startedAt: e14.startedAt, state: shellState, id: e14.toolUseId, ...e14.taskId ? { stoppable: true, taskId: e14.taskId } : {}, ...lastActivityAt ? { lastActivityAt } : {} });
|
|
24846
|
+
out.push({ label: e14.label, startedAt: e14.startedAt, state: shellState, id: e14.toolUseId, ...e14.taskId ? { stoppable: true, taskId: e14.taskId } : {}, ...lastActivityAt ? { lastActivityAt } : {}, ...e14.monitor ? { outputUnavailable: true } : {} });
|
|
24818
24847
|
}
|
|
24819
24848
|
return out;
|
|
24820
24849
|
}
|
|
@@ -25998,7 +26027,7 @@ function landsAfterRead(eventAt, lastReadAt) {
|
|
|
25998
26027
|
if (!Number.isFinite(e14) || !Number.isFinite(r)) return true;
|
|
25999
26028
|
return e14 > r;
|
|
26000
26029
|
}
|
|
26001
|
-
var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS2, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
|
|
26030
|
+
var IDLE_BACKSTOP_MS, RUNTIME_CHASE_MAX, POLL_MS2, MAX_PRIME_ROWS_PER_TICK, PRIME_BUDGET_MS, TRANSCRIPT_READ_WINDOW, EMPTY_BUFFER, MAX_POLL_MS, SUBAGENT_STALE_MS, SHELL_PROBE_TTL_MS, SHELL_PROBE_GRACE_MS, execFileAsync, FOREIGN_FRESH_MS, FOREIGN_MAX, FOREIGN_SCAN_EVERY, CACHE_FLUSH_MS, PRIME_PROGRESS_EVERY, DISCOVER_RETRY_MS, DISCOVER_RETRY_MAX_MS, RETAINED_SUBAGENTS_MAX, RETAINED_SHELLS_MAX, DESCENDANT_TERMINALS_MAX, PENDING_RESUMES_MAX, PENDING_SHELLS_MAX, RESUME_REPLAY_SLACK_MS, FIRST_USER_TEXT_MAX, QUESTION_BLOCK_RE, SIGNAL_FENCE_RE, FENCE_BODY_MAX, LOCAL_COMMAND_RECEIPT, LAUNCH_ACK_RE, AUTO_BACKGROUND_ACK_RE, FOLDED_TERMINALS_MAX, DESCENDANT_SIDECAR_MAX, DESCENDANT_NOTIFY_GRACE_MS, MAX_OWNED_TOOL_USE_IDS, BROKER_LIVENESS_TTL_MS, UNRESTORED_TAIL_FIELDS;
|
|
26002
26031
|
var init_tailer = __esm({
|
|
26003
26032
|
"packages/server/src/tailer.ts"() {
|
|
26004
26033
|
"use strict";
|
|
@@ -26052,6 +26081,7 @@ var init_tailer = __esm({
|
|
|
26052
26081
|
LOCAL_COMMAND_RECEIPT = /^<local-command-(stdout|stderr)>[\s\S]*<\/local-command-\1>$/;
|
|
26053
26082
|
LAUNCH_ACK_RE = /^\s*(Async agent launched successfully|Spawned successfully|Command running in background|Monitor started|Command did not complete within its)/;
|
|
26054
26083
|
AUTO_BACKGROUND_ACK_RE = /^\s*Command did not complete within its .{0,40}?and was moved to the background/;
|
|
26084
|
+
FOLDED_TERMINALS_MAX = 64;
|
|
26055
26085
|
DESCENDANT_SIDECAR_MAX = 512;
|
|
26056
26086
|
DESCENDANT_NOTIFY_GRACE_MS = 5e3;
|
|
26057
26087
|
MAX_OWNED_TOOL_USE_IDS = 25e3;
|
|
@@ -29148,7 +29178,7 @@ var require_websocket = __commonJS({
|
|
|
29148
29178
|
var http = __require("http");
|
|
29149
29179
|
var net2 = __require("net");
|
|
29150
29180
|
var tls = __require("tls");
|
|
29151
|
-
var { randomBytes, createHash:
|
|
29181
|
+
var { randomBytes, createHash: createHash18 } = __require("crypto");
|
|
29152
29182
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
29153
29183
|
var { URL: URL2 } = __require("url");
|
|
29154
29184
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -29816,7 +29846,7 @@ var require_websocket = __commonJS({
|
|
|
29816
29846
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
29817
29847
|
return;
|
|
29818
29848
|
}
|
|
29819
|
-
const digest =
|
|
29849
|
+
const digest = createHash18("sha1").update(key + GUID).digest("base64");
|
|
29820
29850
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
29821
29851
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
29822
29852
|
return;
|
|
@@ -30185,7 +30215,7 @@ var require_websocket_server = __commonJS({
|
|
|
30185
30215
|
var EventEmitter = __require("events");
|
|
30186
30216
|
var http = __require("http");
|
|
30187
30217
|
var { Duplex } = __require("stream");
|
|
30188
|
-
var { createHash:
|
|
30218
|
+
var { createHash: createHash18 } = __require("crypto");
|
|
30189
30219
|
var extension2 = require_extension();
|
|
30190
30220
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
30191
30221
|
var subprotocol2 = require_subprotocol();
|
|
@@ -30492,7 +30522,7 @@ var require_websocket_server = __commonJS({
|
|
|
30492
30522
|
);
|
|
30493
30523
|
}
|
|
30494
30524
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
30495
|
-
const digest =
|
|
30525
|
+
const digest = createHash18("sha1").update(key + GUID).digest("base64");
|
|
30496
30526
|
const headers = [
|
|
30497
30527
|
"HTTP/1.1 101 Switching Protocols",
|
|
30498
30528
|
"Upgrade: websocket",
|
|
@@ -30723,7 +30753,7 @@ var init_codex_mcp = __esm({
|
|
|
30723
30753
|
import { spawn as spawn2 } from "node:child_process";
|
|
30724
30754
|
import { connect } from "node:net";
|
|
30725
30755
|
import { Agent as HttpAgent } from "node:http";
|
|
30726
|
-
import { createHash as
|
|
30756
|
+
import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
|
|
30727
30757
|
import { existsSync as existsSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync15, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
|
|
30728
30758
|
import { join as join20 } from "node:path";
|
|
30729
30759
|
import { PassThrough, Writable } from "node:stream";
|
|
@@ -30735,7 +30765,7 @@ function nativeRecordPath(stateDir, projectId) {
|
|
|
30735
30765
|
return join20(nativeDir(stateDir), `${projectId}.json`);
|
|
30736
30766
|
}
|
|
30737
30767
|
function nativeListenSocketPath(stateDir, projectId) {
|
|
30738
|
-
const key =
|
|
30768
|
+
const key = createHash8("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
30739
30769
|
return frizzIpcPath(`frizz-codex-native-${key}`);
|
|
30740
30770
|
}
|
|
30741
30771
|
function pidAlive2(pid) {
|
|
@@ -31003,7 +31033,7 @@ var init_codex_app_server_native = __esm({
|
|
|
31003
31033
|
// packages/server/src/backend/codex-app-server-host.ts
|
|
31004
31034
|
import { spawn as spawn3 } from "node:child_process";
|
|
31005
31035
|
import { createConnection } from "node:net";
|
|
31006
|
-
import { createHash as
|
|
31036
|
+
import { createHash as createHash9, randomUUID as randomUUID10 } from "node:crypto";
|
|
31007
31037
|
import { existsSync as existsSync7, mkdirSync as mkdirSync12, readFileSync as readFileSync16, unlinkSync as unlinkSync3 } from "node:fs";
|
|
31008
31038
|
import { join as join21 } from "node:path";
|
|
31009
31039
|
import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
|
|
@@ -31015,7 +31045,7 @@ function recordPath(stateDir, projectId) {
|
|
|
31015
31045
|
return join21(daemonDir(stateDir), `${projectId}.json`);
|
|
31016
31046
|
}
|
|
31017
31047
|
function codexAppServerSocketPath(stateDir, projectId) {
|
|
31018
|
-
const key =
|
|
31048
|
+
const key = createHash9("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
31019
31049
|
return frizzIpcPath(`frizz-codex-${key}`);
|
|
31020
31050
|
}
|
|
31021
31051
|
function pidAlive3(pid) {
|
|
@@ -31312,7 +31342,7 @@ var init_codex_app_server_host = __esm({
|
|
|
31312
31342
|
// packages/server/src/backend/claude-quota.ts
|
|
31313
31343
|
import { join as join22 } from "node:path";
|
|
31314
31344
|
import { homedir as homedir9, platform } from "node:os";
|
|
31315
|
-
import { createHash as
|
|
31345
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
31316
31346
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
31317
31347
|
import { execFile as execFile3 } from "node:child_process";
|
|
31318
31348
|
import { promisify as promisify3 } from "node:util";
|
|
@@ -31419,7 +31449,7 @@ function retryAtFrom(res, now) {
|
|
|
31419
31449
|
return now + Math.min(backoff, RATE_LIMIT_MAX_BACKOFF_MS);
|
|
31420
31450
|
}
|
|
31421
31451
|
function cachePaths(cacheDir, configDir) {
|
|
31422
|
-
const profile =
|
|
31452
|
+
const profile = createHash10("sha256").update(configDir).digest("hex").slice(0, 12);
|
|
31423
31453
|
return {
|
|
31424
31454
|
data: join22(cacheDir, `claude-${profile}.json`),
|
|
31425
31455
|
lock: join22(cacheDir, `claude-${profile}.lock`)
|
|
@@ -31599,15 +31629,15 @@ async function tryAcquireLock2(path3) {
|
|
|
31599
31629
|
}
|
|
31600
31630
|
return void 0;
|
|
31601
31631
|
}
|
|
31602
|
-
function rateLimited(
|
|
31603
|
-
return
|
|
31632
|
+
function rateLimited(shared2, now) {
|
|
31633
|
+
return shared2?.retryAt !== void 0 && now < shared2.retryAt;
|
|
31604
31634
|
}
|
|
31605
|
-
function serveRateLimited(
|
|
31606
|
-
if (
|
|
31635
|
+
function serveRateLimited(shared2, now) {
|
|
31636
|
+
if (shared2.quota.status !== "ok" || now - shared2.at >= STALE_MAX_AGE_MS) return UNAVAILABLE;
|
|
31607
31637
|
const minutes = (ms, round) => Math.max(1, round(ms / 6e4));
|
|
31608
31638
|
return {
|
|
31609
|
-
...
|
|
31610
|
-
detail: `Next refresh in ${minutes(
|
|
31639
|
+
...shared2.quota,
|
|
31640
|
+
detail: `Next refresh in ${minutes(shared2.retryAt - now, Math.ceil)}m \xB7 last updated ${minutes(now - shared2.at, Math.round)}m ago`
|
|
31611
31641
|
};
|
|
31612
31642
|
}
|
|
31613
31643
|
function refreshSharedInBackground(paths, claudeBin, deps, now) {
|
|
@@ -32028,7 +32058,7 @@ var init_codex_execution_health = __esm({
|
|
|
32028
32058
|
});
|
|
32029
32059
|
|
|
32030
32060
|
// packages/server/src/backend/codex-app-server.ts
|
|
32031
|
-
import { createHash as
|
|
32061
|
+
import { createHash as createHash11, randomUUID as randomUUID11 } from "node:crypto";
|
|
32032
32062
|
import { existsSync as existsSync8 } from "node:fs";
|
|
32033
32063
|
import { StringDecoder as StringDecoder3 } from "node:string_decoder";
|
|
32034
32064
|
function selectCodexHostKind(flagValue, platform3, hasSpawn) {
|
|
@@ -32376,7 +32406,7 @@ function canonicalJson2(value) {
|
|
|
32376
32406
|
return JSON.stringify(normalize2(value));
|
|
32377
32407
|
}
|
|
32378
32408
|
function logicalRequestId(method, parts) {
|
|
32379
|
-
const digest =
|
|
32409
|
+
const digest = createHash11("sha256").update(JSON.stringify([method, ...parts])).digest("hex");
|
|
32380
32410
|
return `codex-${digest}`;
|
|
32381
32411
|
}
|
|
32382
32412
|
function requestFingerprint(value) {
|
|
@@ -32386,7 +32416,7 @@ function requestFingerprint(value) {
|
|
|
32386
32416
|
delete record.startedAtMs;
|
|
32387
32417
|
delete record.autoResolutionMs;
|
|
32388
32418
|
}
|
|
32389
|
-
return
|
|
32419
|
+
return createHash11("sha256").update(canonicalJson2(normalized)).digest("hex");
|
|
32390
32420
|
}
|
|
32391
32421
|
function decision(id, semantic, label) {
|
|
32392
32422
|
return { id, semantic, label };
|
|
@@ -32674,7 +32704,7 @@ function createCodexAppServerBridge(options) {
|
|
|
32674
32704
|
function codexAppServerBridgeEnabled() {
|
|
32675
32705
|
return true;
|
|
32676
32706
|
}
|
|
32677
|
-
var CODEX_APP_SERVER_PROVIDER, CODEX_NATIVE_LISTEN_FLAG, CODEX_APP_SERVER_SUPPORTED_VERSION, CODEX_APP_SERVER_PROTOCOL_REVISION, aheadVersionWarned, PROTOCOL_FINGERPRINT, CLIENT_INFO, CLIENT_CAPABILITIES, CODEX_SANDBOX_MODES, CODEX_APPROVAL_POLICY, CODEX_DEFAULT_SANDBOX, SANDBOX_CONFIRM_TIMEOUT_MS, SANDBOX_NOOP_GRACE_MS, MAX_JSONL_BYTES, MAX_INBOUND_JSONL_BYTES, MAX_INBOUND_RECORDS, MAX_INBOUND_QUEUED_BYTES, MAX_OUTBOUND_REQUESTS, MAX_STDERR_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, AUTH_REPLACEMENT_WAIT_MS, MAX_AUTH_REPLACEMENT_ATTEMPTS, BRIDGE_DB_SCHEMA_VERSION, RpcIdSchema, Opaque, SafeTimestampMs, NullableString, CommandAction, NetworkApprovalContext, FileSystemSpecialPath, FileSystemPath, FileSystemSandboxEntry, NetworkPermissions, FileSystemPermissions, RequestedPermissions, NetworkPolicyAmendment, CommandApprovalParams, FileApprovalParams, PatchChangeKind, FileUpdateChange, FileChangeItem, CommandExecutionItem, ItemStartedNotification, ItemCompletedNotification, FileChangePatchUpdatedNotification, PermissionsApprovalParams, UserInputQuestion, UserInputParams, McpBase, McpElicitationParams, ResolvedNotification, RpcProtocolError, JsonlRpcConnection, BindingRowSchema, BridgeMetaRowSchema, DISPLAY_REDACTION, UNSAFE_DISPLAY_TEXT, SECRET_NAME, commandDecisionMap, InitializeResponse, ThreadResponse, TurnResponse, TurnSteerResponse, SkillsListResponse, ThreadResumeSandbox, ThreadResumeStatus, ThreadSettingsUpdated, TurnStarted, TurnCompleted, MAX_CORRELATED_FILE_ITEMS, CODEX_APP_SERVER_TABLES, CodexAppServerBridge;
|
|
32707
|
+
var CODEX_APP_SERVER_PROVIDER, CODEX_NATIVE_LISTEN_FLAG, CODEX_APP_SERVER_SUPPORTED_VERSION, CODEX_APP_SERVER_PROTOCOL_REVISION, aheadVersionWarned, PROTOCOL_FINGERPRINT, CLIENT_INFO, CLIENT_CAPABILITIES, CODEX_SANDBOX_MODES, CODEX_APPROVAL_POLICY, CODEX_DEFAULT_SANDBOX, SANDBOX_CONFIRM_TIMEOUT_MS, SANDBOX_NOOP_GRACE_MS, MAX_JSONL_BYTES, MAX_INBOUND_JSONL_BYTES, MAX_INBOUND_RECORDS, MAX_INBOUND_QUEUED_BYTES, MAX_OUTBOUND_REQUESTS, MAX_STDERR_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, AUTH_REPLACEMENT_WAIT_MS, MAX_AUTH_REPLACEMENT_ATTEMPTS, BRIDGE_DB_SCHEMA_VERSION, RpcIdSchema, Opaque, SafeTimestampMs, NullableString, CommandAction, NetworkApprovalContext, FileSystemSpecialPath, FileSystemPath, FileSystemSandboxEntry, NetworkPermissions, FileSystemPermissions, RequestedPermissions, NetworkPolicyAmendment, CommandApprovalParams, FileApprovalParams, PatchChangeKind, FileUpdateChange, FileChangeItem, CommandExecutionItem, BackgroundTerminalsListResponse, ItemStartedNotification, ItemCompletedNotification, FileChangePatchUpdatedNotification, PermissionsApprovalParams, UserInputQuestion, UserInputParams, McpBase, McpElicitationParams, ResolvedNotification, RpcProtocolError, JsonlRpcConnection, BindingRowSchema, BridgeMetaRowSchema, DISPLAY_REDACTION, UNSAFE_DISPLAY_TEXT, SECRET_NAME, commandDecisionMap, InitializeResponse, ThreadResponse, TurnResponse, TurnSteerResponse, SkillsListResponse, ThreadResumeSandbox, ThreadResumeStatus, ThreadSettingsUpdated, TurnStarted, TurnCompleted, MAX_CORRELATED_FILE_ITEMS, CODEX_APP_SERVER_TABLES, CodexAppServerBridge;
|
|
32678
32708
|
var init_codex_app_server = __esm({
|
|
32679
32709
|
"packages/server/src/backend/codex-app-server.ts"() {
|
|
32680
32710
|
"use strict";
|
|
@@ -32845,6 +32875,13 @@ var init_codex_app_server = __esm({
|
|
|
32845
32875
|
status: external_exports.string().max(64).optional(),
|
|
32846
32876
|
exitCode: external_exports.number().nullish()
|
|
32847
32877
|
});
|
|
32878
|
+
BackgroundTerminalsListResponse = external_exports.object({
|
|
32879
|
+
data: external_exports.array(external_exports.object({
|
|
32880
|
+
processId: external_exports.union([external_exports.string().max(128), external_exports.number()]),
|
|
32881
|
+
command: external_exports.string().max(8192).optional()
|
|
32882
|
+
})).max(256),
|
|
32883
|
+
nextCursor: external_exports.string().max(1024).nullish()
|
|
32884
|
+
});
|
|
32848
32885
|
ItemStartedNotification = external_exports.object({
|
|
32849
32886
|
item: external_exports.unknown(),
|
|
32850
32887
|
threadId: Opaque,
|
|
@@ -33296,8 +33333,9 @@ var init_codex_app_server = __esm({
|
|
|
33296
33333
|
// ops-strip row it projects has no handle to address a kill with. This map is what gives a codex
|
|
33297
33334
|
// shell row an id, and the id it gives is exactly what `backgroundTerminals/terminate` accepts.
|
|
33298
33335
|
//
|
|
33299
|
-
// A LEVEL, not an edge log: `item/started` adds, any terminal `item/*` removes,
|
|
33300
|
-
//
|
|
33336
|
+
// A LEVEL, not an edge log: `item/started` adds, any terminal `item/*` removes, a rejoin of the same
|
|
33337
|
+
// process re-seeds it from `backgroundTerminals/list` (seedLiveExecs), and the whole per-thread entry
|
|
33338
|
+
// is dropped when the session is released or the process goes away. Nothing here is
|
|
33301
33339
|
// durable, and it must not be — a processId belongs to one app-server process, so a stale one
|
|
33302
33340
|
// surviving a restart would offer an × that addresses a PTY that no longer exists.
|
|
33303
33341
|
liveExecs = /* @__PURE__ */ new Map();
|
|
@@ -34186,8 +34224,11 @@ var init_codex_app_server = __esm({
|
|
|
34186
34224
|
deathAt: matched?.at || void 0
|
|
34187
34225
|
});
|
|
34188
34226
|
}
|
|
34189
|
-
|
|
34227
|
+
const sameGeneration = attachment.reattached && negotiated.previousGeneration === attachment.generation;
|
|
34228
|
+
const execThreads = sameGeneration ? [...(await this.listLiveExecs(connection, this.boundCodexThreadIds())).keys()] : [];
|
|
34229
|
+
await this.reconcileOwnedSessions(connection, negotiated.sameProcess, execThreads);
|
|
34190
34230
|
if (this.connection !== connection) throw new Error("Codex app-server disconnected during session reconciliation");
|
|
34231
|
+
if (execThreads.length > 0) this.seedLiveExecs(connection, await this.listLiveExecs(connection, execThreads));
|
|
34191
34232
|
return connection;
|
|
34192
34233
|
} catch (error) {
|
|
34193
34234
|
connection.close();
|
|
@@ -34229,16 +34270,27 @@ var init_codex_app_server = __esm({
|
|
|
34229
34270
|
* mid-turn detached rows too; idle detached rows stay lazily rebound on next use, which keeps this
|
|
34230
34271
|
* bounded on a board with a long history.
|
|
34231
34272
|
*
|
|
34273
|
+
* The one exception is `execThreads`: idle threads that still own a running background exec. Over
|
|
34274
|
+
* the native listener subscriptions are per-connection, so an idle thread left detached never
|
|
34275
|
+
* hears its exec END — the `item/completed` goes nowhere and the re-seeded row outlives the command
|
|
34276
|
+
* (measured live, backend/_live_codex_bgterm_reseed.mts). Rebinding them here, exactly as the next
|
|
34277
|
+
* follow-up would, is what re-subscribes this connection to them.
|
|
34278
|
+
*
|
|
34232
34279
|
* `sameProcess` says we rejoined the very app-server that owned these turns (it outlived our
|
|
34233
34280
|
* restart inside the daemon). Then the turns are STILL RUNNING and the only correct action is to
|
|
34234
34281
|
* re-mark the binding active and keep `current_turn_id`: issuing `thread/resume` against a live
|
|
34235
34282
|
* turn would disturb it, and clearing the id would orphan the `turn/completed` still to come.
|
|
34236
34283
|
*/
|
|
34237
|
-
async reconcileOwnedSessions(connection, sameProcess) {
|
|
34284
|
+
async reconcileOwnedSessions(connection, sameProcess, execThreads = []) {
|
|
34238
34285
|
const rows = this.scope.prepare(`
|
|
34239
34286
|
SELECT * FROM codex_app_server_session
|
|
34240
34287
|
WHERE project_id = @project_id AND (state = 'active' OR (state = 'detached' AND current_turn_id IS NOT NULL))
|
|
34241
34288
|
`).all().map(checkedBindingRow);
|
|
34289
|
+
for (const threadId of execThreads) {
|
|
34290
|
+
if (rows.some((row2) => row2.codex_thread_id === threadId)) continue;
|
|
34291
|
+
const row = this.bindingForCodexThread(threadId);
|
|
34292
|
+
if (row) rows.push(row);
|
|
34293
|
+
}
|
|
34242
34294
|
const detach = (row) => {
|
|
34243
34295
|
this.scope.prepare("UPDATE codex_app_server_session SET state = 'detached', updated_at = ? WHERE project_id = @project_id AND frizz_session_id = ?").run(this.now().toISOString(), row.frizz_session_id);
|
|
34244
34296
|
};
|
|
@@ -34688,8 +34740,9 @@ var init_codex_app_server = __esm({
|
|
|
34688
34740
|
// The live background-exec level rides the same lifecycle as the correlated file items — a released
|
|
34689
34741
|
// session and a lost process both invalidate it — but for a different reason. A `processId` names a
|
|
34690
34742
|
// PTY inside ONE app-server process, so a surviving entry after that process goes away would put an ×
|
|
34691
|
-
// on the board that addresses a handle nothing can honour. The next connection's item stream
|
|
34692
|
-
// repopulates it
|
|
34743
|
+
// on the board that addresses a handle nothing can honour. The next connection's item stream only
|
|
34744
|
+
// repopulates it with execs that START after it attached; one already running when we rejoin the same
|
|
34745
|
+
// process is re-learned by seedLiveExecs, because its `item/started` is never sent again.
|
|
34693
34746
|
forgetCorrelatedFileItems(threadId, turnId) {
|
|
34694
34747
|
if (threadId === void 0) {
|
|
34695
34748
|
this.correlatedFileItems.clear();
|
|
@@ -34995,6 +35048,71 @@ var init_codex_app_server = __esm({
|
|
|
34995
35048
|
startedAtMs: existing?.startedAtMs ?? startedAtMs ?? this.now().getTime()
|
|
34996
35049
|
});
|
|
34997
35050
|
}
|
|
35051
|
+
// Re-learn the live background execs after rejoining an app-server we had already been talking to.
|
|
35052
|
+
//
|
|
35053
|
+
// The level above is folded off `item/started`, and that notification went to the client connection
|
|
35054
|
+
// we just lost: the daemon queues only while NO client is attached, and the native listener queues
|
|
35055
|
+
// nothing, so neither ever replays it. The exec, meanwhile, is still running in that process's PTY —
|
|
35056
|
+
// so without this its row vanished from the board after every Frizz restart or dropped socket and
|
|
35057
|
+
// never came back until the exec ended, taking its × with it. `thread/backgroundTerminals/list` is
|
|
35058
|
+
// the app-server's own answer to "what is still running".
|
|
35059
|
+
//
|
|
35060
|
+
// connect() asks TWICE. The first pass goes to every bound thread, because a yielded exec outlives
|
|
35061
|
+
// its turn and the thread most likely to own one is an IDLE one whose binding sat detached; it only
|
|
35062
|
+
// decides which threads reconcile must rebind. The second pass, after that rebind re-subscribed this
|
|
35063
|
+
// connection, is the one that seeds — so an exec that ended in between is not seeded as a row no
|
|
35064
|
+
// `item/completed` will ever clear. A thread the process never loaded answers "thread not found"
|
|
35065
|
+
// (measured on 0.158.0, and the list does not load it), and any failure — that, an older codex
|
|
35066
|
+
// without the method — leaves the thread out, which is exactly the level it had before this existed.
|
|
35067
|
+
// Nothing here throws: a board row is not worth a failed connect.
|
|
35068
|
+
async listLiveExecs(connection, threadIds) {
|
|
35069
|
+
const found = /* @__PURE__ */ new Map();
|
|
35070
|
+
const seenAtMs = this.now().getTime();
|
|
35071
|
+
await Promise.all(threadIds.map(async (threadId) => {
|
|
35072
|
+
const execs = [];
|
|
35073
|
+
let cursor;
|
|
35074
|
+
for (let page = 0; page < 8; page++) {
|
|
35075
|
+
let parsed;
|
|
35076
|
+
try {
|
|
35077
|
+
parsed = BackgroundTerminalsListResponse.parse(await connection.request(
|
|
35078
|
+
"thread/backgroundTerminals/list",
|
|
35079
|
+
cursor === void 0 ? { threadId } : { threadId, cursor }
|
|
35080
|
+
));
|
|
35081
|
+
} catch {
|
|
35082
|
+
return;
|
|
35083
|
+
}
|
|
35084
|
+
for (const terminal of parsed.data) {
|
|
35085
|
+
execs.push({ processId: String(terminal.processId), command: terminal.command, startedAtMs: seenAtMs });
|
|
35086
|
+
}
|
|
35087
|
+
if (!parsed.nextCursor) break;
|
|
35088
|
+
cursor = parsed.nextCursor;
|
|
35089
|
+
}
|
|
35090
|
+
if (execs.length > 0) found.set(threadId, execs);
|
|
35091
|
+
}));
|
|
35092
|
+
return found;
|
|
35093
|
+
}
|
|
35094
|
+
seedLiveExecs(connection, found) {
|
|
35095
|
+
if (this.connection !== connection) return;
|
|
35096
|
+
for (const [threadId, execs] of found) {
|
|
35097
|
+
let byProcess = this.liveExecs.get(threadId);
|
|
35098
|
+
if (!byProcess) {
|
|
35099
|
+
byProcess = /* @__PURE__ */ new Map();
|
|
35100
|
+
this.liveExecs.set(threadId, byProcess);
|
|
35101
|
+
}
|
|
35102
|
+
for (const exec of execs) {
|
|
35103
|
+
if (!byProcess.has(exec.processId)) byProcess.set(exec.processId, exec);
|
|
35104
|
+
}
|
|
35105
|
+
}
|
|
35106
|
+
}
|
|
35107
|
+
boundCodexThreadIds() {
|
|
35108
|
+
try {
|
|
35109
|
+
return this.scope.prepare(
|
|
35110
|
+
"SELECT codex_thread_id FROM codex_app_server_session WHERE project_id = @project_id"
|
|
35111
|
+
).all().map((row) => row.codex_thread_id);
|
|
35112
|
+
} catch {
|
|
35113
|
+
return [];
|
|
35114
|
+
}
|
|
35115
|
+
}
|
|
34998
35116
|
async handleNotification(connection, method, rawParams) {
|
|
34999
35117
|
if (method === "error") {
|
|
35000
35118
|
const parsed = external_exports.object({ threadId: Opaque, turnId: Opaque, error: external_exports.unknown(), willRetry: external_exports.boolean() }).passthrough().safeParse(rawParams);
|
|
@@ -38166,7 +38284,7 @@ var init_claude_agent_broker_bridge = __esm({
|
|
|
38166
38284
|
// packages/server/src/dispatch.ts
|
|
38167
38285
|
import { closeSync as closeSync12, constants as constants2, existsSync as existsSync11, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync13, readFileSync as readFileSync20, realpathSync as realpathSync8, statSync as statSync14, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, rmSync as rmSync9 } from "node:fs";
|
|
38168
38286
|
import { basename as basename6, join as join30, dirname as dirname12 } from "node:path";
|
|
38169
|
-
import { createHash as
|
|
38287
|
+
import { createHash as createHash12, randomUUID as randomUUID13 } from "node:crypto";
|
|
38170
38288
|
function fallbackTitle(prompt) {
|
|
38171
38289
|
const firstLine2 = prompt.trim().split("\n", 1)[0].trim();
|
|
38172
38290
|
let allWords = firstLine2.split(/\s+/).filter(Boolean);
|
|
@@ -38235,7 +38353,7 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
38235
38353
|
size: after.size,
|
|
38236
38354
|
mtimeMs: after.mtimeMs,
|
|
38237
38355
|
ctimeMs: after.ctimeMs,
|
|
38238
|
-
digest:
|
|
38356
|
+
digest: createHash12("sha256").update(contents).digest("hex")
|
|
38239
38357
|
};
|
|
38240
38358
|
} catch {
|
|
38241
38359
|
return null;
|
|
@@ -39029,6 +39147,10 @@ function hasLiveBackgroundWork(tele) {
|
|
|
39029
39147
|
function hasUnretiredOwnAgents(tele) {
|
|
39030
39148
|
return Boolean(tele?.subAgents?.some((agent) => isDirectSubAgent(agent) && (agent.state === "running" || agent.state === "stale")));
|
|
39031
39149
|
}
|
|
39150
|
+
function orphanedAgents(agents, ownerGone) {
|
|
39151
|
+
if (!ownerGone) return agents;
|
|
39152
|
+
return agents.map((agent) => agent.state === "running" ? { ...agent, state: "stale" } : agent);
|
|
39153
|
+
}
|
|
39032
39154
|
function stampStoppable(agents, row) {
|
|
39033
39155
|
if (!isBrokerClaudeRow(row)) return agents;
|
|
39034
39156
|
return agents.map((agent) => agent.state === "running" ? { ...agent, stoppable: true } : agent);
|
|
@@ -39233,6 +39355,14 @@ function hasFreshDelivery(row, processGone) {
|
|
|
39233
39355
|
if (processGone) return false;
|
|
39234
39356
|
return parseDeliveryLedger(row.delivery_ledger).some((d) => d.state === "pending" || d.state === "enqueued" || d.state === "delivered");
|
|
39235
39357
|
}
|
|
39358
|
+
function deriveDeliveryInFlight(row, runtime, needsYou, deliveryProcessGone, answerInFlight, nowMs = Date.now()) {
|
|
39359
|
+
if (needsYou || runtime !== "turn-idle" && runtime !== "exited") return false;
|
|
39360
|
+
if (answerInFlight) return true;
|
|
39361
|
+
if (deliveryProcessGone) return false;
|
|
39362
|
+
return parseDeliveryLedger(row.delivery_ledger).some(
|
|
39363
|
+
(d) => (d.state === "pending" || d.state === "enqueued" || d.state === "delivered") && nowMs - Date.parse(d.at) < DELIVERY_IN_FLIGHT_SPIN_MS
|
|
39364
|
+
);
|
|
39365
|
+
}
|
|
39236
39366
|
function deriveNeedsYou(row, tele, runtime, hasActionableInteraction = false, nowMs = Date.now(), limitPause = void 0, excuseLiveOwnWork = true, deliveryProcessGone = false, github = {}, registeredPrWatches = /* @__PURE__ */ new Set(), armedTimerIds = /* @__PURE__ */ new Set(), armedWatches = [], openQuestions = 0, answerInFlight = false) {
|
|
39237
39367
|
if (futureSnooze(row, nowMs)) return false;
|
|
39238
39368
|
if (hasActionableInteraction) return true;
|
|
@@ -39432,7 +39562,9 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
|
|
|
39432
39562
|
const state = effectiveSessionState(row, registeredLegacyTerminal);
|
|
39433
39563
|
const archived = state === "archived";
|
|
39434
39564
|
const limitPause = resolveLimitPause(row, tele, nowMs);
|
|
39435
|
-
const
|
|
39565
|
+
const answerInFlight = answerAwaitingDelivery(questionRows, rawTele?.lastUserAt, nowMs);
|
|
39566
|
+
const needsYou = archived ? false : deriveNeedsYou(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, true, deliveryProcessGone, github, registeredPrWatches, armedTimerIds, armedWatches, questions.length, answerInFlight);
|
|
39567
|
+
const deliveryInFlight = !archived && deriveDeliveryInFlight(row, runtime, needsYou, deliveryProcessGone, answerInFlight, nowMs);
|
|
39436
39568
|
const awaitingBackground = archived ? false : deriveAwaitingBackground(row, tele, runtime, interactionPresence.needsUser, nowMs, limitPause, deliveryProcessGone, github, registeredPrWatches, armedTimerIds, armedWatches, questions.length);
|
|
39437
39569
|
const crashed = runtime === "exited" && (tele?.turn === "in-flight" || hasLiveBackgroundWork(tele) || headlessLostWork);
|
|
39438
39570
|
const snoozedUntil = futureSnooze(row, nowMs);
|
|
@@ -39465,7 +39597,7 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
|
|
|
39465
39597
|
spawnedAt: row.spawned_at,
|
|
39466
39598
|
lastActivityAt: tele?.lastActivityAt,
|
|
39467
39599
|
lastAssistantAt: tele?.lastAssistantAt,
|
|
39468
|
-
subAgents: stampStoppable(tele?.subAgents ?? [], row),
|
|
39600
|
+
subAgents: stampStoppable(orphanedAgents(tele?.subAgents ?? [], deliveryProcessGone), row),
|
|
39469
39601
|
bgShells: stampStoppableShells(tele?.bgShells ?? [], row),
|
|
39470
39602
|
links: (registries.links.get(row.slug) ?? []).map(threadLinkView),
|
|
39471
39603
|
// ONE SOURCE: the FENCE. Both kinds are derived from what the worker wrote — `prs:` entries
|
|
@@ -39477,6 +39609,7 @@ function sessionThreadView(projectDir, storage, row, rawTele, registeredLegacyTe
|
|
|
39477
39609
|
pendingQuestion: tele?.pendingQuestion ?? false,
|
|
39478
39610
|
questions,
|
|
39479
39611
|
answersInFlight: inFlightAnswers,
|
|
39612
|
+
deliveryInFlight: deliveryInFlight || void 0,
|
|
39480
39613
|
lastUserAt: tele?.lastUserAt,
|
|
39481
39614
|
// Runtime provider-auth rejection (claude-auth plan): only the typed category travels — the raw
|
|
39482
39615
|
// error/provider text never leaves the server. Drives the trusted sign-in recovery card in ChatView.
|
|
@@ -39915,7 +40048,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
39915
40048
|
}
|
|
39916
40049
|
};
|
|
39917
40050
|
}
|
|
39918
|
-
var DEBOUNCE_MS, RECONCILE_MS, STALL_GRACE_MS, LINE_CAP, FRIZZ_WATCH_IGNORED_DIRS, DECLARED_PARK_MAX_MS, ANSWER_IN_FLIGHT_EXCUSAL_MS;
|
|
40051
|
+
var DEBOUNCE_MS, RECONCILE_MS, STALL_GRACE_MS, LINE_CAP, FRIZZ_WATCH_IGNORED_DIRS, DECLARED_PARK_MAX_MS, ANSWER_IN_FLIGHT_EXCUSAL_MS, DELIVERY_IN_FLIGHT_SPIN_MS;
|
|
39919
40052
|
var init_board = __esm({
|
|
39920
40053
|
"packages/server/src/board.ts"() {
|
|
39921
40054
|
"use strict";
|
|
@@ -39940,6 +40073,7 @@ var init_board = __esm({
|
|
|
39940
40073
|
FRIZZ_WATCH_IGNORED_DIRS = ["threads", ".session-state"];
|
|
39941
40074
|
DECLARED_PARK_MAX_MS = 24 * 60 * 60 * 1e3;
|
|
39942
40075
|
ANSWER_IN_FLIGHT_EXCUSAL_MS = 6e4;
|
|
40076
|
+
DELIVERY_IN_FLIGHT_SPIN_MS = 6e4;
|
|
39943
40077
|
}
|
|
39944
40078
|
});
|
|
39945
40079
|
|
|
@@ -40726,7 +40860,7 @@ var init_pr_watch_noise = __esm({
|
|
|
40726
40860
|
// packages/server/src/scheduler.ts
|
|
40727
40861
|
import { execFile as execFile8 } from "node:child_process";
|
|
40728
40862
|
import { promisify as promisify7 } from "node:util";
|
|
40729
|
-
import { createHash as
|
|
40863
|
+
import { createHash as createHash13, randomUUID as randomUUID14 } from "node:crypto";
|
|
40730
40864
|
function failureSignature(rollup) {
|
|
40731
40865
|
const ids = [];
|
|
40732
40866
|
for (const c of Array.isArray(rollup) ? rollup : []) {
|
|
@@ -40736,7 +40870,7 @@ function failureSignature(rollup) {
|
|
|
40736
40870
|
ids.push(`${label}@${c.detailsUrl ?? c.targetUrl ?? c.completedAt ?? ""}`);
|
|
40737
40871
|
}
|
|
40738
40872
|
if (ids.length === 0) return "";
|
|
40739
|
-
return
|
|
40873
|
+
return createHash13("sha1").update(ids.sort().join("\n")).digest("hex").slice(0, 12);
|
|
40740
40874
|
}
|
|
40741
40875
|
function ghPrViewArgs(ref) {
|
|
40742
40876
|
return ["pr", "view", String(ref.number), "--repo", `${ref.owner}/${ref.repo}`, "--json", "state,mergedAt,statusCheckRollup,headRefOid,mergeable,reviewDecision"];
|
|
@@ -40824,7 +40958,7 @@ function githubWatchStatus(pr2, polledAt) {
|
|
|
40824
40958
|
};
|
|
40825
40959
|
}
|
|
40826
40960
|
function wakeDeliveryId(slug, sessionId, fenceId) {
|
|
40827
|
-
return
|
|
40961
|
+
return createHash13("sha256").update(slug).update("\0").update(sessionId).update("\0").update(fenceId).digest("hex");
|
|
40828
40962
|
}
|
|
40829
40963
|
function limitFenceId(fault) {
|
|
40830
40964
|
return `${LIMIT_FENCE_PREFIX}${fault.at}`;
|
|
@@ -40839,7 +40973,7 @@ function isReportFenceId(fenceId) {
|
|
|
40839
40973
|
return fenceId.startsWith(`${REPORT_FENCE_PREFIX}:`);
|
|
40840
40974
|
}
|
|
40841
40975
|
function snoozeFenceId(until, prompt) {
|
|
40842
|
-
const digest =
|
|
40976
|
+
const digest = createHash13("sha256").update(prompt).digest("hex").slice(0, 16);
|
|
40843
40977
|
return `${SNOOZE_FENCE_PREFIX}:${until}:${digest}`;
|
|
40844
40978
|
}
|
|
40845
40979
|
function isSnoozeFenceId(fenceId) {
|
|
@@ -40983,7 +41117,7 @@ function isOwnWatchExpiredFenceId(fenceId) {
|
|
|
40983
41117
|
return fenceId.startsWith(`${OWN_WATCH_EXPIRED_FENCE_PREFIX}:`);
|
|
40984
41118
|
}
|
|
40985
41119
|
function questionAnswerFenceId(ids) {
|
|
40986
|
-
return `${QUESTION_ANSWER_FENCE_PREFIX}:${
|
|
41120
|
+
return `${QUESTION_ANSWER_FENCE_PREFIX}:${createHash13("sha256").update([...ids].sort().join(",")).digest("hex").slice(0, 16)}`;
|
|
40987
41121
|
}
|
|
40988
41122
|
function isQuestionAnswerFenceId(fenceId) {
|
|
40989
41123
|
return fenceId.startsWith(`${QUESTION_ANSWER_FENCE_PREFIX}:`);
|
|
@@ -43470,7 +43604,7 @@ var init_acp_rpc = __esm({
|
|
|
43470
43604
|
// packages/server/src/backend/acp-host.ts
|
|
43471
43605
|
import { spawn as spawn7 } from "node:child_process";
|
|
43472
43606
|
import { createConnection as createConnection2 } from "node:net";
|
|
43473
|
-
import { createHash as
|
|
43607
|
+
import { createHash as createHash14, randomUUID as randomUUID15 } from "node:crypto";
|
|
43474
43608
|
import { existsSync as existsSync14, mkdirSync as mkdirSync15, readFileSync as readFileSync22, readdirSync as readdirSync8, unlinkSync as unlinkSync4 } from "node:fs";
|
|
43475
43609
|
import { join as join34 } from "node:path";
|
|
43476
43610
|
import { PassThrough as PassThrough3, Writable as Writable3 } from "node:stream";
|
|
@@ -43482,7 +43616,7 @@ function acpDaemonRecordPath(stateDir, sessionId) {
|
|
|
43482
43616
|
return join34(daemonDir2(stateDir), `${sessionId}.json`);
|
|
43483
43617
|
}
|
|
43484
43618
|
function acpDaemonSocketPath(stateDir, sessionId) {
|
|
43485
|
-
const key =
|
|
43619
|
+
const key = createHash14("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
|
|
43486
43620
|
return frizzIpcPath(`frizz-acp-${key}`);
|
|
43487
43621
|
}
|
|
43488
43622
|
function pidAlive4(pid) {
|
|
@@ -69792,9 +69926,10 @@ var init_stale_socket_sweep = __esm({
|
|
|
69792
69926
|
});
|
|
69793
69927
|
|
|
69794
69928
|
// packages/server/src/orphan-reaper.ts
|
|
69795
|
-
import {
|
|
69929
|
+
import { execFile as execFile10 } from "node:child_process";
|
|
69796
69930
|
import { readFileSync as readFileSync24 } from "node:fs";
|
|
69797
69931
|
import { dirname as dirname16 } from "node:path";
|
|
69932
|
+
import { promisify as promisify8 } from "node:util";
|
|
69798
69933
|
function firstTokenBasename(command) {
|
|
69799
69934
|
const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
|
|
69800
69935
|
const slash = first.lastIndexOf("/");
|
|
@@ -69893,8 +70028,8 @@ function parseEtimeMs(etime) {
|
|
|
69893
70028
|
else return 0;
|
|
69894
70029
|
return (((days * 24 + h2) * 60 + m) * 60 + s) * 1e3;
|
|
69895
70030
|
}
|
|
69896
|
-
function enumerateProcs(exec = defaultExec, opts = {}) {
|
|
69897
|
-
const base = exec("ps", ["-Aww", "-o", "pid=,ppid=,etime=,command="]);
|
|
70031
|
+
async function enumerateProcs(exec = defaultExec, opts = {}) {
|
|
70032
|
+
const base = await exec("ps", ["-Aww", "-o", "pid=,ppid=,etime=,command="]);
|
|
69898
70033
|
const rows = [];
|
|
69899
70034
|
const byPid = /* @__PURE__ */ new Map();
|
|
69900
70035
|
const pids = [];
|
|
@@ -69927,7 +70062,7 @@ function enumerateProcs(exec = defaultExec, opts = {}) {
|
|
|
69927
70062
|
}
|
|
69928
70063
|
let text2;
|
|
69929
70064
|
try {
|
|
69930
|
-
text2 = exec("ps", ["-Eww", "-o", "pid=,command=", "-p", pids.join(",")]);
|
|
70065
|
+
text2 = await exec("ps", ["-Eww", "-o", "pid=,command=", "-p", pids.join(",")]);
|
|
69931
70066
|
} catch {
|
|
69932
70067
|
return rows;
|
|
69933
70068
|
}
|
|
@@ -69962,12 +70097,12 @@ function parseCpuTimeMs(value) {
|
|
|
69962
70097
|
const ms = ((Number(d ?? 0) * 24 + Number(h2 ?? 0)) * 3600 + Number(min) * 60 + Number(s)) * 1e3;
|
|
69963
70098
|
return Number.isFinite(ms) ? ms : 0;
|
|
69964
70099
|
}
|
|
69965
|
-
function detectRunawayAux(rows, liveSlugs, exec = defaultExec, options = {}) {
|
|
70100
|
+
async function detectRunawayAux(rows, liveSlugs, exec = defaultExec, options = {}) {
|
|
69966
70101
|
const minCores = options.minCores ?? 0.5;
|
|
69967
70102
|
const minAgeMs = options.minAgeMs ?? 30 * 6e4;
|
|
69968
70103
|
let text2;
|
|
69969
70104
|
try {
|
|
69970
|
-
text2 = exec("ps", ["-Ao", "pid=,cputime="]);
|
|
70105
|
+
text2 = await exec("ps", ["-Ao", "pid=,cputime="]);
|
|
69971
70106
|
} catch {
|
|
69972
70107
|
return [];
|
|
69973
70108
|
}
|
|
@@ -69994,13 +70129,13 @@ function summarizeRunaways(runaways) {
|
|
|
69994
70129
|
return `orphan-reaper: thread "${slug}" is holding ~${cores.toFixed(1)} core(s) across ${list.length} background process(es), oldest ${hours}h \u2014 frizz dispatched these but does not reap a LIVE thread's work`;
|
|
69995
70130
|
});
|
|
69996
70131
|
}
|
|
69997
|
-
function sweepOrphansOnce(deps = {}) {
|
|
70132
|
+
async function sweepOrphansOnce(deps = {}) {
|
|
69998
70133
|
const exec = deps.exec ?? defaultExec;
|
|
69999
70134
|
const selfPid = deps.selfPid ?? process.pid;
|
|
70000
70135
|
const minAgeMs = deps.minAgeMs ?? ORPHAN_MIN_AGE_MS;
|
|
70001
70136
|
let rows;
|
|
70002
70137
|
try {
|
|
70003
|
-
rows = enumerateProcs(exec, { platform: deps.platform, readEnv: deps.readEnv });
|
|
70138
|
+
rows = await enumerateProcs(exec, { platform: deps.platform, readEnv: deps.readEnv });
|
|
70004
70139
|
} catch (error) {
|
|
70005
70140
|
const code = error?.code;
|
|
70006
70141
|
return { reaped: 0, deadSlugs: [], liveSlugs: [], ...code === "ENOENT" ? { unavailable: "`ps` is not on PATH" } : {} };
|
|
@@ -70008,7 +70143,7 @@ function sweepOrphansOnce(deps = {}) {
|
|
|
70008
70143
|
const protectedPids = selfAndAncestors(rows, selfPid);
|
|
70009
70144
|
const { reap, liveSlugs } = decideOrphans(rows, { minAgeMs, protectedPids });
|
|
70010
70145
|
if (deps.log && deps.runawayReport !== false) {
|
|
70011
|
-
for (const line of summarizeRunaways(detectRunawayAux(rows, new Set(liveSlugs), exec, deps.runaway))) deps.log(line);
|
|
70146
|
+
for (const line of summarizeRunaways(await detectRunawayAux(rows, new Set(liveSlugs), exec, deps.runaway))) deps.log(line);
|
|
70012
70147
|
}
|
|
70013
70148
|
if (!reap.length) return { reaped: 0, deadSlugs: [], liveSlugs };
|
|
70014
70149
|
const bySlug = new Map(rows.map((r) => [r.pid, r.slug]));
|
|
@@ -70033,34 +70168,60 @@ function startOrphanReaper(deps = {}) {
|
|
|
70033
70168
|
};
|
|
70034
70169
|
}
|
|
70035
70170
|
const intervalMs = deps.intervalMs ?? ORPHAN_REAP_INTERVAL_MS;
|
|
70036
|
-
|
|
70037
|
-
|
|
70038
|
-
|
|
70039
|
-
|
|
70171
|
+
let stopped = false;
|
|
70172
|
+
let timer = null;
|
|
70173
|
+
let sweeping = false;
|
|
70174
|
+
const stopSweeps = () => {
|
|
70175
|
+
if (timer) clearInterval(timer);
|
|
70176
|
+
timer = null;
|
|
70040
70177
|
};
|
|
70041
|
-
|
|
70042
|
-
if (
|
|
70043
|
-
|
|
70044
|
-
} catch {
|
|
70045
|
-
}
|
|
70046
|
-
const timer = setInterval(() => {
|
|
70178
|
+
const sweep = async () => {
|
|
70179
|
+
if (sweeping || stopped) return;
|
|
70180
|
+
sweeping = true;
|
|
70047
70181
|
try {
|
|
70048
|
-
|
|
70182
|
+
const result = await sweepOrphansOnce(deps);
|
|
70183
|
+
if (result.unavailable && !stopped) {
|
|
70184
|
+
stopped = true;
|
|
70185
|
+
stopSweeps();
|
|
70186
|
+
deps.log?.(`orphan-reaper: unavailable on this machine \u2014 ${result.unavailable}; background processes a stopped thread leaves behind are not collected here`);
|
|
70187
|
+
}
|
|
70049
70188
|
} catch {
|
|
70189
|
+
} finally {
|
|
70190
|
+
sweeping = false;
|
|
70050
70191
|
}
|
|
70051
|
-
}
|
|
70052
|
-
|
|
70192
|
+
};
|
|
70193
|
+
void sweep().then(() => {
|
|
70194
|
+
if (stopped) return;
|
|
70195
|
+
timer = setInterval(() => void sweep(), intervalMs);
|
|
70196
|
+
timer.unref?.();
|
|
70197
|
+
});
|
|
70053
70198
|
const socketDelay = setTimeout(sweepStaleBrokerSockets, STALE_SOCKET_SWEEP_DELAY_MS);
|
|
70054
70199
|
socketDelay.unref?.();
|
|
70055
70200
|
const socketTimer = setInterval(sweepStaleBrokerSockets, STALE_SOCKET_SWEEP_INTERVAL_MS);
|
|
70056
70201
|
socketTimer.unref?.();
|
|
70057
70202
|
return () => {
|
|
70058
|
-
|
|
70203
|
+
stopped = true;
|
|
70204
|
+
stopSweeps();
|
|
70059
70205
|
clearTimeout(socketDelay);
|
|
70060
70206
|
clearInterval(socketTimer);
|
|
70061
70207
|
};
|
|
70062
70208
|
}
|
|
70063
|
-
|
|
70209
|
+
function acquireSharedOrphanReaper(deps = {}) {
|
|
70210
|
+
if (!shared) shared = { refs: 0, stop: startOrphanReaper(deps) };
|
|
70211
|
+
const handle = shared;
|
|
70212
|
+
handle.refs++;
|
|
70213
|
+
let released = false;
|
|
70214
|
+
return () => {
|
|
70215
|
+
if (released) return;
|
|
70216
|
+
released = true;
|
|
70217
|
+
handle.refs--;
|
|
70218
|
+
if (handle.refs === 0 && shared === handle) {
|
|
70219
|
+
shared = null;
|
|
70220
|
+
handle.stop();
|
|
70221
|
+
}
|
|
70222
|
+
};
|
|
70223
|
+
}
|
|
70224
|
+
var ORPHAN_REAP_INTERVAL_MS, ORPHAN_MIN_AGE_MS, SLUG_RE, execFileAsync6, defaultExec, defaultReadEnv, defaultKill2, STALE_SOCKET_SWEEP_INTERVAL_MS, STALE_SOCKET_SWEEP_DELAY_MS, CLAUDE_BROKER_SOCKET_PREFIX, UNAVAILABLE_ON_WINDOWS, shared;
|
|
70064
70225
|
var init_orphan_reaper = __esm({
|
|
70065
70226
|
"packages/server/src/orphan-reaper.ts"() {
|
|
70066
70227
|
"use strict";
|
|
@@ -70069,7 +70230,8 @@ var init_orphan_reaper = __esm({
|
|
|
70069
70230
|
ORPHAN_REAP_INTERVAL_MS = 6e4;
|
|
70070
70231
|
ORPHAN_MIN_AGE_MS = 12e4;
|
|
70071
70232
|
SLUG_RE = /FRIZZ_THREAD=([A-Za-z0-9._-]+)/;
|
|
70072
|
-
|
|
70233
|
+
execFileAsync6 = promisify8(execFile10);
|
|
70234
|
+
defaultExec = async (file, args) => (await execFileAsync6(file, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout;
|
|
70073
70235
|
defaultReadEnv = (pid) => {
|
|
70074
70236
|
try {
|
|
70075
70237
|
return readFileSync24(`/proc/${pid}/environ`, "utf8");
|
|
@@ -70087,6 +70249,7 @@ var init_orphan_reaper = __esm({
|
|
|
70087
70249
|
STALE_SOCKET_SWEEP_DELAY_MS = 3e4;
|
|
70088
70250
|
CLAUDE_BROKER_SOCKET_PREFIX = "frizz-claude-";
|
|
70089
70251
|
UNAVAILABLE_ON_WINDOWS = "orphan-reaper: unavailable on Windows \u2014 a worker's FRIZZ_THREAD is read from its process environment, which Windows does not expose; background processes a stopped thread leaves behind are not collected here, and a live thread's runaway work is not reported";
|
|
70252
|
+
shared = null;
|
|
70090
70253
|
}
|
|
70091
70254
|
});
|
|
70092
70255
|
|
|
@@ -70305,7 +70468,7 @@ function createContextUnchecked(opts, resources) {
|
|
|
70305
70468
|
contextUnsubscribers.push(() => clearInterval(quotaRefreshTimer));
|
|
70306
70469
|
}
|
|
70307
70470
|
if (!process.env.FRIZZ_ORPHAN_REAPER_OFF) {
|
|
70308
|
-
contextUnsubscribers.push(
|
|
70471
|
+
contextUnsubscribers.push(acquireSharedOrphanReaper({ log: (m) => log.info("reaper", m) }));
|
|
70309
70472
|
}
|
|
70310
70473
|
opts.startup?.afterPhase?.("orphan reaper");
|
|
70311
70474
|
reconcileSessions(storage);
|
|
@@ -73519,10 +73682,10 @@ var init_edited_files = __esm({
|
|
|
73519
73682
|
});
|
|
73520
73683
|
|
|
73521
73684
|
// packages/server/src/repo-files.ts
|
|
73522
|
-
import { execFileSync as
|
|
73685
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
73523
73686
|
import path2 from "node:path";
|
|
73524
73687
|
function git(args, cwd) {
|
|
73525
|
-
return
|
|
73688
|
+
return execFileSync4("git", args, {
|
|
73526
73689
|
cwd,
|
|
73527
73690
|
encoding: "utf8",
|
|
73528
73691
|
env: { ...process.env, LC_ALL: "C" },
|
|
@@ -73563,7 +73726,7 @@ function probeIgnored(projectDir, inside) {
|
|
|
73563
73726
|
return /* @__PURE__ */ new Set();
|
|
73564
73727
|
}
|
|
73565
73728
|
try {
|
|
73566
|
-
const out =
|
|
73729
|
+
const out = execFileSync4("git", ["check-ignore", "-z", "--stdin"], {
|
|
73567
73730
|
cwd: projectDir,
|
|
73568
73731
|
encoding: "utf8",
|
|
73569
73732
|
env: { ...process.env, LC_ALL: "C" },
|
|
@@ -73755,7 +73918,7 @@ var init_bash_background = __esm({
|
|
|
73755
73918
|
|
|
73756
73919
|
// packages/server/src/transcript.ts
|
|
73757
73920
|
import { closeSync as closeSync14, existsSync as existsSync17, fstatSync as fstatSync3, mkdirSync as mkdirSync18, openSync as openSync15, readdirSync as readdirSync11, readFileSync as readFileSync27, readSync as readSync8, renameSync as renameSync10, statSync as statSync17, unlinkSync as unlinkSync7, writeFileSync as writeFileSync12 } from "node:fs";
|
|
73758
|
-
import { createHash as
|
|
73921
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
73759
73922
|
import { StringDecoder as StringDecoder6 } from "node:string_decoder";
|
|
73760
73923
|
import { join as join39 } from "node:path";
|
|
73761
73924
|
import { homedir as homedir16 } from "node:os";
|
|
@@ -74394,7 +74557,7 @@ function persistDataUrlImage(dataUrl, idKey) {
|
|
|
74394
74557
|
function persistBase64Image(mediaType, data, idKey) {
|
|
74395
74558
|
const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
|
|
74396
74559
|
if (!ext || !data) return void 0;
|
|
74397
|
-
const name =
|
|
74560
|
+
const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
74398
74561
|
const path3 = join39(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
|
|
74399
74562
|
try {
|
|
74400
74563
|
if (existsSync17(path3)) return path3;
|
|
@@ -74416,7 +74579,7 @@ function persistSentFile(srcPath, idKey) {
|
|
|
74416
74579
|
if (!ATTACHMENT_IMAGE_EXTENSIONS.includes(ext)) return void 0;
|
|
74417
74580
|
const outExt = ext === "jpeg" ? "jpg" : ext;
|
|
74418
74581
|
try {
|
|
74419
|
-
const name =
|
|
74582
|
+
const name = createHash15("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
74420
74583
|
const dest = join39(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
|
|
74421
74584
|
if (existsSync17(dest)) return dest;
|
|
74422
74585
|
const size = statSync17(srcPath).size;
|
|
@@ -75230,7 +75393,7 @@ function latestTranscriptWindow(messages) {
|
|
|
75230
75393
|
);
|
|
75231
75394
|
if (tools.length === 0) continue;
|
|
75232
75395
|
pinned.push({
|
|
75233
|
-
sourceId: `pinned-bg:${
|
|
75396
|
+
sourceId: `pinned-bg:${createHash15("sha256").update(message.sourceId).digest("base64url").slice(0, 24)}`,
|
|
75234
75397
|
pinnedFromSourceId: message.sourceId,
|
|
75235
75398
|
role: "assistant",
|
|
75236
75399
|
text: "",
|
|
@@ -76026,7 +76189,7 @@ function fixedSnapshot(source) {
|
|
|
76026
76189
|
};
|
|
76027
76190
|
let allBytes;
|
|
76028
76191
|
const fileKey = `${before.dev}:${before.ino}:${Math.trunc(before.birthtimeMs)}`;
|
|
76029
|
-
const transcriptKey =
|
|
76192
|
+
const transcriptKey = createHash15("sha256").update(`${source.slug}\0${source.sessionId}\0${source.nativeId}\0${source.backend}\0${source.runtimeGeneration}\0${fileKey}`).digest("base64url").slice(0, 32);
|
|
76030
76193
|
let rawText;
|
|
76031
76194
|
return {
|
|
76032
76195
|
...source,
|
|
@@ -76059,7 +76222,7 @@ function projectSnapshot(snapshot) {
|
|
|
76059
76222
|
return retireStaleQueuedBubbles([...entry.fold.allMessages()]);
|
|
76060
76223
|
}
|
|
76061
76224
|
function digestPrefix(bytes, length = bytes.length) {
|
|
76062
|
-
return
|
|
76225
|
+
return createHash15("sha256").update(bytes.subarray(0, length)).digest("base64url");
|
|
76063
76226
|
}
|
|
76064
76227
|
function fullDigest(snapshot) {
|
|
76065
76228
|
const key = `${snapshot.fileKey}\0${snapshot.size}`;
|
|
@@ -76069,7 +76232,7 @@ function fullDigest(snapshot) {
|
|
|
76069
76232
|
fullDigestCache.set(key, hit);
|
|
76070
76233
|
return hit;
|
|
76071
76234
|
}
|
|
76072
|
-
const hash =
|
|
76235
|
+
const hash = createHash15("sha256");
|
|
76073
76236
|
for (let at2 = 0; at2 < snapshot.size; ) {
|
|
76074
76237
|
const buf = snapshot.readRange(at2, Math.min(TRANSCRIPT_DECODE_WINDOW, snapshot.size - at2));
|
|
76075
76238
|
if (buf.length === 0) break;
|
|
@@ -76152,7 +76315,7 @@ function emptyTranscriptPage(source) {
|
|
|
76152
76315
|
beforeCursor: null,
|
|
76153
76316
|
hasEarlier: false,
|
|
76154
76317
|
reachedTurnBoundary: true,
|
|
76155
|
-
transcriptKey:
|
|
76318
|
+
transcriptKey: createHash15("sha256").update(keySeed).digest("base64url").slice(0, 32),
|
|
76156
76319
|
editedFiles: []
|
|
76157
76320
|
};
|
|
76158
76321
|
}
|
|
@@ -76293,7 +76456,7 @@ function projectTranscriptPageAgentLifecycles(page, lookup, peerLookup) {
|
|
|
76293
76456
|
}
|
|
76294
76457
|
function readTranscriptFile(absPath) {
|
|
76295
76458
|
try {
|
|
76296
|
-
const pathKey =
|
|
76459
|
+
const pathKey = createHash15("sha256").update(absPath).digest("base64url").slice(0, 16);
|
|
76297
76460
|
return parseTranscript(readFileSync27(absPath, "utf8"), `claude-file:${pathKey}`);
|
|
76298
76461
|
} catch {
|
|
76299
76462
|
return [];
|
|
@@ -76694,8 +76857,8 @@ var init_github_hovercard = __esm({
|
|
|
76694
76857
|
});
|
|
76695
76858
|
|
|
76696
76859
|
// packages/server/src/backend/account-actions.ts
|
|
76697
|
-
import { execFile as
|
|
76698
|
-
import { promisify as
|
|
76860
|
+
import { execFile as execFile11 } from "node:child_process";
|
|
76861
|
+
import { promisify as promisify9 } from "node:util";
|
|
76699
76862
|
function liveThreadsForBackend(threads, backend) {
|
|
76700
76863
|
let count = 0;
|
|
76701
76864
|
for (const thread of threads) {
|
|
@@ -76715,7 +76878,7 @@ async function runProviderLogout(opts) {
|
|
|
76715
76878
|
const args = opts.backend === "codex" ? ["logout"] : ["auth", "logout"];
|
|
76716
76879
|
let failure;
|
|
76717
76880
|
try {
|
|
76718
|
-
await
|
|
76881
|
+
await execFileAsync7(bin, args, { encoding: "utf8", timeout: opts.timeoutMs ?? 15e3 });
|
|
76719
76882
|
} catch (err) {
|
|
76720
76883
|
const e14 = err;
|
|
76721
76884
|
const stderr = typeof e14.stderr === "string" ? e14.stderr.trim() : "";
|
|
@@ -76725,12 +76888,12 @@ async function runProviderLogout(opts) {
|
|
|
76725
76888
|
if (failure && auth !== "signed-out") return { status: "failed", detail: failure, auth };
|
|
76726
76889
|
return { status: "done", auth };
|
|
76727
76890
|
}
|
|
76728
|
-
var
|
|
76891
|
+
var execFileAsync7, LIVE_RUNTIMES;
|
|
76729
76892
|
var init_account_actions = __esm({
|
|
76730
76893
|
"packages/server/src/backend/account-actions.ts"() {
|
|
76731
76894
|
"use strict";
|
|
76732
76895
|
init_auth_status();
|
|
76733
|
-
|
|
76896
|
+
execFileAsync7 = promisify9(execFile11);
|
|
76734
76897
|
LIVE_RUNTIMES = /* @__PURE__ */ new Set(["spawning", "running", "perm-prompt"]);
|
|
76735
76898
|
}
|
|
76736
76899
|
});
|
|
@@ -77005,8 +77168,8 @@ var init_image_header = __esm({
|
|
|
77005
77168
|
});
|
|
77006
77169
|
|
|
77007
77170
|
// packages/server/src/directory-picker.ts
|
|
77008
|
-
import { execFile as
|
|
77009
|
-
import { promisify as
|
|
77171
|
+
import { execFile as execFile12 } from "node:child_process";
|
|
77172
|
+
import { promisify as promisify10 } from "node:util";
|
|
77010
77173
|
async function pickImageFile(startIn, prompt = "Choose an image for this project", platform3 = process.platform) {
|
|
77011
77174
|
if (platform3 === "darwin") {
|
|
77012
77175
|
const location = startIn ? ` default location POSIX file ${JSON.stringify(startIn)}` : "";
|
|
@@ -77116,7 +77279,7 @@ var run2, PICKER_TIMEOUT_MS, timedOut, unanswered, OSASCRIPT, WINDOWS_PICKER_EDI
|
|
|
77116
77279
|
var init_directory_picker = __esm({
|
|
77117
77280
|
"packages/server/src/directory-picker.ts"() {
|
|
77118
77281
|
"use strict";
|
|
77119
|
-
run2 =
|
|
77282
|
+
run2 = promisify10(execFile12);
|
|
77120
77283
|
PICKER_TIMEOUT_MS = 5 * 6e4;
|
|
77121
77284
|
timedOut = (error) => error.killed === true;
|
|
77122
77285
|
unanswered = (what) => ({
|
|
@@ -78680,6 +78843,7 @@ ${gapNote}` : input.message;
|
|
|
78680
78843
|
fireAtMs: Date.parse(input.fireAt),
|
|
78681
78844
|
createdAtMs: Date.now()
|
|
78682
78845
|
});
|
|
78846
|
+
ctx.board.refresh();
|
|
78683
78847
|
return { id, fireAt: input.fireAt, timers: armedTimerViews(input.slug) };
|
|
78684
78848
|
}
|
|
78685
78849
|
}),
|
|
@@ -78688,6 +78852,7 @@ ${gapNote}` : input.message;
|
|
|
78688
78852
|
output: CancelOwnThreadTimerResult,
|
|
78689
78853
|
handler: async ({ input }) => {
|
|
78690
78854
|
const cancelled = ctx.storage.cancelThreadTimer(input.slug, input.id, Date.now());
|
|
78855
|
+
if (cancelled) ctx.board.refresh();
|
|
78691
78856
|
return { cancelled, timers: armedTimerViews(input.slug) };
|
|
78692
78857
|
}
|
|
78693
78858
|
}),
|
|
@@ -78811,7 +78976,8 @@ ${gapNote}` : input.message;
|
|
|
78811
78976
|
throw new Error(`\`${input.target}\` is not ${kind === "issue" ? "an issue" : "a pull request"} I can watch \u2014 give owner/repo#123 or ${kind === "issue" ? "an issue" : "a PR"} URL`);
|
|
78812
78977
|
}
|
|
78813
78978
|
const armed = ctx.storage.listPrWatches(input.slug, { armedOnly: true });
|
|
78814
|
-
const
|
|
78979
|
+
const sameName = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
78980
|
+
const existing = armed.find((w) => w.kind === kind && sameName(w.owner, ref.owner) && sameName(w.repo, ref.repo) && w.number === ref.number);
|
|
78815
78981
|
const target = `${ref.owner}/${ref.repo}#${ref.number}`;
|
|
78816
78982
|
if (existing) {
|
|
78817
78983
|
const expiresAt = new Date(existing.expires_at ?? Date.now()).toISOString();
|
|
@@ -80645,7 +80811,7 @@ var init_app = __esm({
|
|
|
80645
80811
|
});
|
|
80646
80812
|
|
|
80647
80813
|
// packages/server/src/app-socket.ts
|
|
80648
|
-
import { createHash as
|
|
80814
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
80649
80815
|
function isWsPath(url) {
|
|
80650
80816
|
return (url ?? "").split("?")[0] === WS_PATH;
|
|
80651
80817
|
}
|
|
@@ -80849,7 +81015,7 @@ function createAppSocketServer(deps) {
|
|
|
80849
81015
|
sendEncoded(ws, frame, false);
|
|
80850
81016
|
}
|
|
80851
81017
|
function frameSignature(frame) {
|
|
80852
|
-
return
|
|
81018
|
+
return createHash16("sha256").update(frame.text).digest("base64url");
|
|
80853
81019
|
}
|
|
80854
81020
|
const globalReadTimes = [];
|
|
80855
81021
|
const originReadTimes = /* @__PURE__ */ new Map();
|
|
@@ -81697,7 +81863,7 @@ var init_runtime_lease = __esm({
|
|
|
81697
81863
|
});
|
|
81698
81864
|
|
|
81699
81865
|
// packages/server/src/runtimes.ts
|
|
81700
|
-
import { createHash as
|
|
81866
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
81701
81867
|
import {
|
|
81702
81868
|
chmodSync,
|
|
81703
81869
|
closeSync as closeSync17,
|
|
@@ -81811,7 +81977,7 @@ async function provisionRuntime(backend, options) {
|
|
|
81811
81977
|
const response = await fetchImpl(tarball);
|
|
81812
81978
|
if (!response.ok || !response.body) throw new Error(`tarball download answered ${response.status}`);
|
|
81813
81979
|
const total = Number(response.headers.get("content-length") ?? 0);
|
|
81814
|
-
const hash =
|
|
81980
|
+
const hash = createHash17("sha512");
|
|
81815
81981
|
let seen = 0;
|
|
81816
81982
|
let lastReport = 0;
|
|
81817
81983
|
const hasher = new Transform({
|