frizz-server 0.15.25 → 0.15.27

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 (106) hide show
  1. package/dist/claude-agent-broker.js +14743 -13917
  2. package/dist/dev-child.js +19221 -16124
  3. package/package.json +1 -1
  4. package/runtime/cc-worker/bin/frizzctl.mjs +18 -5
  5. package/runtime/cc-worker/hooks/deny-ask.mjs +5 -5
  6. package/runtime/cc-worker/hooks/deny-plan.mjs +2 -2
  7. package/runtime/cc-worker/hooks/perm-policy.mjs +3 -2
  8. package/runtime/cc-worker/hooks/session-seed.mjs +1 -1
  9. package/runtime/cc-worker/lib/frizz-tools.mjs +203 -308
  10. package/runtime/cc-worker/skills/gh/SKILL.md +2 -2
  11. package/web-dist/assets/{abnfDiagram-VRR7QNED-BUGGhGcL.js → abnfDiagram-VRR7QNED-C1yPcG1z.js} +1 -1
  12. package/web-dist/assets/{arc-DlmiB5Kw.js → arc-DCZhAMyd.js} +1 -1
  13. package/web-dist/assets/architecture-TIHT7OUA-B1iuHL_Y.js +1 -0
  14. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-m4afIjbT.js → architectureDiagram-ZJ3FMSHR-BEVy-3f-.js} +1 -1
  15. package/web-dist/assets/{blockDiagram-677ZJIJ3-Kz2humn5.js → blockDiagram-677ZJIJ3-C1XryTx5.js} +1 -1
  16. package/web-dist/assets/{c4Diagram-LMCZKHZV-SeHCCIRv.js → c4Diagram-LMCZKHZV-BxzRPmz9.js} +1 -1
  17. package/web-dist/assets/channel-DmzWEsVb.js +1 -0
  18. package/web-dist/assets/{chunk-32BRIVSS-Cs4BaciL.js → chunk-32BRIVSS-BOhxnrmS.js} +1 -1
  19. package/web-dist/assets/{chunk-52WLFC77-Hrl54hxN.js → chunk-52WLFC77-DHFFeOOt.js} +1 -1
  20. package/web-dist/assets/{chunk-C7G6YPKG-C_LwXwMT.js → chunk-C7G6YPKG-Bf7iTkYg.js} +1 -1
  21. package/web-dist/assets/{chunk-EX3LRPZG-s0-pq_ja.js → chunk-EX3LRPZG-Tj-fNey7.js} +1 -1
  22. package/web-dist/assets/{chunk-FWX5IMBZ-Ci_L6bRR.js → chunk-FWX5IMBZ-B_587R9r.js} +2 -2
  23. package/web-dist/assets/{chunk-HOUHSVGY-Cn43tXaT.js → chunk-HOUHSVGY-CWYb4IRw.js} +1 -1
  24. package/web-dist/assets/{chunk-ICXQ74PX-DaehSUDb.js → chunk-ICXQ74PX-Jy4FGOLb.js} +1 -1
  25. package/web-dist/assets/{chunk-MOJQB5TN-BOLvHrOY.js → chunk-MOJQB5TN-Doyk0ws3.js} +1 -1
  26. package/web-dist/assets/{chunk-OGEWGWER-B7N0H72R.js → chunk-OGEWGWER-X6cWpyUd.js} +1 -1
  27. package/web-dist/assets/{chunk-PUDLZKDR-D9Tpv5xu.js → chunk-PUDLZKDR-CNCT6yjC.js} +1 -1
  28. package/web-dist/assets/{chunk-Q4XR5HBZ-CZxzEfvh.js → chunk-Q4XR5HBZ-BcAtfHf9.js} +1 -1
  29. package/web-dist/assets/{chunk-RYQCIY6F-CH35JHMA.js → chunk-RYQCIY6F-8CUiRz24.js} +1 -1
  30. package/web-dist/assets/{chunk-V7JOEXUC-28qGatq3.js → chunk-V7JOEXUC-C7UqD_CN.js} +1 -1
  31. package/web-dist/assets/{chunk-VAUOI2AC-CkO9u5CM.js → chunk-VAUOI2AC-Dg3Nzy4F.js} +1 -1
  32. package/web-dist/assets/{chunk-VR4S4FIN-BFszczwO.js → chunk-VR4S4FIN-BrkonRYO.js} +1 -1
  33. package/web-dist/assets/{chunk-WYO6CB5R-CuBoterc.js → chunk-WYO6CB5R-CtzxQkcZ.js} +1 -1
  34. package/web-dist/assets/{chunk-XXDRQBXY-8nlDi-YO.js → chunk-XXDRQBXY-0TbCJaHg.js} +1 -1
  35. package/web-dist/assets/{chunk-ZGVPDNZ5-B5WfIiLa.js → chunk-ZGVPDNZ5-CRkGfJ8p.js} +1 -1
  36. package/web-dist/assets/classDiagram-OUVF2IWQ-BzUHMuoR.js +1 -0
  37. package/web-dist/assets/classDiagram-v2-EOCWNBFH-BzUHMuoR.js +1 -0
  38. package/web-dist/assets/{cose-bilkent-JH36ORCC-Csxg0M3P.js → cose-bilkent-JH36ORCC-CjL8X4g9.js} +1 -1
  39. package/web-dist/assets/{cynefin-VYW2F7L2-DY-oaly-.js → cynefin-VYW2F7L2-2pg1obUS.js} +1 -1
  40. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Baev5OIz.js → cynefinDiagram-TSTJHNR4-CXst9IDq.js} +1 -1
  41. package/web-dist/assets/{dagre-VKFMJZFB-VV2KSHL4.js → dagre-VKFMJZFB-DayLnbRm.js} +1 -1
  42. package/web-dist/assets/{diagram-FQU43EPY-rLuhqzIC.js → diagram-FQU43EPY-6yRM--yJ.js} +1 -1
  43. package/web-dist/assets/{diagram-G47NLZAW-BBRVU5Kr.js → diagram-G47NLZAW-eNczVIx_.js} +1 -1
  44. package/web-dist/assets/{diagram-NH7WQ7WH-BMSjTTHf.js → diagram-NH7WQ7WH-B_b4Cb9a.js} +1 -1
  45. package/web-dist/assets/{diagram-OA4YK3LP-7NO_QsSx.js → diagram-OA4YK3LP-DHW8gg6j.js} +1 -1
  46. package/web-dist/assets/{diagram-WEI45ONY-evQWfr1h.js → diagram-WEI45ONY-CaBjDDII.js} +1 -1
  47. package/web-dist/assets/{dist-BoiR_HZa.js → dist-CTtNsFkL.js} +1 -1
  48. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-BGCXILB-.js → ebnfDiagram-CCIWWBDH-CtmnW6EM.js} +1 -1
  49. package/web-dist/assets/{erDiagram-Q63AITRT-CJSi0YB2.js → erDiagram-Q63AITRT-N214SxuY.js} +1 -1
  50. package/web-dist/assets/eventmodeling-45OFAUF4-C3Xuk6Lf.js +1 -0
  51. package/web-dist/assets/flowDiagram-23GEKE2U-DdLuCY6R.js +1 -0
  52. package/web-dist/assets/{ganttDiagram-NO4QXBWP-DfKGoGJe.js → ganttDiagram-NO4QXBWP-CzuKeYZd.js} +1 -1
  53. package/web-dist/assets/{gitGraph-TEB2WS4Q-DDOEbCVa.js → gitGraph-TEB2WS4Q-CNQpTl8i.js} +1 -1
  54. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-tKMl1T5T.js → gitGraphDiagram-IHSO6WYX-Bo3w9_BM.js} +1 -1
  55. package/web-dist/assets/index-BJngxAUp.js +372 -0
  56. package/web-dist/assets/index-CWk594R-.css +2 -0
  57. package/web-dist/assets/{info-DKCQHKI2-BqMXJJEF.js → info-DKCQHKI2-CQ5sLj3R.js} +1 -1
  58. package/web-dist/assets/{infoDiagram-FWYZ7A6U-DXpmORxt.js → infoDiagram-FWYZ7A6U-H6Ct-2Yz.js} +1 -1
  59. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-D9yCb_iG.js → ishikawaDiagram-FXEZZL3T-rUTDcs-s.js} +1 -1
  60. package/web-dist/assets/{journeyDiagram-5HDEW3XC-DwyXsO1X.js → journeyDiagram-5HDEW3XC-pET45cR6.js} +1 -1
  61. package/web-dist/assets/{kanban-definition-HUTT4EX6-C-BupP2L.js → kanban-definition-HUTT4EX6-CMEmImiX.js} +1 -1
  62. package/web-dist/assets/{line-CVohBkYV.js → line-DmbABxm7.js} +1 -1
  63. package/web-dist/assets/{linear-CUS0dsDf.js → linear-BV686rjE.js} +1 -1
  64. package/web-dist/assets/{mermaid-parser.core-BaUI30hf.js → mermaid-parser.core-BhfkgmJj.js} +3 -3
  65. package/web-dist/assets/{mermaid.core-DRwFVBM9.js → mermaid.core-CjApJjX5.js} +3 -3
  66. package/web-dist/assets/{mindmap-definition-LN4V7U3C-Dwz7wXjl.js → mindmap-definition-LN4V7U3C-C-1ivbvY.js} +1 -1
  67. package/web-dist/assets/{packet-7NZHBO7P-Cc8S-JIW.js → packet-7NZHBO7P-BWeKd3YB.js} +1 -1
  68. package/web-dist/assets/{pegDiagram-2B236MQR-DEvuejFX.js → pegDiagram-2B236MQR-CMt6u9H9.js} +1 -1
  69. package/web-dist/assets/{pie-RZYD4A2V-lDSko9Ox.js → pie-RZYD4A2V-CT1Y-9Bd.js} +1 -1
  70. package/web-dist/assets/{pieDiagram-ENE6RG2P-DoIHahh_.js → pieDiagram-ENE6RG2P-WctsTMEX.js} +1 -1
  71. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL-ttYUswX_.js → quadrantDiagram-ABIIQ3AL-detmDaKK.js} +1 -1
  72. package/web-dist/assets/{radar-I7S5WNFK-Dlai2VWL.js → radar-I7S5WNFK-DNFNnoP7.js} +1 -1
  73. package/web-dist/assets/{railroad-3IZDKUUU-CfOvvQCL.js → railroad-3IZDKUUU-Bzhtn1VK.js} +1 -1
  74. package/web-dist/assets/railroad-abnf-AHOZXSZD-D4qAcwJF.js +1 -0
  75. package/web-dist/assets/railroad-ebnf-EBAXGLYW-C9BHZsDg.js +1 -0
  76. package/web-dist/assets/railroad-peg-LSFZ7HO6-CnYxGTOV.js +1 -0
  77. package/web-dist/assets/{railroadDiagram-RFXS5EU6-BRpMN8zD.js → railroadDiagram-RFXS5EU6-C0ehB7_S.js} +1 -1
  78. package/web-dist/assets/{requirementDiagram-TGXJPOKE-C1f5KNrx.js → requirementDiagram-TGXJPOKE-g7iubHbK.js} +1 -1
  79. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-CjXPLZ2A.js → sankeyDiagram-HTMAVEWB-DIYvCsv4.js} +1 -1
  80. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-BxVxwb4e.js → sequenceDiagram-DBY2YBRQ-7GQEb58j.js} +1 -1
  81. package/web-dist/assets/{src-DjcREoQq.js → src-BwwZrn6Z.js} +1 -1
  82. package/web-dist/assets/{stateDiagram-2N3HPSRC-CCx9rSmu.js → stateDiagram-2N3HPSRC-DRgMko33.js} +1 -1
  83. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BytUD2US.js +1 -0
  84. package/web-dist/assets/{swimlanes-5IMT3BWC-L3Legvfa.js → swimlanes-5IMT3BWC-BleEENNi.js} +1 -1
  85. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BT_dw9UO.js +8 -0
  86. package/web-dist/assets/{timeline-definition-FHXFAJF6-0p22547Z.js → timeline-definition-FHXFAJF6-CnadbNaJ.js} +1 -1
  87. package/web-dist/assets/{treeView-QDETBFTQ-Xv4-kZ7I.js → treeView-QDETBFTQ-By5b6e2R.js} +1 -1
  88. package/web-dist/assets/{treemap-6X3UGDF4-MhycNmte.js → treemap-6X3UGDF4-K3mpMY_i.js} +1 -1
  89. package/web-dist/assets/{vennDiagram-L72KCM5P-P33JCPMu.js → vennDiagram-L72KCM5P-B-0Xnf8Y.js} +1 -1
  90. package/web-dist/assets/{wardley-OPB4EBWU-CS41M7I-.js → wardley-OPB4EBWU-DtS5at8O.js} +1 -1
  91. package/web-dist/assets/{wardleyDiagram-EHGQE667-CbQaI_DG.js → wardleyDiagram-EHGQE667-Rs7Ad73f.js} +1 -1
  92. package/web-dist/assets/{xychartDiagram-FW5EYKEG-tg1lQQ6H.js → xychartDiagram-FW5EYKEG-BSoig2A4.js} +1 -1
  93. package/web-dist/index.html +2 -2
  94. package/web-dist/assets/architecture-TIHT7OUA-DvYaN-Hu.js +0 -1
  95. package/web-dist/assets/channel-Og7O24Xl.js +0 -1
  96. package/web-dist/assets/classDiagram-OUVF2IWQ-DBua7nWT.js +0 -1
  97. package/web-dist/assets/classDiagram-v2-EOCWNBFH-DBua7nWT.js +0 -1
  98. package/web-dist/assets/eventmodeling-45OFAUF4-CMWWvyUk.js +0 -1
  99. package/web-dist/assets/flowDiagram-23GEKE2U-CFOr0Vr_.js +0 -1
  100. package/web-dist/assets/index-DYhjAs_a.js +0 -354
  101. package/web-dist/assets/index-htGvcLfn.css +0 -2
  102. package/web-dist/assets/railroad-abnf-AHOZXSZD-Br3ohVd5.js +0 -1
  103. package/web-dist/assets/railroad-ebnf-EBAXGLYW-DFaY0AnY.js +0 -1
  104. package/web-dist/assets/railroad-peg-LSFZ7HO6-Cy2FBxXb.js +0 -1
  105. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-bSyE7VSt.js +0 -1
  106. package/web-dist/assets/swimlanesDiagram-G3AALYLV-n0v1Z0Xu.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frizz-server",
