frizz-server 0.15.18 → 0.15.20

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 (101) hide show
  1. package/dist/claude-agent-broker.js +12834 -12734
  2. package/dist/dev-child.js +13949 -13821
  3. package/package.json +1 -1
  4. package/runtime/cc-worker/DECISIONS.md +9 -0
  5. package/runtime/cc-worker/bin/frizz-mcp.mjs +104 -9
  6. package/runtime/cc-worker/hooks/agent-dispatch.mjs +3 -2
  7. package/web-dist/assets/{abnfDiagram-VRR7QNED-CN39SboF.js → abnfDiagram-VRR7QNED-B61nQEjt.js} +1 -1
  8. package/web-dist/assets/{arc-BTVl3fKG.js → arc-CR8_qWI3.js} +1 -1
  9. package/web-dist/assets/architecture-TIHT7OUA-CXyjbDft.js +1 -0
  10. package/web-dist/assets/{architectureDiagram-ZJ3FMSHR-CLNnuVr7.js → architectureDiagram-ZJ3FMSHR-6sc4SDOh.js} +1 -1
  11. package/web-dist/assets/{blockDiagram-677ZJIJ3-bTZNRjJP.js → blockDiagram-677ZJIJ3-p-DPTDGB.js} +1 -1
  12. package/web-dist/assets/{c4Diagram-LMCZKHZV-DeekS0uP.js → c4Diagram-LMCZKHZV-cqvAqZE2.js} +1 -1
  13. package/web-dist/assets/channel-uFMfT294.js +1 -0
  14. package/web-dist/assets/{chunk-32BRIVSS-CAVyehgA.js → chunk-32BRIVSS-BNnoKILR.js} +1 -1
  15. package/web-dist/assets/{chunk-52WLFC77-C_ljp3lt.js → chunk-52WLFC77-BmHIWiVu.js} +1 -1
  16. package/web-dist/assets/{chunk-C7G6YPKG-BPdDxqsZ.js → chunk-C7G6YPKG-D7XYFno8.js} +1 -1
  17. package/web-dist/assets/{chunk-EX3LRPZG-DWH-e06D.js → chunk-EX3LRPZG-BUViIha7.js} +1 -1
  18. package/web-dist/assets/{chunk-FWX5IMBZ-yrfMig6k.js → chunk-FWX5IMBZ-3x5Zky3W.js} +2 -2
  19. package/web-dist/assets/{chunk-HOUHSVGY-DOIBrNRJ.js → chunk-HOUHSVGY-C6_RBSov.js} +1 -1
  20. package/web-dist/assets/{chunk-ICXQ74PX-kstLL_Nj.js → chunk-ICXQ74PX-NbVxQ4i1.js} +1 -1
  21. package/web-dist/assets/{chunk-MOJQB5TN-DDtU29dE.js → chunk-MOJQB5TN-nRMfcSHe.js} +1 -1
  22. package/web-dist/assets/{chunk-OGEWGWER-D2c91oEJ.js → chunk-OGEWGWER-BbSXfbEB.js} +1 -1
  23. package/web-dist/assets/{chunk-PUDLZKDR-3Z2pVgx9.js → chunk-PUDLZKDR-Byubn9VY.js} +1 -1
  24. package/web-dist/assets/{chunk-Q4XR5HBZ-rmeb4GSY.js → chunk-Q4XR5HBZ-DLq-aZ3t.js} +1 -1
  25. package/web-dist/assets/{chunk-RYQCIY6F-DE9FW0LM.js → chunk-RYQCIY6F-Dbt66M6V.js} +1 -1
  26. package/web-dist/assets/{chunk-V7JOEXUC-CNvw-r6K.js → chunk-V7JOEXUC-DNFTmXz6.js} +1 -1
  27. package/web-dist/assets/{chunk-VAUOI2AC-DUK5u-DN.js → chunk-VAUOI2AC-QWrszv3X.js} +1 -1
  28. package/web-dist/assets/{chunk-VR4S4FIN-8Qx2Il0y.js → chunk-VR4S4FIN-CJdyjwam.js} +1 -1
  29. package/web-dist/assets/{chunk-WYO6CB5R-Ch0_cnOf.js → chunk-WYO6CB5R-D_786t-3.js} +1 -1
  30. package/web-dist/assets/{chunk-XXDRQBXY-Bmd-5yN2.js → chunk-XXDRQBXY-Bd_2jBj_.js} +1 -1
  31. package/web-dist/assets/{chunk-ZGVPDNZ5-MvQyLrp9.js → chunk-ZGVPDNZ5-DklPG-LG.js} +1 -1
  32. package/web-dist/assets/classDiagram-OUVF2IWQ-D1koMbqS.js +1 -0
  33. package/web-dist/assets/classDiagram-v2-EOCWNBFH-D1koMbqS.js +1 -0
  34. package/web-dist/assets/{cose-bilkent-JH36ORCC-BmksLZVW.js → cose-bilkent-JH36ORCC-C4MtSvEs.js} +1 -1
  35. package/web-dist/assets/{cynefin-VYW2F7L2-nkrhmZuY.js → cynefin-VYW2F7L2-Dr0CmMQz.js} +1 -1
  36. package/web-dist/assets/{cynefinDiagram-TSTJHNR4-Cn3BNg8k.js → cynefinDiagram-TSTJHNR4-BpHXKyDO.js} +1 -1
  37. package/web-dist/assets/{dagre-VKFMJZFB-CTLouEOu.js → dagre-VKFMJZFB-CWAtKn43.js} +1 -1
  38. package/web-dist/assets/{diagram-FQU43EPY-u58-2525.js → diagram-FQU43EPY-B_6PhpPG.js} +1 -1
  39. package/web-dist/assets/{diagram-G47NLZAW-Cqsb2-PB.js → diagram-G47NLZAW-DPNrX-3a.js} +1 -1
  40. package/web-dist/assets/{diagram-NH7WQ7WH-8nRCmdGE.js → diagram-NH7WQ7WH-BL4nqAUm.js} +1 -1
  41. package/web-dist/assets/{diagram-OA4YK3LP-BNuiXQqV.js → diagram-OA4YK3LP-CcFbtuCf.js} +1 -1
  42. package/web-dist/assets/{diagram-WEI45ONY-B0hi_GgE.js → diagram-WEI45ONY-Bkl0nXre.js} +1 -1
  43. package/web-dist/assets/{dist-D3Kuxfbr.js → dist-krVNNn4H.js} +1 -1
  44. package/web-dist/assets/{ebnfDiagram-CCIWWBDH-C5EWDVC_.js → ebnfDiagram-CCIWWBDH-C_51YQqw.js} +1 -1
  45. package/web-dist/assets/{erDiagram-Q63AITRT-BLphelWe.js → erDiagram-Q63AITRT-D8oBhiQB.js} +1 -1
  46. package/web-dist/assets/eventmodeling-45OFAUF4-tWFB9ALb.js +1 -0
  47. package/web-dist/assets/flowDiagram-23GEKE2U-Dz_Opd7B.js +1 -0
  48. package/web-dist/assets/{ganttDiagram-NO4QXBWP-Dr-DMNOU.js → ganttDiagram-NO4QXBWP-BOJJvkcQ.js} +1 -1
  49. package/web-dist/assets/{gitGraph-TEB2WS4Q-eyuwOTFC.js → gitGraph-TEB2WS4Q-DrZGs6X0.js} +1 -1
  50. package/web-dist/assets/{gitGraphDiagram-IHSO6WYX-BGcdlMUE.js → gitGraphDiagram-IHSO6WYX-C0pqDVhD.js} +1 -1
  51. package/web-dist/assets/{index-C1G_Iq1d.js → index-BwC7xvWu.js} +97 -98
  52. package/web-dist/assets/index-CuXKWysP.css +2 -0
  53. package/web-dist/assets/{info-DKCQHKI2-T83_1t8S.js → info-DKCQHKI2-0OcIuVxc.js} +1 -1
  54. package/web-dist/assets/{infoDiagram-FWYZ7A6U-BZ7ZHiPE.js → infoDiagram-FWYZ7A6U-CRAc-N7_.js} +1 -1
  55. package/web-dist/assets/{ishikawaDiagram-FXEZZL3T-BbGaZkdX.js → ishikawaDiagram-FXEZZL3T-D_bHCCxh.js} +1 -1
  56. package/web-dist/assets/{journeyDiagram-5HDEW3XC-74db34k8.js → journeyDiagram-5HDEW3XC-Dbvh7D1e.js} +1 -1
  57. package/web-dist/assets/{kanban-definition-HUTT4EX6-_LDBnhu3.js → kanban-definition-HUTT4EX6-CxOWhFpB.js} +1 -1
  58. package/web-dist/assets/{line-BSQ-_Ld3.js → line-BGqbhtvK.js} +1 -1
  59. package/web-dist/assets/{linear-TtekQ35r.js → linear-DRvKJ3WJ.js} +1 -1
  60. package/web-dist/assets/{mermaid-parser.core-C02mLVGD.js → mermaid-parser.core-C5lIBam8.js} +3 -3
  61. package/web-dist/assets/{mermaid.core-5-Q5DE5L.js → mermaid.core-ChLUqNEE.js} +3 -3
  62. package/web-dist/assets/{mindmap-definition-LN4V7U3C-D3OsE9M2.js → mindmap-definition-LN4V7U3C-BfPv_GOf.js} +1 -1
  63. package/web-dist/assets/{packet-7NZHBO7P-ChHw2m9w.js → packet-7NZHBO7P-CH3B2i7_.js} +1 -1
  64. package/web-dist/assets/{pegDiagram-2B236MQR-Be0eWdVa.js → pegDiagram-2B236MQR-DLuCHUaK.js} +1 -1
  65. package/web-dist/assets/{pie-RZYD4A2V-Y5I7o_6T.js → pie-RZYD4A2V-C-hDlp0h.js} +1 -1
  66. package/web-dist/assets/{pieDiagram-ENE6RG2P-BVzIUwYC.js → pieDiagram-ENE6RG2P-CKVu3PTC.js} +1 -1
  67. package/web-dist/assets/{quadrantDiagram-ABIIQ3AL--WcNeUJ5.js → quadrantDiagram-ABIIQ3AL--tZ3JdyA.js} +1 -1
  68. package/web-dist/assets/{radar-I7S5WNFK-_iLcxlOU.js → radar-I7S5WNFK-C10EMwWx.js} +1 -1
  69. package/web-dist/assets/{railroad-3IZDKUUU-DUaKyIjl.js → railroad-3IZDKUUU-BYegvtJS.js} +1 -1
  70. package/web-dist/assets/railroad-abnf-AHOZXSZD-DLmknJDm.js +1 -0
  71. package/web-dist/assets/railroad-ebnf-EBAXGLYW-BoZF0VpA.js +1 -0
  72. package/web-dist/assets/railroad-peg-LSFZ7HO6-Dib7YVqg.js +1 -0
  73. package/web-dist/assets/{railroadDiagram-RFXS5EU6-JC2ENdbW.js → railroadDiagram-RFXS5EU6-CfpRdkA8.js} +1 -1
  74. package/web-dist/assets/{requirementDiagram-TGXJPOKE-CZISQjoj.js → requirementDiagram-TGXJPOKE-CUajgDbc.js} +1 -1
  75. package/web-dist/assets/{sankeyDiagram-HTMAVEWB-B88W28-Q.js → sankeyDiagram-HTMAVEWB-DRs5oKTx.js} +1 -1
  76. package/web-dist/assets/{sequenceDiagram-DBY2YBRQ-BsoQQ4qC.js → sequenceDiagram-DBY2YBRQ-BTeEqLFC.js} +1 -1
  77. package/web-dist/assets/{src-GZyi5f3X.js → src-Cf1DXZ3M.js} +1 -1
  78. package/web-dist/assets/{stateDiagram-2N3HPSRC-DO6yDa4d.js → stateDiagram-2N3HPSRC-BPcqMj-B.js} +1 -1
  79. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-DiV9dOER.js +1 -0
  80. package/web-dist/assets/{swimlanes-5IMT3BWC-zONynGJq.js → swimlanes-5IMT3BWC-CJTd58TJ.js} +1 -1
  81. package/web-dist/assets/swimlanesDiagram-G3AALYLV-BDeobZmn.js +8 -0
  82. package/web-dist/assets/{timeline-definition-FHXFAJF6-ChT_IFLs.js → timeline-definition-FHXFAJF6-CqbaBVpe.js} +1 -1
  83. package/web-dist/assets/{treeView-QDETBFTQ-BzNyoCOf.js → treeView-QDETBFTQ-B2OQ8r59.js} +1 -1
  84. package/web-dist/assets/{treemap-6X3UGDF4-BGbFAuCU.js → treemap-6X3UGDF4-DGpAdWTA.js} +1 -1
  85. package/web-dist/assets/{vennDiagram-L72KCM5P-CNyyMggu.js → vennDiagram-L72KCM5P-BAS_eWHm.js} +1 -1
  86. package/web-dist/assets/{wardley-OPB4EBWU-uHhpiyKg.js → wardley-OPB4EBWU-DpNHIH3W.js} +1 -1
  87. package/web-dist/assets/{wardleyDiagram-EHGQE667-gYBm-Ips.js → wardleyDiagram-EHGQE667-2N7X1vj8.js} +1 -1
  88. package/web-dist/assets/{xychartDiagram-FW5EYKEG-BhuHU_17.js → xychartDiagram-FW5EYKEG-C8mfLCei.js} +1 -1
  89. package/web-dist/index.html +2 -2
  90. package/web-dist/assets/architecture-TIHT7OUA-BQiZAFL1.js +0 -1
  91. package/web-dist/assets/channel-B7pe0_FG.js +0 -1
  92. package/web-dist/assets/classDiagram-OUVF2IWQ-CRHph3JZ.js +0 -1
  93. package/web-dist/assets/classDiagram-v2-EOCWNBFH-CRHph3JZ.js +0 -1
  94. package/web-dist/assets/eventmodeling-45OFAUF4-C45ENNHn.js +0 -1
  95. package/web-dist/assets/flowDiagram-23GEKE2U-aHbgmUdC.js +0 -1
  96. package/web-dist/assets/index-DN7SaNCi.css +0 -2
  97. package/web-dist/assets/railroad-abnf-AHOZXSZD-nyOfFXMk.js +0 -1
  98. package/web-dist/assets/railroad-ebnf-EBAXGLYW-D4SI1We5.js +0 -1
  99. package/web-dist/assets/railroad-peg-LSFZ7HO6-CWKTA2jO.js +0 -1
  100. package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BXMrHzjW.js +0 -1
  101. package/web-dist/assets/swimlanesDiagram-G3AALYLV-5NqpA4rx.js +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frizz-server",
