frizz 0.12.13 → 0.13.1
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/frizz.js +872 -369
- package/package.json +13 -13
- package/dist/claude-agent-broker.js +0 -35911
- package/dist/codex-app-server-daemon.js +0 -423
- package/dist/dev-child.js +0 -56194
- package/runtime/board/agent-bindings.mjs +0 -287
- package/runtime/board/agent-liveness.mjs +0 -367
- package/runtime/board/agent-status.mjs +0 -178
- package/runtime/board/config.mjs +0 -993
- package/runtime/board/decisions.mjs +0 -97
- package/runtime/board/index.mjs +0 -704
- package/runtime/board/notify-shared.mjs +0 -90
- package/runtime/board/notify.mjs +0 -81
- package/runtime/board/ownership.mjs +0 -120
- package/runtime/board/rest-detect.mjs +0 -213
- package/runtime/board/thread-excerpt.mjs +0 -162
- package/runtime/board/thread-update.mjs +0 -289
- package/runtime/cc-worker/.claude-plugin/plugin.json +0 -10
- package/runtime/cc-worker/DECISIONS.md +0 -1172
- package/runtime/cc-worker/LICENSE +0 -21
- package/runtime/cc-worker/agents/high.md +0 -7
- package/runtime/cc-worker/agents/low.md +0 -7
- package/runtime/cc-worker/agents/max.md +0 -7
- package/runtime/cc-worker/agents/medium.md +0 -7
- package/runtime/cc-worker/agents/xhigh.md +0 -7
- package/runtime/cc-worker/bin/frizz +0 -17
- package/runtime/cc-worker/bin/frizz-mcp.mjs +0 -1612
- package/runtime/cc-worker/bin/frizz-update +0 -18
- package/runtime/cc-worker/hooks/agent-bind.mjs +0 -40
- package/runtime/cc-worker/hooks/agent-dispatch.mjs +0 -121
- package/runtime/cc-worker/hooks/bash-background.d.mts +0 -6
- package/runtime/cc-worker/hooks/bash-background.mjs +0 -247
- package/runtime/cc-worker/hooks/deny-ask.mjs +0 -39
- package/runtime/cc-worker/hooks/deny-plan.mjs +0 -62
- package/runtime/cc-worker/hooks/hooks.json +0 -102
- package/runtime/cc-worker/hooks/perm-policy.mjs +0 -211
- package/runtime/cc-worker/hooks/scratchpad.mjs +0 -417
- package/runtime/cc-worker/hooks/session-seed.mjs +0 -107
- package/runtime/cc-worker/scripts/frizz/agent-bindings.mjs +0 -9
- package/runtime/cc-worker/scripts/frizz/config.mjs +0 -12
- package/runtime/cc-worker/skills/gh/SKILL.md +0 -141
- package/runtime/cc-worker/skills/gh/scripts/ci-watch.mjs +0 -60
- package/runtime/cc-worker/skills/gh/scripts/github-watch.mjs +0 -130
- package/runtime/cc-worker/skills/gh/scripts/review-watch.mjs +0 -54
- package/web-dist/apple-touch-icon.png +0 -0
- package/web-dist/assets/TerminalPane-Cv0c_SNS.js +0 -7
- package/web-dist/assets/abnfDiagram-VRR7QNED-B-wED8ht.js +0 -1
- package/web-dist/assets/arc-BSyeo0Gb.js +0 -1
- package/web-dist/assets/architecture-TIHT7OUA-nsH-QfGr.js +0 -1
- package/web-dist/assets/architectureDiagram-ZJ3FMSHR-kHm_O2sR.js +0 -36
- package/web-dist/assets/array-BifhSqXX.js +0 -1
- package/web-dist/assets/blockDiagram-677ZJIJ3-CdazUaKU.js +0 -132
- package/web-dist/assets/c4Diagram-LMCZKHZV-rauLKZbJ.js +0 -10
- package/web-dist/assets/channel-fvwjeUt3.js +0 -1
- package/web-dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +0 -1
- package/web-dist/assets/chunk-32BRIVSS-DjOqyEDX.js +0 -1
- package/web-dist/assets/chunk-52WLFC77-f1SThegZ.js +0 -10
- package/web-dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +0 -15
- package/web-dist/assets/chunk-7BUUIJ7U-Bb538aSH.js +0 -1
- package/web-dist/assets/chunk-C7G6YPKG-BfQsesjz.js +0 -1
- package/web-dist/assets/chunk-EX3LRPZG-BIzZW7OQ.js +0 -231
- package/web-dist/assets/chunk-FWX5IMBZ-CATINZFC.js +0 -2
- package/web-dist/assets/chunk-HOUHSVGY-DbMBRCCE.js +0 -1
- package/web-dist/assets/chunk-ICXQ74PX-COcoSWx4.js +0 -2
- package/web-dist/assets/chunk-JWPE2WC7-DVXcaiue.js +0 -1
- package/web-dist/assets/chunk-KEIR6QF5-BfrZ3jm6.js +0 -161
- package/web-dist/assets/chunk-MOJQB5TN-CVnI-o_4.js +0 -88
- package/web-dist/assets/chunk-OGEWGWER-U0vdZqB6.js +0 -1
- package/web-dist/assets/chunk-PUDLZKDR-Bukb7rem.js +0 -156
- package/web-dist/assets/chunk-Q4XR5HBZ-Bl019PHd.js +0 -70
- package/web-dist/assets/chunk-RYQCIY6F-Cu_KplZW.js +0 -1
- package/web-dist/assets/chunk-V7JOEXUC-YJR0vzI6.js +0 -206
- package/web-dist/assets/chunk-VAUOI2AC-CK6NU9kj.js +0 -1
- package/web-dist/assets/chunk-VR4S4FIN-B3LBv3C3.js +0 -1
- package/web-dist/assets/chunk-WYO6CB5R-DjRPyRuS.js +0 -127
- package/web-dist/assets/chunk-XXDRQBXY-DYlTP5J-.js +0 -1
- package/web-dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +0 -1
- package/web-dist/assets/chunk-ZGVPDNZ5-BUJCayKP.js +0 -62
- package/web-dist/assets/chunk-ZIRB5QZD-C6fEPe3t.js +0 -32
- package/web-dist/assets/classDiagram-OUVF2IWQ-BRZQ_xnN.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-BRZQ_xnN.js +0 -1
- package/web-dist/assets/cose-bilkent-JH36ORCC-BUIsLrGc.js +0 -1
- package/web-dist/assets/cynefin-VYW2F7L2-CE3ce51v.js +0 -1
- package/web-dist/assets/cynefinDiagram-TSTJHNR4-DSXSPZQV.js +0 -62
- package/web-dist/assets/cytoscape.esm-B3I8pqwA.js +0 -321
- package/web-dist/assets/dagre-CXRCoUWR.js +0 -1
- package/web-dist/assets/dagre-VKFMJZFB-VwBQdjum.js +0 -4
- package/web-dist/assets/defaultLocale-C8Fc0cco.js +0 -1
- package/web-dist/assets/diagram-FQU43EPY-7Tf5_WDu.js +0 -3
- package/web-dist/assets/diagram-G47NLZAW-mu4aclWA.js +0 -24
- package/web-dist/assets/diagram-NH7WQ7WH-B3kAVNwv.js +0 -24
- package/web-dist/assets/diagram-OA4YK3LP-DAaV-2ou.js +0 -30
- package/web-dist/assets/diagram-WEI45ONY-DijPfgly.js +0 -41
- package/web-dist/assets/dist-DoH_9pyS.js +0 -1
- package/web-dist/assets/ebnfDiagram-CCIWWBDH-B1o42Wp-.js +0 -1
- package/web-dist/assets/erDiagram-Q63AITRT-Dqej9Wi3.js +0 -85
- package/web-dist/assets/eventmodeling-45OFAUF4-B8xeGcXU.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-Cnyfcz6Z.js +0 -1
- package/web-dist/assets/ganttDiagram-NO4QXBWP-UoyrLPUT.js +0 -292
- package/web-dist/assets/gitGraph-TEB2WS4Q-CwjIwQ3T.js +0 -1
- package/web-dist/assets/gitGraphDiagram-IHSO6WYX-BxU758_g.js +0 -106
- package/web-dist/assets/graphlib-B8gBHxth.js +0 -1
- package/web-dist/assets/index-CT6k_A5y.css +0 -1
- package/web-dist/assets/index-k8HCkyvh.js +0 -319
- package/web-dist/assets/info-DKCQHKI2-CWtSI6aK.js +0 -1
- package/web-dist/assets/infoDiagram-FWYZ7A6U-n5xRfy_d.js +0 -2
- package/web-dist/assets/init-D6jRqBbL.js +0 -1
- package/web-dist/assets/ishikawaDiagram-FXEZZL3T-DU1LTQY-.js +0 -70
- package/web-dist/assets/journeyDiagram-5HDEW3XC-BzZWHoPv.js +0 -139
- package/web-dist/assets/kanban-definition-HUTT4EX6-CeneyR7c.js +0 -89
- package/web-dist/assets/katex-CddkPoXu.js +0 -257
- package/web-dist/assets/line-DTfkLWnw.js +0 -1
- package/web-dist/assets/linear-z2V0wJk9.js +0 -1
- package/web-dist/assets/map-DsCK-0Cs.js +0 -1
- package/web-dist/assets/mermaid-parser.core-CHzoJ5LT.js +0 -7
- package/web-dist/assets/mermaid.core-Cl84DLN2.js +0 -11
- package/web-dist/assets/mindmap-definition-LN4V7U3C-C39sBNqB.js +0 -96
- package/web-dist/assets/ordinal-hYBb2elL.js +0 -1
- package/web-dist/assets/packet-7NZHBO7P-Bj73rlQn.js +0 -1
- package/web-dist/assets/path-BWPyau1x.js +0 -1
- package/web-dist/assets/pegDiagram-2B236MQR-BEEM1vSv.js +0 -1
- package/web-dist/assets/pie-RZYD4A2V-CJ-fEfdy.js +0 -1
- package/web-dist/assets/pieDiagram-ENE6RG2P-Dcqj3oyh.js +0 -39
- package/web-dist/assets/quadrantDiagram-ABIIQ3AL-D5cljQ3D.js +0 -7
- package/web-dist/assets/radar-I7S5WNFK-G8JqqGPf.js +0 -1
- package/web-dist/assets/railroad-3IZDKUUU-CaGNL0iN.js +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-DWZmdy-r.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-C-XoPuo_.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-BGpxqg46.js +0 -1
- package/web-dist/assets/railroadDiagram-RFXS5EU6-BZGZXMY4.js +0 -1
- package/web-dist/assets/requirementDiagram-TGXJPOKE-Dj5yn_9e.js +0 -84
- package/web-dist/assets/rolldown-runtime-Bh1tDfsg.js +0 -1
- package/web-dist/assets/rough.esm-CSKSodPl.js +0 -1
- package/web-dist/assets/sankeyDiagram-HTMAVEWB-7iJ_NDNf.js +0 -40
- package/web-dist/assets/sequenceDiagram-DBY2YBRQ-Bl54CknA.js +0 -162
- package/web-dist/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +0 -1
- package/web-dist/assets/src-C4XfhTaE.js +0 -1
- package/web-dist/assets/stateDiagram-2N3HPSRC-DuvjeNgJ.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BR-vrMgH.js +0 -1
- package/web-dist/assets/swimlanes-5IMT3BWC-B7-Jj4Sk.js +0 -2
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-C1HvMf2k.js +0 -8
- package/web-dist/assets/timeline-definition-FHXFAJF6-jsey2pEG.js +0 -120
- package/web-dist/assets/treeView-QDETBFTQ-DhPmOzHr.js +0 -1
- package/web-dist/assets/treemap-6X3UGDF4-Dw2IaXqK.js +0 -1
- package/web-dist/assets/vennDiagram-L72KCM5P-CXKZkBab.js +0 -34
- package/web-dist/assets/wardley-OPB4EBWU-CTCdDwyE.js +0 -1
- package/web-dist/assets/wardleyDiagram-EHGQE667-B1w0xIqB.js +0 -78
- package/web-dist/assets/xychartDiagram-FW5EYKEG-gULk-uIl.js +0 -7
- package/web-dist/favicon-16.png +0 -0
- package/web-dist/favicon-32.png +0 -0
- package/web-dist/favicon.svg +0 -34
- package/web-dist/icon-192.png +0 -0
- package/web-dist/icon-512.png +0 -0
- package/web-dist/icon-maskable-512.png +0 -0
- package/web-dist/index.html +0 -44
- package/web-dist/manifest.webmanifest +0 -16
package/dist/frizz.js
CHANGED
|
@@ -4175,10 +4175,10 @@ var require_resolve_block_map = __commonJS({
|
|
|
4175
4175
|
let offset = bm.offset;
|
|
4176
4176
|
let commentEnd = null;
|
|
4177
4177
|
for (const collItem of bm.items) {
|
|
4178
|
-
const { start, key, sep:
|
|
4178
|
+
const { start, key, sep: sep5, value } = collItem;
|
|
4179
4179
|
const keyProps = resolveProps.resolveProps(start, {
|
|
4180
4180
|
indicator: "explicit-key-ind",
|
|
4181
|
-
next: key ??
|
|
4181
|
+
next: key ?? sep5?.[0],
|
|
4182
4182
|
offset,
|
|
4183
4183
|
onError,
|
|
4184
4184
|
parentIndent: bm.indent,
|
|
@@ -4192,7 +4192,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4192
4192
|
else if ("indent" in key && key.indent !== bm.indent)
|
|
4193
4193
|
onError(offset, "BAD_INDENT", startColMsg);
|
|
4194
4194
|
}
|
|
4195
|
-
if (!keyProps.anchor && !keyProps.tag && !
|
|
4195
|
+
if (!keyProps.anchor && !keyProps.tag && !sep5) {
|
|
4196
4196
|
commentEnd = keyProps.end;
|
|
4197
4197
|
if (keyProps.comment) {
|
|
4198
4198
|
if (map.comment)
|
|
@@ -4216,7 +4216,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4216
4216
|
ctx.atKey = false;
|
|
4217
4217
|
if (utilMapIncludes.mapIncludes(ctx, map.items, keyNode))
|
|
4218
4218
|
onError(keyStart, "DUPLICATE_KEY", "Map keys must be unique");
|
|
4219
|
-
const valueProps = resolveProps.resolveProps(
|
|
4219
|
+
const valueProps = resolveProps.resolveProps(sep5 ?? [], {
|
|
4220
4220
|
indicator: "map-value-ind",
|
|
4221
4221
|
next: value,
|
|
4222
4222
|
offset: keyNode.range[2],
|
|
@@ -4232,7 +4232,7 @@ var require_resolve_block_map = __commonJS({
|
|
|
4232
4232
|
if (ctx.options.strict && keyProps.start < valueProps.found.offset - 1024)
|
|
4233
4233
|
onError(keyNode.range, "KEY_OVER_1024_CHARS", "The : indicator must be at most 1024 chars after the start of an implicit block mapping key");
|
|
4234
4234
|
}
|
|
4235
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset,
|
|
4235
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep5, null, valueProps, onError);
|
|
4236
4236
|
if (ctx.schema.compat)
|
|
4237
4237
|
utilFlowIndentCheck.flowIndentCheck(bm.indent, value, onError);
|
|
4238
4238
|
offset = valueNode.range[2];
|
|
@@ -4323,7 +4323,7 @@ var require_resolve_end = __commonJS({
|
|
|
4323
4323
|
let comment = "";
|
|
4324
4324
|
if (end) {
|
|
4325
4325
|
let hasSpace = false;
|
|
4326
|
-
let
|
|
4326
|
+
let sep5 = "";
|
|
4327
4327
|
for (const token of end) {
|
|
4328
4328
|
const { source, type } = token;
|
|
4329
4329
|
switch (type) {
|
|
@@ -4337,13 +4337,13 @@ var require_resolve_end = __commonJS({
|
|
|
4337
4337
|
if (!comment)
|
|
4338
4338
|
comment = cb;
|
|
4339
4339
|
else
|
|
4340
|
-
comment +=
|
|
4341
|
-
|
|
4340
|
+
comment += sep5 + cb;
|
|
4341
|
+
sep5 = "";
|
|
4342
4342
|
break;
|
|
4343
4343
|
}
|
|
4344
4344
|
case "newline":
|
|
4345
4345
|
if (comment)
|
|
4346
|
-
|
|
4346
|
+
sep5 += source;
|
|
4347
4347
|
hasSpace = true;
|
|
4348
4348
|
break;
|
|
4349
4349
|
default:
|
|
@@ -4386,18 +4386,18 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4386
4386
|
let offset = fc.offset + fc.start.source.length;
|
|
4387
4387
|
for (let i = 0; i < fc.items.length; ++i) {
|
|
4388
4388
|
const collItem = fc.items[i];
|
|
4389
|
-
const { start, key, sep:
|
|
4389
|
+
const { start, key, sep: sep5, value } = collItem;
|
|
4390
4390
|
const props = resolveProps.resolveProps(start, {
|
|
4391
4391
|
flow: fcName,
|
|
4392
4392
|
indicator: "explicit-key-ind",
|
|
4393
|
-
next: key ??
|
|
4393
|
+
next: key ?? sep5?.[0],
|
|
4394
4394
|
offset,
|
|
4395
4395
|
onError,
|
|
4396
4396
|
parentIndent: fc.indent,
|
|
4397
4397
|
startOnNewline: false
|
|
4398
4398
|
});
|
|
4399
4399
|
if (!props.found) {
|
|
4400
|
-
if (!props.anchor && !props.tag && !
|
|
4400
|
+
if (!props.anchor && !props.tag && !sep5 && !value) {
|
|
4401
4401
|
if (i === 0 && props.comma)
|
|
4402
4402
|
onError(props.comma, "UNEXPECTED_TOKEN", `Unexpected , in ${fcName}`);
|
|
4403
4403
|
else if (i < fc.items.length - 1)
|
|
@@ -4451,8 +4451,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4451
4451
|
}
|
|
4452
4452
|
}
|
|
4453
4453
|
}
|
|
4454
|
-
if (!isMap && !
|
|
4455
|
-
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end,
|
|
4454
|
+
if (!isMap && !sep5 && !props.found) {
|
|
4455
|
+
const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep5, null, props, onError);
|
|
4456
4456
|
coll.items.push(valueNode);
|
|
4457
4457
|
offset = valueNode.range[2];
|
|
4458
4458
|
if (isBlock(value))
|
|
@@ -4464,7 +4464,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4464
4464
|
if (isBlock(key))
|
|
4465
4465
|
onError(keyNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
4466
4466
|
ctx.atKey = false;
|
|
4467
|
-
const valueProps = resolveProps.resolveProps(
|
|
4467
|
+
const valueProps = resolveProps.resolveProps(sep5 ?? [], {
|
|
4468
4468
|
flow: fcName,
|
|
4469
4469
|
indicator: "map-value-ind",
|
|
4470
4470
|
next: value,
|
|
@@ -4475,8 +4475,8 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4475
4475
|
});
|
|
4476
4476
|
if (valueProps.found) {
|
|
4477
4477
|
if (!isMap && !props.found && ctx.options.strict) {
|
|
4478
|
-
if (
|
|
4479
|
-
for (const st of
|
|
4478
|
+
if (sep5)
|
|
4479
|
+
for (const st of sep5) {
|
|
4480
4480
|
if (st === valueProps.found)
|
|
4481
4481
|
break;
|
|
4482
4482
|
if (st.type === "newline") {
|
|
@@ -4493,7 +4493,7 @@ var require_resolve_flow_collection = __commonJS({
|
|
|
4493
4493
|
else
|
|
4494
4494
|
onError(valueProps.start, "MISSING_CHAR", `Missing , or : between ${fcName} items`);
|
|
4495
4495
|
}
|
|
4496
|
-
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end,
|
|
4496
|
+
const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep5, null, valueProps, onError) : null;
|
|
4497
4497
|
if (valueNode) {
|
|
4498
4498
|
if (isBlock(value))
|
|
4499
4499
|
onError(valueNode.range, "BLOCK_IN_FLOW", blockMsg);
|
|
@@ -4673,7 +4673,7 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
4673
4673
|
chompStart = i + 1;
|
|
4674
4674
|
}
|
|
4675
4675
|
let value = "";
|
|
4676
|
-
let
|
|
4676
|
+
let sep5 = "";
|
|
4677
4677
|
let prevMoreIndented = false;
|
|
4678
4678
|
for (let i = 0; i < contentStart; ++i)
|
|
4679
4679
|
value += lines[i][0].slice(trimIndent) + "\n";
|
|
@@ -4690,24 +4690,24 @@ var require_resolve_block_scalar = __commonJS({
|
|
|
4690
4690
|
indent = "";
|
|
4691
4691
|
}
|
|
4692
4692
|
if (type === Scalar.Scalar.BLOCK_LITERAL) {
|
|
4693
|
-
value +=
|
|
4694
|
-
|
|
4693
|
+
value += sep5 + indent.slice(trimIndent) + content;
|
|
4694
|
+
sep5 = "\n";
|
|
4695
4695
|
} else if (indent.length > trimIndent || content[0] === " ") {
|
|
4696
|
-
if (
|
|
4697
|
-
|
|
4698
|
-
else if (!prevMoreIndented &&
|
|
4699
|
-
|
|
4700
|
-
value +=
|
|
4701
|
-
|
|
4696
|
+
if (sep5 === " ")
|
|
4697
|
+
sep5 = "\n";
|
|
4698
|
+
else if (!prevMoreIndented && sep5 === "\n")
|
|
4699
|
+
sep5 = "\n\n";
|
|
4700
|
+
value += sep5 + indent.slice(trimIndent) + content;
|
|
4701
|
+
sep5 = "\n";
|
|
4702
4702
|
prevMoreIndented = true;
|
|
4703
4703
|
} else if (content === "") {
|
|
4704
|
-
if (
|
|
4704
|
+
if (sep5 === "\n")
|
|
4705
4705
|
value += "\n";
|
|
4706
4706
|
else
|
|
4707
|
-
|
|
4707
|
+
sep5 = "\n";
|
|
4708
4708
|
} else {
|
|
4709
|
-
value +=
|
|
4710
|
-
|
|
4709
|
+
value += sep5 + content;
|
|
4710
|
+
sep5 = " ";
|
|
4711
4711
|
prevMoreIndented = false;
|
|
4712
4712
|
}
|
|
4713
4713
|
}
|
|
@@ -4889,25 +4889,25 @@ var require_resolve_flow_scalar = __commonJS({
|
|
|
4889
4889
|
if (!match)
|
|
4890
4890
|
return source;
|
|
4891
4891
|
let res = match[1];
|
|
4892
|
-
let
|
|
4892
|
+
let sep5 = " ";
|
|
4893
4893
|
let pos = first.lastIndex;
|
|
4894
4894
|
line.lastIndex = pos;
|
|
4895
4895
|
while (match = line.exec(source)) {
|
|
4896
4896
|
if (match[1] === "") {
|
|
4897
|
-
if (
|
|
4898
|
-
res +=
|
|
4897
|
+
if (sep5 === "\n")
|
|
4898
|
+
res += sep5;
|
|
4899
4899
|
else
|
|
4900
|
-
|
|
4900
|
+
sep5 = "\n";
|
|
4901
4901
|
} else {
|
|
4902
|
-
res +=
|
|
4903
|
-
|
|
4902
|
+
res += sep5 + match[1];
|
|
4903
|
+
sep5 = " ";
|
|
4904
4904
|
}
|
|
4905
4905
|
pos = line.lastIndex;
|
|
4906
4906
|
}
|
|
4907
4907
|
const last = /[ \t]*(.*)/sy;
|
|
4908
4908
|
last.lastIndex = pos;
|
|
4909
4909
|
match = last.exec(source);
|
|
4910
|
-
return res +
|
|
4910
|
+
return res + sep5 + (match?.[1] ?? "");
|
|
4911
4911
|
}
|
|
4912
4912
|
function doubleQuotedValue(source, onError) {
|
|
4913
4913
|
let res = "";
|
|
@@ -5717,14 +5717,14 @@ var require_cst_stringify = __commonJS({
|
|
|
5717
5717
|
}
|
|
5718
5718
|
}
|
|
5719
5719
|
}
|
|
5720
|
-
function stringifyItem({ start, key, sep:
|
|
5720
|
+
function stringifyItem({ start, key, sep: sep5, value }) {
|
|
5721
5721
|
let res = "";
|
|
5722
5722
|
for (const st of start)
|
|
5723
5723
|
res += st.source;
|
|
5724
5724
|
if (key)
|
|
5725
5725
|
res += stringifyToken(key);
|
|
5726
|
-
if (
|
|
5727
|
-
for (const st of
|
|
5726
|
+
if (sep5)
|
|
5727
|
+
for (const st of sep5)
|
|
5728
5728
|
res += st.source;
|
|
5729
5729
|
if (value)
|
|
5730
5730
|
res += stringifyToken(value);
|
|
@@ -6891,18 +6891,18 @@ var require_parser = __commonJS({
|
|
|
6891
6891
|
if (this.type === "map-value-ind") {
|
|
6892
6892
|
const prev = getPrevProps(this.peek(2));
|
|
6893
6893
|
const start = getFirstKeyStartProps(prev);
|
|
6894
|
-
let
|
|
6894
|
+
let sep5;
|
|
6895
6895
|
if (scalar.end) {
|
|
6896
|
-
|
|
6897
|
-
|
|
6896
|
+
sep5 = scalar.end;
|
|
6897
|
+
sep5.push(this.sourceToken);
|
|
6898
6898
|
delete scalar.end;
|
|
6899
6899
|
} else
|
|
6900
|
-
|
|
6900
|
+
sep5 = [this.sourceToken];
|
|
6901
6901
|
const map = {
|
|
6902
6902
|
type: "block-map",
|
|
6903
6903
|
offset: scalar.offset,
|
|
6904
6904
|
indent: scalar.indent,
|
|
6905
|
-
items: [{ start, key: scalar, sep:
|
|
6905
|
+
items: [{ start, key: scalar, sep: sep5 }]
|
|
6906
6906
|
};
|
|
6907
6907
|
this.onKeyLine = true;
|
|
6908
6908
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -7055,15 +7055,15 @@ var require_parser = __commonJS({
|
|
|
7055
7055
|
} else if (isFlowToken(it.key) && !includesToken(it.sep, "newline")) {
|
|
7056
7056
|
const start2 = getFirstKeyStartProps(it.start);
|
|
7057
7057
|
const key = it.key;
|
|
7058
|
-
const
|
|
7059
|
-
|
|
7058
|
+
const sep5 = it.sep;
|
|
7059
|
+
sep5.push(this.sourceToken);
|
|
7060
7060
|
delete it.key;
|
|
7061
7061
|
delete it.sep;
|
|
7062
7062
|
this.stack.push({
|
|
7063
7063
|
type: "block-map",
|
|
7064
7064
|
offset: this.offset,
|
|
7065
7065
|
indent: this.indent,
|
|
7066
|
-
items: [{ start: start2, key, sep:
|
|
7066
|
+
items: [{ start: start2, key, sep: sep5 }]
|
|
7067
7067
|
});
|
|
7068
7068
|
} else if (start.length > 0) {
|
|
7069
7069
|
it.sep = it.sep.concat(start, this.sourceToken);
|
|
@@ -7257,13 +7257,13 @@ var require_parser = __commonJS({
|
|
|
7257
7257
|
const prev = getPrevProps(parent);
|
|
7258
7258
|
const start = getFirstKeyStartProps(prev);
|
|
7259
7259
|
fixFlowSeqItems(fc);
|
|
7260
|
-
const
|
|
7261
|
-
|
|
7260
|
+
const sep5 = fc.end.splice(1, fc.end.length);
|
|
7261
|
+
sep5.push(this.sourceToken);
|
|
7262
7262
|
const map = {
|
|
7263
7263
|
type: "block-map",
|
|
7264
7264
|
offset: fc.offset,
|
|
7265
7265
|
indent: fc.indent,
|
|
7266
|
-
items: [{ start, key: fc, sep:
|
|
7266
|
+
items: [{ start, key: fc, sep: sep5 }]
|
|
7267
7267
|
};
|
|
7268
7268
|
this.onKeyLine = true;
|
|
7269
7269
|
this.stack[this.stack.length - 1] = map;
|
|
@@ -11775,7 +11775,7 @@ var init_interactions = __esm({
|
|
|
11775
11775
|
InteractionFieldId = external_exports.string().min(1).max(128).regex(/^[A-Za-z_][A-Za-z0-9_.:-]*$/).refine((value) => !["__proto__", "constructor", "prototype"].includes(value), "reserved field id");
|
|
11776
11776
|
InteractionDecisionId = external_exports.string().min(1).max(80).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/);
|
|
11777
11777
|
InteractionProvider = external_exports.object({
|
|
11778
|
-
kind: external_exports.enum(["claude", "codex", "frizz"]),
|
|
11778
|
+
kind: external_exports.enum(["claude", "codex", "acp", "frizz"]),
|
|
11779
11779
|
name: InteractionLabel.optional(),
|
|
11780
11780
|
version: InteractionOpaqueId.optional()
|
|
11781
11781
|
}).strict();
|
|
@@ -12466,10 +12466,15 @@ var init_shell_writes = __esm({
|
|
|
12466
12466
|
});
|
|
12467
12467
|
|
|
12468
12468
|
// packages/shared/src/index.ts
|
|
12469
|
+
function requireEffortOutsideAcp(profile, ctx) {
|
|
12470
|
+
if (profile.backend !== "acp" && profile.effort === void 0) {
|
|
12471
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["effort"], message: `effort is required for a ${profile.backend} profile` });
|
|
12472
|
+
}
|
|
12473
|
+
}
|
|
12469
12474
|
function fallbackPort(base) {
|
|
12470
12475
|
return base + 1e4;
|
|
12471
12476
|
}
|
|
12472
|
-
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TimerPromptText, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, AskQuestionKind, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, HUMAN_GAP_FLOOR_MS, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12477
|
+
var import_yaml, ATTACHMENT_IMAGE_EXTENSIONS, ATTACHMENT_TEXT_EXTENSIONS, ATTACHMENT_OFFICE_EXTENSIONS, ATTACHMENT_DATA_EXTENSIONS, ATTACHMENT_ARCHIVE_EXTENSIONS, ATTACHMENT_DOC_EXTENSIONS, ATTACHMENT_EXTENSIONS, ATTACHMENT_MAX_BASE64_CHARS, ATTACHMENT_MAX_BYTES, ATTACHMENT_EXT_SET, ATTACHMENT_ACCEPT, FrizzStatus, BlockMechanism, RuntimeState, Backend, CodexModel, AcpAgent, AcpAgentModel, AcpAgentModels, AcpAgentModelsInput, ThreadProfileOption, ThreadAgent, SubAgentView, BgShellView, CompletionHoldOp, CompletionHold, AskOption, AskQuestion, PendingAsk, AwaitingHint, RETIRED_AWAITING_KINDS, RETIRED_LINE_RE, AWAITING_FOR_MAX_MS, SnoozeUntil, SNOOZE_PROMPT_MAX, SnoozePrompt, RECURRING_PROMPT_MAX, RECURRING_MIN_INTERVAL_SECONDS, RECURRING_MAX_INTERVAL_SECONDS, RecurringPromptText, RecurringIntervalSeconds, ThreadRecurringPrompt, TIMER_PROMPT_MAX, TIMER_MAX_DELAY_SECONDS, TimerPromptText, SIGNOFF_NUDGE_MARKER, SIGNOFF_NUDGE_MESSAGE, ThreadWatchKind, GithubChecksState, GithubMergeState, GithubWatchStatus, GithubIssueStatus, ThreadWatchView, PR_WATCH_FOR_MAX_MS, PR_WATCH_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, AskQuestionKind, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, ProviderError, ThreadLinkView, UpsertOwnLinkInput, UpsertOwnLinkResult, DropOwnLinkInput, DropOwnLinkResult, ThreadView, BoardErrorItem, BoardSnapshot, QuotaWindow, ProviderQuota, QuotaSnapshot, ProviderAuth, AccountEmails, AuthSnapshot, AccountBackend, AccountLogoutInput, AccountLogoutResult, AccountLoginStartInput, AccountLoginStartResult, AccountLoginStatusInput, AccountLoginStatusResult, PermissionMode, LocalFileOpener, Settings, DispatchProviderPreferences, DispatchPreferences, DispatchProfileSnapshotShape, DispatchProfileSnapshot, SetDispatchPreferenceInput, DispatchInput, ADOPT_THREAD_MESSAGE_MAX_CHARS, AdoptThreadInput, AdoptThreadResult, AdoptSessionInput, FollowUpInput, UnqueueFollowUpInput, UnqueueFollowUpResult, DeliverQueuedNowInput, DeliverQueuedNowResult, SetThreadSnoozeInput, SetThreadPinnedInput, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, SetOwnThreadTitleInput, SetOwnThreadTitleResult, SetThreadPermissionInput, SetThreadPermissionResult, ThreadProfileOptionsInput, ThreadProfileOptionsResult, ThreadSkillSource, ThreadSkill, ThreadSkillsInput, ThreadSkillsResult, SetThreadProfileInput, SetThreadProfileResult, DISPATCH_TASK_BANNER, DISPATCH_TASK_BANNER_MARKER, HUMAN_GAP_FLOOR_MS, GithubWakeItem, GithubWakeSteer, WAKE_SCOPE, WAKE_REF, WAKE_SINGLE, WAKE_MULTI_HEAD, PR_WATCH_FINISHED, PR_WATCH_CI_PASSED, PR_WATCH_CI_GATED, PR_WATCH_STATE, PR_WATCH_CI_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketFilePath, SocketTranscriptClientMsg, SocketFileClientMsg, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
|
|
12473
12478
|
var init_src = __esm({
|
|
12474
12479
|
"packages/shared/src/index.ts"() {
|
|
12475
12480
|
"use strict";
|
|
@@ -12588,7 +12593,7 @@ var init_src = __esm({
|
|
|
12588
12593
|
"exited"
|
|
12589
12594
|
// the worker process that owned this session is gone, or is no longer driving its turn
|
|
12590
12595
|
]);
|
|
12591
|
-
Backend = external_exports.enum(["claude", "codex"]);
|
|
12596
|
+
Backend = external_exports.enum(["claude", "codex", "acp"]);
|
|
12592
12597
|
CodexModel = external_exports.object({
|
|
12593
12598
|
slug: external_exports.string(),
|
|
12594
12599
|
displayName: external_exports.string(),
|
|
@@ -12602,6 +12607,23 @@ var init_src = __esm({
|
|
|
12602
12607
|
contextWindow: external_exports.number().int().positive().optional(),
|
|
12603
12608
|
maxContextWindow: external_exports.number().int().positive().optional()
|
|
12604
12609
|
});
|
|
12610
|
+
AcpAgent = external_exports.object({
|
|
12611
|
+
id: external_exports.string(),
|
|
12612
|
+
label: external_exports.string(),
|
|
12613
|
+
command: external_exports.string(),
|
|
12614
|
+
available: external_exports.boolean()
|
|
12615
|
+
});
|
|
12616
|
+
AcpAgentModel = external_exports.object({ id: external_exports.string(), name: external_exports.string() });
|
|
12617
|
+
AcpAgentModels = external_exports.object({
|
|
12618
|
+
agentId: external_exports.string(),
|
|
12619
|
+
models: external_exports.array(AcpAgentModel),
|
|
12620
|
+
/** The model the agent opens a session on when Frizz asks for none. */
|
|
12621
|
+
current: external_exports.string().optional(),
|
|
12622
|
+
/** Why the list is empty, when the probe could not open a session (not installed, not logged in…). */
|
|
12623
|
+
error: external_exports.string().optional(),
|
|
12624
|
+
probedAt: external_exports.string()
|
|
12625
|
+
});
|
|
12626
|
+
AcpAgentModelsInput = external_exports.object({ agentId: external_exports.string().min(1).max(100), refresh: external_exports.boolean().optional() }).strict();
|
|
12605
12627
|
ThreadProfileOption = external_exports.object({
|
|
12606
12628
|
model: external_exports.string().min(1),
|
|
12607
12629
|
label: external_exports.string().min(1),
|
|
@@ -12779,7 +12801,7 @@ var init_src = __esm({
|
|
|
12779
12801
|
questions: external_exports.array(AskQuestion)
|
|
12780
12802
|
});
|
|
12781
12803
|
AwaitingHint = external_exports.object({
|
|
12782
|
-
kind: external_exports.enum(["shell", "agent", "timer", "pr", "for", "title"]),
|
|
12804
|
+
kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue", "for", "title"]),
|
|
12783
12805
|
value: external_exports.string()
|
|
12784
12806
|
});
|
|
12785
12807
|
RETIRED_AWAITING_KINDS = ["watch", "pr-watch", "human", "ci", "session", "shell", "agent", "timer", "pr", "reason"];
|
|
@@ -12929,6 +12951,20 @@ var init_src = __esm({
|
|
|
12929
12951
|
* must hear about. Empty when nothing is failing. */
|
|
12930
12952
|
failureSig: external_exports.string().optional()
|
|
12931
12953
|
}).strict();
|
|
12954
|
+
GithubIssueStatus = external_exports.object({
|
|
12955
|
+
/** OPEN | CLOSED, lowercased. A closed issue ends the wait outright. */
|
|
12956
|
+
state: external_exports.enum(["open", "closed"]),
|
|
12957
|
+
/** GitHub's own reason for a close — `completed`, `not_planned`, `duplicate` — lowercased, when it
|
|
12958
|
+
* gave one. Absent while open. */
|
|
12959
|
+
stateReason: external_exports.string().optional(),
|
|
12960
|
+
/** The issue's title, as of the last poll — the one fact a human needs to place a bare `owner/repo#N`
|
|
12961
|
+
* on the card. Capped, because a title is a headline and the card is not the place to read one. */
|
|
12962
|
+
title: external_exports.string().max(200).optional(),
|
|
12963
|
+
/** The conversation's size, so the card can say "14 comments" the way GitHub's list does. */
|
|
12964
|
+
comments: external_exports.number().int().nonnegative(),
|
|
12965
|
+
/** When frizz last heard from GitHub, for the same reason `GithubWatchStatus.polledAt` carries it. */
|
|
12966
|
+
polledAt: external_exports.string()
|
|
12967
|
+
}).strict();
|
|
12932
12968
|
ThreadWatchView = external_exports.object({
|
|
12933
12969
|
id: external_exports.string(),
|
|
12934
12970
|
kind: ThreadWatchKind,
|
|
@@ -12937,6 +12973,15 @@ var init_src = __esm({
|
|
|
12937
12973
|
createdAt: external_exports.string(),
|
|
12938
12974
|
/** `github` rows only, and absent until the first successful poll. */
|
|
12939
12975
|
github: GithubWatchStatus.optional(),
|
|
12976
|
+
/** `github` rows only: WHAT the row watches. A pull request and an issue share the kind — they are one
|
|
12977
|
+
* registry, one ref grammar (`owner/repo#N`) and one place on every surface that lists waits — and
|
|
12978
|
+
* differ in what the poll can read off them, which is what this field lets a card branch on.
|
|
12979
|
+
* Optional, and absent means a pull request — a row from a server that predates issues reads as the
|
|
12980
|
+
* PR it always was, and the non-github kinds never carry it. */
|
|
12981
|
+
subject: external_exports.enum(["pull", "issue"]).optional(),
|
|
12982
|
+
/** `github` rows watching an ISSUE only, and absent until the first successful poll — the twin of the
|
|
12983
|
+
* `github` half above, for the rows whose subject has no checks to report. */
|
|
12984
|
+
issue: GithubIssueStatus.optional(),
|
|
12940
12985
|
/** `timer` rows only: the armed timer's own registration, which is everything the row renders — the
|
|
12941
12986
|
* worker's prompt is the row's NAME (a `tmr_…` id names nothing to a human) and the fire instant is
|
|
12942
12987
|
* its status. Unlike `github` there is no polled half to be absent: a timer that exists is fully
|
|
@@ -12949,10 +12994,15 @@ var init_src = __esm({
|
|
|
12949
12994
|
id: external_exports.string(),
|
|
12950
12995
|
/** `owner/repo#N`, normalized — the same string the board's row and the status book are keyed by. */
|
|
12951
12996
|
target: external_exports.string(),
|
|
12997
|
+
/** A pull request or an issue. Both live in one registry (`pr_watch`) and answer to one drop verb;
|
|
12998
|
+
* `watch_pr` and `watch_issue` each list only their own. Defaulted for a row an older server sends. */
|
|
12999
|
+
kind: external_exports.enum(["pull", "issue"]).default("pull"),
|
|
12952
13000
|
state: external_exports.enum(["armed", "dropped", "settled"]),
|
|
12953
13001
|
createdAt: external_exports.string(),
|
|
12954
13002
|
/** The PR's checks/mergeability as the poller last saw it. Absent until the first successful poll. */
|
|
12955
|
-
github: GithubWatchStatus.optional()
|
|
13003
|
+
github: GithubWatchStatus.optional(),
|
|
13004
|
+
/** An ISSUE's state as the poller last saw it — `kind: "issue"` rows only, absent until polled. */
|
|
13005
|
+
issue: GithubIssueStatus.optional()
|
|
12956
13006
|
}).strict();
|
|
12957
13007
|
AddOwnPrWatchInput = external_exports.object({
|
|
12958
13008
|
slug: ThreadSlug,
|
|
@@ -12977,7 +13027,13 @@ var init_src = __esm({
|
|
|
12977
13027
|
* already running, with no recourse from inside those threads. Absent ⇒ PR_WATCH_DEFAULT_FOR, which
|
|
12978
13028
|
* still BOUNDS the poll; the point of the field is that a worker chooses, and one that cannot choose
|
|
12979
13029
|
* is better bounded than broken. */
|
|
12980
|
-
for: external_exports.string().trim().min(1).max(16).optional()
|
|
13030
|
+
for: external_exports.string().trim().min(1).max(16).optional(),
|
|
13031
|
+
/** What `target` names. `issue` (from `mcp__frizz__watch_issue`, 2026-09-14) registers a watcher on a
|
|
13032
|
+
* GitHub issue — same registry, same poll cadence, same drop verb, but a different probe (`gh issue
|
|
13033
|
+
* view`), a different GraphQL fragment and a report with no CI in it. ABSENT MEANS A PULL REQUEST,
|
|
13034
|
+
* for the same reason `for` is optional on the wire: every `watch_pr` binary dispatched before this
|
|
13035
|
+
* field existed sends nothing here and must go on meaning what it always did. */
|
|
13036
|
+
kind: external_exports.enum(["pull", "issue"]).optional()
|
|
12981
13037
|
}).strict();
|
|
12982
13038
|
AddOwnPrWatchResult = external_exports.object({
|
|
12983
13039
|
id: external_exports.string(),
|
|
@@ -13525,14 +13581,15 @@ var init_src = __esm({
|
|
|
13525
13581
|
codex: ProviderAuth,
|
|
13526
13582
|
emails: AccountEmails
|
|
13527
13583
|
});
|
|
13528
|
-
|
|
13584
|
+
AccountBackend = external_exports.enum(["claude", "codex"]);
|
|
13585
|
+
AccountLogoutInput = external_exports.object({ backend: AccountBackend }).strict();
|
|
13529
13586
|
AccountLogoutResult = external_exports.object({
|
|
13530
13587
|
status: external_exports.enum(["done", "blocked", "failed"]),
|
|
13531
13588
|
auth: ProviderAuth,
|
|
13532
13589
|
activeThreads: external_exports.number().int().positive().optional(),
|
|
13533
13590
|
detail: external_exports.string().max(200).optional()
|
|
13534
13591
|
});
|
|
13535
|
-
AccountLoginStartInput = external_exports.object({ backend:
|
|
13592
|
+
AccountLoginStartInput = external_exports.object({ backend: AccountBackend }).strict();
|
|
13536
13593
|
AccountLoginStartResult = external_exports.object({ attemptId: ThreadSlug });
|
|
13537
13594
|
AccountLoginStatusInput = external_exports.object({ attemptId: ThreadSlug }).strict();
|
|
13538
13595
|
AccountLoginStatusResult = external_exports.object({
|
|
@@ -13607,6 +13664,15 @@ var init_src = __esm({
|
|
|
13607
13664
|
// it (codex compacts at 90% of the resolved window). Unset ⇒ nothing is sent and the model's stock
|
|
13608
13665
|
// window applies. Optional so an old blob parses; defaultSettings leaves it unset.
|
|
13609
13666
|
codexContextWindow: external_exports.number().int().positive().optional(),
|
|
13667
|
+
// The operator's OWN Agent Client Protocol agents, merged over the built-in catalogue by id
|
|
13668
|
+
// (server/backend/acp-agents.ts). `command` is an executable name on PATH or an absolute path;
|
|
13669
|
+
// `args` is what puts it into ACP mode (`["acp"]`, `["--acp"]`). Optional so an old blob parses.
|
|
13670
|
+
acpAgents: external_exports.array(external_exports.object({
|
|
13671
|
+
id: external_exports.string().trim().min(1).max(64).regex(/^[a-z0-9][a-z0-9._-]*$/i),
|
|
13672
|
+
label: external_exports.string().trim().min(1).max(80),
|
|
13673
|
+
command: external_exports.string().trim().min(1).max(1024),
|
|
13674
|
+
args: external_exports.array(external_exports.string().max(1024)).max(32).optional()
|
|
13675
|
+
})).max(32).optional(),
|
|
13610
13676
|
// The GitHub batch-dispatch prompt template (the picker's per-item worker prompt). Optional: when
|
|
13611
13677
|
// unset OR blank the server falls back to its exported DEFAULT_GITHUB_PROMPT. Substitution tokens
|
|
13612
13678
|
// the server fills: {repo} {n} {title} {url} {labels} {body}. The leading `THREAD: <slug>` tag is
|
|
@@ -13633,28 +13699,38 @@ var init_src = __esm({
|
|
|
13633
13699
|
DispatchPreferences = external_exports.object({
|
|
13634
13700
|
backend: Backend,
|
|
13635
13701
|
claude: DispatchProviderPreferences,
|
|
13636
|
-
codex: DispatchProviderPreferences
|
|
13702
|
+
codex: DispatchProviderPreferences,
|
|
13703
|
+
// Optional because every record written before the ACP backend existed lacks it, and a required
|
|
13704
|
+
// key would fail those records' parse and silently reset the operator's saved profile.
|
|
13705
|
+
acp: DispatchProviderPreferences.optional()
|
|
13637
13706
|
});
|
|
13638
|
-
|
|
13707
|
+
DispatchProfileSnapshotShape = external_exports.object({
|
|
13639
13708
|
backend: Backend,
|
|
13640
13709
|
model: external_exports.string().trim().min(1).max(200),
|
|
13641
|
-
|
|
13710
|
+
// Required for Claude and Codex (the refinement below); absent for an ACP agent, which runs with
|
|
13711
|
+
// whatever model and effort its own CLI is configured for — Frizz has no effort axis to offer there.
|
|
13712
|
+
effort: Settings.shape.effort,
|
|
13642
13713
|
// IGNORED: dispatch permission is decided server-side (workerDispatchPermission) from the
|
|
13643
13714
|
// non-interactive floor plus the operator's Settings choice, never per dispatch. Optional so old
|
|
13644
13715
|
// clients that still send it parse.
|
|
13645
13716
|
permissionMode: PermissionMode.optional()
|
|
13646
13717
|
}).strict();
|
|
13718
|
+
DispatchProfileSnapshot = DispatchProfileSnapshotShape.superRefine(requireEffortOutsideAcp);
|
|
13647
13719
|
SetDispatchPreferenceInput = external_exports.discriminatedUnion("field", [
|
|
13648
13720
|
external_exports.object({ field: external_exports.literal("backend"), value: Backend }),
|
|
13649
13721
|
external_exports.object({
|
|
13650
13722
|
field: external_exports.literal("profile"),
|
|
13651
13723
|
backend: Backend,
|
|
13652
13724
|
model: external_exports.string().trim().min(1).max(200),
|
|
13653
|
-
|
|
13725
|
+
// Optional ONLY for an ACP profile (see DispatchProfileSnapshot); a Claude/Codex profile without
|
|
13726
|
+
// an effort is refused below rather than silently stored as "default".
|
|
13727
|
+
effort: Settings.shape.effort
|
|
13654
13728
|
}),
|
|
13655
13729
|
external_exports.object({ field: external_exports.literal("model"), backend: Backend, value: external_exports.string().trim().min(1).max(200) }),
|
|
13656
13730
|
external_exports.object({ field: external_exports.literal("effort"), backend: Backend, value: Settings.shape.effort.unwrap() })
|
|
13657
|
-
])
|
|
13731
|
+
]).superRefine((update, ctx) => {
|
|
13732
|
+
if (update.field === "profile") requireEffortOutsideAcp(update, ctx);
|
|
13733
|
+
});
|
|
13658
13734
|
DispatchInput = external_exports.object({
|
|
13659
13735
|
// Optional: when omitted, dispatch derives a fallback title from the prompt (Claude later renames
|
|
13660
13736
|
// the session via ai-title, which the UI prefers for display). The thread FILE always gets a
|
|
@@ -13806,7 +13882,7 @@ var init_src = __esm({
|
|
|
13806
13882
|
timers: external_exports.array(ThreadTimerView)
|
|
13807
13883
|
}).strict();
|
|
13808
13884
|
ThreadActivityItem = external_exports.object({
|
|
13809
|
-
kind: external_exports.enum(["shell", "agent", "timer", "pr"]),
|
|
13885
|
+
kind: external_exports.enum(["shell", "agent", "timer", "pr", "issue"]),
|
|
13810
13886
|
/** The string a `<kind>:` fence line must carry. For a shell that is the runtime task id the worker
|
|
13811
13887
|
* was shown; for a PR, `owner/repo#N`; for a timer, its `tmr_…` row id. */
|
|
13812
13888
|
id: external_exports.string(),
|
|
@@ -14044,9 +14120,9 @@ ${DISPATCH_TASK_BANNER}
|
|
|
14044
14120
|
page: external_exports.number().int().positive(),
|
|
14045
14121
|
pageCount: external_exports.number().int().positive()
|
|
14046
14122
|
});
|
|
14047
|
-
GithubBatchInput =
|
|
14123
|
+
GithubBatchInput = DispatchProfileSnapshotShape.extend({
|
|
14048
14124
|
items: external_exports.array(external_exports.object({ kind: external_exports.enum(["issue", "pr"]), number: external_exports.number().int().positive() })).min(1)
|
|
14049
|
-
}).strict();
|
|
14125
|
+
}).strict().superRefine(requireEffortOutsideAcp);
|
|
14050
14126
|
GithubBatchResult = external_exports.object({
|
|
14051
14127
|
dispatched: external_exports.array(external_exports.object({ number: external_exports.number(), kind: external_exports.string(), slug: ThreadSlug })),
|
|
14052
14128
|
failed: external_exports.array(external_exports.object({ number: external_exports.number(), kind: external_exports.string(), error: external_exports.string() }))
|
|
@@ -16829,7 +16905,7 @@ var require_websocket = __commonJS({
|
|
|
16829
16905
|
var http = __require("http");
|
|
16830
16906
|
var net = __require("net");
|
|
16831
16907
|
var tls = __require("tls");
|
|
16832
|
-
var { randomBytes: randomBytes2, createHash:
|
|
16908
|
+
var { randomBytes: randomBytes2, createHash: createHash5 } = __require("crypto");
|
|
16833
16909
|
var { Duplex, Readable } = __require("stream");
|
|
16834
16910
|
var { URL: URL2 } = __require("url");
|
|
16835
16911
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -17497,7 +17573,7 @@ var require_websocket = __commonJS({
|
|
|
17497
17573
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
17498
17574
|
return;
|
|
17499
17575
|
}
|
|
17500
|
-
const digest =
|
|
17576
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
17501
17577
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
17502
17578
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
17503
17579
|
return;
|
|
@@ -17866,7 +17942,7 @@ var require_websocket_server = __commonJS({
|
|
|
17866
17942
|
var EventEmitter = __require("events");
|
|
17867
17943
|
var http = __require("http");
|
|
17868
17944
|
var { Duplex } = __require("stream");
|
|
17869
|
-
var { createHash:
|
|
17945
|
+
var { createHash: createHash5 } = __require("crypto");
|
|
17870
17946
|
var extension2 = require_extension();
|
|
17871
17947
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
17872
17948
|
var subprotocol2 = require_subprotocol();
|
|
@@ -18173,7 +18249,7 @@ var require_websocket_server = __commonJS({
|
|
|
18173
18249
|
);
|
|
18174
18250
|
}
|
|
18175
18251
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
18176
|
-
const digest =
|
|
18252
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
18177
18253
|
const headers = [
|
|
18178
18254
|
"HTTP/1.1 101 Switching Protocols",
|
|
18179
18255
|
"Upgrade: websocket",
|
|
@@ -18341,11 +18417,11 @@ function pruneRunLogs(dir, keep = RETAINED_RUNS, days = RETAINED_DAYS, now = Dat
|
|
|
18341
18417
|
}
|
|
18342
18418
|
}
|
|
18343
18419
|
}
|
|
18344
|
-
function formatDiskLine(
|
|
18345
|
-
const at = new Date(
|
|
18420
|
+
function formatDiskLine(record2) {
|
|
18421
|
+
const at = new Date(record2.at);
|
|
18346
18422
|
const pad = (value, width = 2) => String(value).padStart(width, "0");
|
|
18347
18423
|
const clock = `${pad(at.getHours())}:${pad(at.getMinutes())}:${pad(at.getSeconds())}.${pad(at.getMilliseconds(), 3)}`;
|
|
18348
|
-
return `${clock} ${
|
|
18424
|
+
return `${clock} ${record2.level.toUpperCase().padEnd(5)} ${record2.scope.padEnd(12)} ${record2.message}
|
|
18349
18425
|
`;
|
|
18350
18426
|
}
|
|
18351
18427
|
function openLogFile(path) {
|
|
@@ -18372,10 +18448,10 @@ function createLogger(options2 = {}) {
|
|
|
18372
18448
|
const listeners = /* @__PURE__ */ new Set();
|
|
18373
18449
|
const emit = (recordLevel, scope, message) => {
|
|
18374
18450
|
if (LEVEL_ORDER[recordLevel] < threshold) return;
|
|
18375
|
-
const
|
|
18451
|
+
const record2 = { at: now(), level: recordLevel, scope, message };
|
|
18376
18452
|
if (fd !== null) {
|
|
18377
18453
|
try {
|
|
18378
|
-
const line = formatDiskLine(
|
|
18454
|
+
const line = formatDiskLine(record2);
|
|
18379
18455
|
if (written + line.length > maxBytes) {
|
|
18380
18456
|
writeSync(fd, `--- log truncated at ${maxBytes} bytes ---
|
|
18381
18457
|
`);
|
|
@@ -18390,7 +18466,7 @@ function createLogger(options2 = {}) {
|
|
|
18390
18466
|
}
|
|
18391
18467
|
for (const listener of listeners) {
|
|
18392
18468
|
try {
|
|
18393
|
-
listener(
|
|
18469
|
+
listener(record2);
|
|
18394
18470
|
} catch {
|
|
18395
18471
|
}
|
|
18396
18472
|
}
|
|
@@ -18417,13 +18493,13 @@ function setAmbientLogger(logger2) {
|
|
|
18417
18493
|
ambient = logger2;
|
|
18418
18494
|
return logger2;
|
|
18419
18495
|
}
|
|
18420
|
-
function formatFeedLine(
|
|
18421
|
-
return formatDiskLine(
|
|
18496
|
+
function formatFeedLine(record2) {
|
|
18497
|
+
return formatDiskLine(record2).trimEnd();
|
|
18422
18498
|
}
|
|
18423
18499
|
function attachTerminalMirror(logger2, enabled = process.env.FRIZZ_DEBUG === "1") {
|
|
18424
18500
|
if (!enabled) return () => {
|
|
18425
18501
|
};
|
|
18426
|
-
return logger2.onRecord((
|
|
18502
|
+
return logger2.onRecord((record2) => process.stderr.write(`${formatFeedLine(record2)}
|
|
18427
18503
|
`));
|
|
18428
18504
|
}
|
|
18429
18505
|
function ambientLogger() {
|
|
@@ -19120,13 +19196,13 @@ function acquireMutationGuard(stateDir, timeoutMs = GUARD_TIMEOUT_MS, adapter =
|
|
|
19120
19196
|
let fd;
|
|
19121
19197
|
try {
|
|
19122
19198
|
fd = openSync3(path, "wx", 384);
|
|
19123
|
-
const
|
|
19199
|
+
const record2 = {
|
|
19124
19200
|
version: 1,
|
|
19125
19201
|
token,
|
|
19126
19202
|
at: new Date(adapter.now()).toISOString(),
|
|
19127
19203
|
...generation
|
|
19128
19204
|
};
|
|
19129
|
-
writeFileSync6(fd, `${JSON.stringify(
|
|
19205
|
+
writeFileSync6(fd, `${JSON.stringify(record2)}
|
|
19130
19206
|
`, "utf8");
|
|
19131
19207
|
fsyncSync2(fd);
|
|
19132
19208
|
closeSync2(fd);
|
|
@@ -19170,13 +19246,13 @@ function parseDelegates(value) {
|
|
|
19170
19246
|
const seen = /* @__PURE__ */ new Set();
|
|
19171
19247
|
for (const candidate of value) {
|
|
19172
19248
|
if (!candidate || typeof candidate !== "object") return null;
|
|
19173
|
-
const
|
|
19174
|
-
const generation = parseGeneration(
|
|
19175
|
-
if (!generation || !validDelegateRole(
|
|
19249
|
+
const record2 = candidate;
|
|
19250
|
+
const generation = parseGeneration(record2);
|
|
19251
|
+
if (!generation || !validDelegateRole(record2.role) || !validText(record2.registeredAt, 128)) return null;
|
|
19176
19252
|
const key = `${generation.pid}:${generation.processStart}`;
|
|
19177
19253
|
if (seen.has(key)) return null;
|
|
19178
19254
|
seen.add(key);
|
|
19179
|
-
delegates.push({ ...generation, role:
|
|
19255
|
+
delegates.push({ ...generation, role: record2.role, registeredAt: record2.registeredAt });
|
|
19180
19256
|
}
|
|
19181
19257
|
return delegates;
|
|
19182
19258
|
}
|
|
@@ -19210,11 +19286,11 @@ function projectLaunchOwnerPath(stateDir) {
|
|
|
19210
19286
|
function readProjectLaunchOwner(stateDir) {
|
|
19211
19287
|
return parseOwner(projectLaunchOwnerPath(stateDir));
|
|
19212
19288
|
}
|
|
19213
|
-
function sameTarget(
|
|
19214
|
-
return
|
|
19289
|
+
function sameTarget(record2, target2) {
|
|
19290
|
+
return record2.projectId === target2.projectId && record2.projectDir === target2.projectDir;
|
|
19215
19291
|
}
|
|
19216
|
-
function sameProjectIdentity(
|
|
19217
|
-
return
|
|
19292
|
+
function sameProjectIdentity(record2, target2) {
|
|
19293
|
+
return record2.projectId === target2.projectId;
|
|
19218
19294
|
}
|
|
19219
19295
|
function projectLaunchTokenProof(target2, token) {
|
|
19220
19296
|
if (!UUID_RE.test(token)) throw new Error("invalid Frizz project launch owner token");
|
|
@@ -19230,11 +19306,11 @@ function removeStatusesForToken(stateDir, token) {
|
|
|
19230
19306
|
}
|
|
19231
19307
|
}
|
|
19232
19308
|
}
|
|
19233
|
-
function writeNewOwner(path,
|
|
19309
|
+
function writeNewOwner(path, record2) {
|
|
19234
19310
|
let fd;
|
|
19235
19311
|
try {
|
|
19236
19312
|
fd = openSync3(path, "wx", 384);
|
|
19237
|
-
writeFileSync6(fd, `${JSON.stringify(
|
|
19313
|
+
writeFileSync6(fd, `${JSON.stringify(record2)}
|
|
19238
19314
|
`, "utf8");
|
|
19239
19315
|
fsyncSync2(fd);
|
|
19240
19316
|
closeSync2(fd);
|
|
@@ -19250,21 +19326,21 @@ function writeNewOwner(path, record) {
|
|
|
19250
19326
|
throw error;
|
|
19251
19327
|
}
|
|
19252
19328
|
}
|
|
19253
|
-
function makeLease(target2,
|
|
19329
|
+
function makeLease(target2, record2, adapter) {
|
|
19254
19330
|
let released = false;
|
|
19255
19331
|
return {
|
|
19256
19332
|
target: target2,
|
|
19257
|
-
token:
|
|
19258
|
-
pid:
|
|
19259
|
-
processStart:
|
|
19260
|
-
role:
|
|
19333
|
+
token: record2.token,
|
|
19334
|
+
pid: record2.pid,
|
|
19335
|
+
processStart: record2.processStart,
|
|
19336
|
+
role: record2.role,
|
|
19261
19337
|
release: () => {
|
|
19262
19338
|
if (released) return false;
|
|
19263
19339
|
const unlock = acquireMutationGuard(target2.stateDir, GUARD_TIMEOUT_MS, adapter);
|
|
19264
19340
|
try {
|
|
19265
19341
|
const path = projectLaunchOwnerPath(target2.stateDir);
|
|
19266
19342
|
const current = parseOwner(path);
|
|
19267
|
-
if (!current || !sameTarget(current, target2) || current.token !==
|
|
19343
|
+
if (!current || !sameTarget(current, target2) || current.token !== record2.token || current.pid !== record2.pid || current.processStart !== record2.processStart) {
|
|
19268
19344
|
released = true;
|
|
19269
19345
|
return false;
|
|
19270
19346
|
}
|
|
@@ -19299,15 +19375,15 @@ function newOwnerRecord(target2, role, adapter) {
|
|
|
19299
19375
|
}
|
|
19300
19376
|
function installNewOwner(target2, role, adapter) {
|
|
19301
19377
|
const path = projectLaunchOwnerPath(target2.stateDir);
|
|
19302
|
-
const
|
|
19378
|
+
const record2 = newOwnerRecord(target2, role, adapter);
|
|
19303
19379
|
try {
|
|
19304
|
-
writeNewOwner(path,
|
|
19380
|
+
writeNewOwner(path, record2);
|
|
19305
19381
|
} catch (error) {
|
|
19306
19382
|
if (errorCode3(error) === "EEXIST") return { kind: "contended", owner: parseOwner(path) };
|
|
19307
19383
|
throw error;
|
|
19308
19384
|
}
|
|
19309
19385
|
const committed = parseOwner(path);
|
|
19310
|
-
if (!committed || committed.token !==
|
|
19386
|
+
if (!committed || committed.token !== record2.token) return { kind: "contended", owner: committed };
|
|
19311
19387
|
return { kind: "acquired", lease: makeLease(target2, committed, adapter) };
|
|
19312
19388
|
}
|
|
19313
19389
|
function drainDelegates(delegates, options2) {
|
|
@@ -19486,11 +19562,13 @@ function readBootProgress(stateDir) {
|
|
|
19486
19562
|
return null;
|
|
19487
19563
|
}
|
|
19488
19564
|
}
|
|
19489
|
-
var BOOT_PROGRESS_NAME;
|
|
19565
|
+
var BOOT_PROGRESS_NAME, BOOT_STALL_TIMEOUT_MS, BOOT_HARD_TIMEOUT_MS;
|
|
19490
19566
|
var init_boot_progress = __esm({
|
|
19491
19567
|
"packages/server/src/boot-progress.ts"() {
|
|
19492
19568
|
"use strict";
|
|
19493
19569
|
BOOT_PROGRESS_NAME = "boot.progress";
|
|
19570
|
+
BOOT_STALL_TIMEOUT_MS = 3e4;
|
|
19571
|
+
BOOT_HARD_TIMEOUT_MS = 10 * 6e4;
|
|
19494
19572
|
}
|
|
19495
19573
|
});
|
|
19496
19574
|
|
|
@@ -19828,12 +19906,19 @@ var init_project_registry = __esm({
|
|
|
19828
19906
|
}
|
|
19829
19907
|
});
|
|
19830
19908
|
|
|
19909
|
+
// packages/server/src/native-helper.ts
|
|
19910
|
+
var init_native_helper = __esm({
|
|
19911
|
+
"packages/server/src/native-helper.ts"() {
|
|
19912
|
+
"use strict";
|
|
19913
|
+
}
|
|
19914
|
+
});
|
|
19915
|
+
|
|
19831
19916
|
// src/production.ts
|
|
19832
19917
|
init_local_origin();
|
|
19833
|
-
import { readFileSync as
|
|
19918
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
19834
19919
|
import { homedir as homedir11 } from "node:os";
|
|
19835
19920
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
19836
|
-
import { join as
|
|
19921
|
+
import { join as join17 } from "node:path";
|
|
19837
19922
|
|
|
19838
19923
|
// src/browser.ts
|
|
19839
19924
|
import { spawn, execFile } from "node:child_process";
|
|
@@ -19995,12 +20080,12 @@ function manifestIdFor(url) {
|
|
|
19995
20080
|
return url.endsWith("/") ? url : `${url}/`;
|
|
19996
20081
|
}
|
|
19997
20082
|
function execFileP(cmd, args2) {
|
|
19998
|
-
return new Promise((
|
|
20083
|
+
return new Promise((resolve7, reject) => {
|
|
19999
20084
|
execFile(
|
|
20000
20085
|
cmd,
|
|
20001
20086
|
args2,
|
|
20002
20087
|
{ encoding: "utf8", timeout: 1e4 },
|
|
20003
|
-
(err, stdout) => err ? reject(err) :
|
|
20088
|
+
(err, stdout) => err ? reject(err) : resolve7(stdout)
|
|
20004
20089
|
);
|
|
20005
20090
|
});
|
|
20006
20091
|
}
|
|
@@ -20079,9 +20164,9 @@ function openCdpSession(browserPath, dataPath) {
|
|
|
20079
20164
|
cmdPipe.on("error", failAll);
|
|
20080
20165
|
resPipe.on("error", failAll);
|
|
20081
20166
|
child.on("exit", () => failAll(new Error("chrome exited before the CDP handshake completed")));
|
|
20082
|
-
const call2 = (method, params = {}, timeoutMs = 2e4) => new Promise((
|
|
20167
|
+
const call2 = (method, params = {}, timeoutMs = 2e4) => new Promise((resolve7, reject) => {
|
|
20083
20168
|
const id = ++seq;
|
|
20084
|
-
pending.set(id, { resolve:
|
|
20169
|
+
pending.set(id, { resolve: resolve7, reject });
|
|
20085
20170
|
cmdPipe.write(JSON.stringify({ id, method, params }) + "\0");
|
|
20086
20171
|
setTimeout(() => {
|
|
20087
20172
|
if (pending.has(id)) {
|
|
@@ -20094,15 +20179,15 @@ function openCdpSession(browserPath, dataPath) {
|
|
|
20094
20179
|
await call2("Browser.close").catch(() => {
|
|
20095
20180
|
});
|
|
20096
20181
|
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
20097
|
-
await new Promise((
|
|
20182
|
+
await new Promise((resolve7) => {
|
|
20098
20183
|
const t = setTimeout(() => {
|
|
20099
20184
|
child.kill();
|
|
20100
|
-
|
|
20185
|
+
resolve7();
|
|
20101
20186
|
}, 1e4);
|
|
20102
20187
|
t.unref();
|
|
20103
20188
|
child.once("exit", () => {
|
|
20104
20189
|
clearTimeout(t);
|
|
20105
|
-
|
|
20190
|
+
resolve7();
|
|
20106
20191
|
});
|
|
20107
20192
|
});
|
|
20108
20193
|
};
|
|
@@ -22619,6 +22704,7 @@ var RestartSupervisorProxy = class {
|
|
|
22619
22704
|
status() {
|
|
22620
22705
|
const delegated = this.options.status?.();
|
|
22621
22706
|
const updateVersion = this.options.updateVersion?.();
|
|
22707
|
+
const version = typeof this.options.version === "function" ? this.options.version() : this.options.version;
|
|
22622
22708
|
const owner = { state: this.state, ...this.message ? { message: this.message } : {} };
|
|
22623
22709
|
const reported = this.transition === "update" && delegated ? { ...delegated, ...delegated.state === "ready" ? { preparing: true } : {} } : this.restartInFlight !== null || this.state === "failed" ? owner : delegated ?? owner;
|
|
22624
22710
|
return {
|
|
@@ -22630,9 +22716,10 @@ var RestartSupervisorProxy = class {
|
|
|
22630
22716
|
// Sent ONLY when the launcher can actually answer it, so an older client — and frizz-dev, which
|
|
22631
22717
|
// has no notion of "already current" — keeps today's behaviour on its absence.
|
|
22632
22718
|
...this.options.updateAvailable ? { updateAvailable: this.options.updateAvailable() === true } : {},
|
|
22633
|
-
//
|
|
22634
|
-
// supervisors
|
|
22635
|
-
...
|
|
22719
|
+
// The active SERVER version changes on a child-only update. Its absence keeps frizz-dev and
|
|
22720
|
+
// old monolithic supervisors' status payload and versionless UI exactly as they were.
|
|
22721
|
+
...version ? { version } : {},
|
|
22722
|
+
...this.options.launcherVersion ? { launcherVersion: this.options.launcherVersion } : {},
|
|
22636
22723
|
...updateVersion ? { updateVersion } : {},
|
|
22637
22724
|
// Sent only when TRUE, so a published Frizz's payload is byte-identical to what it sends today
|
|
22638
22725
|
// and an older client is unaffected. Absent therefore means "not a development build".
|
|
@@ -23288,7 +23375,7 @@ function serveRelayRequest(frame, options2) {
|
|
|
23288
23375
|
const publicUrl = new URL(options2.publicOrigin);
|
|
23289
23376
|
let cancelled = false;
|
|
23290
23377
|
let abort;
|
|
23291
|
-
const done = new Promise((
|
|
23378
|
+
const done = new Promise((resolve7) => {
|
|
23292
23379
|
const send = (upFrame) => {
|
|
23293
23380
|
if (!cancelled) options2.send(upFrame);
|
|
23294
23381
|
};
|
|
@@ -23322,11 +23409,11 @@ function serveRelayRequest(frame, options2) {
|
|
|
23322
23409
|
});
|
|
23323
23410
|
res.on("end", () => {
|
|
23324
23411
|
send({ t: "res-end", id: frame.id });
|
|
23325
|
-
|
|
23412
|
+
resolve7();
|
|
23326
23413
|
});
|
|
23327
23414
|
res.on("error", () => {
|
|
23328
23415
|
send({ t: "res-end", id: frame.id });
|
|
23329
|
-
|
|
23416
|
+
resolve7();
|
|
23330
23417
|
});
|
|
23331
23418
|
return;
|
|
23332
23419
|
}
|
|
@@ -23343,7 +23430,7 @@ function serveRelayRequest(frame, options2) {
|
|
|
23343
23430
|
...body.byteLength > 0 ? { body: encodeBody(new Uint8Array(body)) } : {},
|
|
23344
23431
|
end: true
|
|
23345
23432
|
});
|
|
23346
|
-
|
|
23433
|
+
resolve7();
|
|
23347
23434
|
return;
|
|
23348
23435
|
}
|
|
23349
23436
|
send({ t: "res", id: frame.id, status: res.statusCode ?? 502, headers: outHeaders, end: false });
|
|
@@ -23355,11 +23442,11 @@ function serveRelayRequest(frame, options2) {
|
|
|
23355
23442
|
});
|
|
23356
23443
|
}
|
|
23357
23444
|
send({ t: "res-end", id: frame.id });
|
|
23358
|
-
|
|
23445
|
+
resolve7();
|
|
23359
23446
|
});
|
|
23360
23447
|
res.on("error", () => {
|
|
23361
23448
|
send({ t: "res", id: frame.id, status: 502, headers: [], end: true });
|
|
23362
|
-
|
|
23449
|
+
resolve7();
|
|
23363
23450
|
});
|
|
23364
23451
|
}
|
|
23365
23452
|
);
|
|
@@ -23372,13 +23459,13 @@ function serveRelayRequest(frame, options2) {
|
|
|
23372
23459
|
body: encodeBody(new TextEncoder().encode(`Frizz is not answering on this machine: ${error.message}`)),
|
|
23373
23460
|
end: true
|
|
23374
23461
|
});
|
|
23375
|
-
|
|
23462
|
+
resolve7();
|
|
23376
23463
|
});
|
|
23377
23464
|
if (frame.body) req.write(Buffer.from(decodeBody(frame.body)));
|
|
23378
23465
|
req.end();
|
|
23379
23466
|
abort = () => {
|
|
23380
23467
|
req.destroy();
|
|
23381
|
-
|
|
23468
|
+
resolve7();
|
|
23382
23469
|
};
|
|
23383
23470
|
});
|
|
23384
23471
|
return {
|
|
@@ -23512,9 +23599,9 @@ function connectRelay(options2) {
|
|
|
23512
23599
|
};
|
|
23513
23600
|
const scheduleRetry = (reason) => {
|
|
23514
23601
|
if (stopped) return;
|
|
23515
|
-
const
|
|
23516
|
-
options2.onStatus?.("retrying", `${reason}; retrying in ${Math.round(
|
|
23517
|
-
retryHandle = setTimer(() => void open(),
|
|
23602
|
+
const delay3 = backoff(attempt++);
|
|
23603
|
+
options2.onStatus?.("retrying", `${reason}; retrying in ${Math.round(delay3 / 1e3)}s`);
|
|
23604
|
+
retryHandle = setTimer(() => void open(), delay3);
|
|
23518
23605
|
};
|
|
23519
23606
|
const open = async () => {
|
|
23520
23607
|
if (stopped) return;
|
|
@@ -23937,9 +24024,9 @@ function createRemoteController(options2) {
|
|
|
23937
24024
|
import { execFile as execFile3 } from "node:child_process";
|
|
23938
24025
|
var PROBE_TIMEOUT_MS = 4e3;
|
|
23939
24026
|
function run2(command, args2) {
|
|
23940
|
-
return new Promise((
|
|
24027
|
+
return new Promise((resolve7) => {
|
|
23941
24028
|
execFile3(command, args2, { encoding: "utf8", timeout: PROBE_TIMEOUT_MS }, (error, stdout) => {
|
|
23942
|
-
|
|
24029
|
+
resolve7(error ? null : stdout);
|
|
23943
24030
|
});
|
|
23944
24031
|
});
|
|
23945
24032
|
}
|
|
@@ -24643,8 +24730,8 @@ init_logging();
|
|
|
24643
24730
|
init_src();
|
|
24644
24731
|
init_project_registry();
|
|
24645
24732
|
var PORT_SCAN_COUNT = 100;
|
|
24646
|
-
var LAUNCH_TIMEOUT_MS =
|
|
24647
|
-
var LAUNCH_HARD_TIMEOUT_MS =
|
|
24733
|
+
var LAUNCH_TIMEOUT_MS = BOOT_STALL_TIMEOUT_MS;
|
|
24734
|
+
var LAUNCH_HARD_TIMEOUT_MS = BOOT_HARD_TIMEOUT_MS;
|
|
24648
24735
|
var RETIRED_NETWORK_FLAGS = ["--host", "--allowed-host", "--public-origin", "--cloud"];
|
|
24649
24736
|
function retiredFlagMessage(flag) {
|
|
24650
24737
|
return `${flag} was retired \u2014 how a board is reached is set up from the running board now: press R in its terminal to pick a private or custom frizz.sh name, a Cloudflare Tunnel, Tailscale or a proxy of your own. The choice is remembered, so a plain launch serves it.`;
|
|
@@ -25178,11 +25265,14 @@ import { basename as basename6, dirname as dirname11, extname as extname2, isAbs
|
|
|
25178
25265
|
import { fileURLToPath } from "node:url";
|
|
25179
25266
|
import watcher from "@parcel/watcher";
|
|
25180
25267
|
init_logging();
|
|
25268
|
+
init_boot_progress();
|
|
25181
25269
|
var DEV_RESTART_DEBOUNCE_MS = 180;
|
|
25182
25270
|
var DEV_CRASH_STABLE_MS = 5e3;
|
|
25183
25271
|
var DEV_CRASH_RETRY_BASE_MS = 500;
|
|
25184
25272
|
var DEV_CRASH_RETRY_MAX_MS = 1e4;
|
|
25185
25273
|
var CHILD_STOP_TIMEOUT_MS = 15e3;
|
|
25274
|
+
var STABLE_UPDATE_READY_TIMEOUT_MS = BOOT_STALL_TIMEOUT_MS;
|
|
25275
|
+
var STABLE_UPDATE_STABILIZE_MS = 1e3;
|
|
25186
25276
|
var CHILD_KILL_GRACE_MS = 5e3;
|
|
25187
25277
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".mjs", ".cjs", ".json"]);
|
|
25188
25278
|
var CONFIG_NAMES = /* @__PURE__ */ new Set(["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml", ".npmrc"]);
|
|
@@ -25389,6 +25479,12 @@ var Supervisor = class {
|
|
|
25389
25479
|
debounce = null;
|
|
25390
25480
|
restartRunning = false;
|
|
25391
25481
|
restartAgain = false;
|
|
25482
|
+
/** Resolves when a pre-existing watcher restart has released the one child slot. */
|
|
25483
|
+
restartCompletion = null;
|
|
25484
|
+
/** Serializes an update candidate with watcher/browser restart requests. */
|
|
25485
|
+
updateChildRunning = false;
|
|
25486
|
+
/** A candidate never joins crash-retry until its selection has committed. */
|
|
25487
|
+
updateCandidate = null;
|
|
25392
25488
|
reloadLauncher = false;
|
|
25393
25489
|
crashAttempts = 0;
|
|
25394
25490
|
crashStableTimer = null;
|
|
@@ -25424,6 +25520,11 @@ var Supervisor = class {
|
|
|
25424
25520
|
lastActivity;
|
|
25425
25521
|
publicProxy;
|
|
25426
25522
|
updateRestart;
|
|
25523
|
+
updateMode;
|
|
25524
|
+
commitUpdate;
|
|
25525
|
+
updateReadyTimeoutMs;
|
|
25526
|
+
updateHardTimeoutMs;
|
|
25527
|
+
updateStabilizeMs;
|
|
25427
25528
|
rollbackUpdate;
|
|
25428
25529
|
durableReexec;
|
|
25429
25530
|
/** Environment of the generation that actually reached ready, never merely the latest pointer. */
|
|
@@ -25464,6 +25565,11 @@ var Supervisor = class {
|
|
|
25464
25565
|
this.errorLine = opts.error ?? ((line) => log.error("supervisor", stripPrefix(line)));
|
|
25465
25566
|
this.onActivity = opts.onActivity;
|
|
25466
25567
|
this.updateRestart = opts.updateRestart;
|
|
25568
|
+
this.updateMode = opts.updateMode ?? "durableReexec";
|
|
25569
|
+
this.commitUpdate = opts.commitUpdate;
|
|
25570
|
+
this.updateReadyTimeoutMs = Math.max(1, opts.updateReadyTimeoutMs ?? STABLE_UPDATE_READY_TIMEOUT_MS);
|
|
25571
|
+
this.updateHardTimeoutMs = Math.max(1, opts.updateHardTimeoutMs ?? BOOT_HARD_TIMEOUT_MS);
|
|
25572
|
+
this.updateStabilizeMs = Math.max(0, opts.updateStabilizeMs ?? STABLE_UPDATE_STABILIZE_MS);
|
|
25467
25573
|
this.rollbackUpdate = opts.rollbackUpdate;
|
|
25468
25574
|
this.durableReexec = opts.durableReexec;
|
|
25469
25575
|
this.publicProxy = new RestartSupervisorProxy({
|
|
@@ -25479,6 +25585,7 @@ var Supervisor = class {
|
|
|
25479
25585
|
updateRestart: this.updateRestart ? () => this.updateFromBrowser() : void 0,
|
|
25480
25586
|
updateAvailable: opts.updateAvailable,
|
|
25481
25587
|
version: opts.version,
|
|
25588
|
+
launcherVersion: opts.launcherVersion,
|
|
25482
25589
|
updateVersion: opts.updateVersion,
|
|
25483
25590
|
dev: opts.dev,
|
|
25484
25591
|
status: () => {
|
|
@@ -25570,6 +25677,10 @@ var Supervisor = class {
|
|
|
25570
25677
|
}
|
|
25571
25678
|
requestRestart(reason, immediate = false, reloadLauncher = false, delayMs = this.debounceMs) {
|
|
25572
25679
|
if (this.closed) return;
|
|
25680
|
+
if (this.updateChildRunning) {
|
|
25681
|
+
this.restartAgain = true;
|
|
25682
|
+
return;
|
|
25683
|
+
}
|
|
25573
25684
|
this.reloadLauncher ||= reloadLauncher;
|
|
25574
25685
|
if (this.debounce) clearTimeout(this.debounce);
|
|
25575
25686
|
const run3 = () => {
|
|
@@ -25585,11 +25696,20 @@ var Supervisor = class {
|
|
|
25585
25696
|
else this.debounce = setTimeout(run3, delayMs);
|
|
25586
25697
|
}
|
|
25587
25698
|
async restart() {
|
|
25699
|
+
if (this.updateChildRunning) {
|
|
25700
|
+
this.restartAgain = true;
|
|
25701
|
+
return;
|
|
25702
|
+
}
|
|
25588
25703
|
if (this.restartRunning) {
|
|
25589
25704
|
this.restartAgain = true;
|
|
25590
25705
|
return;
|
|
25591
25706
|
}
|
|
25592
25707
|
this.restartRunning = true;
|
|
25708
|
+
let completeRestart;
|
|
25709
|
+
const completion = new Promise((resolveCompletion) => {
|
|
25710
|
+
completeRestart = resolveCompletion;
|
|
25711
|
+
});
|
|
25712
|
+
this.restartCompletion = completion;
|
|
25593
25713
|
try {
|
|
25594
25714
|
let shouldReloadLauncher = false;
|
|
25595
25715
|
do {
|
|
@@ -25597,7 +25717,7 @@ var Supervisor = class {
|
|
|
25597
25717
|
shouldReloadLauncher ||= this.reloadLauncher;
|
|
25598
25718
|
this.reloadLauncher = false;
|
|
25599
25719
|
await this.stopChild();
|
|
25600
|
-
if (!this.closed) {
|
|
25720
|
+
if (!this.closed && !this.updateChildRunning) {
|
|
25601
25721
|
const ready = await this.spawnChild();
|
|
25602
25722
|
if (!ready) return;
|
|
25603
25723
|
}
|
|
@@ -25605,6 +25725,8 @@ var Supervisor = class {
|
|
|
25605
25725
|
if (shouldReloadLauncher && !this.closed) await this.reexecLauncher();
|
|
25606
25726
|
} finally {
|
|
25607
25727
|
this.restartRunning = false;
|
|
25728
|
+
completeRestart();
|
|
25729
|
+
if (this.restartCompletion === completion) this.restartCompletion = null;
|
|
25608
25730
|
}
|
|
25609
25731
|
}
|
|
25610
25732
|
/** Called only by the public supervisor control endpoint, never by ordinary document reloads. */
|
|
@@ -25635,6 +25757,7 @@ var Supervisor = class {
|
|
|
25635
25757
|
}
|
|
25636
25758
|
async updateFromBrowser() {
|
|
25637
25759
|
if (!this.updateRestart) return { state: "failed", message: "Update & Restart is unavailable in this launcher mode" };
|
|
25760
|
+
if (this.updateMode === "child") return this.updateChildFromBrowser();
|
|
25638
25761
|
this.emitActivity("updating", "preparing the update \u2014 the running Frizz is untouched until it is ready");
|
|
25639
25762
|
const candidate = await this.updateRestart();
|
|
25640
25763
|
if (candidate.state !== "ready") {
|
|
@@ -25661,6 +25784,115 @@ var Supervisor = class {
|
|
|
25661
25784
|
this.handoffDraining = false;
|
|
25662
25785
|
}
|
|
25663
25786
|
}
|
|
25787
|
+
/**
|
|
25788
|
+
* Update only the disposable application server while retaining the public listener and launcher.
|
|
25789
|
+
* There is deliberately no blue/green overlap: a Frizz child opens SQLite, tailers and schedulers
|
|
25790
|
+
* before it can report ready, so a candidate is started only after the old child is fully gone.
|
|
25791
|
+
*/
|
|
25792
|
+
async updateChildFromBrowser() {
|
|
25793
|
+
if (!this.commitUpdate || !this.rollbackUpdate) {
|
|
25794
|
+
return { state: "failed", message: "child-only Update & Restart requires commit and rollback callbacks" };
|
|
25795
|
+
}
|
|
25796
|
+
this.updateChildRunning = true;
|
|
25797
|
+
try {
|
|
25798
|
+
await this.restartCompletion;
|
|
25799
|
+
this.emitActivity("updating", "preparing the new build \u2014 the running one is untouched until it is ready");
|
|
25800
|
+
let prepared;
|
|
25801
|
+
try {
|
|
25802
|
+
prepared = await this.updateRestart();
|
|
25803
|
+
} catch (error) {
|
|
25804
|
+
return this.failChildUpdate(`the update could not be prepared: ${error instanceof Error ? error.message : error}`, false);
|
|
25805
|
+
}
|
|
25806
|
+
if (prepared.state !== "ready") {
|
|
25807
|
+
return this.failChildUpdate(prepared.message ?? "the update could not be prepared", false);
|
|
25808
|
+
}
|
|
25809
|
+
if (this.closed) return this.failChildUpdate("Frizz supervisor stopped while preparing the update", false);
|
|
25810
|
+
if (prepared.message) this.emitActivity("updating", prepared.message);
|
|
25811
|
+
this.handoffDraining = true;
|
|
25812
|
+
await this.stopChild();
|
|
25813
|
+
if (this.closed) return this.failChildUpdate("Frizz supervisor stopped while starting the update", true);
|
|
25814
|
+
const ready = await this.spawnChild({
|
|
25815
|
+
updateCandidate: true,
|
|
25816
|
+
readinessTimeoutMs: this.updateReadyTimeoutMs,
|
|
25817
|
+
hardTimeoutMs: this.updateHardTimeoutMs
|
|
25818
|
+
});
|
|
25819
|
+
const candidate = this.child;
|
|
25820
|
+
if (!ready || !candidate) {
|
|
25821
|
+
return this.failChildUpdate(this.lastRestartFailure ?? "the update candidate did not become ready", true);
|
|
25822
|
+
}
|
|
25823
|
+
if (!await this.stabilizeUpdateCandidate(candidate)) {
|
|
25824
|
+
return this.failChildUpdate("the update candidate stopped before it became stable", true);
|
|
25825
|
+
}
|
|
25826
|
+
try {
|
|
25827
|
+
await this.commitUpdate();
|
|
25828
|
+
} catch (error) {
|
|
25829
|
+
return this.failChildUpdate(`the update could not be committed: ${error instanceof Error ? error.message : error}`, true);
|
|
25830
|
+
}
|
|
25831
|
+
if (this.closed || this.child !== candidate || candidate.exitCode !== null || candidate.signalCode !== null) {
|
|
25832
|
+
return this.failChildUpdate("the update candidate stopped while committing the update", true);
|
|
25833
|
+
}
|
|
25834
|
+
this.updateCandidate = null;
|
|
25835
|
+
this.lastRestartFailure = void 0;
|
|
25836
|
+
return { state: "ready" };
|
|
25837
|
+
} finally {
|
|
25838
|
+
this.updateChildRunning = false;
|
|
25839
|
+
this.handoffDraining = false;
|
|
25840
|
+
if (this.restartAgain && !this.closed) {
|
|
25841
|
+
this.restartAgain = false;
|
|
25842
|
+
this.requestRestart("changes received while updating", true);
|
|
25843
|
+
}
|
|
25844
|
+
}
|
|
25845
|
+
}
|
|
25846
|
+
/** Wait past a ready event so an immediate post-boot crash cannot be made durable. */
|
|
25847
|
+
async stabilizeUpdateCandidate(candidate) {
|
|
25848
|
+
if (this.child !== candidate || candidate.exitCode !== null || candidate.signalCode !== null) return false;
|
|
25849
|
+
if (this.updateStabilizeMs === 0) return true;
|
|
25850
|
+
return new Promise((resolveStable) => {
|
|
25851
|
+
let settled = false;
|
|
25852
|
+
const finish = (stable) => {
|
|
25853
|
+
if (settled) return;
|
|
25854
|
+
settled = true;
|
|
25855
|
+
clearTimeout(timer);
|
|
25856
|
+
candidate.removeListener("exit", exited);
|
|
25857
|
+
resolveStable(stable);
|
|
25858
|
+
};
|
|
25859
|
+
const exited = () => finish(false);
|
|
25860
|
+
const timer = setTimeout(() => finish(this.child === candidate && !this.closed), this.updateStabilizeMs);
|
|
25861
|
+
timer.unref();
|
|
25862
|
+
candidate.once("exit", exited);
|
|
25863
|
+
});
|
|
25864
|
+
}
|
|
25865
|
+
/** Restore the prepared selection and, if it was drained, put the known-good child back. */
|
|
25866
|
+
async failChildUpdate(message, restoreChild) {
|
|
25867
|
+
const failures = [];
|
|
25868
|
+
const candidate = this.updateCandidate;
|
|
25869
|
+
if (candidate && this.child === candidate) await this.stopChild();
|
|
25870
|
+
this.updateCandidate = null;
|
|
25871
|
+
let rolledBack = false;
|
|
25872
|
+
if (!this.rollbackUpdate) failures.push("rollback callback is unavailable");
|
|
25873
|
+
else {
|
|
25874
|
+
try {
|
|
25875
|
+
await this.rollbackUpdate();
|
|
25876
|
+
rolledBack = true;
|
|
25877
|
+
} catch (error) {
|
|
25878
|
+
failures.push(`rollback failed: ${error instanceof Error ? error.message : error}`);
|
|
25879
|
+
}
|
|
25880
|
+
}
|
|
25881
|
+
if (restoreChild && rolledBack && !this.closed) {
|
|
25882
|
+
try {
|
|
25883
|
+
const restored = await this.spawnChild();
|
|
25884
|
+
if (!restored) failures.push(`control plane recovery failed: ${this.lastRestartFailure ?? "the previous child did not become ready"}`);
|
|
25885
|
+
} catch (error) {
|
|
25886
|
+
failures.push(`control plane recovery failed: ${error instanceof Error ? error.message : error}`);
|
|
25887
|
+
}
|
|
25888
|
+
} else if (restoreChild && !rolledBack) {
|
|
25889
|
+
failures.push("control plane was not restarted because rollback did not restore a known-good selection");
|
|
25890
|
+
}
|
|
25891
|
+
const detail = failures.length > 0 ? `${message}; ${failures.join("; ")}` : message;
|
|
25892
|
+
this.errorLine(`[frizz] ${detail}`);
|
|
25893
|
+
if (!this.closed) this.writeStatus("failed", detail, this.boot);
|
|
25894
|
+
return { state: "failed", message: detail };
|
|
25895
|
+
}
|
|
25664
25896
|
/**
|
|
25665
25897
|
* A promoted pointer is not committed until its durable owner has actually been replaced. If
|
|
25666
25898
|
* that handoff cannot happen, put the previous pointer back before reporting the failure. When
|
|
@@ -25709,7 +25941,7 @@ var Supervisor = class {
|
|
|
25709
25941
|
await this.publicProxy.close();
|
|
25710
25942
|
this.writeStatus("restarting", "immutable artifact promoted; re-executing durable supervisor", null);
|
|
25711
25943
|
}
|
|
25712
|
-
async spawnChild() {
|
|
25944
|
+
async spawnChild(options2 = {}) {
|
|
25713
25945
|
const privatePort = await allocatePrivateDevPort(this.port);
|
|
25714
25946
|
let launch;
|
|
25715
25947
|
try {
|
|
@@ -25748,16 +25980,53 @@ var Supervisor = class {
|
|
|
25748
25980
|
return;
|
|
25749
25981
|
}
|
|
25750
25982
|
this.child = child;
|
|
25983
|
+
if (options2.updateCandidate) this.updateCandidate = child;
|
|
25751
25984
|
this.childPort = privatePort;
|
|
25752
25985
|
this.boot = null;
|
|
25753
25986
|
let started = false;
|
|
25754
25987
|
let ownershipRejected = false;
|
|
25755
25988
|
let spawnSettled = false;
|
|
25989
|
+
let readinessTimer;
|
|
25756
25990
|
const settleSpawn = (ready) => {
|
|
25757
25991
|
if (spawnSettled) return;
|
|
25758
25992
|
spawnSettled = true;
|
|
25993
|
+
if (readinessTimer) clearTimeout(readinessTimer);
|
|
25759
25994
|
settled(ready);
|
|
25760
25995
|
};
|
|
25996
|
+
if (options2.readinessTimeoutMs !== void 0) {
|
|
25997
|
+
const stallMs = options2.readinessTimeoutMs;
|
|
25998
|
+
const hardMs = options2.hardTimeoutMs ?? BOOT_HARD_TIMEOUT_MS;
|
|
25999
|
+
const hardDeadline = Date.now() + hardMs;
|
|
26000
|
+
let stallDeadline = Date.now() + stallMs;
|
|
26001
|
+
let lastStep = -1;
|
|
26002
|
+
let lastPhase;
|
|
26003
|
+
const checkProgress = () => {
|
|
26004
|
+
if (spawnSettled) return;
|
|
26005
|
+
const now = Date.now();
|
|
26006
|
+
const progress = readBootProgress(this.launchTarget.stateDir);
|
|
26007
|
+
if (progress && progress.pid === child.pid && progress.step > lastStep) {
|
|
26008
|
+
lastStep = progress.step;
|
|
26009
|
+
lastPhase = progress.phase;
|
|
26010
|
+
stallDeadline = now + stallMs;
|
|
26011
|
+
}
|
|
26012
|
+
if (now < stallDeadline && now < hardDeadline) {
|
|
26013
|
+
readinessTimer = setTimeout(checkProgress, Math.min(250, stallDeadline - now, hardDeadline - now));
|
|
26014
|
+
readinessTimer.unref();
|
|
26015
|
+
return;
|
|
26016
|
+
}
|
|
26017
|
+
const reason = now >= hardDeadline ? `update candidate did not become ready within ${hardMs}ms` : `update candidate made no boot progress for ${stallMs}ms`;
|
|
26018
|
+
const message = lastPhase ? `${reason}; last boot step: ${lastPhase}` : reason;
|
|
26019
|
+
this.lastRestartFailure = message;
|
|
26020
|
+
this.errorLine(`[frizz] ${message}`);
|
|
26021
|
+
this.writeStatus("failed", message, null);
|
|
26022
|
+
try {
|
|
26023
|
+
child.kill("SIGTERM");
|
|
26024
|
+
} catch {
|
|
26025
|
+
}
|
|
26026
|
+
settleSpawn(false);
|
|
26027
|
+
};
|
|
26028
|
+
checkProgress();
|
|
26029
|
+
}
|
|
25761
26030
|
child.on("message", (message) => {
|
|
25762
26031
|
if (stopOwnerMessage(message) && message.token === this.ownerToken) {
|
|
25763
26032
|
this.resolveStopRequested();
|
|
@@ -25799,7 +26068,7 @@ var Supervisor = class {
|
|
|
25799
26068
|
this.boot = null;
|
|
25800
26069
|
this.activeChildEnvironment = {};
|
|
25801
26070
|
}
|
|
25802
|
-
const expected2 = this.closed || this.stopping === child || ownershipRejected;
|
|
26071
|
+
const expected2 = this.closed || this.stopping === child || ownershipRejected || this.updateCandidate === child;
|
|
25803
26072
|
this.clearCrashStability();
|
|
25804
26073
|
if (!expected2) {
|
|
25805
26074
|
const why = signal ? `signal ${signal}` : `exit ${code ?? "unknown"}`;
|
|
@@ -26012,15 +26281,11 @@ async function startDevSupervisor(opts) {
|
|
|
26012
26281
|
}
|
|
26013
26282
|
|
|
26014
26283
|
// src/production-update.ts
|
|
26015
|
-
init_src();
|
|
26016
26284
|
import { execFile as execFile4, spawn as spawn3 } from "node:child_process";
|
|
26017
26285
|
import { existsSync as existsSync7 } from "node:fs";
|
|
26018
26286
|
import { dirname as dirname12, isAbsolute as isAbsolute5, join as join14 } from "node:path";
|
|
26019
|
-
|
|
26287
|
+
init_src();
|
|
26020
26288
|
var PRODUCTION_REEXEC_FLAG = "--_frizz-production-reexec";
|
|
26021
|
-
function canReexecInPlace(platform = process.platform, execve = process.execve) {
|
|
26022
|
-
return platform !== "win32" && typeof execve === "function";
|
|
26023
|
-
}
|
|
26024
26289
|
var PRODUCTION_PRINT_LAUNCHER_FLAG = "--_frizz-print-launcher";
|
|
26025
26290
|
function resolveNpmInvocation(env = process.env, execPath = process.execPath, exists = existsSync7, platform = process.platform) {
|
|
26026
26291
|
const nodeDir = dirname12(execPath);
|
|
@@ -26040,9 +26305,11 @@ function resolveNpmInvocation(env = process.env, execPath = process.execPath, ex
|
|
|
26040
26305
|
}
|
|
26041
26306
|
function compareReleaseVersions(a, b) {
|
|
26042
26307
|
const parse2 = (value) => {
|
|
26043
|
-
const match = /^v?(\d
|
|
26308
|
+
const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u.exec(value);
|
|
26044
26309
|
if (!match) return null;
|
|
26045
|
-
|
|
26310
|
+
const prerelease = match[4]?.split(".");
|
|
26311
|
+
if (prerelease?.some((part) => /^0\d+$/u.test(part))) return null;
|
|
26312
|
+
return { numeric: [BigInt(match[1]), BigInt(match[2]), BigInt(match[3])], prerelease };
|
|
26046
26313
|
};
|
|
26047
26314
|
const left = parse2(a);
|
|
26048
26315
|
const right = parse2(b);
|
|
@@ -26051,26 +26318,22 @@ function compareReleaseVersions(a, b) {
|
|
|
26051
26318
|
const delta = left.numeric[index] - right.numeric[index];
|
|
26052
26319
|
if (delta) return delta < 0 ? -1 : 1;
|
|
26053
26320
|
}
|
|
26054
|
-
if (left.prerelease
|
|
26321
|
+
if (!left.prerelease && !right.prerelease) return 0;
|
|
26055
26322
|
if (!left.prerelease) return 1;
|
|
26056
26323
|
if (!right.prerelease) return -1;
|
|
26057
|
-
|
|
26058
|
-
|
|
26059
|
-
|
|
26060
|
-
|
|
26061
|
-
|
|
26062
|
-
|
|
26063
|
-
const
|
|
26064
|
-
const
|
|
26065
|
-
if (
|
|
26066
|
-
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
return l < r ? -1 : 1;
|
|
26071
|
-
}
|
|
26072
|
-
if (left.length === right.length) return 0;
|
|
26073
|
-
return left.length < right.length ? -1 : 1;
|
|
26324
|
+
for (let index = 0; index < Math.max(left.prerelease.length, right.prerelease.length); index++) {
|
|
26325
|
+
const a2 = left.prerelease[index];
|
|
26326
|
+
const b2 = right.prerelease[index];
|
|
26327
|
+
if (a2 === b2) continue;
|
|
26328
|
+
if (a2 === void 0) return -1;
|
|
26329
|
+
if (b2 === void 0) return 1;
|
|
26330
|
+
const aNumeric = /^\d+$/u.test(a2);
|
|
26331
|
+
const bNumeric = /^\d+$/u.test(b2);
|
|
26332
|
+
if (aNumeric && bNumeric) return BigInt(a2) < BigInt(b2) ? -1 : 1;
|
|
26333
|
+
if (aNumeric !== bNumeric) return aNumeric ? -1 : 1;
|
|
26334
|
+
return a2 < b2 ? -1 : 1;
|
|
26335
|
+
}
|
|
26336
|
+
return 0;
|
|
26074
26337
|
}
|
|
26075
26338
|
async function planRegistryUpdate(packageName, currentVersion, adapter) {
|
|
26076
26339
|
const latestVersion = (await adapter.latestVersion(packageName)).trim();
|
|
@@ -26080,9 +26343,6 @@ async function planRegistryUpdate(packageName, currentVersion, adapter) {
|
|
|
26080
26343
|
if (comparison >= 0) return null;
|
|
26081
26344
|
return { packageName, currentVersion, latestVersion, packageSpec: `${packageName}@${latestVersion}` };
|
|
26082
26345
|
}
|
|
26083
|
-
function successorArgs(port) {
|
|
26084
|
-
return [PRODUCTION_REEXEC_FLAG, "--port", String(port)];
|
|
26085
|
-
}
|
|
26086
26346
|
function reexecArgv(rawArgs2) {
|
|
26087
26347
|
const kept = [];
|
|
26088
26348
|
for (let index = 0; index < rawArgs2.length; index++) {
|
|
@@ -26097,110 +26357,6 @@ function reexecArgv(rawArgs2) {
|
|
|
26097
26357
|
}
|
|
26098
26358
|
return kept;
|
|
26099
26359
|
}
|
|
26100
|
-
async function resolveRegistrySuccessor(plan, request, adapter) {
|
|
26101
|
-
const result = await adapter.npmExec({
|
|
26102
|
-
packageSpec: plan.packageSpec,
|
|
26103
|
-
// The published bin name tracks the package name (frizz). Never hardcode a stale bin here or
|
|
26104
|
-
// a renamed release would resolve the new package but invoke a bin that no longer exists.
|
|
26105
|
-
bin: plan.packageName,
|
|
26106
|
-
args: [PRODUCTION_PRINT_LAUNCHER_FLAG],
|
|
26107
|
-
cwd: request.cwd,
|
|
26108
|
-
env: request.env
|
|
26109
|
-
});
|
|
26110
|
-
if (result.code !== 0) {
|
|
26111
|
-
const how = result.signal ? `signal ${result.signal}` : `exit ${result.code}`;
|
|
26112
|
-
const tail = result.stderr.trim().split("\n").slice(-6).join("\n").trim();
|
|
26113
|
-
throw new Error(`npm exec ${plan.packageSpec} failed (${how})${tail ? `: ${tail}` : ""}`);
|
|
26114
|
-
}
|
|
26115
|
-
const entry = result.stdout.trim().split("\n").map((line) => line.trim()).filter(Boolean).at(-1) ?? "";
|
|
26116
|
-
if (!isAbsolute5(entry) || !existsSync7(entry))
|
|
26117
|
-
throw new Error(`${plan.packageSpec} did not report its launcher entry (got ${JSON.stringify(entry)})`);
|
|
26118
|
-
return { plan, entry };
|
|
26119
|
-
}
|
|
26120
|
-
function reexecIntoRegistrySuccessor(successor, request, execve = process.execve.bind(process)) {
|
|
26121
|
-
return execve(process.execPath, [process.execPath, successor.entry, ...successorArgs(request.port)], {
|
|
26122
|
-
...request.env,
|
|
26123
|
-
FRIZZ_REGISTRY_PACKAGE: successor.plan.packageName,
|
|
26124
|
-
FRIZZ_REGISTRY_VERSION: successor.plan.latestVersion
|
|
26125
|
-
});
|
|
26126
|
-
}
|
|
26127
|
-
function handoffToRegistrySuccessor(successor, request, adapter) {
|
|
26128
|
-
const child = adapter.spawnDetached({
|
|
26129
|
-
entry: successor.entry,
|
|
26130
|
-
args: successorArgs(request.port),
|
|
26131
|
-
cwd: request.cwd,
|
|
26132
|
-
env: {
|
|
26133
|
-
...request.env,
|
|
26134
|
-
FRIZZ_REGISTRY_PACKAGE: successor.plan.packageName,
|
|
26135
|
-
FRIZZ_REGISTRY_VERSION: successor.plan.latestVersion
|
|
26136
|
-
}
|
|
26137
|
-
});
|
|
26138
|
-
child.once("error", () => {
|
|
26139
|
-
});
|
|
26140
|
-
if (child.pid === void 0) throw new Error(`could not start Frizz ${successor.plan.latestVersion} from ${successor.entry}`);
|
|
26141
|
-
child.unref();
|
|
26142
|
-
return child;
|
|
26143
|
-
}
|
|
26144
|
-
var SUCCESSOR_READY_TIMEOUT_MS = 6e4;
|
|
26145
|
-
async function awaitRegistrySuccessor(child, expected2, watch) {
|
|
26146
|
-
const deadlineMs = watch.deadlineMs ?? SUCCESSOR_READY_TIMEOUT_MS;
|
|
26147
|
-
const intervalMs = watch.intervalMs ?? 250;
|
|
26148
|
-
const now = watch.now ?? Date.now;
|
|
26149
|
-
const sleep = watch.sleep ?? ((ms) => delay3(ms));
|
|
26150
|
-
const where = expected2.logFile ? `; its log is ${expected2.logFile}` : "";
|
|
26151
|
-
let exited = child.exitCode !== null || child.signalCode !== null ? describeExit(child.exitCode, child.signalCode) : void 0;
|
|
26152
|
-
const onExit = (code, signal) => {
|
|
26153
|
-
exited = describeExit(code, signal);
|
|
26154
|
-
};
|
|
26155
|
-
child.once("exit", onExit);
|
|
26156
|
-
try {
|
|
26157
|
-
const started = now();
|
|
26158
|
-
for (; ; ) {
|
|
26159
|
-
if (exited) throw new Error(`Frizz ${expected2.version} exited (${exited}) before it answered on port ${expected2.port}${where}`);
|
|
26160
|
-
const status = await watch.status();
|
|
26161
|
-
if (status?.version === expected2.version) return;
|
|
26162
|
-
if (now() - started >= deadlineMs) {
|
|
26163
|
-
try {
|
|
26164
|
-
child.kill();
|
|
26165
|
-
} catch {
|
|
26166
|
-
}
|
|
26167
|
-
throw new Error(
|
|
26168
|
-
`Frizz ${expected2.version} did not answer on port ${expected2.port} within ${Math.round(deadlineMs / 1e3)}s${where}`
|
|
26169
|
-
);
|
|
26170
|
-
}
|
|
26171
|
-
await sleep(intervalMs);
|
|
26172
|
-
}
|
|
26173
|
-
} finally {
|
|
26174
|
-
child.off("exit", onExit);
|
|
26175
|
-
}
|
|
26176
|
-
}
|
|
26177
|
-
function describeExit(code, signal) {
|
|
26178
|
-
return signal ? `signal ${signal}` : `exit ${code ?? "unknown"}`;
|
|
26179
|
-
}
|
|
26180
|
-
function launcherControlHeaders(port) {
|
|
26181
|
-
return { origin: `http://127.0.0.1:${port}`, "cache-control": "no-store" };
|
|
26182
|
-
}
|
|
26183
|
-
async function readLauncherStatus(port, fetcher = fetch) {
|
|
26184
|
-
const controller = new AbortController();
|
|
26185
|
-
const timeout = setTimeout(() => controller.abort(), 1e3);
|
|
26186
|
-
timeout.unref?.();
|
|
26187
|
-
try {
|
|
26188
|
-
const response = await fetcher(`http://127.0.0.1:${port}${FRIZZ_ROUTE_PREFIX}/control/status`, {
|
|
26189
|
-
signal: controller.signal,
|
|
26190
|
-
headers: launcherControlHeaders(port)
|
|
26191
|
-
});
|
|
26192
|
-
if (!response.ok) return void 0;
|
|
26193
|
-
const body = await response.json();
|
|
26194
|
-
return {
|
|
26195
|
-
...typeof body.version === "string" ? { version: body.version } : {},
|
|
26196
|
-
...typeof body.state === "string" ? { state: body.state } : {}
|
|
26197
|
-
};
|
|
26198
|
-
} catch {
|
|
26199
|
-
return void 0;
|
|
26200
|
-
} finally {
|
|
26201
|
-
clearTimeout(timeout);
|
|
26202
|
-
}
|
|
26203
|
-
}
|
|
26204
26360
|
function isGlobalInstall(bundleDir, env = process.env) {
|
|
26205
26361
|
if (env.npm_execpath) return false;
|
|
26206
26362
|
const segments = bundleDir.split(/[\\/]/u);
|
|
@@ -26294,11 +26450,386 @@ npm exec ${packageSpec} did not finish within ${formatTimeout(execTimeoutMs)} an
|
|
|
26294
26450
|
}
|
|
26295
26451
|
var npmRegistryReleaseAdapter = createNpmRegistryReleaseAdapter();
|
|
26296
26452
|
|
|
26453
|
+
// src/server-release.ts
|
|
26454
|
+
init_frizz_paths();
|
|
26455
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
26456
|
+
import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
|
|
26457
|
+
import {
|
|
26458
|
+
closeSync as closeSync5,
|
|
26459
|
+
existsSync as existsSync8,
|
|
26460
|
+
fsyncSync as fsyncSync5,
|
|
26461
|
+
mkdirSync as mkdirSync12,
|
|
26462
|
+
openSync as openSync6,
|
|
26463
|
+
readFileSync as readFileSync13,
|
|
26464
|
+
realpathSync as realpathSync6,
|
|
26465
|
+
renameSync as renameSync6,
|
|
26466
|
+
rmSync as rmSync9,
|
|
26467
|
+
statSync as statSync5,
|
|
26468
|
+
writeFileSync as writeFileSync11
|
|
26469
|
+
} from "node:fs";
|
|
26470
|
+
import { delimiter as delimiter2, dirname as dirname13, isAbsolute as isAbsolute6, join as join15, relative as relative3, resolve as resolve6, sep as sep4 } from "node:path";
|
|
26471
|
+
var SERVER_PROTOCOL = 1;
|
|
26472
|
+
var SERVER_DATA_EPOCH = 1;
|
|
26473
|
+
var VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
|
|
26474
|
+
var PACKAGE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u;
|
|
26475
|
+
var GENERATION = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u;
|
|
26476
|
+
var CURRENT_COMPATIBILITY = { protocol: SERVER_PROTOCOL, dataEpoch: SERVER_DATA_EPOCH };
|
|
26477
|
+
function assertSpecShape(spec) {
|
|
26478
|
+
if (typeof spec.package !== "string" || typeof spec.version !== "string" || !PACKAGE.test(spec.package) || !VERSION.test(spec.version))
|
|
26479
|
+
throw new Error("invalid exact Frizz server package/version");
|
|
26480
|
+
if (!Number.isSafeInteger(spec.protocol) || spec.protocol < 1 || !Number.isSafeInteger(spec.dataEpoch) || spec.dataEpoch < 1)
|
|
26481
|
+
throw new Error("invalid Frizz server protocol/data epoch");
|
|
26482
|
+
}
|
|
26483
|
+
function assertSpec(spec, compatibility = CURRENT_COMPATIBILITY) {
|
|
26484
|
+
assertSpecShape(spec);
|
|
26485
|
+
if (spec.protocol !== compatibility.protocol || spec.dataEpoch !== compatibility.dataEpoch)
|
|
26486
|
+
throw new Error("this Frizz server requires a newer launcher or a data migration; restart with a compatible Frizz release");
|
|
26487
|
+
}
|
|
26488
|
+
function readJson(path) {
|
|
26489
|
+
return JSON.parse(readFileSync13(path, "utf8"));
|
|
26490
|
+
}
|
|
26491
|
+
function record(value) {
|
|
26492
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("invalid Frizz server manifest");
|
|
26493
|
+
return value;
|
|
26494
|
+
}
|
|
26495
|
+
function serverReleaseSpec(manifest, packageOverride) {
|
|
26496
|
+
const metadata = record(record(manifest).frizzServer);
|
|
26497
|
+
const spec = {
|
|
26498
|
+
package: packageOverride ?? metadata.package,
|
|
26499
|
+
version: metadata.version,
|
|
26500
|
+
protocol: metadata.protocol,
|
|
26501
|
+
dataEpoch: metadata.dataEpoch
|
|
26502
|
+
};
|
|
26503
|
+
assertSpec(spec);
|
|
26504
|
+
return spec;
|
|
26505
|
+
}
|
|
26506
|
+
function containedFile(root, name, directory = false) {
|
|
26507
|
+
const path = realpathSync6(join15(root, name));
|
|
26508
|
+
const rel = relative3(realpathSync6(root), path);
|
|
26509
|
+
if (rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute6(rel))
|
|
26510
|
+
throw new Error(`Frizz server artifact escapes its package: ${name}`);
|
|
26511
|
+
const stat = statSync5(path);
|
|
26512
|
+
if (directory ? !stat.isDirectory() : !stat.isFile()) throw new Error(`invalid Frizz server artifact: ${name}`);
|
|
26513
|
+
return path;
|
|
26514
|
+
}
|
|
26515
|
+
function validateServerGeneration(root, spec, id, compatibility = CURRENT_COMPATIBILITY) {
|
|
26516
|
+
assertSpec(spec, compatibility);
|
|
26517
|
+
if (!GENERATION.test(id)) throw new Error("invalid Frizz server generation id");
|
|
26518
|
+
const manifest = record(readJson(join15(root, "package.json")));
|
|
26519
|
+
const metadata = record(manifest.frizzServer);
|
|
26520
|
+
if (manifest.name !== spec.package || manifest.version !== spec.version)
|
|
26521
|
+
throw new Error(`Frizz server install did not contain ${spec.package}@${spec.version}`);
|
|
26522
|
+
if (metadata.protocol !== spec.protocol || metadata.dataEpoch !== spec.dataEpoch)
|
|
26523
|
+
throw new Error("Frizz server protocol/data epoch is incompatible; the current server has not been stopped");
|
|
26524
|
+
const entry = containedFile(root, "dist/dev-child.js");
|
|
26525
|
+
containedFile(root, "dist/codex-app-server-daemon.js");
|
|
26526
|
+
containedFile(root, "dist/claude-agent-broker.js");
|
|
26527
|
+
containedFile(root, "web-dist/index.html");
|
|
26528
|
+
containedFile(root, "runtime/board/index.mjs");
|
|
26529
|
+
containedFile(root, "runtime/cc-worker/.claude-plugin/plugin.json");
|
|
26530
|
+
return { ...spec, id, root: realpathSync6(root), entry };
|
|
26531
|
+
}
|
|
26532
|
+
function serverGenerationLaunch(generation) {
|
|
26533
|
+
return {
|
|
26534
|
+
entry: generation.entry,
|
|
26535
|
+
environment: {
|
|
26536
|
+
FRIZZ_STABLE_ARTIFACT: `npm:${generation.package}@${generation.version}`,
|
|
26537
|
+
FRIZZ_STABLE_WEB_DIST: join15(generation.root, "web-dist"),
|
|
26538
|
+
FRIZZ_SCRIPTS_DIR: join15(generation.root, "runtime/board"),
|
|
26539
|
+
FRIZZ_WORKER_PLUGIN_DIR: join15(generation.root, "runtime/cc-worker")
|
|
26540
|
+
}
|
|
26541
|
+
};
|
|
26542
|
+
}
|
|
26543
|
+
function resolveNpmCli(env = process.env, executable = process.execPath) {
|
|
26544
|
+
const candidates = [];
|
|
26545
|
+
if (env.npm_execpath?.endsWith("npm-cli.js")) candidates.push(env.npm_execpath);
|
|
26546
|
+
for (const directory of [dirname13(executable), ...(env.PATH ?? env.Path ?? "").split(delimiter2).filter(Boolean)]) {
|
|
26547
|
+
candidates.push(join15(directory, "node_modules/npm/bin/npm-cli.js"), join15(directory, "../lib/node_modules/npm/bin/npm-cli.js"));
|
|
26548
|
+
try {
|
|
26549
|
+
const path = realpathSync6(join15(directory, "npm"));
|
|
26550
|
+
if (path.endsWith("npm-cli.js")) candidates.push(path);
|
|
26551
|
+
} catch {
|
|
26552
|
+
}
|
|
26553
|
+
}
|
|
26554
|
+
const found = candidates.find((path) => existsSync8(path) && statSync5(path).isFile());
|
|
26555
|
+
if (!found) throw new Error("npm was not found beside Node or on PATH; install Node with npm to install Frizz server releases");
|
|
26556
|
+
return resolve6(found);
|
|
26557
|
+
}
|
|
26558
|
+
function npmServerPackageInstaller(env = process.env) {
|
|
26559
|
+
const run3 = (args2, cwd) => new Promise((resolveOutput, reject) => {
|
|
26560
|
+
let cli;
|
|
26561
|
+
try {
|
|
26562
|
+
cli = resolveNpmCli(env);
|
|
26563
|
+
} catch (error) {
|
|
26564
|
+
reject(error);
|
|
26565
|
+
return;
|
|
26566
|
+
}
|
|
26567
|
+
execFile5(process.execPath, [cli, ...args2], {
|
|
26568
|
+
env,
|
|
26569
|
+
cwd,
|
|
26570
|
+
encoding: "utf8",
|
|
26571
|
+
windowsHide: true,
|
|
26572
|
+
timeout: 18e4,
|
|
26573
|
+
killSignal: "SIGKILL",
|
|
26574
|
+
maxBuffer: 4 * 1024 * 1024
|
|
26575
|
+
}, (error, stdout, stderr) => {
|
|
26576
|
+
if (error) {
|
|
26577
|
+
const tail = stderr.trim().split("\n").slice(-8).join("\n");
|
|
26578
|
+
reject(new Error(`Frizz server npm operation failed: ${tail || error.message}`));
|
|
26579
|
+
} else resolveOutput(stdout);
|
|
26580
|
+
});
|
|
26581
|
+
});
|
|
26582
|
+
return {
|
|
26583
|
+
async install(prefix, spec) {
|
|
26584
|
+
assertSpec(spec);
|
|
26585
|
+
await run3([
|
|
26586
|
+
"install",
|
|
26587
|
+
"--prefix",
|
|
26588
|
+
prefix,
|
|
26589
|
+
"--global=false",
|
|
26590
|
+
"--ignore-scripts",
|
|
26591
|
+
"--no-audit",
|
|
26592
|
+
"--no-fund",
|
|
26593
|
+
"--engine-strict",
|
|
26594
|
+
"--install-strategy=hoisted",
|
|
26595
|
+
"--include=optional",
|
|
26596
|
+
"--omit=dev",
|
|
26597
|
+
"--save-exact",
|
|
26598
|
+
`${spec.package}@${spec.version}`
|
|
26599
|
+
], prefix);
|
|
26600
|
+
},
|
|
26601
|
+
async latestVersion(packageName) {
|
|
26602
|
+
if (!PACKAGE.test(packageName)) throw new Error("invalid Frizz server package name");
|
|
26603
|
+
const version = JSON.parse(await run3(["view", `${packageName}@latest`, "version", "--json"]));
|
|
26604
|
+
if (typeof version !== "string" || !VERSION.test(version)) throw new Error("npm returned an invalid Frizz server version");
|
|
26605
|
+
return version;
|
|
26606
|
+
}
|
|
26607
|
+
};
|
|
26608
|
+
}
|
|
26609
|
+
function atomicJson2(path, value) {
|
|
26610
|
+
mkdirSync12(dirname13(path), { recursive: true, mode: 448 });
|
|
26611
|
+
const temp = `${path}.${randomUUID6()}.tmp`;
|
|
26612
|
+
try {
|
|
26613
|
+
const fd = openSync6(temp, "wx", 384);
|
|
26614
|
+
try {
|
|
26615
|
+
writeFileSync11(fd, `${JSON.stringify(value)}
|
|
26616
|
+
`);
|
|
26617
|
+
fsyncSync5(fd);
|
|
26618
|
+
} finally {
|
|
26619
|
+
closeSync5(fd);
|
|
26620
|
+
}
|
|
26621
|
+
renameSync6(temp, path);
|
|
26622
|
+
try {
|
|
26623
|
+
const directory = openSync6(dirname13(path), "r");
|
|
26624
|
+
try {
|
|
26625
|
+
fsyncSync5(directory);
|
|
26626
|
+
} finally {
|
|
26627
|
+
closeSync5(directory);
|
|
26628
|
+
}
|
|
26629
|
+
} catch {
|
|
26630
|
+
}
|
|
26631
|
+
} finally {
|
|
26632
|
+
rmSync9(temp, { force: true });
|
|
26633
|
+
}
|
|
26634
|
+
}
|
|
26635
|
+
var ServerReleaseStore = class {
|
|
26636
|
+
constructor(spec, installer, roots = frizzPaths(), compatibility = CURRENT_COMPATIBILITY) {
|
|
26637
|
+
this.spec = spec;
|
|
26638
|
+
this.installer = installer;
|
|
26639
|
+
this.roots = roots;
|
|
26640
|
+
this.compatibility = compatibility;
|
|
26641
|
+
assertSpec(spec, compatibility);
|
|
26642
|
+
const key = createHash4("sha256").update(spec.package).digest("hex").slice(0, 16);
|
|
26643
|
+
this.generations = join15(roots.cache, "server-releases", key);
|
|
26644
|
+
this.selection = join15(roots.state, "server-releases", key, "active.json");
|
|
26645
|
+
this.compatibilityMarker = join15(roots.state, "server-releases", "data-compatibility.json");
|
|
26646
|
+
}
|
|
26647
|
+
generations;
|
|
26648
|
+
selection;
|
|
26649
|
+
/** One global data marker: every package override opens the same Frizz databases. */
|
|
26650
|
+
compatibilityMarker;
|
|
26651
|
+
packageRoot(id) {
|
|
26652
|
+
return join15(this.generations, id, "node_modules", this.spec.package);
|
|
26653
|
+
}
|
|
26654
|
+
readCompatibilityMarker() {
|
|
26655
|
+
if (!existsSync8(this.compatibilityMarker)) return void 0;
|
|
26656
|
+
try {
|
|
26657
|
+
const marker = record(readJson(this.compatibilityMarker));
|
|
26658
|
+
const compatibility = { protocol: marker.protocol, dataEpoch: marker.dataEpoch };
|
|
26659
|
+
assertSpecShape({ package: this.spec.package, version: this.spec.version, ...compatibility });
|
|
26660
|
+
return compatibility;
|
|
26661
|
+
} catch {
|
|
26662
|
+
throw new Error("invalid saved Frizz server data compatibility marker; refusing to risk a data downgrade");
|
|
26663
|
+
}
|
|
26664
|
+
}
|
|
26665
|
+
assertMarkerIsSupported() {
|
|
26666
|
+
const marker = this.readCompatibilityMarker();
|
|
26667
|
+
if (!marker) return;
|
|
26668
|
+
if (marker.protocol !== this.compatibility.protocol || marker.dataEpoch > this.compatibility.dataEpoch)
|
|
26669
|
+
throw new Error("this Frizz server requires a newer launcher or a data migration; restart with a compatible Frizz release");
|
|
26670
|
+
}
|
|
26671
|
+
/**
|
|
26672
|
+
* Advance the global epoch only after the exact replacement has been staged and validated, but
|
|
26673
|
+
* before handing it to the caller that can launch it. A crash before first boot must never let an
|
|
26674
|
+
* older shell reopen the database the candidate may already have migrated.
|
|
26675
|
+
*/
|
|
26676
|
+
markCompatibilityBeforeLaunch() {
|
|
26677
|
+
const marker = this.readCompatibilityMarker();
|
|
26678
|
+
if (marker?.protocol !== void 0 && marker.protocol !== this.compatibility.protocol)
|
|
26679
|
+
throw new Error("this Frizz server requires a newer launcher or a data migration; restart with a compatible Frizz release");
|
|
26680
|
+
if ((marker?.dataEpoch ?? 0) > this.compatibility.dataEpoch)
|
|
26681
|
+
throw new Error("this Frizz server requires a newer launcher or a data migration; restart with a compatible Frizz release");
|
|
26682
|
+
if (marker?.dataEpoch === this.compatibility.dataEpoch) return;
|
|
26683
|
+
atomicJson2(this.compatibilityMarker, this.compatibility);
|
|
26684
|
+
}
|
|
26685
|
+
async prepareInitial(version) {
|
|
26686
|
+
const generation = await this.prepare(version);
|
|
26687
|
+
this.markCompatibilityBeforeLaunch();
|
|
26688
|
+
return generation;
|
|
26689
|
+
}
|
|
26690
|
+
async load() {
|
|
26691
|
+
this.assertMarkerIsSupported();
|
|
26692
|
+
if (!existsSync8(this.selection)) return this.prepareInitial(this.spec.version);
|
|
26693
|
+
const selected = record(readJson(this.selection));
|
|
26694
|
+
const spec = selected;
|
|
26695
|
+
assertSpecShape(spec);
|
|
26696
|
+
if (spec.package !== this.spec.package || typeof selected.id !== "string" || !GENERATION.test(selected.id))
|
|
26697
|
+
throw new Error("invalid saved Frizz server selection; refusing to fall back to an older server");
|
|
26698
|
+
if (spec.protocol !== this.compatibility.protocol)
|
|
26699
|
+
throw new Error("this Frizz server requires a newer launcher or a data migration; restart with a compatible Frizz release");
|
|
26700
|
+
if (spec.dataEpoch < this.compatibility.dataEpoch) return this.prepareInitial(this.spec.version);
|
|
26701
|
+
if (spec.dataEpoch > this.compatibility.dataEpoch)
|
|
26702
|
+
throw new Error("this Frizz server requires a newer launcher or a data migration; restart with a compatible Frizz release");
|
|
26703
|
+
const root = this.packageRoot(selected.id);
|
|
26704
|
+
const generation = !existsSync8(root) ? await this.prepare(spec.version) : validateServerGeneration(root, spec, selected.id, this.compatibility);
|
|
26705
|
+
this.markCompatibilityBeforeLaunch();
|
|
26706
|
+
return generation;
|
|
26707
|
+
}
|
|
26708
|
+
async prepare(version) {
|
|
26709
|
+
const spec = { ...this.spec, version };
|
|
26710
|
+
assertSpec(spec, this.compatibility);
|
|
26711
|
+
mkdirSync12(this.generations, { recursive: true, mode: 448 });
|
|
26712
|
+
const id = randomUUID6();
|
|
26713
|
+
const staging = join15(this.generations, `${id}.staging`);
|
|
26714
|
+
const destination = join15(this.generations, id);
|
|
26715
|
+
mkdirSync12(staging, { mode: 448 });
|
|
26716
|
+
try {
|
|
26717
|
+
writeFileSync11(join15(staging, "package.json"), '{"private":true}\n', { mode: 384 });
|
|
26718
|
+
await this.installer.install(staging, spec);
|
|
26719
|
+
validateServerGeneration(join15(staging, "node_modules", spec.package), spec, id, this.compatibility);
|
|
26720
|
+
renameSync6(staging, destination);
|
|
26721
|
+
return validateServerGeneration(this.packageRoot(id), spec, id, this.compatibility);
|
|
26722
|
+
} finally {
|
|
26723
|
+
rmSync9(staging, { recursive: true, force: true });
|
|
26724
|
+
}
|
|
26725
|
+
}
|
|
26726
|
+
commit(generation) {
|
|
26727
|
+
if (generation.package !== this.spec.package || generation.root !== realpathSync6(this.packageRoot(generation.id)))
|
|
26728
|
+
throw new Error("cannot select a Frizz server outside this release store");
|
|
26729
|
+
validateServerGeneration(generation.root, generation, generation.id, this.compatibility);
|
|
26730
|
+
const { package: packageName, version, protocol, dataEpoch, id } = generation;
|
|
26731
|
+
atomicJson2(this.selection, { package: packageName, version, protocol, dataEpoch, id });
|
|
26732
|
+
}
|
|
26733
|
+
};
|
|
26734
|
+
|
|
26735
|
+
// src/server-owner.ts
|
|
26736
|
+
init_frizz_paths();
|
|
26737
|
+
init_project_launch();
|
|
26738
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
26739
|
+
import { mkdirSync as mkdirSync13, readFileSync as readFileSync14, realpathSync as realpathSync7 } from "node:fs";
|
|
26740
|
+
import { join as join16 } from "node:path";
|
|
26741
|
+
var STABLE_SERVER_OWNER_NAME = "frizz-server";
|
|
26742
|
+
var STABLE_SERVER_OWNER_PROJECT_ID = "c1fd5810-0f8a-4c1d-91a0-6d7445d28e5a";
|
|
26743
|
+
var ADDRESS_NAME = "address.json";
|
|
26744
|
+
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
26745
|
+
function rootsFor(roots) {
|
|
26746
|
+
return roots ?? frizzPaths();
|
|
26747
|
+
}
|
|
26748
|
+
function stableServerOwnerTarget(roots) {
|
|
26749
|
+
const resolved = rootsFor(roots);
|
|
26750
|
+
mkdirSync13(resolved.data, { recursive: true, mode: 448 });
|
|
26751
|
+
return {
|
|
26752
|
+
projectId: STABLE_SERVER_OWNER_PROJECT_ID,
|
|
26753
|
+
projectDir: realpathSync7(resolved.data),
|
|
26754
|
+
stateDir: join16(resolved.state, STABLE_SERVER_OWNER_NAME)
|
|
26755
|
+
};
|
|
26756
|
+
}
|
|
26757
|
+
function matchingTarget(owner, target2) {
|
|
26758
|
+
return owner.projectId === target2.projectId && owner.projectDir === target2.projectDir;
|
|
26759
|
+
}
|
|
26760
|
+
function readAddress(path) {
|
|
26761
|
+
try {
|
|
26762
|
+
const value = JSON.parse(readFileSync14(path, "utf8"));
|
|
26763
|
+
if (value.version !== 1 || typeof value.ownerToken !== "string" || !UUID_RE2.test(value.ownerToken) || typeof value.publisherToken !== "string" || !UUID_RE2.test(value.publisherToken) || typeof value.pid !== "number" || !Number.isInteger(value.pid) || value.pid <= 0 || typeof value.processStart !== "string" || value.processStart.length === 0 || typeof value.port !== "number" || !Number.isInteger(value.port) || value.port < 1 || value.port > 65535) return null;
|
|
26764
|
+
return value;
|
|
26765
|
+
} catch {
|
|
26766
|
+
return null;
|
|
26767
|
+
}
|
|
26768
|
+
}
|
|
26769
|
+
function readStableServerOwner(roots) {
|
|
26770
|
+
const target2 = stableServerOwnerTarget(roots);
|
|
26771
|
+
const owner = readProjectLaunchOwner(target2.stateDir);
|
|
26772
|
+
if (!owner || !matchingTarget(owner, target2) || processGenerationIsStale(owner)) return { kind: "idle" };
|
|
26773
|
+
const address = readAddress(join16(target2.stateDir, ADDRESS_NAME));
|
|
26774
|
+
if (!address || address.ownerToken !== owner.token || address.pid !== owner.pid || address.processStart !== owner.processStart) return { kind: "busy", owner };
|
|
26775
|
+
return { kind: "running", port: address.port, owner };
|
|
26776
|
+
}
|
|
26777
|
+
function wrapLease(lease) {
|
|
26778
|
+
return {
|
|
26779
|
+
target: lease.target,
|
|
26780
|
+
token: lease.token,
|
|
26781
|
+
pid: lease.pid,
|
|
26782
|
+
processStart: lease.processStart,
|
|
26783
|
+
publisherToken: randomUUID7()
|
|
26784
|
+
};
|
|
26785
|
+
}
|
|
26786
|
+
function acquireStableServerOwner(roots) {
|
|
26787
|
+
const target2 = stableServerOwnerTarget(roots);
|
|
26788
|
+
const attempt = tryAcquireProjectLaunchOwner(target2, "server");
|
|
26789
|
+
if (attempt.kind === "acquired") return { kind: "acquired", lease: holdLease(attempt.lease) };
|
|
26790
|
+
const observed = readStableServerOwner(roots);
|
|
26791
|
+
return observed.kind === "running" || observed.kind === "busy" ? observed : { kind: "busy", owner: attempt.owner };
|
|
26792
|
+
}
|
|
26793
|
+
function publishStableServerAddress(lease, port) {
|
|
26794
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(`invalid stable Frizz server port: ${port}`);
|
|
26795
|
+
const owner = readProjectLaunchOwner(lease.target.stateDir);
|
|
26796
|
+
if (!owner || !matchingTarget(owner, lease.target) || owner.token !== lease.token || owner.pid !== lease.pid || owner.processStart !== lease.processStart || processGenerationIsStale(owner)) throw new Error("cannot publish an address without the exact live stable Frizz server owner");
|
|
26797
|
+
writeProjectStatus(join16(lease.target.stateDir, ADDRESS_NAME), {
|
|
26798
|
+
version: 1,
|
|
26799
|
+
ownerToken: lease.token,
|
|
26800
|
+
pid: lease.pid,
|
|
26801
|
+
processStart: lease.processStart,
|
|
26802
|
+
publisherToken: lease.publisherToken,
|
|
26803
|
+
port
|
|
26804
|
+
});
|
|
26805
|
+
}
|
|
26806
|
+
function releaseStableServerOwner(lease) {
|
|
26807
|
+
return releaseHeldLease(lease);
|
|
26808
|
+
}
|
|
26809
|
+
var heldLeases = /* @__PURE__ */ new Map();
|
|
26810
|
+
function holdLease(lease) {
|
|
26811
|
+
const wrapped = wrapLease(lease);
|
|
26812
|
+
heldLeases.set(wrapped.publisherToken, lease);
|
|
26813
|
+
return wrapped;
|
|
26814
|
+
}
|
|
26815
|
+
function releaseHeldLease(lease) {
|
|
26816
|
+
const held = heldLeases.get(lease.publisherToken);
|
|
26817
|
+
if (!held || held.token !== lease.token || held.pid !== lease.pid || held.processStart !== lease.processStart) return false;
|
|
26818
|
+
const released = held.release();
|
|
26819
|
+
if (!released) return false;
|
|
26820
|
+
heldLeases.delete(lease.publisherToken);
|
|
26821
|
+
removeProjectStatus(join16(lease.target.stateDir, ADDRESS_NAME), {
|
|
26822
|
+
ownerToken: lease.token,
|
|
26823
|
+
pid: lease.pid,
|
|
26824
|
+
processStart: lease.processStart,
|
|
26825
|
+
publisherToken: lease.publisherToken
|
|
26826
|
+
});
|
|
26827
|
+
return true;
|
|
26828
|
+
}
|
|
26829
|
+
|
|
26297
26830
|
// src/preflight.ts
|
|
26831
|
+
init_native_helper();
|
|
26298
26832
|
import { spawnSync } from "node:child_process";
|
|
26299
|
-
import { chmodSync as chmodSync2, statSync as statSync5 } from "node:fs";
|
|
26300
|
-
import { createRequire } from "node:module";
|
|
26301
|
-
import { dirname as dirname13, join as join15 } from "node:path";
|
|
26302
26833
|
var SUPPORTED_NODE_LINES = [
|
|
26303
26834
|
{ major: 22, minor: 13 },
|
|
26304
26835
|
{ major: 23, minor: 4 }
|
|
@@ -26342,25 +26873,6 @@ function assertLaunchPrerequisites(options2 = {}) {
|
|
|
26342
26873
|
);
|
|
26343
26874
|
assertRequiredExecutables(options2.command ?? commandIsAvailable);
|
|
26344
26875
|
}
|
|
26345
|
-
function ensureNativeHelperPermissions(options2 = {}) {
|
|
26346
|
-
const platform = options2.platform ?? process.platform;
|
|
26347
|
-
if (platform === "win32") return;
|
|
26348
|
-
const stat = options2.stat ?? ((path) => statSync5(path));
|
|
26349
|
-
const chmod = options2.chmod ?? ((path, mode) => chmodSync2(path, mode));
|
|
26350
|
-
const resolvePty = options2.resolvePty ?? (() => createRequire(import.meta.url).resolve("node-pty/package.json"));
|
|
26351
|
-
try {
|
|
26352
|
-
const helper = join15(
|
|
26353
|
-
dirname13(resolvePty()),
|
|
26354
|
-
"prebuilds",
|
|
26355
|
-
`${platform}-${options2.arch ?? process.arch}`,
|
|
26356
|
-
"spawn-helper"
|
|
26357
|
-
);
|
|
26358
|
-
const mode = stat(helper).mode;
|
|
26359
|
-
if ((mode & 73) === 73) return;
|
|
26360
|
-
chmod(helper, mode | 493);
|
|
26361
|
-
} catch {
|
|
26362
|
-
}
|
|
26363
|
-
}
|
|
26364
26876
|
|
|
26365
26877
|
// src/production.ts
|
|
26366
26878
|
init_src();
|
|
@@ -26369,7 +26881,7 @@ init_project_identity();
|
|
|
26369
26881
|
var PACKAGE_NAME = process.env.FRIZZ_REGISTRY_PACKAGE ?? "frizz";
|
|
26370
26882
|
function resolvePackageVersion() {
|
|
26371
26883
|
try {
|
|
26372
|
-
const manifest = JSON.parse(
|
|
26884
|
+
const manifest = JSON.parse(readFileSync15(join17(import.meta.dirname, "..", "package.json"), "utf8"));
|
|
26373
26885
|
if (typeof manifest.version === "string" && manifest.version.trim()) return manifest.version.trim();
|
|
26374
26886
|
} catch {
|
|
26375
26887
|
}
|
|
@@ -26433,10 +26945,13 @@ var sandbox = options.sandbox ? prepareSandbox() : null;
|
|
|
26433
26945
|
if (sandbox) process.on("exit", () => cleanupSandbox(sandbox.home));
|
|
26434
26946
|
var remote = null;
|
|
26435
26947
|
var paneHost = null;
|
|
26436
|
-
var rearmPaneHost = null;
|
|
26437
26948
|
var globalInstall = process.env[GLOBAL_INSTALL_ENV] === "1" || isGlobalInstall(import.meta.dirname);
|
|
26438
26949
|
var accessPane = null;
|
|
26439
26950
|
var activeAccessLink = null;
|
|
26951
|
+
var serverOwner;
|
|
26952
|
+
process.on("exit", () => {
|
|
26953
|
+
if (serverOwner) releaseStableServerOwner(serverOwner);
|
|
26954
|
+
});
|
|
26440
26955
|
var launchIntent;
|
|
26441
26956
|
var workspace = (() => {
|
|
26442
26957
|
try {
|
|
@@ -26522,15 +27037,15 @@ if (options.link) {
|
|
|
26522
27037
|
var logger = setAmbientLogger(
|
|
26523
27038
|
process.env.FRIZZ_LOG_FILE ? createLogger({ file: process.env.FRIZZ_LOG_FILE, owner: false }) : createLogger({ file: runLogPath(workspace.stateDir) })
|
|
26524
27039
|
);
|
|
26525
|
-
var readout = reexec || process.env.FRIZZ_PRODUCTION_SUPERVISOR === "1" ? void 0 : new Readout({ debug: options.debug
|
|
26526
|
-
var activityReadout = readout ?? (reexec && process.stdout.isTTY ? noticeOnlyReadout({
|
|
27040
|
+
var readout = reexec || process.env.FRIZZ_PRODUCTION_SUPERVISOR === "1" ? void 0 : new Readout({ debug: options.debug });
|
|
27041
|
+
var activityReadout = readout ?? (reexec && process.stdout.isTTY ? noticeOnlyReadout({}) : void 0);
|
|
26527
27042
|
attachTerminalMirror(logger, options.debug || process.env.FRIZZ_DEBUG === "1");
|
|
26528
27043
|
readout?.plan([
|
|
26529
27044
|
{ key: "server", label: "Server" },
|
|
26530
27045
|
{ key: "browser", label: options.noApp ? "Address" : "Browser" }
|
|
26531
27046
|
]);
|
|
26532
27047
|
readout?.begin("server", "starting");
|
|
26533
|
-
logger.info("launcher", `
|
|
27048
|
+
logger.info("launcher", `Frizz launcher ${PACKAGE_VERSION} starting for ${workspace.root}`);
|
|
26534
27049
|
var target = workspaceLaunchTarget(workspace);
|
|
26535
27050
|
var expected = expectedOwnerHealth(target, readProjectLaunchOwner(workspace.stateDir));
|
|
26536
27051
|
async function existingPort() {
|
|
@@ -26579,7 +27094,7 @@ async function openOrPrint(port, reused, path = "") {
|
|
|
26579
27094
|
readout?.begin("browser", options.appMode ? "requesting app window" : "requesting default browser");
|
|
26580
27095
|
try {
|
|
26581
27096
|
if (options.appMode) {
|
|
26582
|
-
await launchApp(url, { dataPath:
|
|
27097
|
+
await launchApp(url, { dataPath: join17(workspace.stateDir, "browser-profile") });
|
|
26583
27098
|
browser = reused ? "focused the Frizz app window" : "opened the Frizz app window";
|
|
26584
27099
|
} else {
|
|
26585
27100
|
await launchBrowserTab(url);
|
|
@@ -26598,7 +27113,7 @@ async function openOrPrint(port, reused, path = "") {
|
|
|
26598
27113
|
const warnings = [];
|
|
26599
27114
|
if (sandbox) warnings.push(`Sandbox: everything here is throwaway (${sandbox.home}) and is deleted when this terminal closes.`);
|
|
26600
27115
|
if (!readout) {
|
|
26601
|
-
console.log(`${reused ? "reusing" : "started"} Frizz
|
|
27116
|
+
console.log(`${reused ? "reusing" : "started"} Frizz for ${workspace.root}`);
|
|
26602
27117
|
console.log(url);
|
|
26603
27118
|
if (publicOrigin) console.log(activeAccessLink?.url ?? `${publicOrigin}/`);
|
|
26604
27119
|
for (const warning of warnings) console.log(warning);
|
|
@@ -26623,31 +27138,40 @@ async function openOrPrint(port, reused, path = "") {
|
|
|
26623
27138
|
}
|
|
26624
27139
|
);
|
|
26625
27140
|
}
|
|
26626
|
-
async function runSupervisor(port, token) {
|
|
27141
|
+
async function runSupervisor(port, token, onPrepared = () => {
|
|
27142
|
+
}) {
|
|
26627
27143
|
assertLaunchPrerequisites();
|
|
26628
|
-
|
|
27144
|
+
if (!serverOwner) throw new Error("stable server launch is missing global ownership");
|
|
26629
27145
|
const owner = adoptProjectLaunchOwner(target, token, "supervisor");
|
|
26630
27146
|
const env = projectLaunchEnvironment(
|
|
26631
27147
|
{
|
|
26632
27148
|
...process.env,
|
|
26633
27149
|
FRIZZ_PRODUCTION_SUPERVISOR: "1",
|
|
27150
|
+
FRIZZ_SERVER_OWNERSHIP: JSON.stringify(projectLaunchEnvironment({}, serverOwner.target, serverOwner.token)),
|
|
26634
27151
|
...logEnvironment(logger, options.debug ? "debug" : "info"),
|
|
26635
27152
|
...options.debug ? { FRIZZ_DEBUG: "1" } : {}
|
|
26636
27153
|
},
|
|
26637
27154
|
target,
|
|
26638
27155
|
owner.token
|
|
26639
27156
|
);
|
|
26640
|
-
const
|
|
26641
|
-
|
|
26642
|
-
|
|
26643
|
-
|
|
26644
|
-
const
|
|
26645
|
-
|
|
27157
|
+
const spec = serverReleaseSpec(
|
|
27158
|
+
JSON.parse(readFileSync15(join17(import.meta.dirname, "..", "package.json"), "utf8")),
|
|
27159
|
+
process.env.FRIZZ_SERVER_PACKAGE
|
|
27160
|
+
);
|
|
27161
|
+
const installer = npmServerPackageInstaller(env);
|
|
27162
|
+
const store = new ServerReleaseStore(spec, installer);
|
|
27163
|
+
activityReadout?.notice("progress", "Starting", "loading the selected Frizz server release");
|
|
27164
|
+
let active = await store.load();
|
|
27165
|
+
let pending;
|
|
27166
|
+
let previous = active;
|
|
27167
|
+
onPrepared();
|
|
26646
27168
|
let updateAvailable = false;
|
|
26647
27169
|
let updateVersion;
|
|
26648
27170
|
const refreshUpdateAvailable = async () => {
|
|
26649
27171
|
try {
|
|
26650
|
-
const
|
|
27172
|
+
const checkedVersion = active.version;
|
|
27173
|
+
const plan = await planRegistryUpdate(spec.package, checkedVersion, installer);
|
|
27174
|
+
if (active.version !== checkedVersion) return;
|
|
26651
27175
|
updateAvailable = plan !== null;
|
|
26652
27176
|
updateVersion = plan?.latestVersion;
|
|
26653
27177
|
} catch {
|
|
@@ -26673,83 +27197,48 @@ async function runSupervisor(port, token) {
|
|
|
26673
27197
|
launchOwnerToken: owner.token,
|
|
26674
27198
|
env,
|
|
26675
27199
|
watch: false,
|
|
26676
|
-
|
|
26677
|
-
|
|
27200
|
+
childLaunchProvider: () => serverGenerationLaunch(pending ?? active),
|
|
27201
|
+
updateMode: "child",
|
|
26678
27202
|
updateAvailable: () => updateAvailable,
|
|
26679
|
-
version:
|
|
27203
|
+
version: () => active.version,
|
|
27204
|
+
launcherVersion: PACKAGE_VERSION,
|
|
26680
27205
|
updateVersion: () => updateVersion,
|
|
26681
27206
|
// The terminal that owns the board says so when the board goes down and comes back. Everything
|
|
26682
27207
|
// here is triggered from a browser tab or by a crash, so without this the foreground process is
|
|
26683
27208
|
// the last place to learn what happened to it.
|
|
26684
27209
|
onActivity: (event) => renderSupervisorActivity(activityReadout, event),
|
|
26685
27210
|
updateRestart: async () => {
|
|
27211
|
+
previous = active;
|
|
26686
27212
|
try {
|
|
26687
|
-
const plan = await planRegistryUpdate(
|
|
27213
|
+
const plan = await planRegistryUpdate(spec.package, active.version, installer);
|
|
26688
27214
|
if (!plan) {
|
|
26689
27215
|
updateAvailable = false;
|
|
26690
27216
|
updateVersion = void 0;
|
|
26691
|
-
return { state: "failed", message: `Frizz ${
|
|
27217
|
+
return { state: "failed", message: `Frizz ${active.version} is already current` };
|
|
26692
27218
|
}
|
|
27219
|
+
updateAvailable = true;
|
|
26693
27220
|
updateVersion = plan.latestVersion;
|
|
26694
|
-
|
|
26695
|
-
return { state: "ready", message: `Frizz ${plan.latestVersion} is installed
|
|
27221
|
+
pending = await store.prepare(plan.latestVersion);
|
|
27222
|
+
return { state: "ready", message: `Frizz ${plan.latestVersion} is installed and compatible` };
|
|
26696
27223
|
} catch (error) {
|
|
26697
27224
|
return { state: "failed", message: error instanceof Error ? error.message : String(error) };
|
|
26698
27225
|
}
|
|
26699
27226
|
},
|
|
26700
|
-
|
|
26701
|
-
|
|
26702
|
-
|
|
26703
|
-
|
|
26704
|
-
|
|
26705
|
-
|
|
27227
|
+
commitUpdate: () => {
|
|
27228
|
+
if (!pending) throw new Error("no server update was prepared");
|
|
27229
|
+
store.commit(pending);
|
|
27230
|
+
active = pending;
|
|
27231
|
+
pending = void 0;
|
|
27232
|
+
updateAvailable = false;
|
|
27233
|
+
updateVersion = void 0;
|
|
26706
27234
|
},
|
|
26707
|
-
|
|
26708
|
-
|
|
26709
|
-
|
|
26710
|
-
|
|
26711
|
-
const successorEnv = {
|
|
26712
|
-
...env,
|
|
26713
|
-
FRIZZ_REGISTRY_PACKAGE: plan.packageName,
|
|
26714
|
-
FRIZZ_REGISTRY_VERSION: plan.latestVersion,
|
|
26715
|
-
...globalInstall ? { [GLOBAL_INSTALL_ENV]: "1" } : {}
|
|
26716
|
-
};
|
|
26717
|
-
if (canReexecInPlace()) {
|
|
26718
|
-
activityReadout?.notice("progress", "Updating", `reloading this launcher in place on Frizz ${plan.latestVersion}`);
|
|
26719
|
-
paneHost?.dispose();
|
|
26720
|
-
remote?.stop();
|
|
26721
|
-
try {
|
|
26722
|
-
reexecIntoRegistrySuccessor(successor, { port, env: successorEnv });
|
|
26723
|
-
} catch (error) {
|
|
26724
|
-
rearmPaneHost?.();
|
|
26725
|
-
try {
|
|
26726
|
-
await remote?.serveSaved();
|
|
26727
|
-
} catch (remoteError) {
|
|
26728
|
-
const message = remoteError instanceof Error ? remoteError.message : String(remoteError);
|
|
26729
|
-
logger.error("remote", `could not re-arm the saved remote setup after a failed update: ${message}`);
|
|
26730
|
-
}
|
|
26731
|
-
throw error;
|
|
26732
|
-
}
|
|
26733
|
-
}
|
|
26734
|
-
const child = handoffToRegistrySuccessor(successor, { port, cwd: workspace.root, env: successorEnv }, npmRegistryReleaseAdapter);
|
|
26735
|
-
activityReadout?.notice("progress", "Updating", `starting Frizz ${plan.latestVersion} in the background and waiting for it to answer on port ${port}`);
|
|
26736
|
-
await awaitRegistrySuccessor(
|
|
26737
|
-
child,
|
|
26738
|
-
{ version: plan.latestVersion, port, logFile: successorEnv.FRIZZ_LOG_FILE },
|
|
26739
|
-
{ status: () => readLauncherStatus(port) }
|
|
26740
|
-
);
|
|
26741
|
-
paneHost?.dispose();
|
|
26742
|
-
remote?.stop();
|
|
26743
|
-
activityReadout?.notice("done", "Updated", `Frizz ${plan.latestVersion} is serving on port ${port}`);
|
|
26744
|
-
activityReadout?.note(
|
|
26745
|
-
`
|
|
26746
|
-
Frizz ${plan.latestVersion} now runs in the background \u2014 ctrl-c here no longer reaches it. Stop it with ${PACKAGE_NAME} --stop.${globalInstall ? `
|
|
26747
|
-
Update: ${keepUpdateHint(PACKAGE_NAME, plan.latestVersion)}.` : ""}
|
|
26748
|
-
`
|
|
26749
|
-
);
|
|
26750
|
-
process.exit(0);
|
|
27235
|
+
rollbackUpdate: () => {
|
|
27236
|
+
if (active.id !== previous.id) store.commit(previous);
|
|
27237
|
+
active = previous;
|
|
27238
|
+
pending = void 0;
|
|
26751
27239
|
}
|
|
26752
27240
|
});
|
|
27241
|
+
publishStableServerAddress(serverOwner, port);
|
|
26753
27242
|
remote = createRemoteController({ host: supervisor, port, log: logger, say: (message) => console.error(`frizz: ${message}`) });
|
|
26754
27243
|
try {
|
|
26755
27244
|
await remote.serveSaved();
|
|
@@ -26770,16 +27259,14 @@ async function runSupervisor(port, token) {
|
|
|
26770
27259
|
onChanged: (config) => logger.info("remote", config ? `reached at https://${config.hostname}` : "loopback only"),
|
|
26771
27260
|
sandbox: sandbox !== null
|
|
26772
27261
|
});
|
|
26773
|
-
|
|
26774
|
-
const armPaneHost = () => {
|
|
26775
|
-
paneHost = installPaneHost({ bindings });
|
|
26776
|
-
};
|
|
26777
|
-
armPaneHost();
|
|
26778
|
-
rearmPaneHost = armPaneHost;
|
|
27262
|
+
paneHost = installPaneHost({ bindings: { l: accessPane, L: accessPane, r: remotePane, R: remotePane } });
|
|
26779
27263
|
const stop = createSupervisorShutdownHandler({
|
|
26780
27264
|
close: () => supervisor.close(),
|
|
26781
27265
|
force: () => supervisor.forceStop(),
|
|
26782
|
-
release: () =>
|
|
27266
|
+
release: () => {
|
|
27267
|
+
owner.release();
|
|
27268
|
+
if (serverOwner) releaseStableServerOwner(serverOwner);
|
|
27269
|
+
},
|
|
26783
27270
|
// Acknowledge the first signal on the spot; the drain that follows is bounded but not instant.
|
|
26784
27271
|
onStop: () => {
|
|
26785
27272
|
logger.info("launcher", "stop signal received; draining the control plane");
|
|
@@ -26809,17 +27296,28 @@ async function runSupervisor(port, token) {
|
|
|
26809
27296
|
process.on("SIGHUP", stop);
|
|
26810
27297
|
void supervisor.stopRequested.then(stop);
|
|
26811
27298
|
await supervisor.firstBoot;
|
|
27299
|
+
store.commit(active);
|
|
27300
|
+
activityReadout?.notice("done", "Server", `${active.version} \xB7 launcher ${PACKAGE_VERSION}`);
|
|
26812
27301
|
if (reexec) {
|
|
26813
27302
|
activityReadout?.notice(
|
|
26814
27303
|
"done",
|
|
26815
27304
|
"Updated",
|
|
26816
|
-
`Frizz ${
|
|
27305
|
+
`Frizz ${active.version} is serving on port ${port} \xB7 ctrl-c to stop${globalInstall ? ` \xB7 ${keepUpdateHint(PACKAGE_NAME, PACKAGE_VERSION)}` : ""}`
|
|
26817
27306
|
);
|
|
26818
27307
|
}
|
|
26819
27308
|
return await new Promise(() => {
|
|
26820
27309
|
});
|
|
26821
27310
|
}
|
|
26822
27311
|
try {
|
|
27312
|
+
const globalClaim = acquireStableServerOwner();
|
|
27313
|
+
if (globalClaim.kind === "busy") throw new Error("Frizz is starting or recovering on this machine; retry shortly");
|
|
27314
|
+
if (globalClaim.kind === "running") {
|
|
27315
|
+
if (options.port && options.port !== globalClaim.port)
|
|
27316
|
+
throw new Error(`Frizz is already running on port ${globalClaim.port}; --port cannot change a running server`);
|
|
27317
|
+
await openOrPrint(globalClaim.port, true, slugPath());
|
|
27318
|
+
process.exit(0);
|
|
27319
|
+
}
|
|
27320
|
+
serverOwner = globalClaim.lease;
|
|
26823
27321
|
if (process.env.FRIZZ_PRODUCTION_SUPERVISOR === "1" || reexec) {
|
|
26824
27322
|
if (!options.port) throw new Error("internal registry supervisor launch is missing --port");
|
|
26825
27323
|
const token = projectLaunchOwnerTokenFromEnvironment(process.env);
|
|
@@ -26844,9 +27342,14 @@ try {
|
|
|
26844
27342
|
const allocation = await allocatePort(options.port, readPreferredPort(workspace.stateDir), { host: LOOPBACK_BIND_HOST });
|
|
26845
27343
|
const port = allocation.port;
|
|
26846
27344
|
portReservation = allocation.release;
|
|
26847
|
-
|
|
27345
|
+
let didPrepare;
|
|
27346
|
+
const prepared = new Promise((resolve7) => {
|
|
27347
|
+
didPrepare = resolve7;
|
|
27348
|
+
});
|
|
27349
|
+
const running = runSupervisor(port, claim.lease.token, didPrepare);
|
|
26848
27350
|
release();
|
|
26849
27351
|
release = void 0;
|
|
27352
|
+
await Promise.race([prepared, running]);
|
|
26850
27353
|
await Promise.race([
|
|
26851
27354
|
waitForWorkspace(
|
|
26852
27355
|
port,
|