3
- "version": "0.15.25",
3
+ "version": "0.15.27",
4
4
  "private": false,
5
5
  "description": "Replaceable Frizz server runtime",
6
6
  "license": "MIT",
@@ -20,7 +20,7 @@
20
20
  * be bare where the registry says so (`frizzctl title "Fix queue focus"`).
21
21
  * JSON `--input <file>`, `--input -` for stdin, or a JSON object as the first argument — the
22
22
  * same object the command's schema describes. This is `gh api --input`, and it is what
23
- * makes a nested payload (`ask`) or a long one sayable at all.
23
+ * makes a nested payload or a long one sayable at all.
24
24
  * text files any text argument also takes `--<name>-file <path|->` — `gh pr create --body-file`.
25
25
  *
26
26
  * STDIN IS NEVER READ UNLESS `-` ASKS FOR IT. An agent's shell hands a command an open pipe more often
@@ -29,6 +29,11 @@
29
29
  *
30
30
  * EXIT CODES: 0 the command did what it says; 1 it failed, or was called wrongly; 2 it REFUSED — a gate
31
31
  * that held (`done` with a question still open), so `frizzctl done … || …` can tell the two apart.
32
+ *
33
+ * A RETIRED COMMAND (`ask`, `secret`: a question is a ```question fence since 2026-10-13) is still a
34
+ * command, because the worker that reaches for one is the worker that needs to be told what replaced it.
35
+ * It refuses whatever it is given — no argument is parsed, so no usage error can stand in front of the
36
+ * lesson, and stdin is never read — and its `--help` is the same text. `frizzctl --help` does not list it.
32
37
  */
33
38
  import { readFileSync } from "node:fs"
34
39
  import { CLI, HANDLERS, Refused, TOOLS } from "../lib/frizz-tools.mjs"
@@ -281,7 +286,7 @@ function topHelp() {
281
286
  "",
282
287
  "Arguments arrive three ways, and they combine (a flag wins over JSON):",
283
288
  ` flags ${NAME} watch shell bzvtnt3ig --for 2h`,
284
- ` JSON ${NAME} ask --input questions.json (--input - reads stdin; a '{…}' first argument works too)`,
289
+ ` JSON ${NAME} goal start --input goal.json (--input - reads stdin; a '{…}' first argument works too)`,
285
290
  ` text files any text argument takes --<name>-file <path|->: ${NAME} done --body-file handoff.md`,
286
291
  "",
287
292
  "Text holding backticks, $ or quotes goes through a file or a QUOTED heredoc, never a double-quoted",
@@ -347,6 +352,12 @@ function commandHelp(tool) {
347
352
  ].join("\n")
348
353
  }
349
354
 
355
+ /** A retired command's page: its one-line summary, then the text it refuses with — printed as written,
356
+ * never wrapped, because it carries a fence the worker copies. @param {any} tool */
357
+ function retiredHelp(tool) {
358
+ return `${NAME} ${hyphen(tool.name)} — ${CLI[tool.name].summary}\n\n${CLI[tool.name].retired}`
359
+ }
360
+
350
361
  /** Whether the arguments ask for help, read the way parseArgs reads them: a `-h` that is a flag's
351
362
  * VALUE (`steer other --message -h`) is the message, not a request for help, and the command must run
352
363
  * rather than print help and exit 0 having sent nothing. Its own pass, with no side effects, so that
@@ -377,10 +388,12 @@ async function main(argv) {
377
388
  if (!first || first === "--help" || first === "-h" || first === "help") {
378
389
  const about = first === "help" && rest[0] ? toolNamed(rest[0]) : undefined
379
390
  if (first === "help" && rest[0] && !about) throw new UsageError(unknownCommand(rest[0]))
380
- return { code: 0, out: about ? commandHelp(about) : topHelp() }
391
+ return { code: 0, out: about ? (CLI[about.name]?.retired ? retiredHelp(about) : commandHelp(about)) : topHelp() }
381
392
  }
382
393
  const tool = toolNamed(first)
383
394
  if (!tool) throw new UsageError(unknownCommand(first))
395
+ const retired = CLI[tool.name]?.retired
396
+ if (retired) return rest.includes("--help") || rest.includes("-h") ? { code: 0, out: retiredHelp(tool) } : { code: 2, out: retired }
384
397
  const asked = helpAsked(tool, rest)
385
398
  if (asked === "help") return { code: 0, out: commandHelp(tool) }
386
399
  if (asked === "schema") return { code: 0, out: JSON.stringify(tool.inputSchema, null, 2) }
@@ -414,11 +427,11 @@ function distance(a, b) {
414
427
  /** @param {string} raw */
415
428
  function unknownCommand(raw) {
416
429
  const want = under(raw.toLowerCase())
417
- const near = TOOLS.filter((t) => t.name.includes(want) || want.includes(t.name) || distance(t.name, want) <= 2).map((t) => hyphen(t.name))
430
+ const near = TOOLS.filter((t) => !CLI[t.name]?.retired && (t.name.includes(want) || want.includes(t.name) || distance(t.name, want) <= 2)).map((t) => hyphen(t.name))
418
431
  return (
419
432
  `\`${NAME}\` has no command ${JSON.stringify(raw)}.` +
420
433
  (near.length ? ` Did you mean: ${near.join(", ")}?` : "") +
421
- `\nCommands: ${TOOLS.map((t) => hyphen(t.name)).join(", ")}.\nRun \`${NAME} --help\` for what each one does.`
434
+ `\nCommands: ${TOOLS.filter((t) => !CLI[t.name]?.retired).map((t) => hyphen(t.name)).join(", ")}.\nRun \`${NAME} --help\` for what each one does.`
422
435
  )
