frizz 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +3 -2
  2. package/dist/claude-agent-broker.js +15 -1
  3. package/dist/dev-child.js +3819 -1521
  4. package/dist/frizz.js +618 -259
  5. package/package.json +1 -1
  6. package/runtime/board/config.mjs +12 -1
  7. package/runtime/board/index.mjs +5 -0
  8. package/runtime/board/thread-update.mjs +4 -0
  9. package/runtime/cc-worker/.claude-plugin/plugin.json +1 -1
  10. package/runtime/cc-worker/DECISIONS.md +7 -0
  11. package/runtime/cc-worker/bin/frizz-mcp.mjs +561 -46
  12. package/runtime/cc-worker/hooks/scratchpad.mjs +20 -24
  13. package/runtime/cc-worker/hooks/session-seed.mjs +2 -2
  14. package/runtime/cc-worker/skills/gh/scripts/github-watch.mjs +1 -1
  15. package/web-dist/assets/{TerminalPane-BM_laA_I.js → TerminalPane-CNFymHXK.js} +1 -1
  16. package/web-dist/assets/{abnfDiagram-VRR7QNED-C5FCLi1n.js → abnfDiagram-VRR7QNED-DNBrcJfV.js} +1 -1
  17. package/web-dist/assets/architecture-TIHT7OUA-BSUDKbro.js +1 -0
  18. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-Dm7tUnwt.js → architectureDiagram-ZJ3FMSHR-SXVydqly.js} +1 -1
  19. package/web-dist/assets/{blockDiagram-677ZJIJ3-3EhpmwKM.js → blockDiagram-677ZJIJ3-CgI1GSdx.js} +1 -1
  20. package/web-dist/assets/{c4Diagram-LMCZKHZV-Ca-BjDxw.js → c4Diagram-LMCZKHZV-KDmJm2tG.js} +1 -1
  21. package/web-dist/assets/channel-DaCOnTxr.js +1 -0
  22. package/web-dist/assets/{chunk-32BRIVSS-xGbaUlTN.js → chunk-32BRIVSS-j3eOjq4Z.js} +1 -1
  23. package/web-dist/assets/{chunk-52WLFC77-YYhE3F1a.js → chunk-52WLFC77-DZHfa78H.js} +1 -1
  24. package/web-dist/assets/{chunk-C7G6YPKG-SYKXFtUg.js → chunk-C7G6YPKG-CiB5uo24.js} +1 -1
  25. package/web-dist/assets/{chunk-EX3LRPZG-cqjtdM_c.js → chunk-EX3LRPZG-B35Inyjz.js} +1 -1
  26. package/web-dist/assets/{chunk-FWX5IMBZ-qyaTngKT.js → chunk-FWX5IMBZ-D2sRvM5U.js} +2 -2
  27. package/web-dist/assets/{chunk-HOUHSVGY-DBFt1HnE.js → chunk-HOUHSVGY-D247PDv6.js} +1 -1
  28. package/web-dist/assets/{chunk-ICXQ74PX-Bme_2_gm.js → chunk-ICXQ74PX-Bu3Tb6Ec.js} +1 -1
  29. package/web-dist/assets/{chunk-MOJQB5TN-DupTmWhN.js → chunk-MOJQB5TN-C_lQy4on.js} +1 -1
  30. package/web-dist/assets/{chunk-OGEWGWER-DSqmbKCq.js → chunk-OGEWGWER-DU5ZBedR.js} +1 -1
  31. package/web-dist/assets/{chunk-PUDLZKDR-DVnHUoFN.js → chunk-PUDLZKDR-DWRT7ztS.js} +1 -1
  32. package/web-dist/assets/{chunk-Q4XR5HBZ-BIZh_Yuh.js → chunk-Q4XR5HBZ-CCX4AK_n.js} +1 -1
  33. package/web-dist/assets/{chunk-V7JOEXUC-e2G7UgOg.js → chunk-V7JOEXUC-VbixbkDG.js} +1 -1
  34. package/web-dist/assets/{chunk-VAUOI2AC-uYgyYWPh.js → chunk-VAUOI2AC-PJvChxMA.js} +1 -1
  35. package/web-dist/assets/{chunk-VR4S4FIN-BjGjcexQ.js → chunk-VR4S4FIN-BjsMfxj8.js} +1 -1
  36. package/web-dist/assets/{chunk-WYO6CB5R-BKKd_W3B.js → chunk-WYO6CB5R-Bcb97r3w.js} +1 -1
  37. package/web-dist/assets/{chunk-ZGVPDNZ5-D5_hsjnF.js → chunk-ZGVPDNZ5-CT2sZlhT.js} +1 -1
  38. package/web-dist/assets/classDiagram-OUVF2IWQ-BlylbZXV.js +1 -0
  39. package/web-dist/assets/classDiagram-v2-EOCWNBFH-BlylbZXV.js +1 -0
  40. package/web-dist/assets/{cynefin-VYW2F7L2-bkFv7EpV.js → cynefin-VYW2F7L2-dUpO4u0w.js} +1 -1
  41. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Du2-dyuZ.js → cynefinDiagram-TSTJHNR4-BQZ3UIsx.js} +1 -1
  42. package/web-dist/assets/{dagre-VKFMJZFB-CU7w00Ul.js → dagre-VKFMJZFB-K-oO8w51.js} +1 -1
  43. package/web-dist/assets/{diagram-FQU43EPY-BxvVgxWb.js → diagram-FQU43EPY-Cr47GJ_S.js} +1 -1
  44. package/web-dist/assets/{diagram-G47NLZAW-D8VvetwQ.js → diagram-G47NLZAW-BbWzSkoZ.js} +1 -1
  45. package/web-dist/assets/{diagram-NH7WQ7WH-CwsChkED.js → diagram-NH7WQ7WH-BGJJBgGM.js} +1 -1
  46. package/web-dist/assets/{diagram-OA4YK3LP-BIPYbe6L.js → diagram-OA4YK3LP-2W7aunEN.js} +1 -1
  47. package/web-dist/assets/{diagram-WEI45ONY-BoyH4dKl.js → diagram-WEI45ONY-D-4ITFI6.js} +1 -1
  48. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-9A3WRDfU.js → ebnfDiagram-CCIWWBDH-CxUcx103.js} +1 -1
  49. package/web-dist/assets/{erDiagram-Q63AITRT-D3Y9WA4H.js → erDiagram-Q63AITRT-Cf_5SWAE.js} +1 -1
  50. package/web-dist/assets/eventmodeling-45OFAUF4-DxKQnZNV.js +1 -0
  51. package/web-dist/assets/flowDiagram-23GEKE2U-Cdz9YM2Z.js +1 -0
  52. package/web-dist/assets/{ganttDiagram-NO4QXBWP-Bk2-LClm.js → ganttDiagram-NO4QXBWP-CVZI8Ywa.js} +1 -1
  53. package/web-dist/assets/{gitGraph-TEB2WS4Q-CXvPrsio.js → gitGraph-TEB2WS4Q-BsiGpR9l.js} +1 -1
  54. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-BC9D72kT.js → gitGraphDiagram-IHSO6WYX-DVym_4l1.js} +1 -1
  55. package/web-dist/assets/index-CYzJK7u0.js +497 -0
  56. package/web-dist/assets/index-CovJDCWc.css +1 -0
  57. package/web-dist/assets/{info-DKCQHKI2-Beag76kE.js → info-DKCQHKI2-DYcsKFv-.js} +1 -1
  58. package/web-dist/assets/{infoDiagram-FWYZ7A6U-DaqYXHYB.js → infoDiagram-FWYZ7A6U-hjVxlrTT.js} +1 -1
  59. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-D-d4tmLU.js → ishikawaDiagram-FXEZZL3T-B0DKOPSS.js} +1 -1
  60. package/web-dist/assets/{journeyDiagram-5HDEW3XC-kkFYzNg1.js → journeyDiagram-5HDEW3XC-Cohibc5O.js} +1 -1
  61. package/web-dist/assets/{kanban-definition-HUTT4EX6-BYRPjbfv.js → kanban-definition-HUTT4EX6-_6Zr31vM.js} +1 -1
  62. package/web-dist/assets/{line-C8l7y6rG.js → line-B14EZI6M.js} +1 -1
  63. package/web-dist/assets/{mermaid-parser.core-BG3fgy77.js → mermaid-parser.core-DHkc6cqw.js} +3 -3
  64. package/web-dist/assets/{mermaid.core-BCDzcbhr.js → mermaid.core-DuTvdsKf.js} +3 -3
  65. package/web-dist/assets/{mindmap-definition-LN4V7U3C-CP_bgQm8.js → mindmap-definition-LN4V7U3C-DPRF9pW2.js} +1 -1
  66. package/web-dist/assets/{packet-7NZHBO7P-Dgd69pFS.js → packet-7NZHBO7P-Ci8oCcGM.js} +1 -1
  67. package/web-dist/assets/{pegDiagram-2B236MQR-BJUb_DOD.js → pegDiagram-2B236MQR-Cr3ctC6e.js} +1 -1
  68. package/web-dist/assets/{pie-RZYD4A2V-DPbVRAuL.js → pie-RZYD4A2V-EHgA307y.js} +1 -1
  69. package/web-dist/assets/{pieDiagram-ENE6RG2P-DavUeOqM.js → pieDiagram-ENE6RG2P-UW6Bmu6F.js} +1 -1
  70. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-BdvoSedu.js → quadrantDiagram-ABIIQ3AL-D6tAsRj9.js} +1 -1
  71. package/web-dist/assets/{radar-I7S5WNFK-C2TAta9K.js → radar-I7S5WNFK-CAQqojcd.js} +1 -1
  72. package/web-dist/assets/{railroad-3IZDKUUU-DEMjzYqC.js → railroad-3IZDKUUU-BZsAOTrm.js} +1 -1
  73. package/web-dist/assets/railroad-abnf-AHOZXSZD-_2rSHfPz.js +1 -0
  74. package/web-dist/assets/railroad-ebnf-EBAXGLYW-xM3eAMFz.js +1 -0
  75. package/web-dist/assets/railroad-peg-LSFZ7HO6-cZlBUsED.js +1 -0
  76. package/web-dist/assets/{railroadDiagram-RFXS5EU6-C4rERo6H.js → railroadDiagram-RFXS5EU6-bSpff55H.js} +1 -1
  77. package/web-dist/assets/{requirementDiagram-TGXJPOKE-DlIG9D0n.js → requirementDiagram-TGXJPOKE-DIAYvXoB.js} +1 -1
  78. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-DVMrG-qY.js → sankeyDiagram-HTMAVEWB-DEnsSz3F.js} +1 -1
  79. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-DDcDM_-e.js → sequenceDiagram-DBY2YBRQ-DsG7eb9R.js} +1 -1
  80. package/web-dist/assets/{stateDiagram-2N3HPSRC-DuCRKU5t.js → stateDiagram-2N3HPSRC-DT3XNwjo.js} +1 -1
  81. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-C06v0Ltu.js +1 -0
  82. package/web-dist/assets/{swimlanes-5IMT3BWC-CY0fdvUm.js → swimlanes-5IMT3BWC-B5hZwgRo.js} +1 -1
  83. package/web-dist/assets/swimlanesDiagram-G3AALYLV-CXyN7ZyO.js +8 -0
  84. package/web-dist/assets/{timeline-definition-FHXFAJF6-De0fDNdU.js → timeline-definition-FHXFAJF6-BVTsjkfu.js} +1 -1
  85. package/web-dist/assets/{treeView-QDETBFTQ-AIoMhcen.js → treeView-QDETBFTQ-M6HmP4bB.js} +1 -1
  86. package/web-dist/assets/{treemap-6X3UGDF4-CPZ1Ln05.js → treemap-6X3UGDF4-C60TppfC.js} +1 -1
  87. package/web-dist/assets/{vennDiagram-L72KCM5P-FrSO6pmh.js → vennDiagram-L72KCM5P-Dv1y3g4S.js} +1 -1
  88. package/web-dist/assets/{wardley-OPB4EBWU-BbET6cjs.js → wardley-OPB4EBWU-D0lMJMWt.js} +1 -1
  89. package/web-dist/assets/{wardleyDiagram-EHGQE667-DqvcCBjr.js → wardleyDiagram-EHGQE667-B1E5NtZY.js} +1 -1
  90. package/web-dist/assets/{xychartDiagram-FW5EYKEG-91xKEO07.js → xychartDiagram-FW5EYKEG-oA91YOvh.js} +1 -1
  91. package/web-dist/index.html +2 -2
  92. package/web-dist/assets/architecture-TIHT7OUA-ngY1F0r2.js +0 -1
  93. package/web-dist/assets/channel-BpyNaJoi.js +0 -1
  94. package/web-dist/assets/classDiagram-OUVF2IWQ-DTEWwxt7.js +0 -1
  95. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DTEWwxt7.js +0 -1
  96. package/web-dist/assets/eventmodeling-45OFAUF4-D7g9kDF0.js +0 -1
  97. package/web-dist/assets/flowDiagram-23GEKE2U-BqKnxVr3.js +0 -1
  98. package/web-dist/assets/index-CCtNIGi6.js +0 -491
  99. package/web-dist/assets/index-Cq79m8AR.css +0 -1
  100. package/web-dist/assets/railroad-abnf-AHOZXSZD-_4FByoRI.js +0 -1
  101. package/web-dist/assets/railroad-ebnf-EBAXGLYW-DKAvMIMu.js +0 -1
  102. package/web-dist/assets/railroad-peg-LSFZ7HO6-CkJl3c69.js +0 -1
  103. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-90dqEQum.js +0 -1
  104. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BETWueIt.js +0 -8
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: sep3, value } = collItem;
4178
+ const { start, key, sep: sep4, value } = collItem;
4179
4179
  const keyProps = resolveProps.resolveProps(start, {
4180
4180
  indicator: "explicit-key-ind",
4181
- next: key ?? sep3?.[0],
4181
+ next: key ?? sep4?.[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 && !sep3) {
4195
+ if (!keyProps.anchor && !keyProps.tag && !sep4) {
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(sep3 ?? [], {
4219
+ const valueProps = resolveProps.resolveProps(sep4 ?? [], {
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, sep3, null, valueProps, onError);
4235
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : composeEmptyNode(ctx, offset, sep4, 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 sep3 = "";
4326
+ let sep4 = "";
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 += sep3 + cb;
4341
- sep3 = "";
4340
+ comment += sep4 + cb;
4341
+ sep4 = "";
4342
4342
  break;
4343
4343
  }
4344
4344
  case "newline":
4345
4345
  if (comment)
4346
- sep3 += source;
4346
+ sep4 += 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: sep3, value } = collItem;
4389
+ const { start, key, sep: sep4, value } = collItem;
4390
4390
  const props = resolveProps.resolveProps(start, {
4391
4391
  flow: fcName,
4392
4392
  indicator: "explicit-key-ind",
4393
- next: key ?? sep3?.[0],
4393
+ next: key ?? sep4?.[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 && !sep3 && !value) {
4400
+ if (!props.anchor && !props.tag && !sep4 && !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 && !sep3 && !props.found) {
4455
- const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep3, null, props, onError);
4454
+ if (!isMap && !sep4 && !props.found) {
4455
+ const valueNode = value ? composeNode(ctx, value, props, onError) : composeEmptyNode(ctx, props.end, sep4, 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(sep3 ?? [], {
4467
+ const valueProps = resolveProps.resolveProps(sep4 ?? [], {
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 (sep3)
4479
- for (const st of sep3) {
4478
+ if (sep4)
4479
+ for (const st of sep4) {
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, sep3, null, valueProps, onError) : null;
4496
+ const valueNode = value ? composeNode(ctx, value, valueProps, onError) : valueProps.found ? composeEmptyNode(ctx, valueProps.end, sep4, 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 sep3 = "";
4676
+ let sep4 = "";
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 += sep3 + indent.slice(trimIndent) + content;
4694
- sep3 = "\n";
4693
+ value += sep4 + indent.slice(trimIndent) + content;
4694
+ sep4 = "\n";
4695
4695
  } else if (indent.length > trimIndent || content[0] === " ") {
4696
- if (sep3 === " ")
4697
- sep3 = "\n";
4698
- else if (!prevMoreIndented && sep3 === "\n")
4699
- sep3 = "\n\n";
4700
- value += sep3 + indent.slice(trimIndent) + content;
4701
- sep3 = "\n";
4696
+ if (sep4 === " ")
4697
+ sep4 = "\n";
4698
+ else if (!prevMoreIndented && sep4 === "\n")
4699
+ sep4 = "\n\n";
4700
+ value += sep4 + indent.slice(trimIndent) + content;
4701
+ sep4 = "\n";
4702
4702
  prevMoreIndented = true;
4703
4703
  } else if (content === "") {
4704
- if (sep3 === "\n")
4704
+ if (sep4 === "\n")
4705
4705
  value += "\n";
4706
4706
  else
4707
- sep3 = "\n";
4707
+ sep4 = "\n";
4708
4708
  } else {
4709
- value += sep3 + content;
4710
- sep3 = " ";
4709
+ value += sep4 + content;
4710
+ sep4 = " ";
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 sep3 = " ";
4892
+ let sep4 = " ";
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 (sep3 === "\n")
4898
- res += sep3;
4897
+ if (sep4 === "\n")
4898
+ res += sep4;
4899
4899
  else
4900
- sep3 = "\n";
4900
+ sep4 = "\n";
4901
4901
  } else {
4902
- res += sep3 + match[1];
4903
- sep3 = " ";
4902
+ res += sep4 + match[1];
4903
+ sep4 = " ";
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 + sep3 + (match?.[1] ?? "");
4910
+ return res + sep4 + (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: sep3, value }) {
5720
+ function stringifyItem({ start, key, sep: sep4, 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 (sep3)
5727
- for (const st of sep3)
5726
+ if (sep4)
5727
+ for (const st of sep4)
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 sep3;
6894
+ let sep4;
6895
6895
  if (scalar.end) {
6896
- sep3 = scalar.end;
6897
- sep3.push(this.sourceToken);
6896
+ sep4 = scalar.end;
6897
+ sep4.push(this.sourceToken);
6898
6898
  delete scalar.end;
6899
6899
  } else
6900
- sep3 = [this.sourceToken];
6900
+ sep4 = [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: sep3 }]
6905
+ items: [{ start, key: scalar, sep: sep4 }]
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 sep3 = it.sep;
7059
- sep3.push(this.sourceToken);
7058
+ const sep4 = it.sep;
7059
+ sep4.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: sep3 }]
7066
+ items: [{ start: start2, key, sep: sep4 }]
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 sep3 = fc.end.splice(1, fc.end.length);
7261
- sep3.push(this.sourceToken);
7260
+ const sep4 = fc.end.splice(1, fc.end.length);
7261
+ sep4.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: sep3 }]
7266
+ items: [{ start, key: fc, sep: sep4 }]
7267
7267
  };
7268
7268
  this.onKeyLine = true;
7269
7269
  this.stack[this.stack.length - 1] = map;
@@ -12184,6 +12184,16 @@ var init_interactions = __esm({
12184
12184
  });
12185
12185
 
12186
12186
  // packages/shared/src/claim.ts
12187
+ function isAnonymousClaimName(name) {
12188
+ return ANONYMOUS_CLAIM_PATTERN.test(name);
12189
+ }
12190
+ function generateAnonymousClaimName() {
12191
+ const bytes = new Uint8Array(ANONYMOUS_CLAIM_NAME_LENGTH);
12192
+ crypto.getRandomValues(bytes);
12193
+ let name = "";
12194
+ for (const byte of bytes) name += ANONYMOUS_CLAIM_ALPHABET[byte & 31];
12195
+ return name;
12196
+ }
12187
12197
  function toBase64Url(bytes) {
12188
12198
  const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
12189
12199
  let binary = "";
@@ -12267,7 +12277,7 @@ async function claimIdentityFromPrivateKey(pkcs8) {
12267
12277
  return null;
12268
12278
  }
12269
12279
  }
12270
- var CLAIM_PROTOCOL_VERSION, CLAIM_MAX_AGE_MS, CLAIM_LEASE_MS, RESERVED_CLAIM_NAMES, CLAIM_NAME_MIN_LENGTH, CLAIM_NAME_MAX_LENGTH;
12280
+ var CLAIM_PROTOCOL_VERSION, CLAIM_MAX_AGE_MS, CLAIM_LEASE_MS, RESERVED_CLAIM_NAMES, CLAIM_NAME_MIN_LENGTH, CLAIM_NAME_MAX_LENGTH, ANONYMOUS_CLAIM_NAME_LENGTH, ANONYMOUS_CLAIM_ALPHABET, ANONYMOUS_CLAIM_PATTERN;
12271
12281
  var init_claim = __esm({
12272
12282
  "packages/shared/src/claim.ts"() {
12273
12283
  "use strict";
@@ -12306,6 +12316,9 @@ var init_claim = __esm({
12306
12316
  ]);
12307
12317
  CLAIM_NAME_MIN_LENGTH = 3;
12308
12318
  CLAIM_NAME_MAX_LENGTH = 63;
12319
+ ANONYMOUS_CLAIM_NAME_LENGTH = 20;
12320
+ ANONYMOUS_CLAIM_ALPHABET = "abcdefghijklmnopqrstuvwxyz234567";
12321
+ ANONYMOUS_CLAIM_PATTERN = new RegExp(`^[a-z2-7]{${ANONYMOUS_CLAIM_NAME_LENGTH}}$`);
12309
12322
  }
12310
12323
  });
12311
12324
 
@@ -12374,7 +12387,7 @@ function relayHandshakeInput(name, pubkey, issuedAt) {
12374
12387
  ["frizz-relay", `v${RELAY_PROTOCOL_VERSION}`, name, pubkey, String(issuedAt)].join(":")
12375
12388
  );
12376
12389
  }
12377
- var RELAY_PROTOCOL_VERSION, RELAY_STRIPPED_HEADERS, RELAY_MAX_FRAME_BODY, RELAY_MAX_WS_CHUNK, WsMessageAssembler, serializeFrame;
12390
+ var RELAY_PROTOCOL_VERSION, RELAY_STRIPPED_HEADERS, RELAY_MAX_FRAME_BODY, RELAY_MAX_WS_CHUNK, WsMessageAssembler, serializeFrame, RELAY_KEEPALIVE_PING, RELAY_KEEPALIVE_PONG;
12378
12391
  var init_relay_protocol = __esm({
12379
12392
  "packages/shared/src/relay-protocol.ts"() {
12380
12393
  "use strict";
@@ -12440,6 +12453,8 @@ var init_relay_protocol = __esm({
12440
12453
  }
12441
12454
  };
12442
12455
  serializeFrame = (frame) => JSON.stringify(frame);
12456
+ RELAY_KEEPALIVE_PING = serializeFrame({ t: "ping", id: "keepalive" });
12457
+ RELAY_KEEPALIVE_PONG = serializeFrame({ t: "pong", id: "keepalive" });
12443
12458
  }
12444
12459
  });
12445
12460
 
@@ -12447,7 +12462,7 @@ var init_relay_protocol = __esm({
12447
12462
  function fallbackPort(base) {
12448
12463
  return base + 1e4;
12449
12464
  }
12450
- var import_yaml, ATTACHMENT_IMAGE_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_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, 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, SetThreadRecurringPromptInput, SetOwnThreadRecurringPromptInput, SetOwnThreadRecurringPromptResult, GetOwnThreadRecurringPromptInput, OwnThreadRecurringPromptResult, SetOwnThreadTimerInput, CancelOwnThreadTimerInput, ListOwnThreadTimersInput, OwnThreadTimersResult, ThreadActivityItem, ListOwnThreadActivityInput, OwnThreadActivityResult, SetOwnThreadTimerResult, CancelOwnThreadTimerResult, SetOwnThreadStopHookInput, SetOwnThreadHeartbeatInput, ThreadPluginReloadResult, RenameThreadInput, AiRenameThreadInput, AiRenameThreadResult, 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_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
12465
+ 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_DEFAULT_FOR_MS, PrWatchView, AddOwnPrWatchInput, AddOwnPrWatchResult, DropOwnPrWatchInput, DropOwnPrWatchResult, OwnWatchKind, AddOwnWatchInput, OwnWatchView, AddOwnWatchResult, DropOwnWatchInput, DropOwnWatchResult, AskQuestionKind, ASK_MAX_PER_CALL, ASK_MAX_OPEN, AskedOptionSchema, AskedQuestionSchema, AskInput, RegisteredQuestionView, AskResult, UnaskInput, UnaskResult, QuestionAnswerSchema, AnswerQuestionsInput, AnswerQuestionsResult, DismissQuestionsInput, DismissQuestionsResult, MarkOwnDoneInput, MarkOwnDoneResult, ListOwnPrWatchesInput, OwnPrWatchesResult, ThreadTimerView, ThreadFence, LimitWindow, LimitPause, 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, 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_FAILED, GithubStatus, GithubRefCard, GithubRefPreviewInput, GithubRefPreviewResult, GithubItem, GithubListInput, GithubListResult, GithubBatchInput, GithubBatchResult, BoardMeta, ServerEvent, TranscriptEdit, TranscriptTodo, TranscriptToolCall, TranscriptPart, TranscriptMessage, TranscriptPageCursor, EditedFile, TranscriptPage, TranscriptEarlierInput, SocketTranscriptSlug, SocketClientMsg, ProjectCard, PROJECT_ICON_MAX_BASE64_CHARS, DirectoryPickResult, ThreadLocation, FRIZZ_ROUTE_PREFIX, DEFAULT_PORT;
12451
12466
  var init_src = __esm({
12452
12467
  "packages/shared/src/index.ts"() {
12453
12468
  "use strict";
@@ -12464,7 +12479,7 @@ var init_src = __esm({
12464
12479
  init_relay_protocol();
12465
12480
  init_thread_slug();
12466
12481
  ATTACHMENT_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "webp"];
12467
- ATTACHMENT_DOC_EXTENSIONS = [
12482
+ ATTACHMENT_TEXT_EXTENSIONS = [
12468
12483
  "pdf",
12469
12484
  "svg",
12470
12485
  "txt",
@@ -12476,6 +12491,7 @@ var init_src = __esm({
12476
12491
  "tsv",
12477
12492
  "json",
12478
12493
  "jsonl",
12494
+ "ndjson",
12479
12495
  "yaml",
12480
12496
  "yml",
12481
12497
  "toml",
@@ -12512,6 +12528,38 @@ var init_src = __esm({
12512
12528
  "lua",
12513
12529
  "r"
12514
12530
  ];
12531
+ ATTACHMENT_OFFICE_EXTENSIONS = [
12532
+ "xlsx",
12533
+ "xlsm",
12534
+ "xls",
12535
+ "docx",
12536
+ "doc",
12537
+ "pptx",
12538
+ "ppt",
12539
+ "odt",
12540
+ "ods",
12541
+ "odp",
12542
+ "rtf",
12543
+ "epub"
12544
+ ];
12545
+ ATTACHMENT_DATA_EXTENSIONS = [
12546
+ "parquet",
12547
+ "avro",
12548
+ "orc",
12549
+ "arrow",
12550
+ "feather",
12551
+ "ipynb",
12552
+ "db",
12553
+ "sqlite",
12554
+ "sqlite3"
12555
+ ];
12556
+ ATTACHMENT_ARCHIVE_EXTENSIONS = ["zip", "tar", "gz", "tgz", "bz2", "xz", "zst", "7z"];
12557
+ ATTACHMENT_DOC_EXTENSIONS = [
12558
+ ...ATTACHMENT_TEXT_EXTENSIONS,
12559
+ ...ATTACHMENT_OFFICE_EXTENSIONS,
12560
+ ...ATTACHMENT_DATA_EXTENSIONS,
12561
+ ...ATTACHMENT_ARCHIVE_EXTENSIONS
12562
+ ];
12515
12563
  ATTACHMENT_EXTENSIONS = [...ATTACHMENT_IMAGE_EXTENSIONS, ...ATTACHMENT_DOC_EXTENSIONS];
12516
12564
  ATTACHMENT_MAX_BASE64_CHARS = 25e6;
12517
12565
  ATTACHMENT_MAX_BYTES = Math.floor(ATTACHMENT_MAX_BASE64_CHARS / 4) * 3;
@@ -12564,17 +12612,25 @@ var init_src = __esm({
12564
12612
  // clears itself when that work does. Every liveness reading keys on "running", so a rested row holds
12565
12613
  // nothing back: it does not block a rest, hold the queue, or gate Mark-as-done.
12566
12614
  state: external_exports.enum(["running", "stale", "rested"]),
12567
- // The worker-profile cell (model+effort) from the dispatch's `subagent_type`. It is NO LONGER drawn as
12568
- // a tag on the child rows under the prompt box (maintainer 2026-07-27: the profile belongs to the
12569
- // prompt box's own control one line up, not repeated on every child line); the transcript's dispatch
12570
- // card still shows it, the sidebar rail carries it in the row tooltip, and the drill-in passes it to
12571
- // the drawer. Optional — absent on dispatches without it.
12615
+ // The worker-profile cell (model+effort) for the dispatch — RESOLVED, not the raw `subagent_type`:
12616
+ // an effort-only profile carries no model, so the server composes it from the call's own `model` or
12617
+ // the dispatching turn's (server/subagent-profile.ts). It is NO LONGER drawn as a tag on the child
12618
+ // rows under the prompt box (maintainer 2026-07-27: the profile belongs to the prompt box's own
12619
+ // control one line up, not repeated on every child line); the transcript's dispatch card shows it,
12620
+ // the sidebar rail carries it in the row tooltip, and the drill-in passes it to the drawer.
12621
+ // Optional — absent when nothing about the child's runtime is known.
12572
12622
  subagentType: external_exports.string().optional(),
12573
12623
  // The dispatch tool_use id (the stable correlation key: same id on the Agent tool_use block, the
12574
12624
  // completion <task-notification>, and the transcript AgentBlock). Optional — absent on a pre-restart
12575
12625
  // server that doesn't emit it yet → the drill-in drawer's entry point is simply not offered. Present
12576
12626
  // → the banner row / AgentBlock is clickable and resolves this exact child's transcript.
12577
12627
  id: external_exports.string().optional(),
12628
+ // The RUNTIME agent id — the `agentId: a01b2d20b32feab11` line of the Agent tool's launch ack, which
12629
+ // is the only id the MODEL is ever shown for its child (the tool_use id above is invisible to it). So
12630
+ // it is the string a worker writes in an `agents:` fence line or registers a `watch` against, exactly
12631
+ // as BgShellView.taskId is for a shell. Every liveness reading accepts both. Absent for a codex row
12632
+ // and for a Claude row between its tool_use and its launch ack.
12633
+ taskId: external_exports.string().optional(),
12578
12634
  // Can frizz actually END this child's work right now? Computed SERVER-side (board.ts, the one place
12579
12635
  // holding both the session row and the tailer's telemetry) and never re-derived by a client — the
12580
12636
  // same discipline as `steerable`, and for the same reason: the policy depends on the thread's
@@ -12898,6 +12954,137 @@ var init_src = __esm({
12898
12954
  dropped: external_exports.boolean(),
12899
12955
  watches: external_exports.array(PrWatchView)
12900
12956
  }).strict();
12957
+ OwnWatchKind = external_exports.enum(["shell", "agent"]);
12958
+ AddOwnWatchInput = external_exports.object({
12959
+ slug: ThreadSlug,
12960
+ /** What KIND of thing the target is. Stored, and checked against the thread's live telemetry before the
12961
+ * row is written — see the note on `target`. */
12962
+ kind: OwnWatchKind,
12963
+ /** The handle the worker was shown: a runtime task id ("Command running in background with ID: …"), a
12964
+ * launch tool_use id, or the op's own label.
12965
+ *
12966
+ * VALIDATED AGAINST LIVE TELEMETRY, NOT AGAINST ITS SHAPE. A PR ref is checkable by shape because
12967
+ * `owner/repo#123` looks like nothing else; a shell handle and a sub-agent handle are both opaque
12968
+ * runtime strings and overlap completely, so shape can only ever be a guess. What frizz CAN answer
12969
+ * exactly is whether this thread has a live shell — or a live sub-agent — answering to this handle, and
12970
+ * that is both the stronger check and the one that catches the real mistake: naming a sub-agent under
12971
+ * `kind: "shell"`, which is what put two sub-agents under a "Background shells" heading on 2026-08-26. */
12972
+ target: external_exports.string().trim().min(1).max(200),
12973
+ /** REQUIRED, and a DURATION (`30m`, `2h`, `3d` — parseAwaitingDuration, capped at 24h).
12974
+ *
12975
+ * No default and no wire-level optionality, unlike `AddOwnPrWatchInput.for`: that field is optional
12976
+ * only to keep working for sessions dispatched before it existed, and this RPC has no such sessions.
12977
+ * On elapse the row is CANCELLED and the thread woken to re-decide, which is what stops a registration
12978
+ * outliving its own relevance — the one thing an un-restated fence could never do wrong. */
12979
+ for: external_exports.string().trim().min(1).max(16)
12980
+ }).strict();
12981
+ OwnWatchView = external_exports.object({
12982
+ id: external_exports.string(),
12983
+ kind: OwnWatchKind,
12984
+ target: external_exports.string(),
12985
+ /** The op's own label where the target resolved to one, so a read-back names the work rather than an
12986
+ * opaque handle. Absent when the target no longer resolves — the row still stands and names itself. */
12987
+ label: external_exports.string().optional(),
12988
+ createdAt: external_exports.string(),
12989
+ expiresAt: external_exports.string()
12990
+ }).strict();
12991
+ AddOwnWatchResult = external_exports.object({
12992
+ id: external_exports.string(),
12993
+ kind: OwnWatchKind,
12994
+ target: external_exports.string(),
12995
+ /** True when this exact (kind, target) was already watched, so the call registered nothing new and the
12996
+ * existing expiry stands. Re-registering after a wake or a compaction is the common, correct case. */
12997
+ alreadyArmed: external_exports.boolean(),
12998
+ watches: external_exports.array(OwnWatchView)
12999
+ }).strict();
13000
+ DropOwnWatchInput = external_exports.object({
13001
+ slug: ThreadSlug,
13002
+ id: external_exports.string().min(1).max(64)
13003
+ }).strict();
13004
+ DropOwnWatchResult = external_exports.object({
13005
+ dropped: external_exports.boolean(),
13006
+ watches: external_exports.array(OwnWatchView)
13007
+ }).strict();
13008
+ AskQuestionKind = external_exports.enum(["question", "multi"]);
13009
+ ASK_MAX_PER_CALL = 4;
13010
+ ASK_MAX_OPEN = 12;
13011
+ AskedOptionSchema = external_exports.lazy(() => external_exports.object({
13012
+ label: external_exports.string().trim().min(1).max(120),
13013
+ description: external_exports.string().trim().max(400).optional(),
13014
+ recommended: external_exports.boolean().optional(),
13015
+ preview: external_exports.string().max(4e3).optional(),
13016
+ followUps: external_exports.array(AskedQuestionSchema).max(ASK_MAX_PER_CALL).optional()
13017
+ }).strict());
13018
+ AskedQuestionSchema = external_exports.lazy(() => external_exports.object({
13019
+ question: external_exports.string().trim().min(1).max(600),
13020
+ header: external_exports.string().trim().max(24).optional(),
13021
+ kind: AskQuestionKind,
13022
+ danger: external_exports.boolean().optional(),
13023
+ options: external_exports.array(AskedOptionSchema).max(8).optional()
13024
+ }).strict());
13025
+ AskInput = external_exports.object({
13026
+ slug: ThreadSlug,
13027
+ questions: external_exports.array(AskedQuestionSchema).min(1).max(ASK_MAX_PER_CALL)
13028
+ }).strict();
13029
+ RegisteredQuestionView = external_exports.object({
13030
+ /** Minted by frizz. The worker never chose it, which is why an answer RESTATES the question text —
13031
+ * an id alone cannot be correlated back to what was asked. */
13032
+ id: external_exports.string(),
13033
+ spec: AskedQuestionSchema,
13034
+ askedAt: external_exports.string()
13035
+ }).strict();
13036
+ AskResult = external_exports.object({
13037
+ registered: external_exports.array(RegisteredQuestionView),
13038
+ /** Everything still open on this thread afterwards, so a worker never needs a second call. */
13039
+ open: external_exports.array(RegisteredQuestionView)
13040
+ }).strict();
13041
+ UnaskInput = external_exports.object({
13042
+ slug: ThreadSlug,
13043
+ id: external_exports.string().min(1).max(64)
13044
+ }).strict();
13045
+ UnaskResult = external_exports.object({
13046
+ withdrawn: external_exports.boolean(),
13047
+ open: external_exports.array(RegisteredQuestionView)
13048
+ }).strict();
13049
+ QuestionAnswerSchema = external_exports.lazy(() => external_exports.object({
13050
+ questionId: external_exports.string().min(1).max(64),
13051
+ question: external_exports.string().min(1).max(600),
13052
+ chosen: external_exports.array(external_exports.string().max(200)).max(8),
13053
+ text: external_exports.string().max(8e3).optional(),
13054
+ followUps: external_exports.array(QuestionAnswerSchema).max(ASK_MAX_PER_CALL).optional()
13055
+ }).strict());
13056
+ AnswerQuestionsInput = external_exports.object({
13057
+ slug: ThreadSlug,
13058
+ /** SUBMITTED AS A UNIT. The card sends whatever was answered in one call, because a per-question send
13059
+ * would half-wake a turn: the worker would come back to a payload it cannot act on and would have to
13060
+ * ask again for the rest. */
13061
+ answers: external_exports.array(QuestionAnswerSchema).min(1).max(ASK_MAX_OPEN)
13062
+ }).strict();
13063
+ AnswerQuestionsResult = external_exports.object({
13064
+ /** The ids that were open and are now answered. An id that was already settled is silently absent
13065
+ * rather than an error: two browser tabs answering the same card is a race nobody should see. */
13066
+ answered: external_exports.array(external_exports.string()),
13067
+ open: external_exports.array(RegisteredQuestionView)
13068
+ }).strict();
13069
+ DismissQuestionsInput = external_exports.object({
13070
+ slug: ThreadSlug,
13071
+ ids: external_exports.array(external_exports.string().min(1).max(64)).min(1).max(ASK_MAX_OPEN)
13072
+ }).strict();
13073
+ DismissQuestionsResult = external_exports.object({
13074
+ dismissed: external_exports.array(external_exports.string()),
13075
+ open: external_exports.array(RegisteredQuestionView)
13076
+ }).strict();
13077
+ MarkOwnDoneInput = external_exports.object({
13078
+ slug: ThreadSlug,
13079
+ body: external_exports.string().trim().min(1).max(2e4)
13080
+ }).strict();
13081
+ MarkOwnDoneResult = external_exports.object({
13082
+ done: external_exports.boolean(),
13083
+ /** Open questions, by id and question text. */
13084
+ blockingQuestions: external_exports.array(external_exports.object({ id: external_exports.string(), question: external_exports.string() }).strict()),
13085
+ /** Armed registrations, by id and what each names. Watches, PR watchers and timers alike. */
13086
+ blockingWatches: external_exports.array(external_exports.object({ id: external_exports.string(), what: external_exports.string() }).strict())
13087
+ }).strict();
12901
13088
  ListOwnPrWatchesInput = external_exports.object({ slug: ThreadSlug }).strict();
12902
13089
  OwnPrWatchesResult = external_exports.object({ watches: external_exports.array(PrWatchView) }).strict();
12903
13090
  ThreadTimerView = external_exports.object({
@@ -12912,9 +13099,15 @@ var init_src = __esm({
12912
13099
  kind: external_exports.enum(["done", "awaiting"]),
12913
13100
  body: external_exports.string(),
12914
13101
  // fence body minus hint lines, capped server-side; may be ""
12915
- hints: external_exports.array(AwaitingHint).default([])
13102
+ hints: external_exports.array(AwaitingHint).default([]),
13103
+ // Present only on a completion the worker REGISTERED (`mcp__frizz__done`, board.registeredDoneFence)
13104
+ // rather than wrote as a ```done fence in its final message. The two are one fence to every predicate,
13105
+ // but the TRANSCRIPT draws a fence card from the message text it parses — so a registered done, which
13106
+ // is in no message, needs the client to know it must draw the card itself at the bottom of the thread
13107
+ // (maintainer 2026-08-27: a thread that signed off by tool rested with no card at all).
13108
+ registered: external_exports.literal(true).optional()
12916
13109
  });
12917
- LimitWindow = external_exports.enum(["session", "weekly", "unknown"]);
13110
+ LimitWindow = external_exports.enum(["session", "weekly", "model", "unknown"]);
12918
13111
  LimitPause = external_exports.object({
12919
13112
  backend: Backend,
12920
13113
  window: LimitWindow,
@@ -13008,6 +13201,18 @@ var init_src = __esm({
13008
13201
  // Derived safety net (tailer): at rest with an unanswered ```question the worker asked in chat but
13009
13202
  // never encoded as blocked. Defaults false so old snapshots/rows parse. Feeds needsAction.
13010
13203
  pendingQuestion: external_exports.boolean().default(false),
13204
+ // The worker's REGISTERED questions, still open (thread_question). Distinct from `pendingQuestion`
13205
+ // beside it, and the difference is the whole point of the registry: that boolean is recomputed from
13206
+ // the LATEST assistant text on every assistant record and cleared by any human turn, so it cannot
13207
+ // outlive the message that carried it. These rows can, and they carry the question itself rather than
13208
+ // merely asserting one exists — the card renders from this instead of re-parsing prose.
13209
+ questions: external_exports.array(RegisteredQuestionView).default([]),
13210
+ /** The answer the human has already SENT that the worker has not received yet, as the exact message
13211
+ * the delivery will carry (board.answersInFlight → questionAnswerMessage). The chat parses it with
13212
+ * the same reader it uses on the delivered turn, so the in-flight card and the landed one are the
13213
+ * same card and the swap is invisible. Absent whenever there is nothing in flight, which is almost
13214
+ * always — it exists for the seconds between the human sending and the worker being handed it. */
13215
+ answersInFlight: external_exports.string().optional(),
13011
13216
  // ISO8601 of the newest REAL user interaction (answer/steer/dispatch) — the chronological listing
13012
13217
  // sort key. Optional; the listing falls back to spawnedAt when absent (a dispatch IS an interaction).
13013
13218
  lastUserAt: external_exports.string().optional(),
@@ -13193,7 +13398,7 @@ var init_src = __esm({
13193
13398
  key: external_exports.string(),
13194
13399
  // stable id: "5h" | "weekly" (provider-neutral)
13195
13400
  label: external_exports.string(),
13196
- // short human label for the chip ("5h", "Weekly")
13401
+ // short human label for the chip ("5h", "Weekly") — house duration grammar
13197
13402
  usedPercent: external_exports.number(),
13198
13403
  // 0..100
13199
13404
  resetsAt: external_exports.number().optional()
@@ -13490,13 +13695,25 @@ var init_src = __esm({
13490
13695
  /** ISO8601 of when it started or was armed — absent when frizz has no instant for it. */
13491
13696
  since: external_exports.string().optional(),
13492
13697
  /** A timer's fire instant, or a PR's expiry. Absent for shells and sub-agents. */
13493
- until: external_exports.string().optional()
13698
+ until: external_exports.string().optional(),
13699
+ /** The `wch_…` id of the REGISTERED WATCH holding this item, when the worker armed one — so a readout
13700
+ * that exists to hand ids back also hands back the one `unwatch` takes. A separate ROW per watch was
13701
+ * the alternative and it would list the same shell twice, which is exactly the duplication that put
13702
+ * two sub-agents under a "Background shells" heading. */
13703
+ watchId: external_exports.string().optional()
13494
13704
  }).strict();
13495
13705
  ListOwnThreadActivityInput = external_exports.object({
13496
13706
  slug: ThreadSlug
13497
13707
  }).strict();
13498
13708
  OwnThreadActivityResult = external_exports.object({
13499
- activity: external_exports.array(ThreadActivityItem)
13709
+ activity: external_exports.array(ThreadActivityItem),
13710
+ /** Every question still owed an answer. NOT a `ThreadActivityItem` and deliberately its own list: a
13711
+ * question is not running work, it waits on a PERSON, and there is no `questions:` key in the awaiting
13712
+ * fence for it to be written into. Until 2026-08-28 a worker could read its open questions back only
13713
+ * as a side effect of `ask` (which registers another) or `unask` (which withdraws one) — so the ids
13714
+ * that block `done` were readable only by mutating something (maintainer: "Is there a way for the
13715
+ * agent to read out the current set of watchers and questions?"). */
13716
+ questions: external_exports.array(RegisteredQuestionView).default([])
13500
13717
  }).strict();
13501
13718
  SetOwnThreadTimerResult = external_exports.object({
13502
13719
  id: external_exports.string(),
@@ -13531,6 +13748,15 @@ var init_src = __esm({
13531
13748
  });
13532
13749
  AiRenameThreadInput = external_exports.object({ slug: ThreadSlug });
13533
13750
  AiRenameThreadResult = external_exports.object({ title: external_exports.string().min(1).max(200) });
13751
+ SetOwnThreadTitleInput = external_exports.object({
13752
+ slug: ThreadSlug,
13753
+ title: external_exports.string().trim().min(1).max(200)
13754
+ }).strict();
13755
+ SetOwnThreadTitleResult = external_exports.object({
13756
+ accepted: external_exports.boolean(),
13757
+ title: external_exports.string(),
13758
+ lockedByHuman: external_exports.boolean()
13759
+ }).strict();
13534
13760
  SetThreadPermissionInput = external_exports.object({
13535
13761
  slug: ThreadSlug,
13536
13762
  permissionMode: PermissionMode
@@ -13757,7 +13983,11 @@ ${DISPATCH_TASK_BANNER}
13757
13983
  TranscriptEdit = external_exports.object({
13758
13984
  file: external_exports.string(),
13759
13985
  old: external_exports.string(),
13760
- new: external_exports.string()
13986
+ new: external_exports.string(),
13987
+ // Line counts of the UNCAPPED sides, taken at projection time — `old`/`new` above are capped for
13988
+ // transport, so a diffstat recomputed from them undercounts any large edit.
13989
+ added: external_exports.number().int().nonnegative().optional(),
13990
+ removed: external_exports.number().int().nonnegative().optional()
13761
13991
  });
13762
13992
  TranscriptTodo = external_exports.object({
13763
13993
  text: external_exports.string(),
@@ -13829,8 +14059,10 @@ ${DISPATCH_TASK_BANNER}
13829
14059
  // optional so a pre-restart server / older transcript falls back to the plain `Agent(detail)` line.
13830
14060
  prompt: external_exports.string().optional(),
13831
14061
  // the capped dispatch prompt (the AgentBlock's expanded body)
14062
+ // The RESOLVED model+effort cell (e.g. "frizz:opus-high"), not `subagent_type` verbatim: a modern
14063
+ // profile is effort-only, so the server folds the call's `model` — or, when omitted, the model the
14064
+ // dispatching turn itself ran at — back into the cell. See server/subagent-profile.ts.
13832
14065
  subagentType: external_exports.string().optional(),
13833
- // the dispatch's subagent_type verbatim (e.g. "frizz:frizz-opus-high")
13834
14066
  agentId: external_exports.string().optional(),
13835
14067
  // the Agent tool_use id — the correlation key to the live tracked sub-agent
13836
14068
  // Terminal outcome of the dispatched sub-agent, back-filled when a matching completion
@@ -13892,7 +14124,19 @@ ${DISPATCH_TASK_BANNER}
13892
14124
  // The whole to-do list, for the calls that carry it (see TranscriptTodo). The client promotes such a
13893
14125
  // call into a TodoBlock — a checklist card, one row per task with its status. Optional, so a
13894
14126
  // pre-restart server / older transcript falls back to the generic card.
13895
- todos: external_exports.array(TranscriptTodo).optional()
14127
+ todos: external_exports.array(TranscriptTodo).optional(),
14128
+ // ---- Native question (AskUserQuestion) block ----
14129
+ // The structured questions an `AskUserQuestion` tool_use asked, so a SETTLED call renders as a
14130
+ // read-only question card at its place in the transcript instead of a generic tool line buried in a
14131
+ // disclosure. This is what keeps a question the human saw from vanishing: a follow-up sent instead
14132
+ // of an answer retires the pending interaction card (the broker denies the parked call), and without
14133
+ // this field nothing in the transcript ever said what was asked. Optional, so a pre-restart server /
14134
+ // older transcript falls back to the generic card.
14135
+ ask: external_exports.array(AskQuestion).optional(),
14136
+ // The human's answers, parallel to `ask` (null = that question got no answer), parsed from the
14137
+ // call's structured tool result. Absent entirely when the call settled unanswered — the withdrawn /
14138
+ // denied case — which the client renders as "Not answered".
14139
+ askAnswers: external_exports.array(external_exports.string().nullable()).optional()
13896
14140
  });
13897
14141
  TranscriptPart = external_exports.discriminatedUnion("kind", [
13898
14142
  external_exports.object({ kind: external_exports.literal("text"), text: external_exports.string() }),
@@ -14044,12 +14288,23 @@ ${DISPATCH_TASK_BANNER}
14044
14288
  fenceRefused: external_exports.literal(true).optional()
14045
14289
  });
14046
14290
  TranscriptPageCursor = external_exports.string().min(1).max(2048).regex(/^[A-Za-z0-9_-]+$/);
14291
+ EditedFile = external_exports.object({
14292
+ path: external_exports.string().min(1),
14293
+ edits: external_exports.number().int().positive(),
14294
+ lastEditedAt: external_exports.string().optional(),
14295
+ // The file's diffstat, summed over its write calls (each call's counts are the line counts of its
14296
+ // raw old/new sides). A Write counts as all additions — what it replaced is unknowable here.
14297
+ added: external_exports.number().int().nonnegative().optional(),
14298
+ removed: external_exports.number().int().nonnegative().optional()
14299
+ }).strict();
14047
14300
  TranscriptPage = external_exports.object({
14048
14301
  messages: external_exports.array(TranscriptMessage),
14049
14302
  beforeCursor: TranscriptPageCursor.nullable(),
14050
14303
  hasEarlier: external_exports.boolean(),
14051
14304
  reachedTurnBoundary: external_exports.boolean(),
14052
- transcriptKey: external_exports.string().min(1).max(256)
14305
+ transcriptKey: external_exports.string().min(1).max(256),
14306
+ // The LATEST page only (see EditedFile); an earlier page is settled history and carries none.
14307
+ editedFiles: external_exports.array(EditedFile).optional()
14053
14308
  }).strict();
14054
14309
  TranscriptEarlierInput = external_exports.object({
14055
14310
  slug: ThreadSlug,
@@ -14112,6 +14367,85 @@ ${DISPATCH_TASK_BANNER}
14112
14367
  }
14113
14368
  });
14114
14369
 
14370
+ // packages/server/src/frizz-paths.ts
14371
+ import { existsSync } from "node:fs";
14372
+ import { homedir as homedir2, tmpdir } from "node:os";
14373
+ import { dirname as dirname2, isAbsolute as isAbsolute2, join as join3, relative, resolve, sep as sep2 } from "node:path";
14374
+ function legacyFrizzRoot(home = homedir2()) {
14375
+ return join3(home, LEGACY_DIR_NAME);
14376
+ }
14377
+ function xdg(env, name) {
14378
+ const value = env[name];
14379
+ return value && (value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value)) ? value : void 0;
14380
+ }
14381
+ function insideHome(child, home) {
14382
+ const norm = (value) => value.replace(/[\\/]+$/u, "").replaceAll("\\", "/").toLowerCase();
14383
+ const parent = norm(home);
14384
+ const inner = norm(child);
14385
+ return inner === parent || inner.startsWith(`${parent}/`);
14386
+ }
14387
+ function windowsRoots(env, home) {
14388
+ const local = env.LOCALAPPDATA && insideHome(env.LOCALAPPDATA, home) ? env.LOCALAPPDATA : join3(home, "AppData", "Local");
14389
+ const base = join3(local, "Frizz");
14390
+ return {
14391
+ data: join3(base, "Data"),
14392
+ state: join3(base, "State"),
14393
+ cache: join3(base, "Cache")
14394
+ };
14395
+ }
14396
+ function darwinRoots(home) {
14397
+ const support = join3(home, "Library", "Application Support", "Frizz");
14398
+ return {
14399
+ data: support,
14400
+ // macOS has no state directory concept; Application Support is where this belongs, and the log
14401
+ // files themselves already live under each project's own directory.
14402
+ state: support,
14403
+ cache: join3(home, "Library", "Caches", "Frizz")
14404
+ };
14405
+ }
14406
+ function xdgRoots(env, home) {
14407
+ return {
14408
+ data: join3(xdg(env, "XDG_DATA_HOME") ?? join3(home, ".local", "share"), "frizz"),
14409
+ state: join3(xdg(env, "XDG_STATE_HOME") ?? join3(home, ".local", "state"), "frizz"),
14410
+ cache: join3(xdg(env, "XDG_CACHE_HOME") ?? join3(home, ".cache"), "frizz")
14411
+ };
14412
+ }
14413
+ function frizzPaths(options2 = {}) {
14414
+ const env = options2.env ?? process.env;
14415
+ const platform = options2.platform ?? process.platform;
14416
+ const home = options2.home ?? homedir2();
14417
+ const exists = options2.exists ?? existsSync;
14418
+ const legacyRoot = legacyFrizzRoot(home);
14419
+ if (exists(legacyRoot)) {
14420
+ return { data: legacyRoot, state: legacyRoot, cache: legacyRoot, legacy: true };
14421
+ }
14422
+ const explicit = {
14423
+ data: xdg(env, "XDG_DATA_HOME"),
14424
+ state: xdg(env, "XDG_STATE_HOME"),
14425
+ cache: xdg(env, "XDG_CACHE_HOME")
14426
+ };
14427
+ const platformRoots = platform === "win32" ? windowsRoots(env, home) : platform === "darwin" ? darwinRoots(home) : xdgRoots(env, home);
14428
+ return {
14429
+ data: explicit.data ? join3(explicit.data, "frizz") : platformRoots.data,
14430
+ state: explicit.state ? join3(explicit.state, "frizz") : platformRoots.state,
14431
+ cache: explicit.cache ? join3(explicit.cache, "frizz") : platformRoots.cache,
14432
+ legacy: false
14433
+ };
14434
+ }
14435
+ function frizzRoots() {
14436
+ return cached ??= frizzPaths();
14437
+ }
14438
+ function projectStateDir(projectId, home) {
14439
+ return join3(home ? frizzPaths({ home }).data : frizzRoots().data, "projects", projectId);
14440
+ }
14441
+ var LEGACY_DIR_NAME, cached;
14442
+ var init_frizz_paths = __esm({
14443
+ "packages/server/src/frizz-paths.ts"() {
14444
+ "use strict";
14445
+ LEGACY_DIR_NAME = ".frizz";
14446
+ }
14447
+ });
14448
+
14115
14449
  // node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js
14116
14450
  var require_constants = __commonJS({
14117
14451
  "node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/constants.js"(exports, module) {
@@ -17806,85 +18140,6 @@ var init_wrapper = __esm({
17806
18140
  }
17807
18141
  });
17808
18142
 
17809
- // packages/server/src/frizz-paths.ts
17810
- import { existsSync as existsSync2 } from "node:fs";
17811
- import { homedir as homedir5, tmpdir } from "node:os";
17812
- import { dirname as dirname4, join as join5 } from "node:path";
17813
- function legacyFrizzRoot(home = homedir5()) {
17814
- return join5(home, LEGACY_DIR_NAME);
17815
- }
17816
- function xdg(env, name) {
17817
- const value = env[name];
17818
- return value && (value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value)) ? value : void 0;
17819
- }
17820
- function insideHome(child, home) {
17821
- const norm = (value) => value.replace(/[\\/]+$/u, "").replaceAll("\\", "/").toLowerCase();
17822
- const parent = norm(home);
17823
- const inner = norm(child);
17824
- return inner === parent || inner.startsWith(`${parent}/`);
17825
- }
17826
- function windowsRoots(env, home) {
17827
- const local = env.LOCALAPPDATA && insideHome(env.LOCALAPPDATA, home) ? env.LOCALAPPDATA : join5(home, "AppData", "Local");
17828
- const base = join5(local, "Frizz");
17829
- return {
17830
- data: join5(base, "Data"),
17831
- state: join5(base, "State"),
17832
- cache: join5(base, "Cache")
17833
- };
17834
- }
17835
- function darwinRoots(home) {
17836
- const support = join5(home, "Library", "Application Support", "Frizz");
17837
- return {
17838
- data: support,
17839
- // macOS has no state directory concept; Application Support is where this belongs, and the log
17840
- // files themselves already live under each project's own directory.
17841
- state: support,
17842
- cache: join5(home, "Library", "Caches", "Frizz")
17843
- };
17844
- }
17845
- function xdgRoots(env, home) {
17846
- return {
17847
- data: join5(xdg(env, "XDG_DATA_HOME") ?? join5(home, ".local", "share"), "frizz"),
17848
- state: join5(xdg(env, "XDG_STATE_HOME") ?? join5(home, ".local", "state"), "frizz"),
17849
- cache: join5(xdg(env, "XDG_CACHE_HOME") ?? join5(home, ".cache"), "frizz")
17850
- };
17851
- }
17852
- function frizzPaths(options2 = {}) {
17853
- const env = options2.env ?? process.env;
17854
- const platform = options2.platform ?? process.platform;
17855
- const home = options2.home ?? homedir5();
17856
- const exists = options2.exists ?? existsSync2;
17857
- const legacyRoot = legacyFrizzRoot(home);
17858
- if (exists(legacyRoot)) {
17859
- return { data: legacyRoot, state: legacyRoot, cache: legacyRoot, legacy: true };
17860
- }
17861
- const explicit = {
17862
- data: xdg(env, "XDG_DATA_HOME"),
17863
- state: xdg(env, "XDG_STATE_HOME"),
17864
- cache: xdg(env, "XDG_CACHE_HOME")
17865
- };
17866
- const platformRoots = platform === "win32" ? windowsRoots(env, home) : platform === "darwin" ? darwinRoots(home) : xdgRoots(env, home);
17867
- return {
17868
- data: explicit.data ? join5(explicit.data, "frizz") : platformRoots.data,
17869
- state: explicit.state ? join5(explicit.state, "frizz") : platformRoots.state,
17870
- cache: explicit.cache ? join5(explicit.cache, "frizz") : platformRoots.cache,
17871
- legacy: false
17872
- };
17873
- }
17874
- function frizzRoots() {
17875
- return cached ??= frizzPaths();
17876
- }
17877
- function projectStateDir(projectId, home) {
17878
- return join5(home ? frizzPaths({ home }).data : frizzRoots().data, "projects", projectId);
17879
- }
17880
- var LEGACY_DIR_NAME, cached;
17881
- var init_frizz_paths = __esm({
17882
- "packages/server/src/frizz-paths.ts"() {
17883
- "use strict";
17884
- LEGACY_DIR_NAME = ".frizz";
17885
- }
17886
- });
17887
-
17888
18143
  // packages/server/src/logging.ts
17889
18144
  import {
17890
18145
  appendFileSync,
@@ -18223,7 +18478,7 @@ import {
18223
18478
  writeFileSync as writeFileSync5
18224
18479
  } from "node:fs";
18225
18480
  import { homedir as homedir7 } from "node:os";
18226
- import { dirname as dirname5, join as join8, resolve } from "node:path";
18481
+ import { dirname as dirname5, join as join8, resolve as resolve2 } from "node:path";
18227
18482
  import { setTimeout as delay } from "node:timers/promises";
18228
18483
  function errorCode2(error) {
18229
18484
  return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
@@ -18235,7 +18490,7 @@ function canonicalHome(home) {
18235
18490
  try {
18236
18491
  return realpathSync2(home);
18237
18492
  } catch {
18238
- return resolve(home);
18493
+ return resolve2(home);
18239
18494
  }
18240
18495
  }
18241
18496
  function globalLaunchLockPath(home = homedir7()) {
@@ -18440,7 +18695,7 @@ function revParsePath(dir, flag) {
18440
18695
  throw new Error("unable to inspect Git worktree identity");
18441
18696
  }
18442
18697
  try {
18443
- return realpathSync2(resolve(dir, raw));
18698
+ return realpathSync2(resolve2(dir, raw));
18444
18699
  } catch {
18445
18700
  throw new Error("unable to canonicalize Git worktree identity");
18446
18701
  }
@@ -18512,7 +18767,7 @@ function syncGitConfig(dir) {
18512
18767
  } catch {
18513
18768
  throw new Error("unable to locate git config after writing frizz.id");
18514
18769
  }
18515
- const path = resolve(dir, raw);
18770
+ const path = resolve2(dir, raw);
18516
18771
  syncGitConfigPath(path);
18517
18772
  }
18518
18773
  function createGitProjectId(dir) {
@@ -18638,7 +18893,7 @@ import {
18638
18893
  statSync as statSync4,
18639
18894
  writeFileSync as writeFileSync6
18640
18895
  } from "node:fs";
18641
- import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute2, join as join9 } from "node:path";
18896
+ import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute3, join as join9 } from "node:path";
18642
18897
  function errorCode3(error) {
18643
18898
  return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
18644
18899
  }
@@ -18794,7 +19049,7 @@ function parseOwner(path) {
18794
19049
  try {
18795
19050
  const value = JSON.parse(readFileSync7(path, "utf8"));
18796
19051
  const generation = parseGeneration(value);
18797
- if (value.version !== 1 && value.version !== OWNER_VERSION || !generation || typeof value.token !== "string" || !UUID_RE.test(value.token) || typeof value.projectId !== "string" || !UUID_RE.test(value.projectId) || !validText(value.projectDir) || !isAbsolute2(value.projectDir) || !validRole(value.role) || !validText(value.acquiredAt, 128) || !validText(value.updatedAt, 128)) return null;
19052
+ if (value.version !== 1 && value.version !== OWNER_VERSION || !generation || typeof value.token !== "string" || !UUID_RE.test(value.token) || typeof value.projectId !== "string" || !UUID_RE.test(value.projectId) || !validText(value.projectDir) || !isAbsolute3(value.projectDir) || !validRole(value.role) || !validText(value.acquiredAt, 128) || !validText(value.updatedAt, 128)) return null;
18798
19053
  const delegates = value.version === 1 ? [] : parseDelegates(value.delegates);
18799
19054
  const state = value.version === 1 ? "active" : value.state;
18800
19055
  if (!delegates || state !== "active" && state !== "draining") return null;
@@ -19031,7 +19286,7 @@ function projectLaunchTargetFromEnvironment(env) {
19031
19286
  const projectDir = env[FRIZZ_LAUNCH_PROJECT_DIR];
19032
19287
  const stateDir = env[FRIZZ_LAUNCH_STATE_DIR];
19033
19288
  const scope = env[FRIZZ_LAUNCH_IDENTITY_SCOPE];
19034
- if (!projectId || !UUID_RE.test(projectId) || !projectDir || !isAbsolute2(projectDir) || !stateDir || !isAbsolute2(stateDir) || scope !== "repository" && scope !== "worktree") return null;
19289
+ if (!projectId || !UUID_RE.test(projectId) || !projectDir || !isAbsolute3(projectDir) || !stateDir || !isAbsolute3(stateDir) || scope !== "repository" && scope !== "worktree") return null;
19035
19290
  return {
19036
19291
  projectId,
19037
19292
  projectDir,
@@ -19108,7 +19363,7 @@ var init_boot_progress = __esm({
19108
19363
  import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
19109
19364
  import { closeSync as closeSync3, existsSync as existsSync3, fsyncSync as fsyncSync3, mkdirSync as mkdirSync8, openSync as openSync4, readFileSync as readFileSync9, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync8 } from "node:fs";
19110
19365
  import { homedir as homedir8 } from "node:os";
19111
- import { dirname as dirname8, join as join11, parse, resolve as resolve2 } from "node:path";
19366
+ import { dirname as dirname8, join as join11, parse, resolve as resolve3 } from "node:path";
19112
19367
  function projectIdPath(root) {
19113
19368
  return join11(root, FRIZZ_DIR, ID_FILE);
19114
19369
  }
@@ -19189,9 +19444,9 @@ function hasAny(dir, names) {
19189
19444
  function isHomeDirectory(dir, home = homedir8()) {
19190
19445
  const canonical = (value) => {
19191
19446
  try {
19192
- return realpathSync3(resolve2(value));
19447
+ return realpathSync3(resolve3(value));
19193
19448
  } catch {
19194
- return resolve2(value);
19449
+ return resolve3(value);
19195
19450
  }
19196
19451
  };
19197
19452
  try {
@@ -19218,11 +19473,11 @@ function hasProjectMarker(dir) {
19218
19473
  function discoverProjectRoot(cwd = process.cwd(), home = homedir8()) {
19219
19474
  let dir;
19220
19475
  try {
19221
- dir = resolve2(cwd);
19476
+ dir = resolve3(cwd);
19222
19477
  } catch {
19223
- return resolve2(cwd);
19478
+ return resolve3(cwd);
19224
19479
  }
19225
- const stop = resolve2(home);
19480
+ const stop = resolve3(home);
19226
19481
  const filesystemRoot = parse(dir).root;
19227
19482
  for (let at = dir; ; at = dirname8(at)) {
19228
19483
  if (at === stop || at === filesystemRoot) break;
@@ -19605,12 +19860,12 @@ function manifestIdFor(url) {
19605
19860
  return url.endsWith("/") ? url : `${url}/`;
19606
19861
  }
19607
19862
  function execFileP(cmd, args2) {
19608
- return new Promise((resolve5, reject) => {
19863
+ return new Promise((resolve6, reject) => {
19609
19864
  execFile(
19610
19865
  cmd,
19611
19866
  args2,
19612
19867
  { encoding: "utf8", timeout: 1e4 },
19613
- (err, stdout) => err ? reject(err) : resolve5(stdout)
19868
+ (err, stdout) => err ? reject(err) : resolve6(stdout)
19614
19869
  );
19615
19870
  });
19616
19871
  }
@@ -19689,9 +19944,9 @@ function openCdpSession(browserPath, dataPath) {
19689
19944
  cmdPipe.on("error", failAll);
19690
19945
  resPipe.on("error", failAll);
19691
19946
  child.on("exit", () => failAll(new Error("chrome exited before the CDP handshake completed")));
19692
- const call2 = (method, params = {}, timeoutMs = 2e4) => new Promise((resolve5, reject) => {
19947
+ const call2 = (method, params = {}, timeoutMs = 2e4) => new Promise((resolve6, reject) => {
19693
19948
  const id = ++seq;
19694
- pending.set(id, { resolve: resolve5, reject });
19949
+ pending.set(id, { resolve: resolve6, reject });
19695
19950
  cmdPipe.write(JSON.stringify({ id, method, params }) + "\0");
19696
19951
  setTimeout(() => {
19697
19952
  if (pending.has(id)) {
@@ -19704,15 +19959,15 @@ function openCdpSession(browserPath, dataPath) {
19704
19959
  await call2("Browser.close").catch(() => {
19705
19960
  });
19706
19961
  if (child.exitCode !== null || child.signalCode !== null) return;
19707
- await new Promise((resolve5) => {
19962
+ await new Promise((resolve6) => {
19708
19963
  const t = setTimeout(() => {
19709
19964
  child.kill();
19710
- resolve5();
19965
+ resolve6();
19711
19966
  }, 1e4);
19712
19967
  t.unref();
19713
19968
  child.once("exit", () => {
19714
19969
  clearTimeout(t);
19715
- resolve5();
19970
+ resolve6();
19716
19971
  });
19717
19972
  });
19718
19973
  };
@@ -22451,7 +22706,15 @@ function createAccessPane(options2) {
22451
22706
  ticker.unref?.();
22452
22707
  return true;
22453
22708
  },
22454
- key() {
22709
+ key(key) {
22710
+ if (key === "l" || key === "L") {
22711
+ const link = options2.issue();
22712
+ if (!link) return "close";
22713
+ shown = link;
22714
+ consumed = false;
22715
+ paint();
22716
+ return "keep";
22717
+ }
22455
22718
  return "close";
22456
22719
  },
22457
22720
  close() {
@@ -22473,25 +22736,26 @@ function createAccessPane(options2) {
22473
22736
  }
22474
22737
 
22475
22738
  // src/remote-controller.ts
22476
- import { homedir as homedir4 } from "node:os";
22739
+ import { homedir as homedir5 } from "node:os";
22477
22740
 
22478
22741
  // src/cloud.ts
22479
22742
  init_src();
22480
22743
  import { spawn as spawn2 } from "node:child_process";
22481
- import { existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, rmSync } from "node:fs";
22744
+ import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3, rmSync } from "node:fs";
22482
22745
  import { createInterface } from "node:readline/promises";
22483
- import { homedir as homedir3 } from "node:os";
22484
- import { dirname as dirname3, join as join4 } from "node:path";
22746
+ import { homedir as homedir4 } from "node:os";
22747
+ import { dirname as dirname4, join as join5 } from "node:path";
22485
22748
 
22486
22749
  // src/identity.ts
22750
+ init_frizz_paths();
22487
22751
  init_src();
22488
22752
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
22489
- import { homedir as homedir2 } from "node:os";
22490
- import { dirname as dirname2, join as join3 } from "node:path";
22491
- function claimIdentityPath(home = homedir2()) {
22492
- return join3(home, ".frizz", "identity.key");
22753
+ import { homedir as homedir3 } from "node:os";
22754
+ import { dirname as dirname3, join as join4 } from "node:path";
22755
+ function claimIdentityPath(home = homedir3()) {
22756
+ return join4(frizzPaths({ home }).state, "identity.key");
22493
22757
  }
22494
- async function loadOrCreateClaimIdentity(home = homedir2()) {
22758
+ async function loadOrCreateClaimIdentity(home = homedir3()) {
22495
22759
  const path = claimIdentityPath(home);
22496
22760
  let stored;
22497
22761
  try {
@@ -22507,7 +22771,7 @@ async function loadOrCreateClaimIdentity(home = homedir2()) {
22507
22771
  );
22508
22772
  }
22509
22773
  const identity = await generateClaimIdentity();
22510
- mkdirSync2(dirname2(path), { recursive: true });
22774
+ mkdirSync2(dirname3(path), { recursive: true });
22511
22775
  writeFileSync2(path, await exportClaimPrivateKey(identity.privateKey), { mode: 384 });
22512
22776
  return identity;
22513
22777
  }
@@ -22645,7 +22909,12 @@ function serveRelayRequest(frame, options2) {
22645
22909
  const target2 = new URL(frame.url);
22646
22910
  const local = new URL(options2.origin);
22647
22911
  const publicUrl = new URL(options2.publicOrigin);
22648
- return new Promise((resolve5) => {
22912
+ let cancelled = false;
22913
+ let abort;
22914
+ const done = new Promise((resolve6) => {
22915
+ const send = (upFrame) => {
22916
+ if (!cancelled) options2.send(upFrame);
22917
+ };
22649
22918
  const headers = {};
22650
22919
  for (const [name, value] of stripHopByHop(frame.headers)) headers[name] = value;
22651
22920
  headers.host = publicUrl.host;
@@ -22664,10 +22933,10 @@ function serveRelayRequest(frame, options2) {
22664
22933
  );
22665
22934
  const streaming = shouldStream(outHeaders);
22666
22935
  if (streaming) {
22667
- options2.send({ t: "res", id: frame.id, status: res.statusCode ?? 502, headers: outHeaders, end: false });
22936
+ send({ t: "res", id: frame.id, status: res.statusCode ?? 502, headers: outHeaders, end: false });
22668
22937
  res.on("data", (chunk) => {
22669
22938
  for (let at = 0; at < chunk.length; at += RELAY_MAX_FRAME_BODY) {
22670
- options2.send({
22939
+ send({
22671
22940
  t: "res-chunk",
22672
22941
  id: frame.id,
22673
22942
  data: encodeBody(new Uint8Array(chunk.subarray(at, at + RELAY_MAX_FRAME_BODY)))
@@ -22675,12 +22944,12 @@ function serveRelayRequest(frame, options2) {
22675
22944
  }
22676
22945
  });
22677
22946
  res.on("end", () => {
22678
- options2.send({ t: "res-end", id: frame.id });
22679
- resolve5();
22947
+ send({ t: "res-end", id: frame.id });
22948
+ resolve6();
22680
22949
  });
22681
22950
  res.on("error", () => {
22682
- options2.send({ t: "res-end", id: frame.id });
22683
- resolve5();
22951
+ send({ t: "res-end", id: frame.id });
22952
+ resolve6();
22684
22953
  });
22685
22954
  return;
22686
22955
  }
@@ -22689,7 +22958,7 @@ function serveRelayRequest(frame, options2) {
22689
22958
  res.on("end", () => {
22690
22959
  const body = Buffer.concat(chunks);
22691
22960
  if (body.byteLength <= RELAY_MAX_FRAME_BODY) {
22692
- options2.send({
22961
+ send({
22693
22962
  t: "res",
22694
22963
  id: frame.id,
22695
22964
  status: res.statusCode ?? 502,
@@ -22697,28 +22966,28 @@ function serveRelayRequest(frame, options2) {
22697
22966
  ...body.byteLength > 0 ? { body: encodeBody(new Uint8Array(body)) } : {},
22698
22967
  end: true
22699
22968
  });
22700
- resolve5();
22969
+ resolve6();
22701
22970
  return;
22702
22971
  }
22703
- options2.send({ t: "res", id: frame.id, status: res.statusCode ?? 502, headers: outHeaders, end: false });
22972
+ send({ t: "res", id: frame.id, status: res.statusCode ?? 502, headers: outHeaders, end: false });
22704
22973
  for (let at = 0; at < body.byteLength; at += RELAY_MAX_FRAME_BODY) {
22705
- options2.send({
22974
+ send({
22706
22975
  t: "res-chunk",
22707
22976
  id: frame.id,
22708
22977
  data: encodeBody(new Uint8Array(body.subarray(at, at + RELAY_MAX_FRAME_BODY)))
22709
22978
  });
22710
22979
  }
22711
- options2.send({ t: "res-end", id: frame.id });
22712
- resolve5();
22980
+ send({ t: "res-end", id: frame.id });
22981
+ resolve6();
22713
22982
  });
22714
22983
  res.on("error", () => {
22715
- options2.send({ t: "res", id: frame.id, status: 502, headers: [], end: true });
22716
- resolve5();
22984
+ send({ t: "res", id: frame.id, status: 502, headers: [], end: true });
22985
+ resolve6();
22717
22986
  });
22718
22987
  }
22719
22988
  );
22720
22989
  req.on("error", (error) => {
22721
- options2.send({
22990
+ send({
22722
22991
  t: "res",
22723
22992
  id: frame.id,
22724
22993
  status: 502,
@@ -22726,11 +22995,23 @@ function serveRelayRequest(frame, options2) {
22726
22995
  body: encodeBody(new TextEncoder().encode(`Frizz is not answering on this machine: ${error.message}`)),
22727
22996
  end: true
22728
22997
  });
22729
- resolve5();
22998
+ resolve6();
22730
22999
  });
22731
23000
  if (frame.body) req.write(Buffer.from(decodeBody(frame.body)));
22732
23001
  req.end();
23002
+ abort = () => {
23003
+ req.destroy();
23004
+ resolve6();
23005
+ };
22733
23006
  });
23007
+ return {
23008
+ done,
23009
+ cancel: () => {
23010
+ if (cancelled) return;
23011
+ cancelled = true;
23012
+ abort?.();
23013
+ }
23014
+ };
22734
23015
  }
22735
23016
  var HANDSHAKE_HEADERS = /* @__PURE__ */ new Set([
22736
23017
  "sec-websocket-key",
@@ -22812,6 +23093,7 @@ function defaultBackoff(attempt, random = Math.random) {
22812
23093
  const base = Math.min(3e4, 500 * 2 ** Math.min(attempt, 6));
22813
23094
  return Math.round(base / 2 + random() * (base / 2));
22814
23095
  }
23096
+ var RELAY_KEEPALIVE_INTERVAL_MS = 45e3;
22815
23097
  async function signRelayHandshake(name, identity, issuedAt) {
22816
23098
  const pubkey = await exportClaimPublicKey(identity.publicKey);
22817
23099
  const signature = await crypto.subtle.sign(
@@ -22829,9 +23111,22 @@ function connectRelay(options2) {
22829
23111
  const makeSocket = options2.socketFactory ?? ((url) => new WebSocket(url));
22830
23112
  let socket = null;
22831
23113
  const nested = /* @__PURE__ */ new Map();
23114
+ const requests = /* @__PURE__ */ new Map();
22832
23115
  let attempt = 0;
22833
23116
  let stopped = false;
22834
23117
  let retryHandle;
23118
+ let keepaliveHandle;
23119
+ let awaitingPong = false;
23120
+ const clearKeepalive = () => {
23121
+ if (keepaliveHandle !== void 0) {
23122
+ clearTimer(keepaliveHandle);
23123
+ keepaliveHandle = void 0;
23124
+ }
23125
+ };
23126
+ const cancelRequests = () => {
23127
+ for (const request of requests.values()) request.cancel();
23128
+ requests.clear();
23129
+ };
22835
23130
  const send = (frame) => {
22836
23131
  try {
22837
23132
  socket?.send(serializeFrame(frame));
@@ -22858,7 +23153,26 @@ function connectRelay(options2) {
22858
23153
  const next = makeSocket(url);
22859
23154
  socket = next;
22860
23155
  let settled;
23156
+ const beat = () => {
23157
+ if (stopped || socket !== next) return;
23158
+ if (awaitingPong) {
23159
+ dropped();
23160
+ try {
23161
+ next.close();
23162
+ } catch {
23163
+ }
23164
+ return;
23165
+ }
23166
+ awaitingPong = true;
23167
+ try {
23168
+ next.send(RELAY_KEEPALIVE_PING);
23169
+ } catch {
23170
+ }
23171
+ keepaliveHandle = setTimer(beat, RELAY_KEEPALIVE_INTERVAL_MS);
23172
+ };
22861
23173
  next.addEventListener("open", () => {
23174
+ awaitingPong = false;
23175
+ keepaliveHandle = setTimer(beat, RELAY_KEEPALIVE_INTERVAL_MS);
22862
23176
  settled = setTimer(() => {
22863
23177
  attempt = 0;
22864
23178
  }, SETTLED_MS);
@@ -22872,12 +23186,25 @@ function connectRelay(options2) {
22872
23186
  send({ t: "pong", id: frame.id });
22873
23187
  return;
22874
23188
  }
23189
+ if (frame.t === "pong") {
23190
+ awaitingPong = false;
23191
+ return;
23192
+ }
22875
23193
  if (frame.t === "req") {
22876
- void serveRelayRequest(frame, {
23194
+ const handle = serveRelayRequest(frame, {
22877
23195
  origin: options2.boardOrigin,
22878
23196
  publicOrigin: options2.publicOrigin,
22879
23197
  send
22880
23198
  });
23199
+ requests.set(frame.id, handle);
23200
+ void handle.done.then(() => {
23201
+ if (requests.get(frame.id) === handle) requests.delete(frame.id);
23202
+ });
23203
+ return;
23204
+ }
23205
+ if (frame.t === "req-cancel") {
23206
+ requests.get(frame.id)?.cancel();
23207
+ requests.delete(frame.id);
22881
23208
  return;
22882
23209
  }
22883
23210
  if (frame.t === "ws-open") {
@@ -22906,9 +23233,11 @@ function connectRelay(options2) {
22906
23233
  clearTimer(settled);
22907
23234
  settled = void 0;
22908
23235
  }
23236
+ clearKeepalive();
22909
23237
  socket = null;
22910
23238
  for (const session of nested.values()) session.close();
22911
23239
  nested.clear();
23240
+ cancelRequests();
22912
23241
  options2.onStatus?.("disconnected");
22913
23242
  scheduleRetry("the relay connection closed");
22914
23243
  };
@@ -22920,12 +23249,14 @@ function connectRelay(options2) {
22920
23249
  stop() {
22921
23250
  stopped = true;
22922
23251
  if (retryHandle !== void 0) clearTimer(retryHandle);
23252
+ clearKeepalive();
22923
23253
  try {
22924
23254
  socket?.close();
22925
23255
  } catch {
22926
23256
  }
22927
23257
  for (const session of nested.values()) session.close();
22928
23258
  nested.clear();
23259
+ cancelRequests();
22929
23260
  socket = null;
22930
23261
  },
22931
23262
  get connected() {
@@ -22957,7 +23288,7 @@ function zoneClaimLabel(hostname) {
22957
23288
  const label = hostname.slice(0, -suffix.length);
22958
23289
  return label.length > 0 && !label.includes(".") ? label : null;
22959
23290
  }
22960
- async function reconcileCloudConfig(config, port, home = homedir3(), onNotice, origin, github = githubCli) {
23291
+ async function reconcileCloudConfig(config, port, home = homedir4(), onNotice, origin, github = githubCli) {
22961
23292
  if (isRelayConfig(config)) return config;
22962
23293
  const label = config.claim ?? zoneClaimLabel(config.hostname);
22963
23294
  if (!label) return config;
@@ -22966,10 +23297,10 @@ async function reconcileCloudConfig(config, port, home = homedir3(), onNotice, o
22966
23297
  );
22967
23298
  return establishCloudConfig(label, port, home, origin, github);
22968
23299
  }
22969
- function cloudConfigPath(home = homedir3()) {
22970
- return join4(home, ".frizz", "cloud.json");
23300
+ function cloudConfigPath(home = homedir4()) {
23301
+ return join5(home, ".frizz", "cloud.json");
22971
23302
  }
22972
- function readCloudConfig(home = homedir3()) {
23303
+ function readCloudConfig(home = homedir4()) {
22973
23304
  try {
22974
23305
  const parsed = JSON.parse(readFileSync4(cloudConfigPath(home), "utf8"));
22975
23306
  if (typeof parsed.hostname !== "string" || !parsed.hostname) return null;
@@ -22989,10 +23320,10 @@ function readCloudConfig(home = homedir3()) {
22989
23320
  return null;
22990
23321
  }
22991
23322
  }
22992
- function tunnelTokenPath(home = homedir3()) {
22993
- return join4(home, ".frizz", "tunnel-token");
23323
+ function tunnelTokenPath(home = homedir4()) {
23324
+ return join5(home, ".frizz", "tunnel-token");
22994
23325
  }
22995
- function readTunnelToken(home = homedir3()) {
23326
+ function readTunnelToken(home = homedir4()) {
22996
23327
  try {
22997
23328
  const token = readFileSync4(tunnelTokenPath(home), "utf8").trim();
22998
23329
  return token.length > 0 ? token : null;
@@ -23000,18 +23331,18 @@ function readTunnelToken(home = homedir3()) {
23000
23331
  return null;
23001
23332
  }
23002
23333
  }
23003
- function writeTunnelToken(token, home = homedir3()) {
23334
+ function writeTunnelToken(token, home = homedir4()) {
23004
23335
  const path = tunnelTokenPath(home);
23005
- mkdirSync3(dirname3(path), { recursive: true });
23336
+ mkdirSync3(dirname4(path), { recursive: true });
23006
23337
  writeFileSync3(path, `${token}
23007
23338
  `, { mode: 384 });
23008
23339
  }
23009
- function deleteCloudConfig(home = homedir3()) {
23340
+ function deleteCloudConfig(home = homedir4()) {
23010
23341
  rmSync(cloudConfigPath(home), { force: true });
23011
23342
  }
23012
- function writeCloudConfig(config, home = homedir3()) {
23343
+ function writeCloudConfig(config, home = homedir4()) {
23013
23344
  const path = cloudConfigPath(home);
23014
- mkdirSync3(dirname3(path), { recursive: true });
23345
+ mkdirSync3(dirname4(path), { recursive: true });
23015
23346
  writeFileSync3(path, `${JSON.stringify(config, null, 2)}
23016
23347
  `);
23017
23348
  }
@@ -23032,7 +23363,7 @@ async function promptForTunnelName(hostname, fallback) {
23032
23363
  rl.close();
23033
23364
  }
23034
23365
  }
23035
- async function establishCloudConfig(answer, port, home = homedir3(), origin, github = githubCli) {
23366
+ async function establishCloudConfig(answer, port, home = homedir4(), origin, github = githubCli) {
23036
23367
  if (answer.includes(".")) {
23037
23368
  const hostname = normalizeHostname(answer);
23038
23369
  const tunnel = await promptForTunnelName(hostname, hostname.split(".")[0]);
@@ -23043,17 +23374,23 @@ async function establishCloudConfig(answer, port, home = homedir3(), origin, git
23043
23374
  "claiming a name on frizz.sh is not available yet.\n Reach this board through a tunnel of your own instead \u2014 see docs/remote-access.md \u2014 and\n answer with its hostname rather than a bare name."
23044
23375
  );
23045
23376
  }
23046
- if (!claimNameIsValid(answer)) {
23377
+ const anonymous = answer === "" || isAnonymousClaimName(answer);
23378
+ if (!anonymous && !claimNameIsValid(answer)) {
23047
23379
  normalizeClaimName(answer);
23048
23380
  }
23049
- const name = normalizeClaimName(answer);
23381
+ const name = answer === "" ? generateAnonymousClaimName() : normalizeClaimName(answer);
23050
23382
  const identity = await loadOrCreateClaimIdentity(home);
23051
- const token = await github.accessToken();
23052
- const login = await github.login();
23053
- if (login) console.log(` claiming ${name}.frizz.sh for GitHub user ${login}`);
23383
+ let token;
23384
+ if (!anonymous) {
23385
+ token = await github.accessToken();
23386
+ const login = await github.login();
23387
+ if (login) console.log(` claiming ${name}.frizz.sh for GitHub user ${login}`);
23388
+ } else {
23389
+ console.log(" claiming a private name on frizz.sh \u2014 no account needed");
23390
+ }
23054
23391
  let result;
23055
23392
  try {
23056
- result = await claimName({ name, port, identity, github: token, ...origin ? { origin } : {} });
23393
+ result = await claimName({ name, port, identity, ...token ? { github: token } : {}, ...origin ? { origin } : {} });
23057
23394
  } catch (error) {
23058
23395
  if (error instanceof ClaimError && error.code === "unreachable") {
23059
23396
  throw new ClaimError(
@@ -23070,7 +23407,7 @@ async function establishCloudConfig(answer, port, home = homedir3(), origin, git
23070
23407
  }
23071
23408
  return { hostname: result.hostname, claim: name, serve: "relay" };
23072
23409
  }
23073
- async function resolveRunToken(config, port, home = homedir3(), onWarning, origin) {
23410
+ async function resolveRunToken(config, port, home = homedir4(), onWarning, origin) {
23074
23411
  if (!isClaimedConfig(config)) return null;
23075
23412
  const cached2 = readTunnelToken(home);
23076
23413
  try {
@@ -23087,12 +23424,12 @@ async function resolveRunToken(config, port, home = homedir3(), onWarning, origi
23087
23424
  throw error;
23088
23425
  }
23089
23426
  }
23090
- function resolveTunnelConfigPath(config, home = homedir3()) {
23427
+ function resolveTunnelConfigPath(config, home = homedir4()) {
23091
23428
  if (config.config) return config.config;
23092
- const candidate = join4(home, ".cloudflared", "frizz.yml");
23093
- return existsSync(candidate) ? candidate : null;
23429
+ const candidate = join5(home, ".cloudflared", "frizz.yml");
23430
+ return existsSync2(candidate) ? candidate : null;
23094
23431
  }
23095
- async function startRelay(config, port, home = homedir3(), onStatus) {
23432
+ async function startRelay(config, port, home = homedir4(), onStatus) {
23096
23433
  const identity = await loadOrCreateClaimIdentity(home);
23097
23434
  const origin = `https://${config.hostname}`;
23098
23435
  return connectRelay({
@@ -23110,7 +23447,7 @@ async function startRelay(config, port, home = homedir3(), onStatus) {
23110
23447
  } : {}
23111
23448
  });
23112
23449
  }
23113
- function startTunnel(config, onExit, onError, home = homedir3(), runToken) {
23450
+ function startTunnel(config, onExit, onError, home = homedir4(), runToken) {
23114
23451
  const configPath = runToken ? null : resolveTunnelConfigPath(config, home);
23115
23452
  const args2 = runToken ? ["tunnel", "--no-autoupdate", "run", "--token", runToken] : [
23116
23453
  "tunnel",
@@ -23141,7 +23478,7 @@ function startTunnel(config, onExit, onError, home = homedir3(), runToken) {
23141
23478
 
23142
23479
  // src/remote-controller.ts
23143
23480
  function createRemoteController(options2) {
23144
- const home = options2.home ?? homedir4();
23481
+ const home = options2.home ?? homedir5();
23145
23482
  let config = null;
23146
23483
  let transport = null;
23147
23484
  const stopTransport = () => {
@@ -23223,9 +23560,9 @@ function createRemoteController(options2) {
23223
23560
  import { execFile as execFile3 } from "node:child_process";
23224
23561
  var PROBE_TIMEOUT_MS = 4e3;
23225
23562
  function run2(command, args2) {
23226
- return new Promise((resolve5) => {
23563
+ return new Promise((resolve6) => {
23227
23564
  execFile3(command, args2, { encoding: "utf8", timeout: PROBE_TIMEOUT_MS }, (error, stdout) => {
23228
- resolve5(error ? null : stdout);
23565
+ resolve6(error ? null : stdout);
23229
23566
  });
23230
23567
  });
23231
23568
  }
@@ -23253,8 +23590,10 @@ async function probeTailscale() {
23253
23590
  }
23254
23591
 
23255
23592
  // src/remote-pane.ts
23593
+ init_src();
23256
23594
  var CHOICES = [
23257
- { kind: "frizz", title: "frizz.sh name", blurb: "<name>.frizz.sh \u2014 nothing to install; needs the GitHub CLI" },
23595
+ { kind: "private", title: "Private name", blurb: "an unguessable name on frizz.sh \u2014 no account, nothing to install" },
23596
+ { kind: "frizz", title: "Custom name", blurb: "<name>.frizz.sh of your choosing; needs the GitHub CLI" },
23258
23597
  { kind: "cloudflare", title: "Cloudflare Tunnel", blurb: "a domain you own on Cloudflare; cloudflared on this machine" },
23259
23598
  { kind: "tailscale", title: "Tailscale", blurb: "your tailnet; tailscale serve does the TLS" },
23260
23599
  { kind: "other", title: "Something else", blurb: "any proxy or tunnel you run \u2014 tell Frizz its address" },
@@ -23269,7 +23608,7 @@ var TAB = " ";
23269
23608
  var SHIFT_TAB = "\x1B[Z";
23270
23609
  function kindOf(config) {
23271
23610
  if (!config) return "off";
23272
- if (isClaimedConfig(config)) return "frizz";
23611
+ if (isClaimedConfig(config)) return isAnonymousClaimName(config.claim) ? "private" : "frizz";
23273
23612
  if (isExternalConfig(config)) return config.provider === "tailscale" ? "tailscale" : "other";
23274
23613
  return "cloudflare";
23275
23614
  }
@@ -23356,10 +23695,10 @@ function createRemotePane(options2) {
23356
23695
  if (kind === "frizz") {
23357
23696
  const gh = github === "pending" || github === null ? `${DIM}GitHub CLI checking\u2026${RESET2}` : !github.installed ? "GitHub CLI not installed \u2014 see https://cli.github.com, then `gh auth login`" : github.login ? check(true, `GitHub CLI signed in as ${github.login}`) : "GitHub CLI not signed in \u2014 run `gh auth login` in another terminal";
23358
23697
  return [
23359
- "frizz.sh name",
23698
+ "Custom frizz.sh name",
23360
23699
  "",
23361
23700
  ...wrap(
23362
- "Claims <name>.frizz.sh for your GitHub account. The board dials out to frizz.sh \u2014 no port, no DNS record, no tunnel binary. One name per account; a name nobody runs for 30 days is released."
23701
+ "Claims <name>.frizz.sh of your choosing, tied to your GitHub account so names cannot be squatted. The board dials out to frizz.sh \u2014 no port, no DNS record, no tunnel binary. One name per account; a name nobody runs for 30 days is released. (A private name needs none of this.)"
23363
23702
  ),
23364
23703
  ...options2.sandbox ? ["", ...wrap("This is a sandbox, but a claim is real: it binds this machine's one name to your account, and your real board keeps it. Only the setup saved here is thrown away.")] : [],
23365
23704
  "",
@@ -23480,6 +23819,22 @@ function createRemotePane(options2) {
23480
23819
  }
23481
23820
  paint();
23482
23821
  };
23822
+ const claimPrivate = async () => {
23823
+ const back = { name: "menu", index: 0 };
23824
+ screen = { name: "busy", message: "claiming a private name on frizz.sh\u2026" };
23825
+ paint();
23826
+ try {
23827
+ const next = await options2.claim("");
23828
+ screen = { name: "busy", message: `serving ${next.hostname}\u2026` };
23829
+ paint();
23830
+ await options2.apply(next, { justClaimed: true });
23831
+ options2.onChanged?.(next);
23832
+ screen = { name: "done", message: `Serving https://${next.hostname} (${describeCloudConfig(next)}).`, link: options2.issueLink(), config: next };
23833
+ } catch (error) {
23834
+ screen = { name: "error", message: error instanceof Error ? error.message : String(error), back };
23835
+ }
23836
+ paint();
23837
+ };
23483
23838
  const turnOff = async () => {
23484
23839
  screen = { name: "busy", message: "back to loopback only\u2026" };
23485
23840
  paint();
@@ -23515,10 +23870,11 @@ function createRemotePane(options2) {
23515
23870
  if (key === ESC || key === "q") return "close";
23516
23871
  if (key === UP || key === "k") s.index = (s.index + CHOICES.length - 1) % CHOICES.length;
23517
23872
  else if (key === DOWN || key === "j") s.index = (s.index + 1) % CHOICES.length;
23518
- else if (/^[1-5]$/.test(key)) s.index = Number(key) - 1;
23873
+ else if (/^[1-6]$/.test(key)) s.index = Number(key) - 1;
23519
23874
  else if (ENTER.has(key)) {
23520
23875
  const choice = CHOICES[s.index];
23521
23876
  if (choice.kind === "off") void turnOff();
23877
+ else if (choice.kind === "private") void claimPrivate();
23522
23878
  else openForm(choice.kind);
23523
23879
  return "keep";
23524
23880
  }
@@ -23894,22 +24250,22 @@ init_project_launch();
23894
24250
  init_local_origin();
23895
24251
  init_boot_progress();
23896
24252
  init_frizz_paths();
23897
- init_project_root();
23898
- init_logging();
23899
- init_src();
23900
- init_project_registry();
23901
24253
  import { execFileSync as execFileSync3 } from "node:child_process";
23902
24254
  import { createServer as createServer2 } from "node:net";
23903
24255
  import { existsSync as existsSync5, mkdirSync as mkdirSync10, mkdtempSync, readdirSync as readdirSync3, readFileSync as readFileSync11, realpathSync as realpathSync5, rmSync as rmSync8, symlinkSync as symlinkSync2, writeFileSync as writeFileSync10 } from "node:fs";
23904
24256
  import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
23905
- import { basename as basename5, join as join13, resolve as resolve3 } from "node:path";
24257
+ import { basename as basename5, dirname as dirname10, join as join13, resolve as resolve4 } from "node:path";
23906
24258
  import { setTimeout as delay2 } from "node:timers/promises";
24259
+ init_project_root();
24260
+ init_logging();
24261
+ init_src();
24262
+ init_project_registry();
23907
24263
  var PORT_SCAN_COUNT = 100;
23908
24264
  var LAUNCH_TIMEOUT_MS = 3e4;
23909
24265
  var LAUNCH_HARD_TIMEOUT_MS = 10 * 6e4;
23910
24266
  var RETIRED_NETWORK_FLAGS = ["--host", "--allowed-host", "--public-origin", "--cloud"];
23911
24267
  function retiredFlagMessage(flag) {
23912
- 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 frizz.sh name, a Cloudflare Tunnel, Tailscale or a proxy of your own. The choice is remembered, so a plain launch serves it.`;
24268
+ 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.`;
23913
24269
  }
23914
24270
  function parseCliArgs(argv) {
23915
24271
  const args2 = new Set(argv);
@@ -24042,9 +24398,11 @@ function shareCredentials(realHome, home) {
24042
24398
  } catch {
24043
24399
  }
24044
24400
  };
24045
- mkdirSync10(join13(realHome, ".frizz"), { recursive: true });
24046
- mkdirSync10(join13(home, ".frizz"), { recursive: true });
24047
- link(join13(realHome, ".frizz", "identity.key"), join13(home, ".frizz", "identity.key"));
24401
+ const realKey = claimIdentityPath(realHome);
24402
+ const sandboxKey = claimIdentityPath(home);
24403
+ mkdirSync10(dirname10(realKey), { recursive: true });
24404
+ mkdirSync10(dirname10(sandboxKey), { recursive: true });
24405
+ link(realKey, sandboxKey);
24048
24406
  if (existsSync5(join13(realHome, ".config", "gh"))) {
24049
24407
  mkdirSync10(join13(home, ".config"), { recursive: true });
24050
24408
  link(join13(realHome, ".config", "gh"), join13(home, ".config", "gh"));
@@ -24326,7 +24684,7 @@ import { fork } from "node:child_process";
24326
24684
  import { randomUUID as randomUUID5 } from "node:crypto";
24327
24685
  import { existsSync as existsSync6, mkdirSync as mkdirSync11, readFileSync as readFileSync12 } from "node:fs";
24328
24686
  import { createServer as createNetServer } from "node:net";
24329
- import { basename as basename6, dirname as dirname10, extname as extname2, isAbsolute as isAbsolute3, relative, resolve as resolve4, sep as sep2 } from "node:path";
24687
+ import { basename as basename6, dirname as dirname11, extname as extname2, isAbsolute as isAbsolute4, relative as relative2, resolve as resolve5, sep as sep3 } from "node:path";
24330
24688
  import { fileURLToPath } from "node:url";
24331
24689
  import watcher from "@parcel/watcher";
24332
24690
  init_logging();
@@ -24417,29 +24775,29 @@ function createSupervisorShutdownHandler(options2) {
24417
24775
  );
24418
24776
  };
24419
24777
  }
24420
- var packagesDir = resolve4(import.meta.dirname, "..", "..");
24421
- var workspaceDir = resolve4(packagesDir, "..");
24778
+ var packagesDir = resolve5(import.meta.dirname, "..", "..");
24779
+ var workspaceDir = resolve5(packagesDir, "..");
24422
24780
  var INITIAL_BOOT_REASON = "initial boot";
24423
24781
  function defaultDevWatchRoots() {
24424
24782
  return [workspaceDir];
24425
24783
  }
24426
24784
  function isWithin(path, root) {
24427
- const rel = relative(root, path);
24428
- return rel === "" || rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute3(rel);
24785
+ const rel = relative2(root, path);
24786
+ return rel === "" || rel !== ".." && !rel.startsWith(`..${sep3}`) && !isAbsolute4(rel);
24429
24787
  }
24430
24788
  function ignoredDevPath(path) {
24431
- const parts = resolve4(path).split(sep2);
24789
+ const parts = resolve5(path).split(sep3);
24432
24790
  const name = parts.at(-1) ?? "";
24433
24791
  return parts.some((part) => GENERATED_DIRS.has(part) || part === "fixtures" || part.endsWith(".fixtures")) || /\.(?:test|spec)\.[^.]+$/.test(name) || name.includes(".golden.");
24434
24792
  }
24435
24793
  function classifyDevChange(path, roots = defaultDevWatchRoots()) {
24436
- const absolute = resolve4(path);
24437
- const root = roots.find((candidate) => isWithin(absolute, resolve4(candidate)));
24794
+ const absolute = resolve5(path);
24795
+ const root = roots.find((candidate) => isWithin(absolute, resolve5(candidate)));
24438
24796
  if (!root) return null;
24439
24797
  if (ignoredDevPath(absolute)) return null;
24440
24798
  const name = basename6(absolute);
24441
- const relToWorkspace = relative(resolve4(root), absolute);
24442
- const parts = relToWorkspace.split(sep2);
24799
+ const relToWorkspace = relative2(resolve5(root), absolute);
24800
+ const parts = relToWorkspace.split(sep3);
24443
24801
  const packageName = parts[0] === "packages" ? parts[1] : void 0;
24444
24802
  if (name === "package.json" && parts.length === 3 && packageName && CHILD_PACKAGE_METADATA.has(packageName)) {
24445
24803
  return "child";
@@ -24586,10 +24944,10 @@ var Supervisor = class {
24586
24944
  if (launchOwner.pid !== callerGeneration.pid || launchOwner.processStart !== callerGeneration.processStart) throw new Error("dev supervisor caller is not the exact project launch owner");
24587
24945
  this.port = opts.port;
24588
24946
  this.launchTarget = opts.launchTarget;
24589
- this.cwd = resolve4(opts.cwd ?? opts.launchTarget.projectDir);
24947
+ this.cwd = resolve5(opts.cwd ?? opts.launchTarget.projectDir);
24590
24948
  if (this.cwd !== opts.launchTarget.projectDir) throw new Error("dev supervisor cwd does not match its owned project");
24591
24949
  this.parentEnv = projectLaunchEnvironment(opts.env ?? process.env, opts.launchTarget, opts.launchOwnerToken);
24592
- this.roots = (opts.watchRoots ?? defaultDevWatchRoots()).map((root) => resolve4(root));
24950
+ this.roots = (opts.watchRoots ?? defaultDevWatchRoots()).map((root) => resolve5(root));
24593
24951
  this.watchEnabled = opts.watch !== false;
24594
24952
  this.childEnvironment = opts.childEnvironment ?? (() => ({}));
24595
24953
  this.debounceMs = opts.debounceMs ?? DEV_RESTART_DEBOUNCE_MS;
@@ -24599,10 +24957,10 @@ var Supervisor = class {
24599
24957
  this.childArgs = opts.childArgs ?? [];
24600
24958
  this.watchSubscribe = opts.watchSubscribe ?? ((root, callback, options2) => watcher.subscribe(root, callback, options2));
24601
24959
  this.reexec = opts.reexec ?? (typeof process.execve === "function" ? (request) => process.execve(request.executable, request.argv, request.env) : void 0);
24602
- if (opts.stateDir && resolve4(opts.stateDir) !== opts.launchTarget.stateDir) {
24960
+ if (opts.stateDir && resolve5(opts.stateDir) !== opts.launchTarget.stateDir) {
24603
24961
  throw new Error("dev supervisor state directory does not match its owned project");
24604
24962
  }
24605
- this.supervisorLock = resolve4(opts.launchTarget.stateDir, "dev-supervisor.lock");
24963
+ this.supervisorLock = resolve5(opts.launchTarget.stateDir, "dev-supervisor.lock");
24606
24964
  this.ownerToken = opts.launchOwnerToken;
24607
24965
  this.logLine = opts.log ?? ((line) => log.info("supervisor", stripPrefix(line)));
24608
24966
  this.errorLine = opts.error ?? ((line) => log.error("supervisor", stripPrefix(line)));
@@ -24654,7 +25012,7 @@ var Supervisor = class {
24654
25012
  }
24655
25013
  async start() {
24656
25014
  if (this.supervisorLock) {
24657
- mkdirSync11(dirname10(this.supervisorLock), { recursive: true });
25015
+ mkdirSync11(dirname11(this.supervisorLock), { recursive: true });
24658
25016
  this.writeStatus("starting", "watcher initializing");
24659
25017
  }
24660
25018
  try {
@@ -24709,7 +25067,7 @@ var Supervisor = class {
24709
25067
  return;
24710
25068
  }
24711
25069
  this.crashAttempts = 0;
24712
- this.requestRestart(relative(workspaceDir, relevant.path), false, kind === "launcher");
25070
+ this.requestRestart(relative2(workspaceDir, relevant.path), false, kind === "launcher");
24713
25071
  }
24714
25072
  }
24715
25073
  requestRestart(reason, immediate = false, reloadLauncher = false, delayMs = this.debounceMs) {
@@ -25187,7 +25545,7 @@ var npmRegistryReleaseAdapter = {
25187
25545
  import { spawnSync } from "node:child_process";
25188
25546
  import { chmodSync as chmodSync2, statSync as statSync5 } from "node:fs";
25189
25547
  import { createRequire } from "node:module";
25190
- import { dirname as dirname11, join as join14 } from "node:path";
25548
+ import { dirname as dirname12, join as join14 } from "node:path";
25191
25549
  var SUPPORTED_NODE_LINES = [
25192
25550
  { major: 22, minor: 13 },
25193
25551
  { major: 23, minor: 4 }
@@ -25239,7 +25597,7 @@ function ensureNativeHelperPermissions(options2 = {}) {
25239
25597
  const resolvePty = options2.resolvePty ?? (() => createRequire(import.meta.url).resolve("node-pty/package.json"));
25240
25598
  try {
25241
25599
  const helper = join14(
25242
- dirname11(resolvePty()),
25600
+ dirname12(resolvePty()),
25243
25601
  "prebuilds",
25244
25602
  `${platform}-${options2.arch ?? process.arch}`,
25245
25603
  "spawn-helper"
@@ -25304,7 +25662,8 @@ Options:
25304
25662
 
25305
25663
 
25306
25664
  To reach the board from a phone or another machine, press R in the terminal running it: a short
25307
- walkthrough sets up a frizz.sh name, a Cloudflare Tunnel, Tailscale, or a proxy of your own, and
25665
+ walkthrough sets up a private frizz.sh name (no account needed), a custom one, a Cloudflare
25666
+ Tunnel, Tailscale, or a proxy of your own, and
25308
25667
  remembers the choice, so a plain launch serves it from then on. The board stays on loopback and
25309
25668
  shows a single-use sign-in link as a QR; press L for a fresh one, or run --link from another shell.`
25310
25669
  );