3
- "version": "0.15.18",
3
+ "version": "0.15.20",
4
4
  "private": false,
5
5
  "description": "Replaceable Frizz server runtime",
6
6
  "license": "MIT",
@@ -1170,3 +1170,12 @@ A Fable helper on `nubjs/nub` ("Investigate Node SEA as container", 118 tool cal
1170
1170
  - **`agent-dispatch.mjs` is the home for the same reason the 2026-07-31 entry gives**: it fires at every depth and is the only seam that reaches a helper, whose dispatch prompt is otherwise whatever its parent thought to write. The root worker contract carries no equivalent — it reaches the one agent that cannot be stranded this way.
1171
1171
  - **The same change CORRECTED the nested-collection sentence**, which had promised since 2026-07-31 that a helper's *"completion is delivered to you automatically"*. It is not, and the experiment is one dispatch: a child told to dispatch one helper and stop the instant the Agent tool returned came back `DISPATCHED: yes / SAW_HELPER_REPLY: no`, and was never resumed to read the reply. That sentence sat four paragraphs below the new rule and is exactly what a helper told not to wait would reason its way back to, so it now reads *"a helper cannot wake you either: a dispatcher that stops is never resumed to read the reply"*. The anti-polling instruction the 2026-07-31 entry wrote it to carry — the `.output` symlink, the unreliable `"type":"result"` record — is untouched; only its false premise is. It also strengthens the 2026-08-04 default-off rule with a mechanism rather than a preference: a child that fans out cannot collect what it dispatched.
1172
1172
  - **Rejected: denying `run_in_background:true` from a sub-agent in `bash-background.mjs`.** The hook input does identify a child (`agent_id`, which `scratchpad.mjs` already reads), so it is available — but a helper launching several builds and collecting them inside one turn is legitimate, and the foreground cap makes a blanket denial actively worse. Same call as the depth-2 DENY rejected on 2026-07-31: too blunt for a hook that exists because helpers are allowed.
1173
+
1174
+ ## 2026-10-09: agents steer each other — `mcp__frizz__steer` between threads, `SendMessage` by agent id inside one
1175
+
1176
+ The maintainer, after a worker asked to send an audit's results to a resting thread spent sixteen tool calls finding the board's `followUp` route, the slug and the session id, and then curled it: *"We need to educate and encourage sub-agents to steer each other. And provide better mechanisms for doing so."*
1177
+
1178
+ - **Between threads: `steer`, a frizz MCP tool over a new `steerThread` RPC.** Claude Code's cross-session `SendMessage` reaches only a session whose process is live, so a resting thread had no channel at all short of the board's own RPC. `steerThread` is the operator's follow-up delivery (one shared `deliverFollowUp` in `router.ts`), so it wakes a resting thread, queues into a running one, and reopens a done one. The server reads the target's current session itself and stamps the sender's name from its own row; the shim takes the sender from its env. The body arrives wrapped in `<thread-message from-thread=… from-title=…>` with a guidance line naming the sender's slug, and the chat draws it as the existing "Message from «thread»" hairline. Same project only, as `spawn_thread` is.
1179
+ - **`spawn_thread` now names the spawner at the end of the child's prompt**, so a spawned thread asked for results can `steer` them back. Its "results NEVER come back to you" premise was true only because nothing could carry them; the doctrine (last resort, do-or-ask first) is unchanged.
1180
+ - **Inside one session: measured, then taught.** Measured live on Claude Code 2.1.295 (2026-10-09, headless `claude -p` sessions, read off the sub-agent transcripts and token files each recipient wrote): a parent's `SendMessage` to a RUNNING child's full agent id is delivered when the child's current tool call returns; a child's `SendMessage` to a running sibling's id is delivered the same way, and to a finished sibling's id resumes it. Only the full id resolves — a prefix, the description or the `subagent_type` answers `No agent named '<x>' is reachable`. Children have no `ListAgents`, so a sibling is reachable only by an id someone hands it, or by replying to the `from=` of a message it received. The epilogue gains one sentence for the sideways channels; the worker contract gains one paragraph under Sub-agents and a short section for `steer`.
1181
+ - **Rejected: a separate tag under the `<frizz-…>` prefix.** That prefix is Frizz's plumbing (`NOISE_PREFIXES`), which the transcript drops whole; the first draft's `<frizz-thread-message>` vanished from the chat entirely.
@@ -54,7 +54,9 @@ const SPAWN_THREAD = {
54
54
  "lands on YOUR card under one review), do that instead; if the human should choose, ASK instead. " +
55
55
  "Spawn a brand-new, separate top-level frizz thread — its own board card, session, and scratchpad, " +
56
56
  "driving INDEPENDENTLY. This is FIRE-AND-FORGET: the new thread reports to the HUMAN on the board via " +
57
- "its own final message, and its results NEVER come back to you, the caller. It is NOT an in-session " +
57
+ "its own final message, and its results come back to you, the caller, only if it sends them with " +
58
+ "`steer` — which its prompt is told it can, and which you must ASK for in that prompt if you need " +
59
+ "them. You cannot wait on it as you wait on a sub-agent. It is NOT an in-session " +
58
60
  "sub-agent. It returns only the new thread's slug and a ready-to-paste markdown link " +
59
61
  "`[title](/thread/<slug>)` that opens the thread in the frizz drawer — put that link in your handoff. " +
60
62
  "USE IT ONLY for a distinct, self-contained effort that belongs on the board in its own right and whose " +
@@ -63,9 +65,10 @@ const SPAWN_THREAD = {
63
65
  "those are in-session sub-agents (Claude: the Agent tool with `run_in_background`; Codex: native " +
64
66
  "delegation), which return their findings to you. Spawning such a helper here STRANDS it — its work lands " +
65
67
  "on another card and never reaches you, so you gain nothing. " +
66
- "Because nothing it learns ever returns to you OR to its siblings, a chain of spawned threads re-derives " +
67
- "the same facts in parallel and nobody notices — measured here: one thread spawned four, three of those " +
68
- "spawned more, and three descendants independently rediscovered the same root cause over twenty hours. " +
68
+ "Because nothing it learns returns to you OR to its siblings unless somebody steers it across, a chain of " +
69
+ "spawned threads re-derives the same facts in parallel and nobody notices — measured here: one thread " +
70
+ "spawned four, three of those spawned more, and three descendants independently rediscovered the same " +
71
+ "root cause over twenty hours. " +
69
72
  "Spawn only when the work genuinely cannot ride on your own card: a different repo, a different long-lived " +
70
73
  "runtime, an effort that must outlive yours. Never spawn merely to clear your own `done` fence. " +
71
74
  "You MUST deliberately choose `model` and `effort` to match the NEW thread's task complexity — they are " +
@@ -690,6 +693,59 @@ const SECRET = {
690
693
  },
691
694
  }
692
695
 
696
+ // STEER (2026-10-09): one thread messaging ANOTHER thread of the same project. Claude Code's own
697
+ // cross-session `SendMessage` reaches a session only while its process is live, so a worker told to hand
698
+ // its results to a resting thread had no tool for it, and went looking for the board's `followUp` route
699
+ // to curl by hand — sixteen tool calls to find the route, the slug and the session id. This is that
700
+ // delivery, as a tool: the server reads the target's current session, wraps the body so the receiver
701
+ // and the chat both know who sent it, and wakes, queues into, or reopens the target as a human
702
+ // follow-up would.
703
+ const STEER = {
704
+ name: "steer",
705
+ description:
706
+ "SEND A MESSAGE TO ANOTHER THREAD on this board, running or resting, and it reads it as its next " +
707
+ "input. A running thread reads it at its next tool boundary; a resting thread is WOKEN by it and " +
708
+ "starts a turn on it; a thread marked done is reopened. The receiver sees which thread sent it and " +
709
+ "can answer with this same tool.\n\n" +
710
+ "USE IT INSTEAD OF RELAYING THROUGH THE HUMAN. Whenever another thread needs what you have, send it " +
711
+ "there yourself: results a thread is waiting on (\"when the audit is done, send the results to " +
712
+ "<thread>\"), a finding that changes another thread's work (it is chasing the bug you just fixed, it " +
713
+ "depends on a commit you just landed, it is about to redo what you already did), or the answer to a " +
714
+ "message another thread sent you. A finding that sits in your handoff until the human copies it " +
715
+ "across costs them a trip and the other thread hours; sending it costs one call. A thread you spawned " +
716
+ "with `spawn_thread`, or the one that spawned you, is reachable the same way.\n\n" +
717
+ "WRITE IT TO BE READ COLD. The receiver has none of your context: say what you found or what you " +
718
+ "need, with the evidence, paths, commits and links it needs to act — in one complete message, not a " +
719
+ "drip of partial ones. Every steer costs the receiver a turn on its full context, so do not send " +
720
+ "progress chatter, and do not send what it did not need.\n\n" +
721
+ "IT IS A COLLEAGUE'S MESSAGE, NOT THE HUMAN'S: it does not override the human's instructions to that " +
722
+ "thread, and it is not a way to hand off work the human did not ask for. Nothing waits on a reply " +
723
+ "unless your message asks for one, and you do not need to rest waiting for it: a reply wakes you " +
724
+ "whenever it comes, even after `done`.\n\n" +
725
+ "NOT FOR YOUR OWN SUB-AGENTS — those are inside your session; reach them with `SendMessage` to " +
726
+ "their agent id. Not for your own thread, and not across projects: `to` names a thread on THIS " +
727
+ "project's board.",
728
+ inputSchema: {
729
+ type: "object",
730
+ properties: {
731
+ to: {
732
+ type: "string",
733
+ description:
734
+ "The thread to message: its slug (`fix-queue-focus`), or any link naming it — the " +
735
+ "`[title](/thread/<slug>)` link `spawn_thread` returns, or a full board URL such as " +
736
+ "`http://localhost:9393/project/frizz/thread/<slug>/full`.",
737
+ },
738
+ message: {
739
+ type: "string",
740
+ description:
741
+ "The message, as markdown. Self-contained: the receiver has none of your context. It arrives " +
742
+ "wrapped with your thread's name and slug, so do not sign it.",
743
+ },
744
+ },
745
+ required: ["to", "message"],
746
+ },
747
+ }
748
+
693
749
  const DONE = {
694
750
  name: "done",
695
751
  description:
@@ -818,9 +874,10 @@ const UNLINK = {
818
874
  },
819
875
  }
820
876
 
821
- // WATCH_ISSUE rides at the END (2026-09-14): the tool list is read by position in frizz-mcp.test.ts, and a
822
- // worker's runtime reads it by name, so the order costs nothing and appending breaks nothing.
823
- const TOOLS = [SPAWN_THREAD, GOAL, TIMER, WATCH_PR, WATCH, UNWATCH, ASK, UNASK, DONE, TITLE, ACTIVITY, LINK, UNLINK, WATCH_ISSUE, SECRET]
877
+ // WATCH_ISSUE rides at the END (2026-09-14), and SECRET and STEER after it: the tool list is read by position
878
+ // in frizz-mcp.test.ts, and a worker's runtime reads it by name, so the order costs nothing and appending
879
+ // breaks nothing.
880
+ const TOOLS = [SPAWN_THREAD, GOAL, TIMER, WATCH_PR, WATCH, UNWATCH, ASK, UNASK, DONE, TITLE, ACTIVITY, LINK, UNLINK, WATCH_ISSUE, SECRET, STEER]
824
881
 
825
882
  /** @type {Record<string, (args: Record<string, unknown>) => Promise<string>>} */
826
883
  const HANDLERS = {
@@ -839,6 +896,35 @@ const HANDLERS = {
839
896
  [ACTIVITY.name]: activity,
840
897
  [LINK.name]: link,
841
898
  [UNLINK.name]: unlink,
899
+ [STEER.name]: steer,
900
+ }
901
+
902
+ // The slug out of whatever a worker has in hand for a thread: the slug itself, the `[title](/thread/<slug>)`
903
+ // link spawn_thread returns, or a board URL (`…/project/<p>/thread/<slug>/full`).
904
+ const THREAD_LINK = /\/thread\/([^/?#)\s]+)/
905
+
906
+ /** The `steer` handler: deliver a message into ANOTHER thread of this project.
907
+ * @param {Record<string, unknown>} args @returns {Promise<string>} */
908
+ async function steer(args) {
909
+ const raw = typeof args.to === "string" ? args.to.trim() : ""
910
+ const message = typeof args.message === "string" ? args.message.trim() : ""
911
+ if (!raw) throw new Error("`to` is required — the slug of the thread to message, or a link naming it")
912
+ if (!message) throw new Error("`message` is required and must be a non-empty string")
913
+ const to = decodeURIComponent(THREAD_LINK.exec(raw)?.[1] ?? raw)
914
+ // THE SENDER IS THE ENV'S, never the model's: the receiver is told which thread sent this, and that
915
+ // has to be true.
916
+ const result = (await callRpc("steerThread", { from: threadSlug(), to, message }))?.result
917
+ if (!result?.slug) throw new Error(`steerThread returned no receipt: ${JSON.stringify(result)?.slice(0, 300)}`)
918
+ const how = result.delivery === "running"
919
+ ? "It is mid-turn, so it reads this at its next tool boundary."
920
+ : result.delivery === "reopened"
921
+ ? "It had been marked done; this message reopened it and started a turn."
922
+ : "It was resting; this message woke it and started a turn."
923
+ return (
924
+ `Delivered to «${result.title}» (\`${result.slug}\`). ${how}\n\n` +
925
+ "Its reply, if it sends one, arrives as your next input and wakes you — do not rest waiting for it. " +
926
+ `Link for your handoff: [${result.title}](/thread/${result.slug})`
927
+ )
842
928
  }
843
929
 
844
930
  /** @param {Record<string, unknown>} args @returns {Promise<string>} */
@@ -1120,8 +1206,15 @@ async function spawnThread(args) {
1120
1206
  const effort = typeof args.effort === "string" ? args.effort.trim() : ""
1121
1207
  if (!effort) throw new Error("`effort` is required — choose one by complexity (low/medium/high/xhigh/max). There is no default.")
1122
1208
 
1209
+ // THE WAY BACK. A spawned thread starts with nothing but this prompt, so without its spawner's slug it
1210
+ // could not `steer` anything back even when asked to — the footer names it, once, at the end.
1211
+ const parent = process.env.FRIZZ_THREAD_SLUG || process.env.FRIZZ_THREAD
1212
+ const footer = parent
1213
+ ? `\n\n---\nSpawned by the Frizz thread \`${parent}\`. If this prompt asks for results back, or you find ` +
1214
+ `something that thread must know, send it there with the frizz \`steer\` tool (\`to: "${parent}"\`).`
1215
+ : ""
1123
1216
  /** @type {Record<string, unknown>} */
1124
- const body = { prompt, model, effort }
1217
+ const body = { prompt: prompt + footer, model, effort }
1125
1218
  if (typeof args.title === "string" && args.title.trim()) body.title = args.title.trim()
1126
1219
  if (args.backend === "claude" || args.backend === "codex") body.backend = args.backend
1127
1220
 
@@ -1153,7 +1246,9 @@ async function spawnThread(args) {
1153
1246
  const label = typeof body.title === "string" ? body.title : slug
1154
1247
  return (
1155
1248
  `Spawned a new frizz thread \`${slug}\`. It is now on the board driving independently — it reports ` +
1156
- `to the human via its own final message, NOT back to you, so do not wait on a result from it.\n\n` +
1249
+ `to the human via its own final message, so do not wait on a result from it. It knows your slug: if ` +
1250
+ `its prompt asked for results back, they arrive as a \`steer\` that wakes you. You can message it ` +
1251
+ `the same way, with \`steer\` and \`to: "${slug}"\`.\n\n` +
1157
1252
  `Paste this link to let the human open it in the drawer:\n\n[${label}](/thread/${slug})`
1158
1253
  )
1159
1254
  }
@@ -8,7 +8,8 @@
8
8
  // wrong and never returns cleanly), so scrub both silently.
9
9
  // 3) AUTO-APPEND a short ORCHESTRATION EPILOGUE carrying only what a helper cannot discover on
10
10
  // its own: that its final message is the return value, that nothing can WAKE it so it must not
11
- // end a turn on a waiter, the `SendMessage({to: "main"})` upward channel, the own-file rule for
11
+ // end a turn on a waiter, the `SendMessage({to: "main"})` upward channel and its sideways forms (a
12
+ // sibling by agent id, another thread by `mcp__frizz__steer`), the own-file rule for
12
13
  // the scratch directory, no fan-out of its own unless asked, and how a helper it DID dispatch
13
14
  // is collected. It carries no handoff format and no build, test, git or process policy — the
14
15
  // maintainer had the handoff-format doctrine cut on 2026-08-26.
@@ -70,7 +71,7 @@ const EPILOGUE = `
70
71
  [ORCHESTRATION EPILOGUE — auto-appended by the frizz worker dispatch hook] You are a helper sub-agent for a frizz worker. Your final message is the handoff your dispatcher reads: what you did, what you verified, what remains.
71
72
  NOTHING CAN WAKE YOU — ending your turn IS your return. A job you backgrounded (Bash \`run_in_background:true\` above all) reports to your DISPATCHER, never to you, so a turn that ends while one is outstanding hands back unfinished work and leaves its result somewhere you will never read. So never end a turn waiting for something to finish: run long commands in the FOREGROUND, and where one would outrun the foreground limit, make the command itself loop until its own terminal condition rather than backgrounding it. If you did background something, collect it in the SAME turn. And if your dispatcher named a scratch directory, write anything you would not want to lose into your own file there AS YOU GO — a turn that ends early takes with it everything you had neither written down nor said.
72
73
  If the worker names its scratch directory: Write your OWN file there — never edit or delete a file another agent wrote. That file is Frizz coordination state, not a project deliverable or source edit, so it stays allowed under limits such as "write only <path>" or "do not modify the repo"; never classify it as unauthorized or roll it back. Every other file is governed by your delegated authority; its location alone neither permits nor forbids editing. Do not edit other \`.frizz/\` state unless your prompt asks.
73
- Upward channel: \`SendMessage({to: "main", summary: "<5-10 words>", message: "…"})\` reaches your dispatcher while you work (load it first with ToolSearch \`select:SendMessage\` if it is deferred). Use it only when the dispatcher acting before you finish would change the outcome — a blocker, a milestone another task needs, instructions that should change — not for progress updates.
74
+ Upward channel: \`SendMessage({to: "main", summary: "<5-10 words>", message: "…"})\` reaches your dispatcher while you work (load it first with ToolSearch \`select:SendMessage\` if it is deferred). Use it only when the dispatcher acting before you finish would change the outcome — a blocker, a milestone another task needs, instructions that should change — not for progress updates. The same tool reaches a SIBLING sub-agent by the full agent id your prompt gives you (a message from one arrives as \`<agent-message from="<id>">\`; reply to that id), and \`mcp__frizz__steer\` reaches another Frizz THREAD by its slug: when your prompt says your result belongs to another thread or sibling, send it there yourself before you return, and say in your final message that you did.
74
75
  Do the work yourself: do NOT dispatch sub-agents of your own unless your dispatch prompt explicitly tells you to. You are already one prong of someone else's fan-out; a slice that feels large is still yours to work through in your own turn.
75
76
  If your prompt DOES ask you to dispatch a helper, the rule above still binds — a helper cannot wake you either: a dispatcher that stops is never resumed to read the reply. So collect it before your turn ends, or do not dispatch it. Never hand-roll a wait loop over a helper's transcript or \`.output\` path: that path is a SYMLINK (\`stat\` without \`-L\` reports the link's own ~150-byte size and frozen mtime) and the \`"type":"result"\` record is not reliably written, so a helper working hard reads as tiny, stale and dead, and you will discard live work and redo it. Judge a helper only by what it actually returns to you, and give it a \`description\` naming its narrower slice.`;
76
77
 
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-C02mLVGD.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-GZyi5f3X.js";import"./chunk-WYO6CB5R-Ch0_cnOf.js";import"./chunk-VAUOI2AC-DUK5u-DN.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-DDtU29dE.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-C5lIBam8.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-Cf1DXZ3M.js";import"./chunk-WYO6CB5R-D_786t-3.js";import"./chunk-VAUOI2AC-QWrszv3X.js";import{n as i,r as a,t as o}from"./chunk-MOJQB5TN-nRMfcSHe.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
@@ -1 +1 @@
1
- import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-D3Kuxfbr.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i)if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
1
+ import{n as e,t}from"./path-BWPyau1x.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-krVNNn4H.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i)if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
@@ -0,0 +1 @@
1
+ import"./chunk-KEIR6QF5-BfrZ3jm6.js";import{M as e}from"./mermaid-parser.core-C5lIBam8.js";export{e as createArchitectureServices};