423
436
  }
424
437
 
@@ -2,9 +2,9 @@
2
2
  // @ts-check
3
3
  // PreToolUse hook on AskUserQuestion (frizz-worker). A frizz worker runs under a dashboard, not a
4
4
  // live chat: an interactive question prompt would hang the session invisibly (nobody is at the
5
- // keyboard to click it). Deny with a redirect to the async pattern: register the question with
6
- // `frizzctl ask` (a row; the free-form ```question fence was retired 2026-09-11), keep working, and
7
- // rest normally; the answer arrives as its own wake.
5
+ // keyboard to click it). Deny with a redirect to the async pattern: ask it in a structured ```question
6
+ // fence in the worker's own message (a row, registered when the message lands — since 2026-10-13; it
7
+ // was `frizzctl ask` before that), keep working, and rest normally; the answer arrives as its own wake.
8
8
  // GATE: inert unless FRIZZ_THREAD is set. FAIL OPEN on parse errors.
9
9
  //
10
10
  // SECOND GATE: also inert when FRIZZ_NATIVE_ASK=1. The premise above — "nobody is at the keyboard" —
@@ -13,7 +13,7 @@
13
13
  // operator answers and which returns the chosen labels to the tool. The broker bridge sets that var
14
14
  // only when an InteractionStore is actually wired to render and resolve the card, so a denial here
