frizz 0.8.1 → 0.10.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/README.md +3 -2
- package/dist/claude-agent-broker.js +156 -13
- package/dist/dev-child.js +4603 -1769
- package/dist/frizz.js +684 -263
- package/package.json +1 -1
- package/runtime/board/config.mjs +12 -1
- package/runtime/board/index.mjs +5 -0
- package/runtime/board/thread-update.mjs +4 -0
- package/runtime/cc-worker/.claude-plugin/plugin.json +1 -1
- package/runtime/cc-worker/DECISIONS.md +18 -0
- package/runtime/cc-worker/bin/frizz-mcp.mjs +604 -55
- package/runtime/cc-worker/hooks/scratchpad.mjs +20 -24
- package/runtime/cc-worker/hooks/session-seed.mjs +2 -2
- package/runtime/cc-worker/skills/gh/scripts/github-watch.mjs +1 -1
- package/web-dist/assets/{TerminalPane-BM_laA_I.js → TerminalPane-XNji7D_c.js} +1 -1
- package/web-dist/assets/{abnfDiagram-VRR7QNED-C5FCLi1n.js → abnfDiagram-VRR7QNED-gPeb-B7g.js} +1 -1
- package/web-dist/assets/architecture-TIHT7OUA-BsgSgexh.js +1 -0
- package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-Dm7tUnwt.js → architectureDiagram-ZJ3FMSHR-DV69ktbl.js} +1 -1
- package/web-dist/assets/{blockDiagram-677ZJIJ3-3EhpmwKM.js → blockDiagram-677ZJIJ3-D8vw5eim.js} +1 -1
- package/web-dist/assets/{c4Diagram-LMCZKHZV-Ca-BjDxw.js → c4Diagram-LMCZKHZV--9PLGn-L.js} +1 -1
- package/web-dist/assets/channel-ClLnncxh.js +1 -0
- package/web-dist/assets/{chunk-32BRIVSS-xGbaUlTN.js → chunk-32BRIVSS-D4BSk0FZ.js} +1 -1
- package/web-dist/assets/{chunk-52WLFC77-YYhE3F1a.js → chunk-52WLFC77-WNcmTkcR.js} +1 -1
- package/web-dist/assets/{chunk-C7G6YPKG-SYKXFtUg.js → chunk-C7G6YPKG-BDlcLa5W.js} +1 -1
- package/web-dist/assets/{chunk-EX3LRPZG-cqjtdM_c.js → chunk-EX3LRPZG-CFnqFt7s.js} +1 -1
- package/web-dist/assets/{chunk-FWX5IMBZ-qyaTngKT.js → chunk-FWX5IMBZ-Ci9LgOOg.js} +2 -2
- package/web-dist/assets/{chunk-HOUHSVGY-DBFt1HnE.js → chunk-HOUHSVGY-BTD_X5OP.js} +1 -1
- package/web-dist/assets/{chunk-ICXQ74PX-Bme_2_gm.js → chunk-ICXQ74PX-D2Y3Ys5K.js} +1 -1
- package/web-dist/assets/{chunk-MOJQB5TN-DupTmWhN.js → chunk-MOJQB5TN-C-GDt7vC.js} +1 -1
- package/web-dist/assets/{chunk-OGEWGWER-DSqmbKCq.js → chunk-OGEWGWER-DvnPoUnz.js} +1 -1
- package/web-dist/assets/{chunk-PUDLZKDR-DVnHUoFN.js → chunk-PUDLZKDR-C3AymM-j.js} +1 -1
- package/web-dist/assets/{chunk-Q4XR5HBZ-BIZh_Yuh.js → chunk-Q4XR5HBZ-DmyBNAl6.js} +1 -1
- package/web-dist/assets/{chunk-V7JOEXUC-e2G7UgOg.js → chunk-V7JOEXUC-DTuPUeRa.js} +1 -1
- package/web-dist/assets/{chunk-VAUOI2AC-uYgyYWPh.js → chunk-VAUOI2AC-CcW8PviB.js} +1 -1
- package/web-dist/assets/{chunk-VR4S4FIN-BjGjcexQ.js → chunk-VR4S4FIN-0tm6n83G.js} +1 -1
- package/web-dist/assets/{chunk-WYO6CB5R-BKKd_W3B.js → chunk-WYO6CB5R-CH3ADqeI.js} +1 -1
- package/web-dist/assets/{chunk-ZGVPDNZ5-D5_hsjnF.js → chunk-ZGVPDNZ5-BHFnlpXH.js} +1 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-CwLnPgud.js +1 -0
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-CwLnPgud.js +1 -0
- package/web-dist/assets/{cynefin-VYW2F7L2-bkFv7EpV.js → cynefin-VYW2F7L2-DtFCLOIN.js} +1 -1
- package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Du2-dyuZ.js → cynefinDiagram-TSTJHNR4-llFTHp2q.js} +1 -1
- package/web-dist/assets/{dagre-VKFMJZFB-CU7w00Ul.js → dagre-VKFMJZFB-CvBRVl_k.js} +1 -1
- package/web-dist/assets/{diagram-FQU43EPY-BxvVgxWb.js → diagram-FQU43EPY-D1QXo6ri.js} +1 -1
- package/web-dist/assets/{diagram-G47NLZAW-D8VvetwQ.js → diagram-G47NLZAW-2pZew-Bk.js} +1 -1
- package/web-dist/assets/{diagram-NH7WQ7WH-CwsChkED.js → diagram-NH7WQ7WH-Ch9JRwGN.js} +1 -1
- package/web-dist/assets/{diagram-OA4YK3LP-BIPYbe6L.js → diagram-OA4YK3LP-BIbrLf02.js} +1 -1
- package/web-dist/assets/{diagram-WEI45ONY-BoyH4dKl.js → diagram-WEI45ONY-D3KtL2s-.js} +1 -1
- package/web-dist/assets/{ebnfDiagram-CCIWWBDH-9A3WRDfU.js → ebnfDiagram-CCIWWBDH-D829sKG_.js} +1 -1
- package/web-dist/assets/{erDiagram-Q63AITRT-D3Y9WA4H.js → erDiagram-Q63AITRT-Cj3Grovg.js} +1 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-CzZyv3HA.js +1 -0
- package/web-dist/assets/flowDiagram-23GEKE2U-rQ7PRoGL.js +1 -0
- package/web-dist/assets/{ganttDiagram-NO4QXBWP-Bk2-LClm.js → ganttDiagram-NO4QXBWP-CGHaXF-g.js} +1 -1
- package/web-dist/assets/{gitGraph-TEB2WS4Q-CXvPrsio.js → gitGraph-TEB2WS4Q-BbxeaotX.js} +1 -1
- package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-BC9D72kT.js → gitGraphDiagram-IHSO6WYX-C4WHE0cI.js} +1 -1
- package/web-dist/assets/index-BpCFdr7Z.css +1 -0
- package/web-dist/assets/index-CiaKj-0V.js +506 -0
- package/web-dist/assets/{info-DKCQHKI2-Beag76kE.js → info-DKCQHKI2-3fKpn7Qr.js} +1 -1
- package/web-dist/assets/{infoDiagram-FWYZ7A6U-DaqYXHYB.js → infoDiagram-FWYZ7A6U-CDQl4JMv.js} +1 -1
- package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-D-d4tmLU.js → ishikawaDiagram-FXEZZL3T-CDKjMW-u.js} +1 -1
- package/web-dist/assets/{journeyDiagram-5HDEW3XC-kkFYzNg1.js → journeyDiagram-5HDEW3XC-BOsabu1Z.js} +1 -1
- package/web-dist/assets/{kanban-definition-HUTT4EX6-BYRPjbfv.js → kanban-definition-HUTT4EX6-KTuh-6eN.js} +1 -1
- package/web-dist/assets/{line-C8l7y6rG.js → line-KaxbYSN3.js} +1 -1
- package/web-dist/assets/{mermaid-parser.core-BG3fgy77.js → mermaid-parser.core-B53huyyd.js} +3 -3
- package/web-dist/assets/{mermaid.core-BCDzcbhr.js → mermaid.core-Bz6B5ouC.js} +3 -3
- package/web-dist/assets/{mindmap-definition-LN4V7U3C-CP_bgQm8.js → mindmap-definition-LN4V7U3C-Bb7T7B3a.js} +1 -1
- package/web-dist/assets/{packet-7NZHBO7P-Dgd69pFS.js → packet-7NZHBO7P-w3lynC8r.js} +1 -1
- package/web-dist/assets/{pegDiagram-2B236MQR-BJUb_DOD.js → pegDiagram-2B236MQR-nQ7c2Z03.js} +1 -1
- package/web-dist/assets/{pie-RZYD4A2V-DPbVRAuL.js → pie-RZYD4A2V-B3Yko5Wb.js} +1 -1
- package/web-dist/assets/{pieDiagram-ENE6RG2P-DavUeOqM.js → pieDiagram-ENE6RG2P-CN4Lp5HG.js} +1 -1
- package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-BdvoSedu.js → quadrantDiagram-ABIIQ3AL-3QTB92dH.js} +1 -1
- package/web-dist/assets/{radar-I7S5WNFK-C2TAta9K.js → radar-I7S5WNFK-8ZsXt0FI.js} +1 -1
- package/web-dist/assets/{railroad-3IZDKUUU-DEMjzYqC.js → railroad-3IZDKUUU-C4IKxzEZ.js} +1 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-g2si5iUv.js +1 -0
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-BikkLG6y.js +1 -0
- package/web-dist/assets/railroad-peg-LSFZ7HO6-Dv4rDehz.js +1 -0
- package/web-dist/assets/{railroadDiagram-RFXS5EU6-C4rERo6H.js → railroadDiagram-RFXS5EU6-DrGnmjpD.js} +1 -1
- package/web-dist/assets/{requirementDiagram-TGXJPOKE-DlIG9D0n.js → requirementDiagram-TGXJPOKE-Bh9XNuxa.js} +1 -1
- package/web-dist/assets/{sankeyDiagram-HTMAVEWB-DVMrG-qY.js → sankeyDiagram-HTMAVEWB-CXy3ra5-.js} +1 -1
- package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DDcDM_-e.js → sequenceDiagram-DBY2YBRQ-B7ESCT52.js} +1 -1
- package/web-dist/assets/{stateDiagram-2N3HPSRC-DuCRKU5t.js → stateDiagram-2N3HPSRC-DFr9k5Xv.js} +1 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BQUd0MEa.js +1 -0
- package/web-dist/assets/{swimlanes-5IMT3BWC-CY0fdvUm.js → swimlanes-5IMT3BWC-B2RKoz1q.js} +1 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-GWn4zXxj.js +8 -0
- package/web-dist/assets/{timeline-definition-FHXFAJF6-De0fDNdU.js → timeline-definition-FHXFAJF6-KpTqaG5g.js} +1 -1
- package/web-dist/assets/{treeView-QDETBFTQ-AIoMhcen.js → treeView-QDETBFTQ-oB1a6ikv.js} +1 -1
- package/web-dist/assets/{treemap-6X3UGDF4-CPZ1Ln05.js → treemap-6X3UGDF4-DO8OvvZg.js} +1 -1
- package/web-dist/assets/{vennDiagram-L72KCM5P-FrSO6pmh.js → vennDiagram-L72KCM5P-BgTjK4_q.js} +1 -1
- package/web-dist/assets/{wardley-OPB4EBWU-BbET6cjs.js → wardley-OPB4EBWU-CGyjn939.js} +1 -1
- package/web-dist/assets/{wardleyDiagram-EHGQE667-DqvcCBjr.js → wardleyDiagram-EHGQE667-CM_HxruS.js} +1 -1
- package/web-dist/assets/{xychartDiagram-FW5EYKEG-91xKEO07.js → xychartDiagram-FW5EYKEG-vamHu0jN.js} +1 -1
- package/web-dist/index.html +2 -2
- package/web-dist/assets/architecture-TIHT7OUA-ngY1F0r2.js +0 -1
- package/web-dist/assets/channel-BpyNaJoi.js +0 -1
- package/web-dist/assets/classDiagram-OUVF2IWQ-DTEWwxt7.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-DTEWwxt7.js +0 -1
- package/web-dist/assets/eventmodeling-45OFAUF4-D7g9kDF0.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-BqKnxVr3.js +0 -1
- package/web-dist/assets/index-CCtNIGi6.js +0 -491
- package/web-dist/assets/index-Cq79m8AR.css +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-_4FByoRI.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-DKAvMIMu.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-CkJl3c69.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-90dqEQum.js +0 -1
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-BETWueIt.js +0 -8
package/README.md
CHANGED
|
@@ -151,7 +151,8 @@ Options:
|
|
|
151
151
|
|
|
152
152
|
|
|
153
153
|
To reach the board from a phone or another machine, press R in the terminal running it: a short
|
|
154
|
-
walkthrough sets up a frizz.sh name
|
|
154
|
+
walkthrough sets up a private frizz.sh name (no account needed), a custom one, a Cloudflare
|
|
155
|
+
Tunnel, Tailscale, or a proxy of your own, and
|
|
155
156
|
remembers the choice, so a plain launch serves it from then on. The board stays on loopback and
|
|
156
157
|
shows a single-use sign-in link as a QR; press L for a fresh one, or run --link from another shell.
|
|
157
158
|
```
|
|
@@ -216,7 +217,7 @@ shows a single-use sign-in link as a QR; press L for a fresh one, or run --link
|
|
|
216
217
|
<details>
|
|
217
218
|
<summary><b>Can I reach it from anywhere, not just my LAN?</b></summary>
|
|
218
219
|
|
|
219
|
-
> Same answer: press **R** and pick a frizz.sh name, a Cloudflare Tunnel, or Tailscale. Each is reachable from anywhere the transport is — a frizz.sh name and a Cloudflare Tunnel from the open internet, Tailscale from your own devices.
|
|
220
|
+
> Same answer: press **R** and pick a private frizz.sh name (unguessable, no account), a custom frizz.sh name, a Cloudflare Tunnel, or Tailscale. Each is reachable from anywhere the transport is — a frizz.sh name and a Cloudflare Tunnel from the open internet, Tailscale from your own devices.
|
|
220
221
|
>
|
|
221
222
|
> Frizz has no accounts, so the single-use sign-in link **is** the door: a phone that scans it gets a session; nobody else gets in. Sessions are per device and can be listed and revoked with `npx frizz --sessions` and `npx frizz --sign-out`.
|
|
222
223
|
|
|
@@ -2,7 +2,7 @@ import { createRequire as __frizzCreateRequire } from "node:module"; const requi
|
|
|
2
2
|
|
|
3
3
|
// packages/server/src/backend/claude-agent-broker.ts
|
|
4
4
|
import net from "node:net";
|
|
5
|
-
import { readFileSync as
|
|
5
|
+
import { readFileSync as readFileSync4, realpathSync as realpathSync2, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
|
|
@@ -20714,10 +20714,12 @@ function startClaudeQuery(executablePath, options) {
|
|
|
20714
20714
|
// broker session gets the frizz sub-agent profiles + hooks, mount the frizz MCP server, and
|
|
20715
20715
|
// pre-approve it. EMPTY is skipped, not passed: since frizz stopped mounting a browser (2026-08-26)
|
|
20716
20716
|
// a resolved-nothing worker env is a real state, and `{}`/`[]` are truthy — handing the SDK an
|
|
20717
|
-
// empty allowlist is not the same as handing it none. The project's own `.mcp.json` servers
|
|
20718
|
-
//
|
|
20717
|
+
// empty allowlist is not the same as handing it none. The project's own `.mcp.json` servers arrive
|
|
20718
|
+
// INSIDE `mcpServers` — the broker daemon merges them (project-mcp-servers.ts) — because
|
|
20719
|
+
// `strictMcpConfig` stops the CLI discovering any MCP scope by itself.
|
|
20719
20720
|
...options.pluginDir ? { plugins: [{ type: "local", path: options.pluginDir }] } : {},
|
|
20720
20721
|
...options.mcpServers && Object.keys(options.mcpServers).length > 0 ? { mcpServers: options.mcpServers } : {},
|
|
20722
|
+
...options.strictMcpConfig ? { strictMcpConfig: true } : {},
|
|
20721
20723
|
...options.allowedTools?.length ? { allowedTools: options.allowedTools } : {},
|
|
20722
20724
|
...options.disallowedTools?.length ? { disallowedTools: [...options.disallowedTools] } : {},
|
|
20723
20725
|
persistSession: options.persistSession ?? false,
|
|
@@ -21502,13 +21504,151 @@ function objectValue(value, label) {
|
|
|
21502
21504
|
return value;
|
|
21503
21505
|
}
|
|
21504
21506
|
|
|
21505
|
-
// packages/server/src/backend/
|
|
21506
|
-
import {
|
|
21507
|
+
// packages/server/src/backend/project-mcp-servers.ts
|
|
21508
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
21509
|
+
import { homedir } from "node:os";
|
|
21507
21510
|
import { join } from "node:path";
|
|
21511
|
+
function readJsonObject(path) {
|
|
21512
|
+
try {
|
|
21513
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
21514
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
21515
|
+
} catch {
|
|
21516
|
+
return void 0;
|
|
21517
|
+
}
|
|
21518
|
+
}
|
|
21519
|
+
function objectField(source, key) {
|
|
21520
|
+
const value = source?.[key];
|
|
21521
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
21522
|
+
}
|
|
21523
|
+
function stringList(source, key) {
|
|
21524
|
+
const value = source?.[key];
|
|
21525
|
+
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
21526
|
+
}
|
|
21527
|
+
function stringMap(value) {
|
|
21528
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
21529
|
+
const out = {};
|
|
21530
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
21531
|
+
if (typeof entry === "string") out[key] = entry;
|
|
21532
|
+
}
|
|
21533
|
+
return out;
|
|
21534
|
+
}
|
|
21535
|
+
var ENV_REF = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
|
|
21536
|
+
function expandMcpEnvRefs(value, env) {
|
|
21537
|
+
let unresolved = false;
|
|
21538
|
+
const out = value.replace(ENV_REF, (_match, name, fallback) => {
|
|
21539
|
+
const resolved = env[name];
|
|
21540
|
+
if (resolved !== void 0) return resolved;
|
|
21541
|
+
if (fallback !== void 0) return fallback;
|
|
21542
|
+
unresolved = true;
|
|
21543
|
+
return "";
|
|
21544
|
+
});
|
|
21545
|
+
return unresolved ? void 0 : out;
|
|
21546
|
+
}
|
|
21547
|
+
function expandMap(map, env) {
|
|
21548
|
+
if (!map) return void 0;
|
|
21549
|
+
const out = {};
|
|
21550
|
+
for (const [key, value] of Object.entries(map)) {
|
|
21551
|
+
const expanded = expandMcpEnvRefs(value, env);
|
|
21552
|
+
if (expanded === void 0) return null;
|
|
21553
|
+
out[key] = expanded;
|
|
21554
|
+
}
|
|
21555
|
+
return out;
|
|
21556
|
+
}
|
|
21557
|
+
function normalizeMcpServer(raw, env) {
|
|
21558
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
21559
|
+
const record = raw;
|
|
21560
|
+
const type = typeof record.type === "string" ? record.type : void 0;
|
|
21561
|
+
if (type === "http" || type === "sse") {
|
|
21562
|
+
if (typeof record.url !== "string") return void 0;
|
|
21563
|
+
const url = expandMcpEnvRefs(record.url, env);
|
|
21564
|
+
const headers = expandMap(stringMap(record.headers), env);
|
|
21565
|
+
if (url === void 0 || headers === null) return void 0;
|
|
21566
|
+
return { type, url, ...headers ? { headers } : {} };
|
|
21567
|
+
}
|
|
21568
|
+
if (type !== void 0 && type !== "stdio") return void 0;
|
|
21569
|
+
if (typeof record.command !== "string") return void 0;
|
|
21570
|
+
const command = expandMcpEnvRefs(record.command, env);
|
|
21571
|
+
if (command === void 0) return void 0;
|
|
21572
|
+
const args = [];
|
|
21573
|
+
for (const entry of Array.isArray(record.args) ? record.args : []) {
|
|
21574
|
+
if (typeof entry !== "string") return void 0;
|
|
21575
|
+
const expanded = expandMcpEnvRefs(entry, env);
|
|
21576
|
+
if (expanded === void 0) return void 0;
|
|
21577
|
+
args.push(expanded);
|
|
21578
|
+
}
|
|
21579
|
+
const serverEnv = expandMap(stringMap(record.env), env);
|
|
21580
|
+
if (serverEnv === null) return void 0;
|
|
21581
|
+
return { command, ...args.length ? { args } : {}, ...serverEnv ? { env: serverEnv } : {} };
|
|
21582
|
+
}
|
|
21583
|
+
function collectApproval(layers) {
|
|
21584
|
+
const approval = { all: false, enabled: /* @__PURE__ */ new Set(), disabled: /* @__PURE__ */ new Set() };
|
|
21585
|
+
for (const layer of layers) {
|
|
21586
|
+
if (layer?.enableAllProjectMcpServers === true) approval.all = true;
|
|
21587
|
+
for (const name of stringList(layer, "enabledMcpjsonServers")) approval.enabled.add(name);
|
|
21588
|
+
for (const name of stringList(layer, "disabledMcpjsonServers")) approval.disabled.add(name);
|
|
21589
|
+
}
|
|
21590
|
+
return approval;
|
|
21591
|
+
}
|
|
21592
|
+
function userScopeRemoteServers(account, cwd, env) {
|
|
21593
|
+
const out = {};
|
|
21594
|
+
const maps = [objectField(account, "mcpServers"), objectField(objectField(objectField(account, "projects"), cwd), "mcpServers")];
|
|
21595
|
+
for (const map of maps) {
|
|
21596
|
+
for (const [name, raw] of Object.entries(map ?? {})) {
|
|
21597
|
+
const server = normalizeMcpServer(raw, env);
|
|
21598
|
+
if (server && server.type !== void 0 && server.type !== "stdio") out[name] = server;
|
|
21599
|
+
}
|
|
21600
|
+
}
|
|
21601
|
+
return out;
|
|
21602
|
+
}
|
|
21603
|
+
function projectMcpServers(cwd, options = {}) {
|
|
21604
|
+
const env = options.env ?? process.env;
|
|
21605
|
+
const home = options.home ?? homedir();
|
|
21606
|
+
const configOverride = options.claudeConfigDir ?? (env.CLAUDE_CONFIG_DIR?.trim() ? env.CLAUDE_CONFIG_DIR.trim() : void 0);
|
|
21607
|
+
const accountFile = configOverride ? join(configOverride, ".claude.json") : join(home, ".claude.json");
|
|
21608
|
+
const userSettingsFile = join(configOverride ?? join(home, ".claude"), "settings.json");
|
|
21609
|
+
const account = readJsonObject(accountFile);
|
|
21610
|
+
const out = userScopeRemoteServers(account, cwd, env);
|
|
21611
|
+
const declared = objectField(readJsonObject(join(cwd, ".mcp.json")), "mcpServers");
|
|
21612
|
+
if (!declared) return out;
|
|
21613
|
+
const approval = collectApproval([
|
|
21614
|
+
readJsonObject(join(cwd, ".claude", "settings.json")),
|
|
21615
|
+
readJsonObject(join(cwd, ".claude", "settings.local.json")),
|
|
21616
|
+
readJsonObject(userSettingsFile),
|
|
21617
|
+
objectField(objectField(account, "projects"), cwd)
|
|
21618
|
+
]);
|
|
21619
|
+
for (const [name, raw] of Object.entries(declared)) {
|
|
21620
|
+
if (approval.disabled.has(name)) continue;
|
|
21621
|
+
if (!approval.all && !approval.enabled.has(name)) continue;
|
|
21622
|
+
const server = normalizeMcpServer(raw, env);
|
|
21623
|
+
if (server) out[name] = server;
|
|
21624
|
+
}
|
|
21625
|
+
return out;
|
|
21626
|
+
}
|
|
21627
|
+
function workerMcpServers(project, frizz) {
|
|
21628
|
+
return { ...project ?? {}, ...frizz ?? {} };
|
|
21629
|
+
}
|
|
21630
|
+
|
|
21631
|
+
// packages/server/src/backend/types.ts
|
|
21632
|
+
var CLAUDE_WORKER_ENV = {
|
|
21633
|
+
CLAUDE_CODE_TOTAL_TOKENS_REMINDER: "infinite",
|
|
21634
|
+
BASH_DEFAULT_TIMEOUT_MS: "60000",
|
|
21635
|
+
BASH_MAX_TIMEOUT_MS: String(24 * 60 * 60 * 1e3)
|
|
21636
|
+
};
|
|
21637
|
+
var CLAUDE_AUTO_COMPACT_WINDOW_ENV = "CLAUDE_CODE_AUTO_COMPACT_WINDOW";
|
|
21638
|
+
function claudeCompactionWindowOf(env) {
|
|
21639
|
+
const raw = env?.[CLAUDE_AUTO_COMPACT_WINDOW_ENV];
|
|
21640
|
+
if (raw === void 0) return void 0;
|
|
21641
|
+
const window2 = Number(raw);
|
|
21642
|
+
return Number.isInteger(window2) && window2 > 0 ? window2 : void 0;
|
|
21643
|
+
}
|
|
21644
|
+
|
|
21645
|
+
// packages/server/src/backend/claude-broker-diagnostics.ts
|
|
21646
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync as renameSync2, statSync as statSync2 } from "node:fs";
|
|
21647
|
+
import { join as join2 } from "node:path";
|
|
21508
21648
|
var MAX_BYTES = 4 * 1024 * 1024;
|
|
21509
21649
|
function appendRecord(path, record) {
|
|
21510
21650
|
try {
|
|
21511
|
-
mkdirSync2(
|
|
21651
|
+
mkdirSync2(join2(path, ".."), { recursive: true });
|
|
21512
21652
|
try {
|
|
21513
21653
|
if (statSync2(path).size > MAX_BYTES) renameSync2(path, `${path}.1`);
|
|
21514
21654
|
} catch {
|
|
@@ -21570,21 +21710,24 @@ function runClaudeBroker(config) {
|
|
|
21570
21710
|
const writeDiagnostic = config.diagnosticLogPath ? createClaudeBrokerDiagnosticWriter(config.diagnosticLogPath, { daemonPid: process.pid, generation }) : void 0;
|
|
21571
21711
|
const writeExit = config.diagnosticLogPath ? createClaudeBrokerExitWriter(config.diagnosticLogPath, { daemonPid: process.pid, generation }) : void 0;
|
|
21572
21712
|
const factory = createClaudeQueryFactory({ enabled: true, executablePath: config.executablePath });
|
|
21713
|
+
const env = { ...inheritWorkerEnvironment(config.env), ...config.workerEnv ?? {} };
|
|
21573
21714
|
const handle = factory.start({
|
|
21574
21715
|
cwd: config.cwd,
|
|
21575
21716
|
session: config.resume ? { kind: "resume", sessionId: config.sessionId } : { kind: "new", sessionId: config.sessionId },
|
|
21576
21717
|
permissionMode: config.permissionMode ?? "default",
|
|
21577
|
-
|
|
21578
|
-
// frizz worker vars it DOES need (FRIZZ_THREAD, FRIZZ_PERM_DIR) ride workerEnv and are merged on
|
|
21579
|
-
// top — which is also what gives them THIS thread's values instead of the server's.
|
|
21580
|
-
env: { ...inheritWorkerEnvironment(config.env), ...config.workerEnv ?? {} },
|
|
21718
|
+
env,
|
|
21581
21719
|
persistSession: true,
|
|
21582
21720
|
// write the tailer-readable transcript JSONL
|
|
21583
21721
|
appendSystemPrompt: config.appendSystemPrompt,
|
|
21584
21722
|
model: config.model,
|
|
21585
21723
|
effort: config.effort,
|
|
21586
21724
|
pluginDir: config.pluginDir,
|
|
21587
|
-
|
|
21725
|
+
// The WHOLE MCP surface of this thread, and STRICT so the CLI discovers nothing else: the project's
|
|
21726
|
+
// approved `.mcp.json` (and the operator's remote user-scope servers) under the frizz mount, which
|
|
21727
|
+
// wins a name collision. Read at every fork, not once per project, so a `.mcp.json` edit reaches the
|
|
21728
|
+
// next dispatch the way it reaches the next plain `claude`. project-mcp-servers.ts has the reasons.
|
|
21729
|
+
mcpServers: workerMcpServers(projectMcpServers(config.cwd, { env }), config.mcpServers),
|
|
21730
|
+
strictMcpConfig: true,
|
|
21588
21731
|
allowedTools: config.allowedTools,
|
|
21589
21732
|
// NO `disallowedTools` here, and the asymmetry with the argv path (WORKER_DISALLOWED_TOOLS →
|
|
21590
21733
|
// `--disallowedTools=AskUserQuestion`) is DELIBERATE. That flag exists because a worker launched as
|
|
@@ -21746,7 +21889,7 @@ function runClaudeBroker(config) {
|
|
|
21746
21889
|
const recordOwner = () => {
|
|
21747
21890
|
if (!config.recordPath) return null;
|
|
21748
21891
|
try {
|
|
21749
|
-
return JSON.parse(
|
|
21892
|
+
return JSON.parse(readFileSync4(config.recordPath, "utf8")).daemonPid;
|
|
21750
21893
|
} catch {
|
|
21751
21894
|
return null;
|
|
21752
21895
|
}
|
|
@@ -21812,7 +21955,7 @@ function runClaudeBroker(config) {
|
|
|
21812
21955
|
server.listen(config.socketPath, () => {
|
|
21813
21956
|
published = true;
|
|
21814
21957
|
if (config.recordPath) {
|
|
21815
|
-
const record = { daemonPid: process.pid, socketPath: config.socketPath, sessionId: config.sessionId, generation, createdAt: (/* @__PURE__ */ new Date()).toISOString(), capabilities: BROKER_CAPABILITIES };
|
|
21958
|
+
const record = { daemonPid: process.pid, socketPath: config.socketPath, sessionId: config.sessionId, generation, createdAt: (/* @__PURE__ */ new Date()).toISOString(), capabilities: BROKER_CAPABILITIES, compactionWindow: claudeCompactionWindowOf(config.workerEnv) };
|
|
21816
21959
|
try {
|
|
21817
21960
|
writeFileSync(config.recordPath, JSON.stringify(record), { mode: 384 });
|
|
21818
21961
|
} catch {
|