15
15
  // would block a question the operator CAN see. Any other path leaves the var unset, so it keeps the
16
- // deny plus the `frizzctl ask` redirect.
16
+ // deny plus the ```question fence redirect.
17
17
  import { readFileSync } from 'node:fs';
18
18
 
19
19
  const slug = process.env.FRIZZ_THREAD;
@@ -32,7 +32,7 @@ process.stdout.write(
32
32
  hookEventName: 'PreToolUse',
33
33
  permissionDecision: 'deny',
34
34
  permissionDecisionReason:
35
- 'Interactive prompts freeze headless workers (no one is at the keyboard to answer). Register the question with `frizzctl ask` instead (a command you run from your shell; `frizzctl ask --help` has its arguments) — several in one command, each self-contained (context + the specific question + options with a one-line trade-off each, the recommended one first), written actor-explicit — never "I" or "you", which flip meaning when the human clicks an option; the frizz Queue renders each as a card. Do NOT write it as a ```question fence: that fence is retired, and a question in a fence body is plain prose nobody can answer. Registering does not end your turn — keep doing what does not depend on the answer, then rest normally: an open registered question IS the handback (no done/awaiting fence beside it, and do NOT invoke this tool again). The answer arrives as your next user message.',
35
+ 'Interactive prompts freeze headless workers (no one is at the keyboard to answer). Ask it in a ```question fence in your own message instead: `id:` (a slug of your choosing), `kind:` (`choice`, `multi`, `text` or `secret`), a one-line `question:`, and `options:` as `- label:` items with a one-line `description:` each, the recommended one first with `recommended: true`; context for the human goes below a `---` line, in any Markdown. One fence per question, each self-contained, written actor-explicit — never "I" or "you", which flip meaning when the human clicks an option. Frizz registers it when your message lands and draws its card where you wrote it (`frizzctl ask --help` shows the whole grammar). Asking does not end your turn — keep doing what does not depend on the answer, then rest normally: the question IS the handback (no done fence beside it, and do NOT invoke this tool again). The answer arrives as your next user message.',
36
36
  },
37
37
  }),
38
38
  );
@@ -23,7 +23,7 @@
23
23
  // instead — frizz NEVER spawns a worker in plan mode (dispatch.ts coerces `--permission-mode plan`
24
24
  // → `auto` in both command builders), so a real frizz worker is never in plan mode and this deny
25
25
  // only ever meets a SPURIOUS ExitPlanMode call (nothing to exit → deny + redirect is correct). A
26
- // worker "plans" by writing a durable plan file and asking via `frizzctl ask`,
26
+ // worker "plans" by writing a durable plan file and asking in a ```question fence,
27
27
  // never via interactive plan mode.
28
28
  // RESIDUAL GAP (accepted, documented): the deny could softlock only a FOREIGN session that is
29
29
  // simultaneously in plan mode AND running with FRIZZ_THREAD set AND this plugin loaded — a combo
@@ -48,7 +48,7 @@ try {
48
48
  // the model reads is `additionalContext`, injected as a plain-text system-reminder. Exit 0 with
49
49
  // this JSON on stdout (exit 2 would make Claude Code ignore the JSON — never mix).
50
50
  const reason =
51
- 'Interactive plan-approval prompts freeze headless workers (no one is at the keyboard to approve). Do NOT present a plan for approval. Instead: if the plan is settled, just proceed with the work. If the plan is the deliverable, write it into a durable plan file — wherever the dispatch or the project\'s conventions name; your scratch directory works when nothing names one. If it needs a human call before you build, register a two-option question with `frizzctl ask` stating what you need approved (never a ```question fence — that fence is retired), then come to rest — the human reviews it from the frizz queue.';
51
+ 'Interactive plan-approval prompts freeze headless workers (no one is at the keyboard to approve). Do NOT present a plan for approval. Instead: if the plan is settled, just proceed with the work. If the plan is the deliverable, write it into a durable plan file — wherever the dispatch or the project\'s conventions name; your scratch directory works when nothing names one. If it needs a human call before you build, ask a two-option `kind: choice` question in a ```question fence stating what you need approved, then come to rest — the human reviews it from the frizz queue.';
52
52
 
53
53
  process.stdout.write(
54
54
  JSON.stringify({
@@ -84,8 +84,9 @@ function isDiskWrite(cmd) {
84
84
  // (`_live_broker_frizzctl.mts`): a bare call, an inline JSON argument, `--input <file>`, `< file`,
85
85
  // `frizzctl … && frizzctl …` and a quoted heredoc of PROSE all ran unasked, and a quoted heredoc whose
86
86
  // body holds a JSON object raised a prompt — Claude Code's own command checks read the braces and
87
- // quotes of a body the shell never interprets. That is the one shape `ask` most needs, since a
88
- // question's options do not fit on a command line.
87
+ // quotes of a body the shell never interprets. That was the one shape `ask` most needed, since a
88
+ // question's options do not fit on a command line; `ask` refuses since 2026-10-13 (a question is a
89
+ // ```question fence the worker writes), and the shape stays approved for every other `--input -`.
89
90
  //
90
91
  // So this recognises exactly that shape, and it is deliberately narrower than the rule it backs up.
91
92
  // The first line is `frizzctl`, then words made only of characters the shell does not interpret, then
@@ -68,7 +68,7 @@ const scratch = sid
68
68
  // prompt. Trimmed 2026-08-26 (maintainer: "Definitely trim the session seed hook if it's fully
69
69
  // repetitive") as part of cutting the per-session token overhead Frizz adds over a plain TUI session.
70
70
  const core =
71
- '⟦frizz worker contract⟧ You are a frizz WORKER driving EXACTLY ONE effort. Your FULL operating contract — the end-of-turn signal fences (```done / ```awaiting — a question is a registered row, `frizzctl ask`, and the only ```question fence is the EMPTY placement marker naming its id), the scratch-directory rules, the sub-agent rules, the question handback and the stop criterion — lives in your SYSTEM PROMPT; follow it there. ALWAYS SIGN OFF — a fence OR a registration (`frizzctl ask`, `frizzctl done`); an open question is one, so rest normally and write no question fence for it. A rest on running work takes the ```awaiting fence with `status: working|watching|needs_input` — `working` and `watching` are quiet parks and need no write-up.\n' +
71
+ '⟦frizz worker contract⟧ You are a frizz WORKER driving EXACTLY ONE effort. Your FULL operating contract — the end-of-turn signal fences (```done / ```awaiting), the ```question fence that asks the human (a new `id:` registers a question where you write it; an `id:` alone references one you asked before), the scratch-directory rules, the sub-agent rules, the question handback and the stop criterion — lives in your SYSTEM PROMPT; follow it there. ALWAYS SIGN OFF — a fence OR a registration (`frizzctl done`, or a question you ask or reference at this rest, which is the sign-off: rest normally). A rest on running work takes the ```awaiting fence with `status: working|watching|needs_input` — `working` and `watching` are quiet parks and need no write-up.\n' +
72
72
  'SCRATCH DIRECTORY (OPTIONAL): `' + scratch + '` — a folder kept FOR YOU, nothing in it read automatically, never a substitute for doing the work. Give each sub-agent its OWN file rather than a shared one.';
73
73
 
74
74
  const grounding =