zidane 7.2.5 → 8.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +34 -6
- package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
- package/dist/acp-DQDhi2dj.js.map +1 -0
- package/dist/acp-cli.d.ts +1 -1
- package/dist/acp-cli.js +9 -66
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +10 -590
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +3 -3
- package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
- package/dist/agent-DSLNmBp0.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -2
- package/dist/aliasing-lVFbm81n.js +217 -0
- package/dist/aliasing-lVFbm81n.js.map +1 -0
- package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
- package/dist/anthropic-CD00LhUP.js.map +1 -0
- package/dist/artifacts-CV2hUKnL.js.map +1 -1
- package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
- package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
- package/dist/call-tool-dHlbGOIY.js +70 -0
- package/dist/call-tool-dHlbGOIY.js.map +1 -0
- package/dist/chat/pure.d.ts +372 -6
- package/dist/chat/pure.d.ts.map +1 -1
- package/dist/chat/pure.js +35 -244
- package/dist/chat/pure.js.map +1 -1
- package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
- package/dist/chat-JPJJ8uu5.js.map +1 -0
- package/dist/chat.d.ts +4 -6
- package/dist/chat.js +23 -12
- package/dist/cli-shared-C-YCaglL.js +159 -0
- package/dist/cli-shared-C-YCaglL.js.map +1 -0
- package/dist/client-core-BQSyDALT.d.ts +2115 -0
- package/dist/client-core-BQSyDALT.d.ts.map +1 -0
- package/dist/codemode-worker.d.ts +1 -0
- package/dist/codemode-worker.js +155 -0
- package/dist/codemode-worker.js.map +1 -0
- package/dist/codemode.d.ts +352 -0
- package/dist/codemode.d.ts.map +1 -0
- package/dist/codemode.js +5 -0
- package/dist/connection-Dr-Js4yZ.d.ts +28 -0
- package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
- package/dist/connection-loop-gdh22LTI.js +112 -0
- package/dist/connection-loop-gdh22LTI.js.map +1 -0
- package/dist/context-segments-BHKlagL6.js +1016 -0
- package/dist/context-segments-BHKlagL6.js.map +1 -0
- package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
- package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +19 -8
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +1 -440
- package/dist/contexts/docker.d.ts +36 -7
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js +1 -456
- package/dist/contexts/e2b.d.ts +68 -13
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +1 -382
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/contexts/sandbox.js +5 -0
- package/dist/contexts/sandbox.js.map +1 -1
- package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
- package/dist/contexts-d7UolYot.js.map +1 -0
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/cred-keys-GpBg71cP.js +105 -0
- package/dist/cred-keys-GpBg71cP.js.map +1 -0
- package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
- package/dist/credentials-JttEuRON.js.map +1 -0
- package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
- package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
- package/dist/daemon-cli.d.ts +1 -1
- package/dist/daemon-cli.js +3 -2
- package/dist/daemon-cli.js.map +1 -1
- package/dist/daytona-DG3omipZ.js +513 -0
- package/dist/daytona-DG3omipZ.js.map +1 -0
- package/dist/defaults-Cx3zvDOV.js +23 -0
- package/dist/defaults-Cx3zvDOV.js.map +1 -0
- package/dist/dispatcher-BMlu2BmZ.js +4941 -0
- package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
- package/dist/docker-BZhMMJUp.js +727 -0
- package/dist/docker-BZhMMJUp.js.map +1 -0
- package/dist/e2b-CEVOdRib.js +480 -0
- package/dist/e2b-CEVOdRib.js.map +1 -0
- package/dist/edit-utils-EGosADZq.js +234 -0
- package/dist/edit-utils-EGosADZq.js.map +1 -0
- package/dist/environment-8wsKE2Ln.js +214 -0
- package/dist/environment-8wsKE2Ln.js.map +1 -0
- package/dist/eval-BNcvle_J.js +1595 -0
- package/dist/eval-BNcvle_J.js.map +1 -0
- package/dist/eval.d.ts +2 -2
- package/dist/eval.js +1 -1489
- package/dist/executor-Cx5-8yqi.js +621 -0
- package/dist/executor-Cx5-8yqi.js.map +1 -0
- package/dist/extension-authoring-DyGGmq9V.js +385 -0
- package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +3 -3
- package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
- package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
- package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
- package/dist/format-C2NQEVUH.js.map +1 -0
- package/dist/format-bytes-C7tfc3Zm.js +55 -0
- package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
- package/dist/headless-C_rNUuYC.js +960 -0
- package/dist/headless-C_rNUuYC.js.map +1 -0
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -413
- package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
- package/dist/history-search-CcYzF8-0.js.map +1 -0
- package/dist/history-search-worker.d.ts +1 -1
- package/dist/history-search-worker.js +1 -1
- package/dist/host-D7NrI03V.js +378 -0
- package/dist/host-D7NrI03V.js.map +1 -0
- package/dist/host-signals-BcP5QKUD.js +118 -0
- package/dist/host-signals-BcP5QKUD.js.map +1 -0
- package/dist/identity-CwfO8K-t.js +26 -0
- package/dist/identity-CwfO8K-t.js.map +1 -0
- package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
- package/dist/index-BGe1fQT7.d.ts.map +1 -0
- package/dist/index-BVQsIKGn.d.ts +448 -0
- package/dist/index-BVQsIKGn.d.ts.map +1 -0
- package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
- package/dist/index-CHABJd-L.d.ts.map +1 -0
- package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
- package/dist/index-D6a7qXpg.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +27 -23
- package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
- package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
- package/dist/ipc/remote.d.ts +313 -0
- package/dist/ipc/remote.d.ts.map +1 -0
- package/dist/ipc/remote.js +4 -0
- package/dist/ipc.d.ts +6 -964
- package/dist/ipc.js +403 -4
- package/dist/ipc.js.map +1 -0
- package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
- package/dist/isolation-D9L650W5.d.ts.map +1 -0
- package/dist/json-rpc--HXQti1E.js +350 -0
- package/dist/json-rpc--HXQti1E.js.map +1 -0
- package/dist/links-j8rED1sR.js +603 -0
- package/dist/links-j8rED1sR.js.map +1 -0
- package/dist/local-terminal-D8QThwo_.js +252 -0
- package/dist/local-terminal-D8QThwo_.js.map +1 -0
- package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
- package/dist/logger-Gtqlayx8.js.map +1 -0
- package/dist/logs-view-CWG8aUAG.js.map +1 -1
- package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
- package/dist/mcp-_wecH9Qe.js.map +1 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/media-sniff-UKijEaiQ.js.map +1 -1
- package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
- package/dist/messages-BqiwcD2Q.js.map +1 -0
- package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
- package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
- package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
- package/dist/openai-compat-CFrpH7uq.js.map +1 -0
- package/dist/orchestration-BCGmB8Ps.js +511 -0
- package/dist/orchestration-BCGmB8Ps.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -2
- package/dist/output/stream-json.d.ts.map +1 -1
- package/dist/output/stream-json.js +1 -1
- package/dist/output/terminal.d.ts +1 -2
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +13 -7
- package/dist/output/terminal.js.map +1 -1
- package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
- package/dist/plugins-DS7mahzZ.js.map +1 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -2
- package/dist/prelude-Cxo4t74B.js +517 -0
- package/dist/prelude-Cxo4t74B.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -2
- package/dist/project-root-B8zADr4o.js +167 -0
- package/dist/project-root-B8zADr4o.js.map +1 -0
- package/dist/project-user-paths-BSgtrRxl.js +58 -0
- package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
- package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
- package/dist/prompts-DYcvqShf.d.ts.map +1 -0
- package/dist/protocol-DnhqqSmE.js +13 -0
- package/dist/protocol-DnhqqSmE.js.map +1 -0
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +1 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +3 -2
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -2
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +15 -12
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +3 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +3 -3
- package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
- package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +4 -4
- package/dist/registry-D6ShBWJU.js +5234 -0
- package/dist/registry-D6ShBWJU.js.map +1 -0
- package/dist/remote-hosts-BtA_9ZGp.js +97 -0
- package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
- package/dist/restate.d.ts +2 -3
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js +631 -572
- package/dist/restate.js.map +1 -1
- package/dist/run-summary-CklLiZ4y.js +288 -0
- package/dist/run-summary-CklLiZ4y.js.map +1 -0
- package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
- package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
- package/dist/session/sqlite.d.ts +1 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -616
- package/dist/session-factory-BUGY5P40.js +1576 -0
- package/dist/session-factory-BUGY5P40.js.map +1 -0
- package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
- package/dist/session-xh9JXu6i.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/settings-keys-Ckf29NeM.js +677 -0
- package/dist/settings-keys-Ckf29NeM.js.map +1 -0
- package/dist/shell-path-Dqaoow2J.js +412 -0
- package/dist/shell-path-Dqaoow2J.js.map +1 -0
- package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
- package/dist/skills-DKqZJm4X.js.map +1 -0
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -2
- package/dist/source-mPExaUm8.js +381 -0
- package/dist/source-mPExaUm8.js.map +1 -0
- package/dist/sqlite-DV1DQzN2.js +698 -0
- package/dist/sqlite-DV1DQzN2.js.map +1 -0
- package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
- package/dist/src-BRMYRJib.js.map +1 -0
- package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
- package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
- package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
- package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
- package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
- package/dist/timeout-DEaqslLO.d.ts.map +1 -1
- package/dist/todo-edits-Dn251YUP.js +1790 -0
- package/dist/todo-edits-Dn251YUP.js.map +1 -0
- package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
- package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
- package/dist/tool-state-Dku6YqAB.js +989 -0
- package/dist/tool-state-Dku6YqAB.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +1 -2
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -7
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -2
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +2 -2
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools-_DnT3AGM.js +578 -0
- package/dist/tools-_DnT3AGM.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -2
- package/dist/tui.d.ts +534 -517
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +34933 -27243
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-B8sokwi5.js +333 -0
- package/dist/turn-operations-B8sokwi5.js.map +1 -0
- package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
- package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
- package/dist/types-C7ZFOztE.d.ts +132 -0
- package/dist/types-C7ZFOztE.d.ts.map +1 -0
- package/dist/types-CH5XpIHw.js +114 -0
- package/dist/types-CH5XpIHw.js.map +1 -0
- package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
- package/dist/types-Cu0ZGDu9.js.map +1 -0
- package/dist/types-IqegbJEE.d.ts +624 -0
- package/dist/types-IqegbJEE.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js +1 -1
- package/dist/url-D8HCl65b.js +1259 -0
- package/dist/url-D8HCl65b.js.map +1 -0
- package/dist/wasm-BVT-j5cl.js +33 -0
- package/dist/wasm-BVT-j5cl.js.map +1 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
- package/dist/ws-CIHMvlSh.js +952 -0
- package/dist/ws-CIHMvlSh.js.map +1 -0
- package/dist/ws-client-N7NxzvQp.js +230 -0
- package/dist/ws-client-N7NxzvQp.js.map +1 -0
- package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
- package/dist/xai-CvJTeLrI.js.map +1 -0
- package/dist/xdg-zweed0-t.js +117 -0
- package/dist/xdg-zweed0-t.js.map +1 -0
- package/docs/ACP.md +52 -0
- package/docs/ARCHITECTURE.md +103 -6
- package/docs/ARTIFACTS.md +8 -4
- package/docs/CHAT.md +165 -14
- package/docs/EXECUTION_CONTEXT.md +8 -0
- package/docs/EXTENSIONS.md +123 -2
- package/docs/HEADLESS.md +2 -0
- package/docs/IPC.md +775 -64
- package/docs/MACHINES.md +456 -0
- package/docs/PANELS.md +3 -0
- package/docs/README.md +4 -0
- package/docs/RESTATE.md +3 -2
- package/docs/RUN_IN_BACKGROUND.md +10 -2
- package/docs/SERVER.md +1085 -0
- package/docs/SKILL.md +6 -1
- package/docs/TERMINAL.md +75 -0
- package/docs/TUI.md +65 -14
- package/package.json +58 -26
- package/scripts/eval.ts +4 -0
- package/dist/acp-D-tVyUjw.js.map +0 -1
- package/dist/agent-D0zZnGbt.js.map +0 -1
- package/dist/anthropic-C2aole0G.js.map +0 -1
- package/dist/approvals-DKaJZYlm.js.map +0 -1
- package/dist/atomic-write-B7zr1ddF.js.map +0 -1
- package/dist/auth-BG2rVKSt.js.map +0 -1
- package/dist/completion-core-BRo86R_L.js.map +0 -1
- package/dist/contexts/daytona.js.map +0 -1
- package/dist/contexts/docker.js.map +0 -1
- package/dist/contexts/e2b.js.map +0 -1
- package/dist/contexts-CRE9pw07.js.map +0 -1
- package/dist/eval.js.map +0 -1
- package/dist/format-BF745pLL.js.map +0 -1
- package/dist/glob-DluQFSw1.js +0 -270
- package/dist/glob-DluQFSw1.js.map +0 -1
- package/dist/headless.js.map +0 -1
- package/dist/history-search-C4bk1Wz_.js.map +0 -1
- package/dist/index-BgN1T3lk.d.ts.map +0 -1
- package/dist/index-C37_ppWv.d.ts.map +0 -1
- package/dist/index-C6NEd5y_.d.ts.map +0 -1
- package/dist/ipc-BKVIIOqH.js +0 -331
- package/dist/ipc-BKVIIOqH.js.map +0 -1
- package/dist/ipc.d.ts.map +0 -1
- package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
- package/dist/json-rpc-rSWMUh9b.js +0 -192
- package/dist/json-rpc-rSWMUh9b.js.map +0 -1
- package/dist/logger--C1VQjwJ.js.map +0 -1
- package/dist/mcp-CgNd-f3F.js.map +0 -1
- package/dist/messages-2jcOA_5R.js.map +0 -1
- package/dist/openai-compat-Dy56weK8.js.map +0 -1
- package/dist/output-cap-C9zukcCj.js +0 -100
- package/dist/output-cap-C9zukcCj.js.map +0 -1
- package/dist/panels-B6gRk4bf.js +0 -789
- package/dist/panels-B6gRk4bf.js.map +0 -1
- package/dist/plugins-gbI7SBA6.js.map +0 -1
- package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
- package/dist/run-summary-BU_NgwUT.js +0 -269
- package/dist/run-summary-BU_NgwUT.js.map +0 -1
- package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
- package/dist/session/sqlite.js.map +0 -1
- package/dist/session-BqRP1hS7.js.map +0 -1
- package/dist/shell-path-DfdXrGg9.js +0 -1549
- package/dist/shell-path-DfdXrGg9.js.map +0 -1
- package/dist/skills-BC3dodWp.js.map +0 -1
- package/dist/src-CkNQKFKr.js.map +0 -1
- package/dist/todo-edits-UOwgxGKu.js +0 -528
- package/dist/todo-edits-UOwgxGKu.js.map +0 -1
- package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
- package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
- package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
- package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
- package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
- package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
- package/dist/turn-operations-DrbJlpq9.js.map +0 -1
- package/dist/types-CWgENVLY.js.map +0 -1
- package/dist/xai-CazjStOK.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-JPJJ8uu5.js","names":["errorMessage","SETUP_TIMEOUT_SECONDS","findGitRoot","debugLog","logger","text","findGitRoot","text","findGitRoot","debugLog","truncate","findGitRoot","errorMessage","statusText","findGitRoot","renderBlock","findGitRoot","artifactsPreset","FILE_MODE","readAll","createSessionInStore","createSessionInSharedStore","forkSharedSession","OPT_OUT_VARS","findGitRoot","errorMessage","errorMessage","errorMessage"],"sources":["../src/chat/host/approvals.ts","../src/chat/host/compaction/run.ts","../src/chat/host/compaction/now.ts","../src/chat/host/compaction/index.ts","../src/chat/host/edit-outcome-ledger.ts","../src/chat/mcp-tools-cache.ts","../src/chat/plugins-discovery.ts","../src/chat/session-cwd.ts","../src/chat/host/helpers.ts","../src/chat/host/approval-gate/index.ts","../src/chat/repeat-guard-notice.ts","../src/chat/run-end-notice.ts","../src/chat/host/debug.ts","../src/chat/host/notices/index.ts","../src/chat/host/machines/context.ts","../src/chat/host/machines/errors.ts","../src/chat/host/machines/folders.ts","../src/chat/environments/git.ts","../src/chat/environments/git-remote.ts","../src/chat/environments/remote-sandbox.ts","../src/chat/environments/daytona.ts","../src/chat/environments/worktree.ts","../src/chat/environments/docker.ts","../src/chat/environments/e2b.ts","../src/chat/environments/local.ts","../src/chat/environments/index.ts","../src/chat/host/machines/providers.ts","../src/chat/host/machines/project-files.ts","../src/chat/host/machines/link.ts","../src/chat/host/machines/registry.ts","../src/chat/host/machines/index.ts","../src/mcp/warn-log.ts","../src/chat/host/mcp/index.ts","../src/chat/host/models/index.ts","../src/chat/agents-md.ts","../src/chat/browser/tools.ts","../src/contexts/terminal-keys.ts","../src/chat/terminal/tools.ts","../src/chat/host/prompt/index.ts","../src/chat/host/provider-diagnostic.ts","../src/tools/read-chat-turns.ts","../src/chat/attachment-part.ts","../src/chat/auto-compact.ts","../src/chat/thinking-binding.ts","../src/chat/host/host-runtime.ts","../src/chat/builtin-commands.ts","../src/chat/skills-discovery.ts","../src/chat/host/commands/catalog.ts","../src/chat/host/commands/errors.ts","../src/chat/interactions.tsx","../src/chat/host/commands/interaction.ts","../src/chat/host/commands/output.ts","../src/chat/host/commands/run-agent.ts","../src/chat/host/commands/run-settings.ts","../src/chat/host/commands/spawn-agents.ts","../src/chat/host/commands/index.ts","../src/chat/host/signals.ts","../src/chat/host/todos/index.ts","../src/chat/host/runs/guard.ts","../src/chat/host/runs/receipt.ts","../src/chat/host/runs/prepare.ts","../src/chat/host/runs/controls.ts","../src/chat/host/runs/steer.ts","../src/chat/host/runs/index.ts","../src/chat/pinned-skills.ts","../src/chat/host/skills/index.ts","../src/chat/host/agent-build/active-run.ts","../src/chat/host/agent-build/command-seam.ts","../src/chat/host/launch-overrides.ts","../src/chat/host/cwd/index.ts","../src/chat/host/edits/index.ts","../src/chat/host/transcript/spawn.ts","../src/chat/host/transcript/stream.ts","../src/chat/host/transcript/tools.ts","../src/chat/host/transcript/turns.ts","../src/chat/host/work/index.ts","../src/chat/host/agent-build/hooks.ts","../src/chat/host/agent-build/preset.ts","../src/chat/host/orchestration/delivery.ts","../src/chat/host/orchestration/directory.ts","../src/chat/host/orchestration/projections.ts","../src/chat/host/orchestration/signals.ts","../src/chat/host/orchestration/state.ts","../src/chat/host/orchestration/verbs.ts","../src/chat/host/orchestration/tool.ts","../src/chat/host/orchestration/index.ts","../src/chat/host/agent-build/tools.ts","../src/chat/host/agent-build/plugins.ts","../src/chat/host/agent-build/index.ts","../src/chat/host/agents/index.ts","../src/chat/host/broadcast.ts","../src/chat/host/browser.ts","../src/chat/workspace-confinement.ts","../src/chat/host/context.ts","../src/chat/execution-cache.ts","../src/chat/environment-credentials.ts","../src/chat/environment-settings.ts","../src/chat/host/execution/environments.ts","../src/chat/host/execution/methods.ts","../src/chat/environment-provisioning.ts","../src/chat/host/execution/provisioning.ts","../src/chat/mcp-credentials.ts","../src/chat/sandbox-settings.ts","../src/chat/host/launch-execution.ts","../src/chat/host/execution/session-execution.ts","../src/chat/host/execution/suspension.ts","../src/chat/host/terminal/agent-methods.ts","../src/contexts/terminal-mouse.ts","../src/chat/host/terminal/lifecycle.ts","../src/chat/host/terminal/client-methods.ts","../src/chat/host/terminal/output.ts","../src/chat/host/terminal/registry.ts","../src/chat/host/terminal/session-methods.ts","../src/chat/host/terminal/views.ts","../src/chat/host/terminal/index.ts","../src/chat/host/execution/terminals.ts","../src/chat/host/execution/index.ts","../src/chat/host/interactions.ts","../src/chat/host/queue/methods.ts","../src/chat/host/queue/store.ts","../src/chat/host/queue/index.ts","../src/chat/host/session-ops/index.ts","../src/chat/host/session-title.ts","../src/chat/host/teardown/index.ts","../src/chat/host/engine.ts","../src/chat/artifacts-view.ts","../src/chat/env-opt-out.ts","../src/chat/auto-update.ts","../src/chat/auto-update-companion.ts","../src/chat/auto-update-restart.ts","../src/chat/auto-update-cli.ts","../src/chat/auto-update-hook.ts","../src/chat/auto-update-service.ts","../src/chat/boot-profiler.ts","../src/chat/browser.ts","../src/chat/mcps-write.ts","../src/chat/claude-import.ts","../src/chat/completion.ts","../src/chat/completion-artifacts.ts","../src/chat/user-config.ts","../src/chat/config.ts","../src/chat/config-context.tsx","../src/chat/discovery-context.tsx","../src/chat/discovery-slot.ts","../src/chat/editor-command.ts","../src/chat/enabled-toggle-set.ts","../src/chat/extension-mcp-host.ts","../src/chat/files-discovery.ts","../src/chat/footer-hints.ts","../src/chat/hints.ts","../src/chat/mcp-auth-context.tsx","../src/chat/mcp-rows.ts","../src/chat/mcp-tool-toggle.ts","../src/chat/oauth.ts","../src/chat/oauth-redirect.ts","../src/chat/path-display.ts","../src/chat/provider-usage.ts","../src/chat/safe-mode-context.tsx","../src/chat/session-export.ts","../src/chat/streaming.ts","../src/chat/theme-context.tsx","../src/chat/todo-anchor.ts","../src/chat/transcript-anchors.ts"],"sourcesContent":["/**\n * Approval hub — safe-mode HITL gate.\n *\n * Tiered gate matching the TUI:\n * 1. `IMPLICITLY_SAFE_TOOLS` (covered inside `isOnSafelist`) — read-only built-ins pass.\n * 2. Project safelist (`getSafelistForCwd`: keyed by the project root of\n * cwd, the same read as the TUI) — persisted matches pass.\n * 3. Otherwise queue + broadcast an `approval:request` and wait for ANY\n * client to resolve it.\n *\n * Requests are persisted through `PendingApprovalsStore` BEFORE broadcasting\n * so a crash between insert and resolve still surfaces the request after\n * restart (rehydrated as a \"ghost\" — resolvable in the UI, but the original\n * awaiting run died with the previous process).\n */\nimport type { ApprovalDecision } from '../safe-mode-context'\nimport type { EditPayload } from '../types'\nimport type { PendingApprovalsStore } from './environment'\nimport type { ApprovalOriginator, HostSignal, SerializedPreview, WireApprovalRequest } from './signals'\nimport { randomUUID } from 'node:crypto'\nimport { addToSafelistForCwd, getSafelistForCwd, isOnSafelist, suggestSafelistEntries } from '../safe-mode'\n\ninterface PendingRequest {\n request: WireApprovalRequest\n resolve: (decision: ApprovalDecision) => void\n}\n\nexport interface ApprovalRequestInput {\n sessionId: string\n cwd: string\n tool: string\n input: Record<string, unknown>\n edit?: EditPayload\n priorContent?: string | null\n preview?: SerializedPreview\n originator?: ApprovalOriginator\n /** Skip the persisted safelist and offer nothing to remember: the prompt must show every time. */\n alwaysAsk?: boolean\n}\n\nexport interface ApprovalHub {\n request: (input: ApprovalRequestInput) => Promise<ApprovalDecision>\n resolve: (id: string, decision: ApprovalDecision) => void\n denyAll: (sessionId?: string) => void\n listPending: () => WireApprovalRequest[]\n /** Register ghost resolvers for approvals persisted by a prior process lifetime. */\n rehydrate: () => void\n}\n\n/** In-memory fallback when the host doesn't provide durable persistence. */\nexport function createMemoryApprovalsStore(): PendingApprovalsStore {\n const rows = new Map<string, WireApprovalRequest>()\n return {\n insert: request => void rows.set(request.id, request),\n delete: id => void rows.delete(id),\n clear: () => rows.clear(),\n list: () => [...rows.values()],\n }\n}\n\nexport function createApprovalHub(options: {\n broadcast: (signal: HostSignal) => void\n /** Base dir for the shared `projects.json` safelist (`~/.zidane`). */\n userDataDir: () => string\n persistence?: PendingApprovalsStore\n}): ApprovalHub {\n const { broadcast, userDataDir } = options\n const persistence = options.persistence ?? createMemoryApprovalsStore()\n const pending = new Map<string, PendingRequest>()\n\n return {\n async request(input) {\n if (!input.alwaysAsk && isOnSafelist(getSafelistForCwd(userDataDir(), input.cwd), input.tool, input.input))\n return 'accept-once'\n\n const id = randomUUID()\n const full: WireApprovalRequest = {\n id,\n sessionId: input.sessionId,\n cwd: input.cwd,\n tool: input.tool,\n input: input.input,\n suggestedSafelistEntries: input.alwaysAsk ? [] : suggestSafelistEntries(input.tool, input.input),\n ...(input.edit ? { edit: input.edit } : {}),\n ...(input.priorContent !== undefined ? { priorContent: input.priorContent } : {}),\n ...(input.preview ? { preview: input.preview } : {}),\n // Omit the implicit `'parent'` case so the payload stays minimal.\n ...(input.originator && input.originator.kind === 'child' ? { originator: input.originator } : {}),\n }\n\n /*\n * Persist before broadcasting so a crash between insert and resolve\n * still surfaces the request on next start. The persisted row is the\n * source of truth; the in-memory Map only adds the live resolver.\n */\n persistence.insert(full)\n\n return new Promise<ApprovalDecision>((resolve) => {\n pending.set(id, { request: full, resolve })\n broadcast({ kind: 'approval:request', request: full })\n })\n },\n\n resolve(id, decision) {\n const entry = pending.get(id)\n\n /*\n * Persist safelist BEFORE removing the pending row so a crash between\n * the two doesn't leak: either the safelist write lands and we lose\n * the row, or both roll back.\n */\n if (entry && decision === 'accept-safelist') {\n try {\n const entries\n = entry.request.suggestedSafelistEntries\n ?? suggestSafelistEntries(entry.request.tool, entry.request.input)\n addToSafelistForCwd(userDataDir(), entry.request.cwd, entries)\n }\n catch {\n // Best-effort — the user still gets accept-once semantics below.\n }\n }\n\n persistence.delete(id)\n\n if (!entry)\n return\n\n pending.delete(id)\n entry.resolve(decision)\n broadcast({ kind: 'approval:resolved', sessionId: entry.request.sessionId, requestId: id, decision })\n },\n\n denyAll(sessionId) {\n if (sessionId === undefined) {\n for (const [id, entry] of pending) {\n entry.resolve('deny')\n broadcast({ kind: 'approval:resolved', sessionId: entry.request.sessionId, requestId: id, decision: 'deny' })\n }\n pending.clear()\n persistence.clear()\n return\n }\n\n for (const [id, entry] of pending) {\n if (entry.request.sessionId !== sessionId)\n continue\n entry.resolve('deny')\n pending.delete(id)\n persistence.delete(id)\n broadcast({ kind: 'approval:resolved', sessionId, requestId: id, decision: 'deny' })\n }\n },\n\n listPending() {\n return persistence.list()\n },\n\n rehydrate() {\n for (const req of persistence.list()) {\n if (pending.has(req.id))\n continue\n /*\n * Ghost resolver: the original agent run died with the previous\n * process. Resolving just clears the slot; the persisted row is\n * removed by `resolve` (and `accept-safelist` still persists the\n * safelist entry — useful on resume).\n */\n pending.set(req.id, { request: req, resolve: () => undefined })\n }\n },\n }\n}\n","/**\n * Manual \"compact now\" + the shared compaction body. Owns:\n * - `runCompaction(entry)` — provider call → summary turn → post-compact\n * attachment turns.\n * - The broadcast pair (`compacting:start` / `compacting:end`) that\n * drives client footer indicators.\n *\n * Decoupled from `engine.ts` so the auto-compact policy + the manual\n * \"compact now\" affordance both route through one body.\n */\nimport type { Agent } from '../../../index'\nimport type { SessionStore } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { ProviderKey } from '../../auth'\nimport type { ProviderDescriptor } from '../../providers'\nimport type { HostSignal } from '../signals'\nimport {\n applyCompactSummaryCutoff,\n buildPostCompactAttachments,\n compactConversation,\n selectFilesFromSession,\n summaryToTurn,\n} from '../../../index'\nimport { effectiveInputFromTurn } from '../../../stats'\nimport { BUILTIN_PROVIDERS } from '../../providers'\nimport { compactSummaryEvent } from '../../store'\n\n/** What a compaction did, for the caller's confirmation (the TUI's \"compacted N turns\" banner). */\nexport interface CompactionReport {\n /** Turns absorbed into the summary. */\n replacedCount: number\n /** Turns the prompt-too-long retry had to drop without summarizing (context lost). */\n droppedCount: number\n /** Recently-read files and active skills re-injected after the summary. */\n restoredFiles: number\n restoredSkills: number\n model: string\n inputTokens: number\n outputTokens: number\n /** Estimated context size on the next turn: the summary plus the restored content. */\n effectiveTokens: number\n}\n\nexport interface CompactionEntry {\n sessionId: string\n cwd: string\n agent: Agent\n providerKey: ProviderKey\n providerDescriptor?: ProviderDescriptor\n model: string\n compactionController?: AbortController\n}\n\n/**\n * Run `compactConversation` against the session's current turns, persist\n * the resulting summary as a new turn, and emit a compact-summary stream\n * event. Brackets the in-flight window with `compacting:start` /\n * `compacting:end` signals. Resolves what it did, or `null` when nothing\n * was compacted (no session, cancelled, failed: reported as an event).\n */\nexport async function runCompaction(\n entry: CompactionEntry,\n broadcast: (signal: HostSignal) => void,\n store: SessionStore,\n): Promise<CompactionReport | null> {\n broadcast({ kind: 'compacting:start', sessionId: entry.sessionId })\n\n let ok = false\n let report: CompactionReport | null = null\n entry.compactionController = new AbortController()\n const { signal } = entry.compactionController\n\n try {\n const data = await store.load(entry.sessionId)\n if (!data)\n return null\n\n const turns: SessionTurn[] = data.turns\n\n /*\n * Compaction uses the same provider the agent is running on so the\n * summary lives in the right model's context window. Falls back to\n * anthropic when the entry's provider can't be reconstructed.\n */\n const compactionProvider\n = entry.providerDescriptor?.factory()\n ?? BUILTIN_PROVIDERS[entry.providerKey]?.factory()\n ?? BUILTIN_PROVIDERS.anthropic.factory()\n\n const result = await compactConversation({\n provider: compactionProvider,\n model: entry.model,\n // Compact the WIRE view (same as the SDK's loop-native path): raw\n // turns still contain everything prior markers replaced, so\n // re-compacting raw history re-summarizes the same content forever\n // and the wire never shrinks.\n turns: applyCompactSummaryCutoff(turns),\n scope: 'tail',\n signal,\n })\n const summaryTurn = summaryToTurn({\n summary: result.summary,\n replacesTurnIds: result.summarizedTurnIds,\n usage: result.usage,\n model: entry.model,\n })\n\n /*\n * Post-compact restoration — fold recently-read files + active skills\n * back into the conversation as a synthetic `assistant(tool_calls) →\n * user(tool_results)` pair right after the summary turn. Without this\n * the model loses the read-state cache and the next turn often\n * re-reads everything just trimmed.\n */\n const session = entry.agent.session\n const handle = entry.agent.handle ?? undefined\n const attachments = session\n ? await buildPostCompactAttachments({\n recentFiles: selectFilesFromSession(session, handle?.cwd ?? entry.cwd),\n activeSkills: entry.agent.activeSkills,\n execution: entry.agent.execution,\n handle,\n // Thread the compaction abort signal so a cancel stops the\n // post-compact file reads instead of hanging on FS I/O.\n signal,\n })\n : { turns: [], restoredFiles: 0, restoredSkills: 0, estimatedTokens: 0 }\n\n const compactedTurns = [summaryTurn, ...attachments.turns]\n if (session)\n await session.appendTurns(compactedTurns)\n else\n await store.appendTurns(entry.sessionId, compactedTurns)\n report = {\n replacedCount: result.summarizedTurnIds.length,\n droppedCount: result.droppedDueToPtl.length,\n restoredFiles: attachments.restoredFiles,\n restoredSkills: attachments.restoredSkills,\n model: entry.model,\n inputTokens: effectiveInputFromTurn(result.usage),\n outputTokens: result.usage.output ?? 0,\n effectiveTokens: (result.usage.output ?? 0) + attachments.estimatedTokens,\n }\n\n // Surface the boundary card via the same mapper `eventsFromTurns` uses\n // on reload, so the live card matches the reloaded one byte-for-byte.\n const summaryBlock = summaryTurn.content.find(b => b.type === 'compact-summary')\n if (summaryBlock && summaryBlock.type === 'compact-summary') {\n broadcast({\n kind: 'event',\n sessionId: entry.sessionId,\n event: compactSummaryEvent(summaryBlock, summaryTurn.id),\n })\n }\n ok = true\n }\n catch (err) {\n if (signal.aborted) {\n broadcast({\n kind: 'event',\n sessionId: entry.sessionId,\n event: { kind: 'info', text: 'Auto-compaction cancelled.' },\n })\n }\n else {\n broadcast({\n kind: 'event',\n sessionId: entry.sessionId,\n event: { kind: 'error', text: `Auto-compaction failed: ${(err as Error).message}` },\n })\n }\n }\n finally {\n entry.compactionController = undefined\n broadcast({ kind: 'compacting:end', sessionId: entry.sessionId, ok })\n }\n return report\n}\n","import type { SessionStore } from '../../../session/index'\nimport type { ChatHost } from '../host-api'\nimport type { HostSignal } from '../signals'\nimport type { ActiveRun } from '../types'\nimport { runCompaction } from './run'\n\nexport function createCompactSessionNow({ active, broadcast, store, ensureAgent }: {\n active: Map<string, ActiveRun>\n broadcast: (signal: HostSignal) => void\n store: SessionStore\n ensureAgent: (sessionId: string) => Promise<ActiveRun>\n}): ChatHost['compactSessionNow'] {\n /**\n * Manual \"compact now\" — runs the same compaction the auto-compact\n * policy would fire, but unconditionally. No-op error when the session\n * isn't currently tracked (compaction needs an `Agent`-bound provider).\n */\n return async function compactSessionNow(sessionId) {\n // Any session, not only one a window has run: build its agent when none\n // is live (the summary needs its provider, the restoration its execution).\n const entry = active.get(sessionId) ?? await ensureAgent(sessionId)\n\n // Already in flight (auto-compact racing the click) — share its result.\n if (entry.compacting)\n return entry.compacting\n\n entry.compacting = runCompaction(entry, broadcast, store).finally(() => {\n const live = active.get(sessionId)\n if (live && live.compacting === entry.compacting)\n live.compacting = undefined\n })\n return entry.compacting\n }\n}\n","/**\n * Compaction: the manual \"compact now\" run (`run.ts`) and the hooks that\n * mirror loop-native auto-compaction onto the same broadcast surface.\n */\nimport type { EmitNotice } from '../notices'\nimport type { AgentHookContext } from '../types'\nimport { compactSummaryEvent } from '../../store'\n\nexport { createCompactSessionNow } from './now'\nexport type { CompactionEntry, CompactionReport } from './run'\nexport { runCompaction } from './run'\n\nexport function installAutoCompactionHooks({ sessionId, agent, broadcast }: AgentHookContext, emitNotice: EmitNotice): void {\n /*\n * Auto-compaction is loop-native (`behavior.autoCompact`, injected per\n * run in `sendPrompt`). These hooks mirror the manual-compaction\n * broadcast surface so client footers + boundary cards light up.\n */\n agent.hooks.hook('compact:start', ({ usedFraction }) => {\n broadcast({ kind: 'compacting:start', sessionId })\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'info', text: `🗜 Auto-compacting conversation (used ${Math.round(usedFraction * 100)}% of effective context)…` },\n })\n })\n // Throttled by the loop — a low-rate progress tick, not a stream.\n agent.hooks.hook('compact:progress', ({ estOutputTokens }) => {\n broadcast({ kind: 'compacting:progress', sessionId, estOutputTokens })\n })\n agent.hooks.hook('compact:end', (ctx) => {\n if (ctx.status === 'success') {\n // Surface the boundary card live via the SAME mapper\n // `eventsFromTurns` uses on reload, reading the marker the loop\n // just appended — live and reloaded cards stay identical.\n const markerTurn = [...(agent.session?.turns ?? [])]\n .reverse()\n .find(t => t.content.some(b => b.type === 'compact-summary'))\n const marker = markerTurn?.content.find(b => b.type === 'compact-summary')\n if (markerTurn && marker && marker.type === 'compact-summary')\n broadcast({ kind: 'event', sessionId, event: compactSummaryEvent(marker, markerTurn.id) })\n }\n else {\n // Aborts (run cancelled mid-summary) aren't failures — stay silent.\n const msg = (ctx.error as Error)?.message ?? String(ctx.error)\n if (!/abort/i.test(msg))\n emitNotice({ severity: 'error', label: 'auto-compaction' }, msg)\n }\n broadcast({\n kind: 'compacting:end',\n sessionId,\n ok: ctx.status === 'success',\n // Post-compact context estimate — drops footer gauges everywhere.\n ...(ctx.status === 'success' && typeof ctx.effectiveTokens === 'number'\n ? { effectiveTokens: ctx.effectiveTokens }\n : {}),\n })\n })\n}\n","/**\n * Per-callId stash for the per-edit approval pipeline. Written by\n * `tool:gate` on a `partial` decision and consumed by `tool:transform`\n * to append the canonical `<edit-outcomes>` annotation onto the tool's\n * natural output.\n *\n * Carries the original input + payload so `tool:before` can paint the\n * `tool` stream event with ALL hunks (including denied ones) badged\n * via outcomes — `ctx.input` has been reduced to the approved subset\n * by then, so `extractEditPayload` on the live ctx would miss the\n * denied hunks.\n *\n * Lifecycle: `tool:gate` writes; `tool:transform` reads + clears;\n * `tool:error` clears (no transform on the throw path); `agent:done`\n * clears the whole map so entries whose transform never fired\n * (validation reject / gate throw / retry loops) stay bounded by run\n * lifetime rather than session lifetime.\n */\nimport type { EditOutcome, EditPayload } from '../types'\n\nexport interface PendingAnnotation {\n outcomes: readonly EditOutcome[]\n originalInput: Record<string, unknown>\n originalPayload: EditPayload\n}\n\nexport class EditOutcomeLedger {\n private _entries = new Map<string, PendingAnnotation>()\n\n stash(callId: string, payload: PendingAnnotation): void {\n this._entries.set(callId, payload)\n }\n\n /** Read + remove the entry for `callId`. `null` when no stash exists. */\n drain(callId: string): PendingAnnotation | null {\n const entry = this._entries.get(callId)\n if (!entry)\n return null\n this._entries.delete(callId)\n return entry\n }\n\n /** Non-removing peek — used by `tool:before` to paint events without consuming the stash. */\n peek(callId: string): PendingAnnotation | null {\n return this._entries.get(callId) ?? null\n }\n\n /** Drop entry without reading — used by `tool:error` (no transform on throw path). */\n discard(callId: string): void {\n this._entries.delete(callId)\n }\n\n /** Clear every entry — called on `agent:done` and session disposal. */\n clear(): void {\n this._entries.clear()\n }\n}\n","/**\n * Per-server MCP tool-catalog cache.\n *\n * Stores the raw `tools/list` schemas zidane saw on the most recent\n * successful bootstrap of each server, so the TUI's MCP settings panel\n * (and any other host UI) can display every advertised tool — name,\n * description, input-schema — without forcing a fresh bootstrap on\n * every open. The cache also survives across launches so the very\n * first paint of the settings panel after a process restart isn't\n * blank.\n *\n * Wired via the framework's `mcp:tools:list` hook (see\n * `AgentHooks['mcp:tools:list']`). Hosts call\n * {@link subscribeMcpToolsCache} once per agent and the subscriber\n * persists every successful bootstrap to disk; the settings UI reads\n * via {@link loadMcpToolsCache}.\n *\n * Atomic write + best-effort read: a corrupt cache file is treated as\n * empty (the next bootstrap repopulates it). The cache is purely an\n * accelerator — losing it never changes the agent's runtime behavior.\n *\n * Sits in `chat/` not `mcp/` because it depends on a per-host data\n * directory (`<userDir>/mcp-tools-cache.json`) and pairs with the\n * settings + UI surfaces that consume it. Renderer-agnostic — no React,\n * no OpenTUI — so a future GUI host can subscribe the same way.\n */\n\nimport type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js'\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { McpServerConfig, McpToolSchema } from '../mcp'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { writeFileAtomic } from '../atomic-write'\nimport { errorMessage } from '../errors'\nimport { connectMcpServers } from '../mcp'\n\n/**\n * Disk filename. Versioned so a future schema change (e.g. adding\n * provenance / TTL) can ship a parallel `v2` file without colliding.\n */\nconst CACHE_FILENAME = 'mcp-tools-cache.json'\n\n/**\n * One server's cached entry.\n *\n * - `tools` — verbatim copy of the raw `tools/list` payload (pre any\n * `disabledTools` / `toolFilter` filtering). The settings UI ranges\n * over this to render the full server surface; the host applies its\n * own deny-list on top via `Settings.disabledMcpTools` (see\n * `buildMcpServers` in `mcps-discovery.ts`).\n * - `updatedAt` — ms-epoch of the bootstrap that populated this entry.\n * Useful for \"last seen N hours ago\" affordances and for cache\n * eviction policies a host might layer on later.\n * - `transport` — informational only; lets the UI distinguish a stdio\n * server's tool list from an http server with the same name in\n * \"stale catalog\" warnings.\n */\nexport interface CachedMcpToolList {\n tools: McpToolSchema[]\n updatedAt: number\n transport: 'stdio' | 'sse' | 'streamable-http'\n}\n\n/**\n * `serverName → catalog`. Map shape on disk so adding / removing\n * servers is an O(1) JSON edit instead of an array rewrite.\n */\nexport type McpToolsCache = Record<string, CachedMcpToolList>\n\n/**\n * Resolve the on-disk cache path under a host's data directory. Exposed\n * for tests + advanced hosts that want to inspect / delete the file\n * without re-implementing the path convention.\n */\nexport function mcpToolsCachePath(dataDir: string): string {\n return resolve(dataDir, CACHE_FILENAME)\n}\n\n/**\n * Best-effort cache read. Returns `{}` when the file is missing, when\n * JSON.parse rejects, or when the top-level shape isn't a plain object —\n * a corrupt cache must never crash the host on startup.\n *\n * Per-entry shape validation is light (presence of an array `tools`):\n * deeper validation would lock the cache to a single zidane version,\n * which is the opposite of what a long-lived cache wants. Entries that\n * survive the light check feed back through `McpToolSchema`'s `unknown`\n * `inputSchema` so downstream readers stay tolerant of upstream churn.\n */\nexport function loadMcpToolsCache(opts: { dataDir: string }): McpToolsCache {\n const path = mcpToolsCachePath(opts.dataDir)\n if (!existsSync(path))\n return {}\n try {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw) as unknown\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))\n return {}\n const out: McpToolsCache = {}\n for (const [name, entry] of Object.entries(parsed as Record<string, unknown>)) {\n if (isCachedEntry(entry))\n out[name] = entry\n }\n return out\n }\n catch {\n return {}\n }\n}\n\n/**\n * Atomic full-cache write. Used by {@link subscribeMcpToolsCache} after\n * each upsert. Failures bubble up as the underlying `writeFileAtomic`\n * error — the caller logs under `ZIDANE_DEBUG` and swallows.\n */\nexport function saveMcpToolsCache(opts: { dataDir: string, cache: McpToolsCache }): void {\n writeFileAtomic(\n mcpToolsCachePath(opts.dataDir),\n `${JSON.stringify(opts.cache, null, 2)}\\n`,\n { ensureDir: true },\n )\n}\n\n/**\n * Drop entries for one or more servers, or wipe the cache when no\n * server is named. Idempotent — entries that aren't present are\n * silently skipped. Returns the resulting cache so callers can refresh\n * any in-memory mirror without re-reading from disk.\n *\n * Intended for a future \"rescan server\" affordance in the settings UI\n * (clear → trigger a real bootstrap → cache repopulates on the\n * `mcp:tools:list` hook).\n */\nexport function clearMcpToolsCache(opts: { dataDir: string, serverNames?: readonly string[] }): McpToolsCache {\n const current = loadMcpToolsCache(opts)\n if (!opts.serverNames) {\n saveMcpToolsCache({ dataDir: opts.dataDir, cache: {} })\n return {}\n }\n const next: McpToolsCache = { ...current }\n for (const name of opts.serverNames)\n delete next[name]\n saveMcpToolsCache({ dataDir: opts.dataDir, cache: next })\n return next\n}\n\n/**\n * Subscribe to `mcp:tools:list` and persist every successful bootstrap\n * into the on-disk cache. Returns an unsubscribe function — call it\n * during agent teardown so a long-lived host (Settings modal that\n * outlives one agent) doesn't accumulate stale subscribers.\n *\n * Each write loads the current cache, upserts the named entry, then\n * atomic-writes the full file. The read-modify-write is safe under\n * Node single-threaded event loop semantics — concurrent bootstraps in\n * the same process serialize through the hook bus.\n *\n * Optional `onChange` callback fires synchronously after every\n * successful disk write with the entry that was just upserted. Lets a\n * React host trigger a state refresh without polling the disk.\n *\n * Write failures are swallowed (logged under `ZIDANE_DEBUG`): the cache\n * is an accelerator, not a correctness boundary. If the disk is full\n * the agent run still works — the settings UI just shows stale data\n * until the next successful write.\n */\nexport function subscribeMcpToolsCache(\n hooks: Hookable<AgentHooks>,\n opts: {\n dataDir: string\n onChange?: (entry: { name: string } & CachedMcpToolList) => void\n },\n): () => void {\n const unsubscribe = hooks.hook('mcp:tools:list', (ctx) => {\n const entry: CachedMcpToolList = {\n tools: [...ctx.tools],\n updatedAt: Date.now(),\n transport: ctx.transport,\n }\n try {\n const current = loadMcpToolsCache({ dataDir: opts.dataDir })\n const next: McpToolsCache = { ...current, [ctx.name]: entry }\n saveMcpToolsCache({ dataDir: opts.dataDir, cache: next })\n opts.onChange?.({ name: ctx.name, ...entry })\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] mcp-tools-cache write failed for \"${ctx.name}\": ${errorMessage(err)}\\n`)\n }\n })\n return unsubscribe\n}\n\n/**\n * Force-refresh the on-disk tools cache by opening a transient MCP\n * connection to every server, capturing the `mcp:tools:list` hook on\n * the way through, and closing the connection immediately. The\n * underlying `connectMcpServers` runs every server's bootstrap in\n * parallel, so the wall-clock cost collapses to the slowest server.\n *\n * Two design choices worth noting:\n *\n * - **Shared hook bus.** The caller passes the SAME `Hookable`\n * instance that has the cache subscriber wired (typically\n * `agent.hooks` after `subscribeMcpToolsCache(agent.hooks, …)`\n * ran). That way `mcp:tools:list` fires on the bus the\n * subscriber is listening to and the cache lands on disk\n * without a separate write path.\n * - **Transient, NOT shared with the live agent.** The connection\n * opened here is closed immediately. The agent's own MCP\n * connection is untouched, so a refresh never disrupts an\n * in-flight tool call.\n *\n * The function intentionally swallows per-server failures (they're\n * already surfaced via `mcp:bootstrap:end ok: false` for any host\n * that wired the listener). The Promise resolves once every server's\n * bootstrap settles, success or otherwise.\n */\nexport async function refreshMcpToolsCatalog(opts: {\n servers: readonly McpServerConfig[]\n hooks: Hookable<AgentHooks>\n /**\n * Same OAuth-provider factory the agent's bootstrap uses. Required\n * for OAuth-tagged servers — without it those servers fire\n * `mcp:auth:required` and skip, and their tools never refresh.\n */\n buildAuthProvider?: (config: McpServerConfig) => OAuthClientProvider | undefined\n}): Promise<void> {\n if (opts.servers.length === 0)\n return\n const connection = await connectMcpServers(\n opts.servers as McpServerConfig[],\n undefined,\n opts.hooks,\n opts.buildAuthProvider ? { buildAuthProvider: opts.buildAuthProvider } : undefined,\n )\n // `mcp:tools:list` already fired during the bootstrap (see\n // `src/mcp/index.ts:bootstrapServer`) so the cache subscriber has\n // already taken its snapshot. Close fast — leaving the transient\n // connection alive would double the MCP socket count for no gain.\n await connection.close().catch((err) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] mcp-tools-cache transient close failed: ${errorMessage(err)}\\n`)\n })\n}\n\n/**\n * Type-narrowing check used by {@link loadMcpToolsCache}. Kept private\n * — callers that want a richer validation surface should layer it on\n * top of the loose disk shape rather than tightening this predicate.\n */\nfunction isCachedEntry(value: unknown): value is CachedMcpToolList {\n if (!value || typeof value !== 'object')\n return false\n const entry = value as Partial<CachedMcpToolList>\n if (!Array.isArray(entry.tools))\n return false\n if (typeof entry.updatedAt !== 'number' || !Number.isFinite(entry.updatedAt))\n return false\n if (entry.transport !== 'stdio' && entry.transport !== 'sse' && entry.transport !== 'streamable-http')\n return false\n // Per-tool shape is intentionally NOT validated — the MCP SDK's tool\n // schema surface is open-ended (`inputSchema: unknown`) and we want\n // the cache to keep working when an upstream tool sprouts a new\n // field zidane doesn't model yet. Downstream readers handle unknowns.\n return true\n}\n","/**\n * Agent Plugins discovery for the chat layer.\n *\n * Walks the same four project + user roots every other zidane discovery\n * surface uses, loads each immediate child as an Agent Plugin, and folds the\n * user's enabled-toggle list into the contributions the agent picks up at\n * construction time.\n *\n * Pattern mirrors `skills-discovery.ts` / `mcps-discovery.ts`. The strict\n * loading itself lives in `../plugins` — this module owns only the \"where to\n * look\" and \"which ones did the user enable\" halves.\n *\n * Failure model, matching how the Extensions tab already treats a broken\n * extension: a plugin that fails to load is still RETURNED, carrying\n * `ok: false` and its diagnostics, so the settings list can show it and say\n * why. `errors` is reserved for problems that produced no plugin at all\n * (an unreadable root directory) — otherwise the same failure would be\n * reported twice in two different places.\n */\n\nimport type { McpServerConfig } from '../mcp'\nimport type { LoadedPlugin } from '../plugins'\nimport type { SkillConfig } from '../skills'\nimport type { DiscoveryError } from './mcps-discovery'\nimport type { ProjectUserPath } from './project-user-paths'\nimport { existsSync } from 'node:fs'\nimport { readdir, stat } from 'node:fs/promises'\nimport { basename, delimiter, join } from 'node:path'\nimport { defaultPluginDataRoot, loadAgentPlugin } from '../plugins'\nimport { projectUserPaths } from './project-user-paths'\n\n/** Subdirectory each search root is probed for. */\nconst PLUGINS_SUBPATH = 'plugins'\n\n/** One plugin found on disk, loaded (successfully or not). */\nexport interface DiscoveredPlugin {\n /**\n * Identity for dedup + the enabled allowlist. The manifest's `name` when\n * the plugin loaded; the directory basename when it didn't, so a rejected\n * plugin still has something stable to key a row and a toggle on.\n */\n name: string\n /** Load result. Check `ok` before trusting `manifest`. */\n plugin: LoadedPlugin\n /** Which search root it came from. */\n source: 'project' | 'user'\n /** Plugin root directory, as discovered. */\n path: string\n}\n\n/**\n * Resolve the plugin search roots. First-found wins on name collision;\n * earlier entries take precedence.\n *\n * Search order — see {@link projectUserPaths}:\n *\n * 1. `{project}/.agents/plugins`\n * 2. `{project}/.zidane/plugins`\n * 3. `~/.agents/plugins`\n * 4. `~/.zidane/plugins`\n *\n * Non-existent paths are returned; the walk skips them.\n *\n * Unlike skills and MCP servers there is no foreign-agent or Ruler variant:\n * Agent Plugins is a vendor-neutral format, so `.agents/plugins` IS the\n * cross-tool location. Nothing to import from a competitor's directory.\n */\nexport function defaultPluginScanPaths(opts: {\n cwd?: string\n home?: string\n prefix?: string\n} = {}): ProjectUserPath[] {\n return projectUserPaths({ subPath: PLUGINS_SUBPATH, ...opts })\n}\n\n/**\n * Parse a platform-delimited list of additional plugin scan roots. Mirrors\n * `parseExtensionScanPathEnv` in `../extensions/discovery`:\n *\n * ZIDANE_PLUGIN_DIRS=/repo/plugins bun run tui\n *\n * Each path is a scan ROOT whose immediate children are plugin directories\n * (`<root>/<name>/plugin.json`), not a single plugin directory.\n *\n * This exists because the four default roots are all dot-directories, and\n * `.zidane/` is gitignored — so a repo has nowhere TRACKED to keep example or\n * first-party plugins for local dogfooding. Extensions solved the same\n * problem the same way.\n */\nexport function parsePluginScanPathEnv(\n value: string | undefined = process.env.ZIDANE_PLUGIN_DIRS,\n): string[] {\n if (!value)\n return []\n return value.split(delimiter).map(p => p.trim()).filter(Boolean)\n}\n\n/**\n * Load every plugin reachable from the default search roots.\n *\n * Each immediate child directory of a root is one plugin — the same\n * depth-1 rule the spec applies inside `skills/`. A child that isn't a\n * directory, or that holds no `plugin.json`, is silently skipped: dropping a\n * README next to your plugins is not an error.\n *\n * Dedup is by plugin NAME, not directory name, because the manifest owns\n * identity — two directories called `tools/` shipping different plugins are\n * two plugins, and one plugin vendored at two scopes is one plugin.\n */\nexport async function discoverProjectPlugins(opts: {\n cwd?: string\n home?: string\n prefix?: string\n /**\n * Extra scan roots appended AFTER the four defaults — typically from\n * {@link parsePluginScanPathEnv}. Ordered last so a real project or user\n * plugin always wins a name collision against a dev/host-provided root.\n *\n * Scoped `'project'`: they're supplied by whoever launched the process, the\n * same trust level as a plugin sitting in the working tree.\n */\n extraRoots?: readonly string[]\n signal?: AbortSignal\n} = {}): Promise<{ plugins: DiscoveredPlugin[], errors: DiscoveryError[] }> {\n const roots = [\n ...defaultPluginScanPaths(opts),\n ...(opts.extraRoots ?? []).map(path => ({ path, source: 'project' as const })),\n ].filter(p => existsSync(p.path))\n const dataRoot = defaultPluginDataRoot({\n ...(opts.prefix !== undefined ? { prefix: opts.prefix } : {}),\n ...(opts.home !== undefined ? { home: opts.home } : {}),\n })\n const plugins: DiscoveredPlugin[] = []\n const errors: DiscoveryError[] = []\n const seen = new Set<string>()\n\n for (const root of roots) {\n if (opts.signal?.aborted)\n break\n\n let entries: string[]\n try {\n entries = await readdir(root.path)\n }\n catch (err) {\n errors.push({\n path: root.path,\n source: root.source,\n message: `Could not read plugin directory: ${err instanceof Error ? err.message : String(err)}`,\n })\n continue\n }\n\n // Sorted so the catalog order is deterministic rather than inode-order.\n for (const entry of entries.sort()) {\n if (opts.signal?.aborted)\n break\n const dir = join(root.path, entry)\n try {\n // `stat`, not `lstat` — a SYMLINKED plugin directory is followed here,\n // where the extension scanner deliberately refuses one\n // (`extensions/discovery.ts`: \"Do not follow symlinks out of the\n // configured scan roots\"). The asymmetry is intentional, not an\n // oversight:\n //\n // An extension's entry file is IMPORTED — arbitrary code runs the\n // moment it's found, so the only defence is never resolving outside\n // the configured root. A plugin executes nothing at discovery time,\n // and `loadAgentPlugin` independently re-establishes a realpath\n // boundary from wherever the directory actually lives, so every\n // package file it goes on to read is contained relative to the\n // RESOLVED root. Following the link costs nothing there and supports\n // the monorepo pattern of linking a workspace package into\n // `.agents/plugins/`.\n if (!(await stat(dir)).isDirectory())\n continue\n }\n catch {\n continue // raced away between readdir and stat\n }\n\n // `dataRoot` is threaded explicitly: `loadAgentPlugin`'s fallback calls\n // `defaultPluginDataRoot()` with no options, and `resolveStorageDirs`\n // defaults `prefix` to `.zidane` rather than reading `ZIDANE_PREFIX`\n // itself. Without this a custom prefix would scan `{project}/.acme/\n // plugins` while writing plugin data to `~/.zidane/plugin-data/`.\n const loaded = await loadAgentPlugin(dir, {\n source: root.source,\n dataRoot,\n })\n // A directory with no manifest isn't a plugin at all — that's the one\n // rejection worth staying quiet about, since bundling docs or a\n // scratch folder alongside plugins is legal.\n if (!loaded.ok && loaded.diagnostics.some(d => d.code === 'manifest-missing'))\n continue\n\n const name = loaded.manifest?.name ?? basename(dir)\n if (seen.has(name))\n continue\n seen.add(name)\n plugins.push({ name, plugin: loaded, source: root.source, path: dir })\n }\n }\n\n return { plugins, errors }\n}\n\n/**\n * Map the user's enabled-plugin list onto the contributions a host merges\n * into the agent.\n *\n * Conventions match `enabledSkills` / `enabledMcps`:\n * - `undefined` → every discovered plugin is enabled (default)\n * - `[]` → all off\n * - `[names]` → allowlist\n *\n * A plugin that failed to load contributes nothing regardless of the\n * allowlist — `ok: false` means components were never discovered.\n */\nexport function buildPluginContributions(opts: {\n discovered: readonly DiscoveredPlugin[]\n enabled?: readonly string[]\n}): { skills: SkillConfig[], mcpServers: McpServerConfig[] } {\n const allow = opts.enabled === undefined ? null : new Set(opts.enabled)\n const skills: SkillConfig[] = []\n const mcpServers: McpServerConfig[] = []\n\n for (const entry of opts.discovered) {\n if (!entry.plugin.ok)\n continue\n if (allow !== null && !allow.has(entry.name))\n continue\n skills.push(...entry.plugin.skills)\n mcpServers.push(...entry.plugin.mcpServers)\n }\n\n return { skills, mcpServers }\n}\n","/**\n * Working-directory resolution for sessions.\n *\n * Directory-less (\"pure chat\") sessions carry neither a `metadata.cwd`\n * (the folder the user picked in the GUI) nor a `projectRoot` (its git\n * root). Their tools still need a real process cwd — we anchor at the\n * user's HOME directory, mirroring the TUI's semantics when zidane is\n * launched from `~`: cwd = home, git-less scope, user-level config and\n * skills only.\n *\n * Explicitly NOT `process.cwd()`: in a packaged Electron app that points\n * at the bundle's resources directory — somewhere the user never chose\n * and tools should never operate in.\n */\nimport { homedir } from 'node:os'\n\n/** Process cwd used for sessions with no folder binding. */\nexport function folderlessCwd(): string {\n return homedir()\n}\n\n/**\n * Effective process cwd for a persisted session row: the GUI-recorded\n * `metadata.cwd` when present, else the canonical `projectRoot`\n * (TUI-created sessions), else the directory-less HOME anchor. Empty\n * strings count as unset — forks of directory-less sessions persist\n * `cwd: ''`.\n */\nexport function resolveSessionCwd(row: {\n metadata?: Record<string, unknown> | undefined\n projectRoot?: string | undefined\n}): string {\n const recorded = typeof row.metadata?.cwd === 'string' ? row.metadata.cwd : undefined\n\n return recorded || row.projectRoot || folderlessCwd()\n}\n\n/**\n * Map a renderer-supplied scope cwd to the directory the main process\n * should actually operate in. The renderer signals \"no folder\" with an\n * empty string (`SidebarSession.cwd` is `''` for directory-less\n * sessions); catalogs (@-files, skills, commands, extensions, MCPs)\n * then root at HOME, matching what the TUI offers when run from `~`.\n */\nexport function scopeCwd(cwd: string): string {\n return cwd || folderlessCwd()\n}\n","import type { Provider } from '../../providers'\nimport type { SessionData } from '../../session/index'\nimport type { ProviderKey } from '../auth'\nimport type { PreviewResult } from '../edit-diff'\n/**\n * Small helpers shared by the host engine's gate + preview pipeline.\n */\nimport type { EditPayload } from '../types'\nimport type { ChatHostEnvironment } from './environment'\nimport type { SerializedPreview } from './signals'\nimport { readFile } from 'node:fs/promises'\nimport { extractEditPayload } from '../edit-diff'\n\nexport { isThinkingLevel } from '../../types'\n\n/**\n * While a run is active, re-assert the persisted `running` marker on this\n * cadence (targeted single-column UPDATE — never a full-document save, so\n * it can't clobber concurrent turn appends). Long quiet tool calls (a\n * 10-minute build is routine) produce no turn persistence, and without\n * the beat the marker would look stale and another process would start a\n * second run on the session. Well under `STALE_RUN_MARKER_MS`.\n */\nexport const RUN_HEARTBEAT_MS = 60 * 1000\n\n/**\n * Cross-process run heartbeat, shared by prompt runs (`sendPrompt`) and\n * `/` command dispatches (one heartbeat spanning the whole command, its\n * sub-runs and spawn batches included). Keeps the persisted `running`\n * marker fresh through long quiet tool calls — see\n * {@link RUN_HEARTBEAT_MS}.\n *\n * `isRunning` is checked at beat time, but the write itself is async — a\n * beat launched JUST before run end can land after the loop settles the\n * final status, leaving a fresh 'running' marker that every process's\n * guard then refuses for 5 minutes. `end()` therefore chains the settle\n * write behind the last in-flight beat: after it lands, the loop's\n * settled status is re-asserted so a late 'running' write can never be\n * final. Callers must snapshot `settledStatus` SYNCHRONOUSLY at run end\n * (reading status off an already-destroyed agent would silently skip the\n * settle write).\n *\n * Like the cross-process guard, the heartbeat (and its straggler settle)\n * exists solely for daemon/multi-process coexistence — gated on the same\n * `useDaemon` read, so with IPC disabled this is a no-op end to end and\n * the loop's own status writes are the only marker writes.\n */\nexport function startRunHeartbeat(opts: {\n env: ChatHostEnvironment\n sessionId: string\n isRunning: () => boolean\n /**\n * Write the marker now instead of at the first interval tick. Command\n * dispatches need it: unlike a prompt run, no loop persistence marks the\n * session 'running' when a command starts.\n */\n immediate?: boolean\n}): {\n /**\n * Re-assert 'running' now, chained behind any in-flight write. A command\n * calls it after each sub-run / spawn batch, whose loop just settled the\n * marker to a terminal status while the command itself continues.\n */\n beat: () => void\n end: (settledStatus: SessionData['status'] | undefined) => Promise<void>\n} {\n const enabled = opts.env.multiProcess === true || opts.env.readSettings().useDaemon === true\n let lastBeat: Promise<unknown> = Promise.resolve()\n let beatInFlight = false\n let ending: Promise<void> | undefined\n const beat = (): void => {\n const write = (): Promise<unknown> => opts.env.store.updateStatus(opts.sessionId, 'running')\n // Chain behind an in-flight write (explicit `beat()` can overlap one) so\n // writes land in order; otherwise start now. Either way the latest write\n // stays reachable by end().\n // The executor runs synchronously: the write starts now, and a store that\n // throws synchronously still lands in the catch below.\n const started = beatInFlight ? lastBeat.then(write) : new Promise(resolve => resolve(write()))\n beatInFlight = true\n const current = started\n .catch(() => undefined)\n .finally(() => {\n if (lastBeat === current)\n beatInFlight = false\n })\n lastBeat = current\n }\n if (enabled && opts.immediate)\n beat()\n const timer = enabled\n ? setInterval(() => {\n if (!ending && !beatInFlight && opts.isRunning())\n beat()\n }, RUN_HEARTBEAT_MS)\n : undefined\n return {\n beat() {\n if (enabled && !ending)\n beat()\n },\n end(settledStatus) {\n if (ending)\n return ending\n if (timer !== undefined)\n clearInterval(timer)\n ending = lastBeat\n .then(async () => {\n if (enabled && settledStatus && settledStatus !== 'running')\n await opts.env.store.updateStatus(opts.sessionId, settledStatus)\n })\n .catch(() => undefined)\n return ending\n },\n }\n}\n\n/**\n * Optional dedicated compaction summarizer from the `compactionModel`\n * setting (`\"providerKey/modelId\"`, split on the FIRST slash only —\n * model ids may contain slashes, provider keys never do). `undefined`\n * for unset / malformed / same-as-main / unbuildable provider: silent\n * fallback to the main model is the designed behavior. Shared by the\n * engine's prompt runs and the command module's sub-runs so both resolve\n * compaction identically.\n */\nexport function resolveCompactionSummarizer(\n raw: string | undefined,\n buildProvider: (key: ProviderKey) => Provider,\n main: { providerKey: ProviderKey, model: string },\n): { provider: Provider, model: string } | undefined {\n if (!raw)\n return undefined\n const slash = raw.indexOf('/')\n if (slash <= 0 || slash === raw.length - 1)\n return undefined\n const providerKey = raw.slice(0, slash) as ProviderKey\n const model = raw.slice(slash + 1)\n if (providerKey === main.providerKey && model === main.model)\n return undefined\n try {\n return { provider: buildProvider(providerKey), model }\n }\n catch {\n return undefined\n }\n}\n\nexport async function readFileSafe(path: string): Promise<string> {\n try {\n return await readFile(path, 'utf8')\n }\n catch {\n return ''\n }\n}\n\n/** Resolve a workspace-relative path against the session's `cwd`. Absolute paths pass through. */\nexport function resolveCwdPath(cwd: string, p: string): string {\n if (p.startsWith('/'))\n return p\n return `${cwd.replace(/\\/$/, '')}/${p.replace(/^\\//, '')}`\n}\n\n/**\n * Gate-time `extractEditPayload` wrapper — same as `tool:before` but\n * without the prior-content second pass for `write_file`. The gate\n * only needs the payload shape (hunk count, paths) to drive the\n * approval surface; the diff resolver works against the freshly-read\n * `priorContent` passed to `previewEditPayload` directly.\n */\nexport function extractEditPayloadForGate(name: string, input: Record<string, unknown>): EditPayload | undefined {\n if (name === 'edit' || name === 'multi_edit')\n return extractEditPayload(name, input)\n if (name === 'write_file')\n return extractEditPayload(name, input, '')\n return undefined\n}\n\n/**\n * Strip readonly markers so the `PreviewResult` survives structured-clone\n * and JSON transports. Field-for-field copy — the resolver output is\n * already JSON-safe primitives.\n */\nexport function serializePreview(preview: PreviewResult): SerializedPreview {\n return {\n diffText: preview.diffText,\n perHunkDiff: [...preview.perHunkDiff],\n resolution: preview.resolution.map(r => ({ ...r })),\n resolvedPayload: {\n ...preview.resolvedPayload,\n hunks: preview.resolvedPayload.hunks.map(h => ({ ...h })),\n ...(preview.resolvedPayload.outcomes\n ? { outcomes: preview.resolvedPayload.outcomes.map(o => ({ ...o })) }\n : {}),\n },\n }\n}\n","/**\n * The per-call approval gate (parent, child and MCP tool gates): safe-mode\n * and safelist checks, the approval request with its edit diff preview, the\n * partial-accept reduction stashed in the edit ledger, and the synthetic\n * transcript pair for a blocked edit. Plus the per-session \"accept for this\n * session\" safelists it consults.\n */\nimport type { ExecutionContext, ExecutionHandle } from '../../../contexts/types'\nimport type { StreamEvent } from '../../types'\nimport type { ApprovalHub } from '../approvals'\nimport type { EditOutcomeLedger } from '../edit-outcome-ledger'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { ApprovalOriginator } from '../signals'\nimport type { TerminalManager } from '../terminal'\nimport type { AgentHookContext } from '../types'\nimport { posix } from 'node:path'\nimport { buildEditOutcomesAnnotation, resolveApprovalForPayload } from '../../edit-approval'\nimport { previewEditPayload } from '../../edit-diff'\nimport { isOnSafelist, suggestSafelistEntries } from '../../safe-mode'\nimport { toolCallPreview } from '../../store'\nimport { extractEditPayloadForGate, readFileSafe, resolveCwdPath, serializePreview } from '../helpers'\n\nexport function createSessionSafelists(): { sessionSafelists: Map<string, Set<string>>, sessionSafelistFor: (sessionId: string) => Set<string> } {\n /**\n * \"Accept for this session\" safelist entries, per session. Kept here, not\n * on the agent: agents are rebuilt for ordinary reasons (a model pick, a\n * settings change, an MCP login) and the user must not approve the same\n * call again. Forgotten when the session is deleted.\n */\n const sessionSafelists = new Map<string, Set<string>>()\n function sessionSafelistFor(sessionId: string): Set<string> {\n let safelist = sessionSafelists.get(sessionId)\n if (!safelist) {\n safelist = new Set()\n sessionSafelists.set(sessionId, safelist)\n }\n return safelist\n }\n return { sessionSafelists, sessionSafelistFor }\n}\n\nexport function createSessionFileReader({ cwd, promptCwd, sessionExecutionHandle }: {\n cwd: string\n promptCwd: string | undefined\n sessionExecutionHandle: { context: ExecutionContext, handle: () => Promise<ExecutionHandle> }\n}): (path: string) => Promise<string> {\n /*\n * A file as the agent sees it — for approval diffs. When commands run\n * somewhere else (`promptCwd`: a sandbox's clone), the file lives there,\n * not in the host checkout it was cloned from.\n */\n const readSessionFile = async (path: string): Promise<string> => {\n if (!promptCwd)\n return readFileSafe(resolveCwdPath(cwd, path))\n try {\n return await sessionExecutionHandle.context.readFile(await sessionExecutionHandle.handle(), posix.isAbsolute(path) ? path : posix.join(promptCwd, path))\n }\n catch {\n return ''\n }\n }\n return readSessionFile\n}\n\nexport function installApprovalGate(\n { sessionId, agent, broadcast }: AgentHookContext,\n input: {\n env: Pick<ChatHostEnvironment, 'readSettings'>\n approvals: ApprovalHub\n terminals: TerminalManager\n cwd: string\n readSessionFile: (path: string) => Promise<string>\n sessionSafelist: Set<string>\n ledger: EditOutcomeLedger\n manuallyEmittedGateBlocks: Set<string>\n },\n): void {\n const { env, approvals, terminals, cwd, readSessionFile, sessionSafelist, ledger, manuallyEmittedGateBlocks } = input\n /**\n * Unified gate handler — registered on both the parent and child tool\n * gates so subagent-issued edit approvals route through the same\n * surface. The `originator` carries the child label to clients.\n *\n * On a `partial` decision we (i) reduce `ctx.input.edits` to the\n * approved subset so the tool runs atomically over a smaller batch,\n * (ii) stash the outcomes keyed by `callId` for `tool:transform`. On\n * `deny` / all-denied partial we set `ctx.block = true` and emit the\n * synthetic transcript pair so clients still see a `tool` +\n * `tool-result` row.\n */\n const applyGate = async (\n ctx: {\n block: boolean\n reason: string\n name: string\n input: Record<string, unknown>\n callId: string\n turnId?: string\n childId?: string\n depth?: number\n },\n originator: ApprovalOriginator,\n ): Promise<void> => {\n if (ctx.block) {\n // upstream already refused (e.g. skill allowlist); nothing to do\n return\n }\n\n const input = ctx.input\n\n /*\n * `safeMode` is read at gate-evaluation time (not agent build time)\n * so flipping it mid-session takes effect on the next tool call.\n */\n // Typing into a terminal the user opened always asks: they may be mid-command.\n const alwaysAsk = ctx.name === 'terminal_write' && terminals.ownerOf(String(input.id)) !== 'agent'\n if (env.readSettings().safeMode === false || (!alwaysAsk && isOnSafelist([...sessionSafelist], ctx.name, input)))\n return\n\n const payload = extractEditPayloadForGate(ctx.name, input)\n\n let priorContent: string | null = null\n let preview: ReturnType<typeof serializePreview> | undefined\n\n if (payload) {\n const path = typeof input.path === 'string' ? input.path : undefined\n priorContent = path ? await readSessionFile(path) : ''\n\n try {\n /*\n * `contextLines: 3` matches the canonical TUI default — clients\n * compute their own tight per-hunk diffs; we only need the\n * resolver pass to populate `resolution` / `resolvedPayload`.\n */\n const result = previewEditPayload(payload, priorContent, 3)\n preview = serializePreview(result)\n }\n catch {\n // resolver fell over — clients fall back to the JSON view\n }\n }\n\n const decision = await approvals.request({\n sessionId,\n cwd,\n tool: ctx.name,\n input,\n ...(payload ? { edit: payload, priorContent } : {}),\n ...(preview ? { preview } : {}),\n ...(originator.kind === 'child' ? { originator } : {}),\n ...(alwaysAsk ? { alwaysAsk } : {}),\n })\n\n if (decision === 'accept-session' && !alwaysAsk) {\n for (const entry of suggestSafelistEntries(ctx.name, input))\n sessionSafelist.add(entry)\n }\n\n if (payload) {\n const resolved = resolveApprovalForPayload(decision, payload)\n\n if (resolved.shouldBlock) {\n ctx.block = true\n ctx.reason = decision === 'deny' ? 'User denied this tool call' : 'All edits denied'\n\n /*\n * Live transcript bookkeeping for the blocked call. Without this,\n * `tool:before` never fires and clients miss the row entirely\n * until reload. Mirror what canonical eventsFromTurns would emit.\n */\n const ownership\n = ctx.childId !== undefined && ctx.depth !== undefined ? { childId: ctx.childId, depth: ctx.depth } : undefined\n\n const syntheticEdit = resolved.syntheticEvent ?? { ...payload, outcomes: resolved.outcomes }\n\n const toolEvent: StreamEvent = {\n kind: 'tool',\n text: toolCallPreview(ctx.name, input),\n tool: ctx.name,\n callId: ctx.callId,\n input,\n edit: syntheticEdit,\n ...(ctx.turnId ? { turnId: ctx.turnId } : {}),\n ...(ownership ?? {}),\n }\n broadcast({ kind: 'event', sessionId, event: toolEvent })\n\n const annotation = buildEditOutcomesAnnotation(resolved.outcomes)\n\n const resultEvent: StreamEvent = {\n kind: 'tool-result',\n text: `Blocked: ${ctx.reason}\\n\\n${annotation}`,\n tool: ctx.name,\n callId: ctx.callId,\n ...(ctx.turnId ? { turnId: ctx.turnId } : {}),\n ...(ownership ?? {}),\n }\n broadcast({ kind: 'event', sessionId, event: resultEvent })\n manuallyEmittedGateBlocks.add(ctx.callId)\n\n return\n }\n\n /*\n * Partial-accept path: reduce `ctx.input.edits` to the approved\n * subset so `multi_edit` runs atomically over only those edits, and\n * stash outcomes + original input/payload for `tool:before` /\n * `tool:transform`. Full accepts fall through unchanged.\n */\n if (typeof decision === 'object' && decision.kind === 'partial' && Array.isArray(input.edits)) {\n const reducedEdits = (input.edits as unknown[]).filter((_, i) => decision.mask[i] === true)\n ctx.input = { ...input, edits: reducedEdits }\n ledger.stash(ctx.callId, {\n outcomes: resolved.outcomes,\n originalInput: input,\n originalPayload: payload,\n })\n }\n\n return\n }\n\n /*\n * Non-edit tools: `accept-*` pass through; `deny` blocks; `partial`\n * shouldn't occur but is treated as deny defensively.\n */\n if (decision === 'deny' || (typeof decision === 'object' && decision.kind === 'partial')) {\n ctx.block = true\n ctx.reason = 'User denied this tool call'\n }\n }\n\n agent.hooks.hook('tool:gate', ctx => applyGate(ctx, { kind: 'parent' }))\n agent.hooks.hook('child:tool:gate', ctx => applyGate(ctx, { kind: 'child', label: ctx.childId }))\n agent.hooks.hook('mcp:tool:gate', async (ctx) => {\n const gate = {\n block: ctx.block,\n reason: ctx.reason,\n name: ctx.displayName,\n input: ctx.input,\n callId: ctx.callId,\n turnId: ctx.turnId,\n }\n await applyGate(gate, { kind: 'parent' })\n ctx.block = gate.block\n ctx.reason = gate.reason\n ctx.input = gate.input\n })\n agent.hooks.hook('child:mcp:tool:gate', async (ctx) => {\n const gate = {\n block: ctx.block,\n reason: ctx.reason,\n name: ctx.displayName,\n input: ctx.input,\n callId: ctx.callId,\n turnId: ctx.turnId,\n childId: ctx.childId,\n depth: ctx.depth,\n }\n await applyGate(gate, { kind: 'child', label: ctx.childId })\n ctx.block = gate.block\n ctx.reason = gate.reason\n ctx.input = gate.input\n })\n}\n","import type { AgentHooks } from '../agent'\nimport type { StreamEvent } from './types'\n\n/**\n * The repeat-guard trip notice, the same row on every surface (the TUI's\n * local agent and the shared host): `error` when the run was stopped, `warn`\n * when the model was asked to change approach.\n */\nexport function repeatGuardNotice(\n { tool, count, action }: Pick<Parameters<AgentHooks['repeat-guard:exceeded']>[0], 'tool' | 'count' | 'action'>,\n): { notice: NonNullable<StreamEvent['notice']>, text: string } {\n const aborted = action === 'abort'\n return {\n notice: { severity: aborted ? 'error' : 'warn', label: 'repeat guard' },\n text: aborted\n ? `${tool} repeated ${count} times with the same input, run stopped`\n : `${tool} repeated ${count} times with the same input, asked the model to change approach`,\n }\n}\n","import type { TurnFinishReason } from '../types'\n/**\n * The run-end \"why did this stop?\" notice, in one place.\n *\n * When a run ends because the model bumped a ceiling rather than finishing,\n * the transcript otherwise shows an ordinary — often empty — assistant turn.\n * That is the classic \"the session just stalled\" report: nothing errored, so\n * nothing was said.\n *\n * This lived in TWO implementations with divergent copy: the TUI's in-process\n * `agent:done` hook and the shared chat host's (which serves the GUI and\n * daemon-attached windows). Same three conditions, three different message\n * texts, so the same run explained itself differently depending on which\n * surface you happened to be looking at.\n *\n * Returns a STRUCTURED notice — `{ severity, label }` plus text — rather than\n * a bare string, because the transcript renders notices with a severity glyph\n * and a label chip (`StreamEvent.notice`). Returning text alone would force\n * each surface to invent the label, which is exactly the divergence this\n * module exists to prevent. The text therefore carries no leading glyph and\n * starts lowercase: the renderer supplies the glyph, and the label is the\n * headline.\n *\n * The `length` copy names the two settings that change the outcome. Both carry\n * these exact labels on every surface (`resumeOnMaxTokens` → \"Auto-resume on\n * output limit\", `maxOutputTokens` → \"Max output tokens\"), so the instruction\n * is followable wherever the notice appears; `test/run-end-notice.test.ts`\n * pins the labels so a rename cannot turn it into a lie.\n */\nimport type { StreamEvent } from './types'\n\nexport interface RunEndNotice {\n notice: NonNullable<StreamEvent['notice']>\n text: string\n}\n\n/**\n * Structured stop notice for an abnormal `finishReason`, or `undefined` for a\n * normal end.\n *\n * Normal completions (`stop` / `tool-calls`) and user aborts return\n * `undefined` — and so does a SUCCESSFUL auto-resume, because recovery ends\n * the run on `stop`. That is what keeps the notice quiet exactly when the\n * ceiling was handled rather than hit. `error` runs already surface their own\n * error event, so a second notice would double-report.\n */\nexport function runEndNotice(reason: TurnFinishReason | undefined): RunEndNotice | undefined {\n switch (reason) {\n case 'length':\n return {\n notice: { severity: 'warn', label: 'output limit' },\n text: 'stopped at the model output limit (max_tokens). Turn on \"Auto-resume on output limit\" or raise \"Max output tokens\" in Settings to continue past it.',\n }\n case 'pause':\n return {\n notice: { severity: 'warn', label: 'pause cap' },\n text: 'stopped after repeated empty pause turns from the provider (maxConsecutivePauseTurns cap is armed).',\n }\n case 'content-filter':\n /*\n * Refusal stop (e.g. Anthropic `stop_reason: refusal`, often after\n * PDF-heavy tool results). The loop already retried with synthetic\n * continues before giving up, so reaching here means the refusal\n * persisted — say so rather than letting the run end as a silent,\n * empty \"completion\".\n */\n return {\n notice: { severity: 'warn', label: 'refusal' },\n text: 'the provider refused to continue (safety filter / refusal stop) despite automatic retries. Rephrase the request, or start a fresh session if it keeps happening.',\n }\n default:\n return undefined\n }\n}\n","import { createDebugLog } from '../../debug-log'\n\n/**\n * `ZIDANE_DEBUG`-gated sink for host diagnostics (cache-break lines, plugin\n * discovery failures). Module-scoped: the sink is stateless and the scope\n * label is fixed.\n */\nexport const hostDebug = createDebugLog('chat-host')\n","/**\n * Harness notices in the transcript: the `emitNotice` carrier (live event +\n * persisted display-only `command` turn), the repeat-guard trip notice, the\n * cache-break row, the sandbox warning, the abnormal run-end notice, and the\n * recovery notices (history repair, model fallback).\n */\nimport type { CacheBreakInfo } from '../../../cache-telemetry'\nimport type { Agent, AgentHooks } from '../../../index'\nimport type { StreamEvent } from '../../types'\nimport type { AgentHookContext } from '../types'\nimport { randomUUID } from 'node:crypto'\nimport { installCacheBreakLogger } from '../../../index'\nimport { cacheBreakChip, cacheBreakNoticeText } from '../../footer-chips'\nimport { repeatGuardNotice } from '../../repeat-guard-notice'\nimport { runEndNotice } from '../../run-end-notice'\nimport { noticeTurnContent } from '../../store'\nimport { CACHE_NOTICE_LABEL } from '../../turn-selection'\nimport { hostDebug } from '../debug'\n\nexport type EmitNotice = (\n notice: NonNullable<StreamEvent['notice']>,\n text: string,\n owner?: { childId: string, depth: number },\n) => void\n\n/**\n * A harness notice in a session's transcript, from anywhere in the host\n * (the machines feature too): broadcast live and persisted on the live\n * agent's session as a display-only `command` turn with the same id.\n */\nexport function emitSessionNotice(\n { sessionId, agent, broadcast }: Pick<AgentHookContext, 'sessionId' | 'broadcast'> & { agent: Pick<Agent, 'session'> | undefined },\n notice: NonNullable<StreamEvent['notice']>,\n text: string,\n owner?: { childId: string, depth: number },\n): void {\n const turnId = randomUUID()\n broadcast({ kind: 'event', sessionId, event: { kind: notice.severity === 'error' ? 'error' : 'info', text, notice, turnId, ...(owner ?? {}) } })\n void agent?.session\n ?.appendTurns([{ id: turnId, role: 'command', createdAt: Date.now(), content: noticeTurnContent(notice, text, owner) }])\n .catch(err => hostDebug('notice', `${notice.label} persist failed: ${String(err)}`))\n}\n\n/**\n * Installs the cache-break logger, the repeat-guard notices and the\n * cache-break transcript row; returns the build's `emitNotice`.\n */\nexport function installNotices({ sessionId, agent, broadcast }: AgentHookContext): EmitNotice {\n /*\n * Cache-break detection is per-agent closure state (it diffs successive\n * request prefixes), so it has to be installed on the agent that actually\n * runs. In daemon mode that is this one, not the window's — without this\n * the footer's cache chip and the debug lines are dead exactly where a\n * long-lived shared daemon makes prefix churn most likely.\n */\n installCacheBreakLogger(agent.hooks, { log: line => hostDebug('cache-break', line) })\n /*\n * A harness notice in the transcript: broadcast live and persisted as a\n * display-only `command` turn with the same id, so the reloaded row (and\n * the run-end resync) is the live row. Same wording and labels as the\n * TUI's local `emitNotice`.\n */\n const emitNotice: EmitNotice = (notice, text, owner) => emitSessionNotice({ sessionId, agent, broadcast }, notice, text, owner)\n\n /*\n * A repeat-guard trip, once per (tool, action) per run: without it a\n * guard stop looks exactly like the user pressing esc.\n */\n const guardNoticed = new Set<string>()\n // A subagent's trip (bubbled as `child:*`) is attributed to that subagent.\n const noticeRepeatGuard = (\n trip: Parameters<AgentHooks['repeat-guard:exceeded']>[0],\n owner?: { childId: string, depth: number },\n ): void => {\n const key = `${owner?.childId ?? ''}\\u0000${trip.tool}\\u0000${trip.action}`\n if (guardNoticed.has(key))\n return\n guardNoticed.add(key)\n const { notice, text } = repeatGuardNotice(trip)\n emitNotice(notice, text, owner)\n }\n agent.hooks.hook('repeat-guard:exceeded', trip => noticeRepeatGuard(trip))\n agent.hooks.hook('child:repeat-guard:exceeded', ({ childId, depth, ...trip }) => noticeRepeatGuard(trip, { childId, depth }))\n agent.hooks.hook('agent:done', () => guardNoticed.clear())\n\n /*\n * The chip signal goes out immediately. The transcript ROW is a\n * persisted harness notice (a display-only `command` turn, same carrier\n * as the other notices) so it survives a reload — but it must land\n * AFTER the assistant turn it describes. `cache:break` fires from\n * `turn:after` before the loop's own `turn:after` persist hook runs, so\n * appending here would file the notice ahead of the message. Hold it\n * until the next `session:turns` (the persist of that very turn) and\n * append + broadcast then; the live event shares the persisted turn id\n * so the reloaded row IS the live row.\n */\n let pendingCacheNotice: CacheBreakInfo | null = null\n agent.hooks.hook('cache:break', (info) => {\n broadcast({ kind: 'cache:break', sessionId, info })\n pendingCacheNotice = info\n })\n agent.hooks.hook('session:turns', () => {\n const info = pendingCacheNotice\n if (!info)\n return\n pendingCacheNotice = null\n const session = agent.session\n if (!session)\n return\n const chip = cacheBreakChip(info)\n // The row carries the detector's culprit (`message[N] … rewritten in\n // place`, `system: …`) so a break is diagnosable from the transcript\n // without ZIDANE_DEBUG; the footer chip stays terse.\n const text = cacheBreakNoticeText(info)\n const notice = { severity: chip.tone === 'warn' ? 'warn' as const : 'info' as const, label: CACHE_NOTICE_LABEL }\n const turnId = randomUUID()\n void session\n .appendTurns([{ id: turnId, role: 'command', createdAt: Date.now(), content: noticeTurnContent(notice, text) }])\n .then(() => broadcast({ kind: 'event', sessionId, event: { kind: 'info', text, notice, turnId } }))\n .catch(err => hostDebug('cache-break', `notice persist failed: ${String(err)}`))\n })\n return emitNotice\n}\n\n/** The OS-sandbox warning, once per agent build. */\nexport function broadcastSandboxWarning({ sessionId, broadcast }: Pick<AgentHookContext, 'sessionId' | 'broadcast'>, sandbox: { warning?: string }): void {\n // The process context refuses every command while the sandbox can't be\n // enforced (fail closed); say so once at activation so the first refusal\n // isn't a surprise. Display-only, not persisted — it's about this host.\n if (sandbox.warning) {\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'info', text: sandbox.warning, notice: { severity: 'warn', label: 'sandbox' } },\n })\n }\n}\n\nexport function installRunEndNotice(agent: Agent, emitNotice: EmitNotice): void {\n /**\n * Run-end visibility for abnormal finish reasons (mirrors the TUI's\n * in-process run-end banner). Without this, a run ended by the\n * provider's safety filter (`content-filter`, e.g. Anthropic\n * `stop_reason: refusal` after PDF-heavy tool results — the loop\n * already retried before giving up), the output-token cap, or the\n * empty-pause cap stops silently with an empty assistant turn — the\n * classic \"stalled session\" report. Lives in the host rather than the\n * GUI adapter so daemon-attached windows get the same notice.\n */\n agent.hooks.hook('agent:done', (stats) => {\n const stop = runEndNotice(stats.turnUsage?.at(-1)?.finishReason)\n if (stop)\n emitNotice(stop.notice, stop.text)\n })\n}\n\nexport function installRecoveryNotices({ sessionId, agent, broadcast }: AgentHookContext, emitNotice: EmitNotice): void {\n /*\n * Canonical-history repair (provider rejected stale reasoning\n * signatures; the loop scrubbed + persisted). Same info line the\n * local TUI paints — the recovery must be visible, not silent.\n */\n agent.hooks.hook('history:repair', (ctx) => {\n const blocks = `${ctx.removedBlocks} stale reasoning block${ctx.removedBlocks === 1 ? '' : 's'}`\n emitNotice({ severity: 'warn', label: 'history repair' }, `removed ${blocks} the provider rejected${ctx.persisted ? '' : ' (session not yet persisted)'}`)\n })\n\n /*\n * Run-level model fallback — the dedicated signal drives model pills,\n * the transcript info line makes the switch part of the record.\n */\n agent.hooks.hook('model:fallback', (ctx) => {\n broadcast({ kind: 'model:fallback', sessionId, from: ctx.from, to: ctx.to })\n const reason = (ctx.err as Error)?.message ?? String(ctx.err)\n emitNotice({ severity: 'warn', label: 'model fallback' }, `${ctx.from.provider}/${ctx.from.model} failed (${reason}), continuing on ${ctx.to.provider}/${ctx.to.model}`)\n })\n}\n","/**\n * `ExecutionContext` over a machine link (`docs/MACHINES.md` § Protocol):\n * every method is one machine call, 1:1. The machine confines paths itself;\n * this side only names the handle (`{ id, cwd }`) on every call so a\n * restarted machine rebuilds it. A `sandbox`-typed context: its filesystem\n * is not this host's, so host-side workspace checks leave it to the machine.\n */\nimport type { ContextCapabilities, ExecutionContext, ExecutionHandle, ListFilesEntry, StreamHandle, TaskEntry, TaskExitInfo, TaskHandle, TerminalOptions, TerminalProcess } from '../../../contexts/types'\nimport type { MachineCapabilities, MachineHandleRef } from '../../machine-protocol'\nimport type { MachineLink, TerminalListener } from './link'\nimport { Buffer } from 'node:buffer'\nimport { randomUUID } from 'node:crypto'\nimport { StreamQueue } from '../../../contexts/stream-queue'\nimport { MACHINE_STREAM_CHUNK_BYTES } from '../../machine-protocol'\n\nexport interface MachineContextInput {\n link: MachineLink\n /** The session the calls are for (its offline notices). */\n sessionId?: string\n /** Default handle cwd, on the machine. */\n cwd: string\n /** What the machine registered with: `stream` turns `execStream` on. */\n capabilities?: Partial<MachineCapabilities>\n}\n\nconst CAPABILITIES: ContextCapabilities = {\n shell: true,\n filesystem: true,\n glob: true,\n network: true,\n gpu: false,\n stream: false,\n isolated: false,\n detachedTasks: 'process-lifetime',\n}\n\n/** `execStream` over `exec.stream*`: the queues are registered before the call, so no early byte is lost. */\nfunction machineStream(link: MachineLink, base: { sessionId?: string }, refOf: (handle: ExecutionHandle) => MachineHandleRef): NonNullable<ExecutionContext['execStream']> {\n return async (handle, command, options = {}) => {\n const callId = randomUUID()\n const stdout = new StreamQueue()\n const stderr = new StreamQueue()\n let resolveExit!: (code: number) => void\n const exited = new Promise<number>((resolve) => {\n resolveExit = resolve\n })\n link.streams.set(callId, {\n data: (stream, bytes) => (stream === 'stderr' ? stderr : stdout).push(bytes),\n exit: (code) => {\n stdout.close()\n stderr.close()\n resolveExit(code)\n },\n })\n const cancel = (): void => link.notify('exec.cancel', { callId })\n let started: { pid: number }\n try {\n started = await link.call('exec.stream', {\n handle: refOf(handle),\n callId,\n command,\n ...(options.cwd ? { cwd: options.cwd } : {}),\n ...(options.env ? { env: options.env } : {}),\n }, { ...base, ...(options.signal ? { signal: options.signal } : {}), onAbort: cancel })\n }\n catch (err) {\n link.streams.get(callId)?.exit(-1)\n link.streams.delete(callId)\n throw err\n }\n options.signal?.addEventListener('abort', cancel, { once: true })\n void exited.then(() => options.signal?.removeEventListener('abort', cancel))\n const stream: StreamHandle = {\n pid: started.pid,\n stdout,\n stderr,\n async write(data) {\n for (let at = 0; at < data.byteLength; at += MACHINE_STREAM_CHUNK_BYTES)\n await link.call('exec.stream.write', { callId, data: Buffer.from(data.subarray(at, at + MACHINE_STREAM_CHUNK_BYTES)).toString('base64') }, { ...base, wait: false })\n },\n async kill() {\n if (link.streams.has(callId))\n await link.call('exec.cancel', { callId }, { ...base, wait: false }).catch(() => undefined)\n },\n exited,\n }\n return stream\n }\n}\n\nexport function createMachineContext(input: MachineContextInput): ExecutionContext {\n const { link, sessionId } = input\n const streams = input.capabilities?.stream === true\n const base = sessionId !== undefined ? { sessionId } : {}\n const refOf = (handle: ExecutionHandle): MachineHandleRef => ({ id: handle.id, cwd: handle.cwd })\n /** Task id → the handle that started it, and its owner's exit callback. */\n const owners = new Map<string, { handleId: string, onExit?: (info: TaskExitInfo) => void }>()\n\n const watchTask = (taskId: string, handleId: string, onExit?: (info: TaskExitInfo) => void): void => {\n owners.set(taskId, { handleId, ...(onExit ? { onExit } : {}) })\n link.tasks.set(taskId, (exit) => {\n const owner = owners.get(taskId)\n owner?.onExit?.(exit as TaskExitInfo)\n })\n }\n\n function terminalProcess(terminalId: string, options: TerminalOptions): TerminalProcess {\n let resolveExit!: (code: number) => void\n const exited = new Promise<number>((resolve) => {\n resolveExit = resolve\n })\n const listener: TerminalListener = { onData: options.onData, exit: resolveExit, seen: 0 }\n link.terminals.set(terminalId, listener)\n const quietly = (promise: Promise<unknown>): void => void promise.catch(() => undefined)\n return {\n id: terminalId,\n reconnectable: true,\n write: data => quietly(link.call('terminal.write', { terminalId, data: Buffer.from(typeof data === 'string' ? Buffer.from(data) : data).toString('base64') }, { ...base, wait: false })),\n resize: (cols, rows) => quietly(link.call('terminal.resize', { terminalId, cols, rows }, { ...base, wait: false })),\n kill: async () => {\n link.terminals.delete(terminalId)\n await link.call('terminal.kill', { terminalId }, { ...base, wait: false }).catch(() => undefined)\n resolveExit(-1)\n },\n detach: async () => {\n link.terminals.delete(terminalId)\n await link.call('terminal.detach', { terminalId }, { ...base, wait: false }).catch(() => undefined)\n },\n exited,\n }\n }\n\n return {\n type: 'sandbox',\n // `isolated`: the machine's own sandbox (its user's settings), never the host's.\n capabilities: { ...CAPABILITIES, stream: streams, isolated: input.capabilities?.sandboxed === true },\n ...(streams ? { execStream: machineStream(link, base, refOf) } : {}),\n\n async spawn(config) {\n const ref = { id: `m-${randomUUID()}`, cwd: config?.cwd ?? input.cwd }\n const spawned = await link.call('exec.spawn', { handle: ref }, base)\n return { id: spawned.id, type: 'sandbox', cwd: spawned.cwd }\n },\n\n async exec(handle, command, options = {}) {\n const callId = randomUUID()\n return link.call('exec.run', {\n handle: refOf(handle),\n callId,\n command,\n ...(options.cwd ? { cwd: options.cwd } : {}),\n ...(options.env ? { env: options.env } : {}),\n ...(options.timeout !== undefined ? { timeout: options.timeout } : {}),\n }, { ...base, ...(options.signal ? { signal: options.signal } : {}), onAbort: () => link.notify('exec.cancel', { callId }) })\n },\n\n async readFile(handle, path) {\n return (await link.call('fs.read', { handle: refOf(handle), path }, base)).content\n },\n\n async readFileBinary(handle, path) {\n return new Uint8Array(Buffer.from((await link.call('fs.read', { handle: refOf(handle), path, binary: true }, base)).content, 'base64'))\n },\n\n async fileSize(handle, path) {\n return (await link.call('fs.size', { handle: refOf(handle), path }, base)).size\n },\n\n async writeFile(handle, path, content, encoding) {\n const bytes = typeof content === 'string' ? Buffer.from(content, encoding ?? 'utf8') : content\n await link.call('fs.write', { handle: refOf(handle), path, content: bytes.toString('base64') }, base)\n },\n\n async listFiles(handle, path, options = {}) {\n const { signal: _signal, ...rest } = options\n return (await link.call('fs.list', { handle: refOf(handle), path, options: rest }, base)).entries as ListFilesEntry[]\n },\n\n async execBackground(handle, command, options): Promise<TaskHandle> {\n // `outputDir` is a host path: the machine writes task logs under its own data dir.\n const task = await link.call('bg.start', {\n handle: refOf(handle),\n command,\n ...(options.cwd ? { cwd: options.cwd } : {}),\n ...(options.env ? { env: options.env } : {}),\n ...(options.maxOutputBytes ? { maxOutputBytes: options.maxOutputBytes } : {}),\n }, base)\n watchTask(task.taskId, handle.id, options.onExit)\n return { taskId: task.taskId, pid: task.pid, outputPath: task.outputPath }\n },\n\n async listBackground(handle) {\n return (await link.call('bg.list', { handle: refOf(handle) }, base)).tasks as unknown as TaskEntry[]\n },\n\n async killBackground(handle, taskId) {\n return (await link.call('bg.kill', { handle: refOf(handle), taskId }, base)).exit as unknown as TaskExitInfo | null\n },\n\n async waitBackground(handle, taskId, options = {}) {\n return (await link.call('bg.wait', { handle: refOf(handle), taskId, ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}) }, { ...base, ...(options.signal ? { signal: options.signal } : {}) })).exit as unknown as TaskExitInfo | null\n },\n\n async reassignBackgroundTasks(from, to, newOnExit) {\n const running = ((await link.call('bg.list', { handle: refOf(from) }, base)).tasks as unknown as TaskEntry[]).filter(task => task.status === 'running')\n for (const task of running) {\n if (from.id === to.id || owners.get(task.taskId)?.handleId === from.id)\n watchTask(task.taskId, to.id, newOnExit ?? owners.get(task.taskId)?.onExit)\n }\n return running\n },\n\n async openTerminal(handle, options) {\n const { terminalId } = await link.call('terminal.open', { handle: refOf(handle), cols: options.cols, rows: options.rows, ...(options.cwd ? { cwd: options.cwd } : {}) }, base)\n return terminalProcess(terminalId, options)\n },\n\n async reconnectTerminal(_handle, terminalId, options) {\n const { attached, backlog } = await link.call('terminal.attach', { terminalId }, base)\n if (!attached)\n return null\n const process = terminalProcess(terminalId, options)\n const bytes = Buffer.from(backlog, 'base64')\n if (bytes.byteLength > 0) {\n link.terminals.get(terminalId)!.seen += bytes.byteLength\n options.onData(bytes)\n }\n return process\n },\n\n async destroy(handle) {\n // Never waits for an offline machine: its tasks keep running there.\n await link.call('exec.destroy', { handle: refOf(handle) }, { ...base, wait: false }).catch(() => undefined)\n },\n }\n}\n","/** Errors of the machine link (`docs/MACHINES.md` § Offline). */\nimport { MachineErrorCode } from '../../machine-protocol'\n\n/** The transport lost the machine's connection with this call in flight (its reply will never come). */\nexport class MachineLinkLostError extends Error {\n constructor() {\n super('The machine connection closed.')\n this.name = 'MachineLinkLostError'\n }\n}\n\n/** Sent, then the link dropped: the call may have run, so it is not re-sent. */\nexport class MachineResultLostError extends Error {\n constructor(name: string) {\n super(`result lost: ${name} disconnected during the call. It may or may not have run; check before retrying.`)\n this.name = 'MachineResultLostError'\n }\n}\n\n/** The machine stayed offline past the wait (or the caller would not wait). */\nexport class MachineUnavailableError extends Error {\n constructor(name: string, minutes?: number) {\n super(minutes === undefined\n ? `${name} is unavailable: the machine is offline.`\n : `${name} is unavailable: the machine stayed offline for ${minutes} min.`)\n this.name = 'MachineUnavailableError'\n }\n}\n\n/** A `machine.register` the host refuses; `code` goes on the JSON-RPC error. */\nexport class MachineProtocolError extends Error {\n constructor(readonly code: number, message: string) {\n super(message)\n this.name = 'MachineProtocolError'\n }\n}\n\nexport const INVALID_PARAMS = -32602\n\nexport function versionSkew(theirs: number, ours: number): MachineProtocolError {\n return new MachineProtocolError(MachineErrorCode.VersionSkew, `Machine protocol ${theirs} is not supported by this host (it speaks ${ours}). Update the older side.`)\n}\n","/**\n * Whose folder is this? (`docs/MACHINES.md` § Folders.) A machine kind's\n * folders are checked by its provider against the machine's roots, never\n * by this host's own workspace confinement: a confined server would refuse\n * every machine path, an unconfined host would treat it as one of its own.\n * Every entry point taking a folder (environments, `/` commands, catalogs,\n * the session folder, launch overrides) goes through here.\n */\nimport type { EnvironmentRegistry } from '../../environment'\nimport type { WorkspaceConfinement } from '../../workspace-confinement'\nimport { parseMachineKind } from '../../machine-protocol'\n\nexport interface ResolvedFolder {\n cwd: string\n /** Set when the folder is a machine's: its name and its `local@` kind. */\n machine?: { name: string, kind: string }\n}\n\nexport type FolderResolver = (cwd: string, kind?: string) => ResolvedFolder\n\nexport function createFolderResolver(input: { environments: EnvironmentRegistry, workspace: Pick<WorkspaceConfinement, 'checkFolder'> }): FolderResolver {\n const { environments, workspace } = input\n\n const onMachine = (kind: string, cwd: string): ResolvedFolder | undefined => {\n const parsed = parseMachineKind(kind)\n const provider = parsed ? environments.get(kind) : undefined\n if (!parsed || !provider?.checkFolder)\n return undefined\n return { cwd: provider.checkFolder(cwd), machine: { name: parsed.name, kind: `local@${parsed.name}` } }\n }\n\n return (cwd, kind) => {\n // Named: the kind decides, and its refusal stands.\n const named = kind ? onMachine(kind, cwd) : undefined\n if (named)\n return named\n try {\n return { cwd: workspace.checkFolder(cwd) }\n }\n catch (err) {\n // Not this host's: the one known machine whose roots hold it (an older client names no kind).\n for (const provider of environments.list()) {\n if (!provider.machine?.() || parseMachineKind(provider.kind)?.base !== 'local')\n continue\n try {\n const found = onMachine(provider.kind, cwd)\n if (found)\n return found\n }\n catch {\n // Outside this machine's roots: the next one.\n }\n }\n throw err\n }\n }\n}\n","/**\n * Minimal async git runner for environment providers — argv only (never a\n * shell), bounded time and output, abortable. Errors carry git's own stderr,\n * which is what the user needs to see (\"fatal: a branch named … already\n * exists\").\n */\nimport { execFile } from 'node:child_process'\n\nexport interface GitResult {\n stdout: string\n stderr: string\n}\n\nexport class GitError extends Error {\n readonly stderr: string\n readonly code: number | string | undefined\n constructor(args: readonly string[], stderr: string, code: number | string | undefined) {\n super(stderr.trim() || `git ${args.join(' ')} failed${code !== undefined ? ` (${code})` : ''}`)\n this.name = 'GitError'\n this.stderr = stderr\n this.code = code\n }\n}\n\nexport function git(cwd: string, args: readonly string[], options: { signal?: AbortSignal, timeoutMs?: number } = {}): Promise<GitResult> {\n return new Promise((resolve, reject) => {\n execFile('git', args, {\n cwd,\n timeout: options.timeoutMs ?? 60_000,\n maxBuffer: 16 * 1024 * 1024,\n encoding: 'utf8',\n ...(options.signal ? { signal: options.signal } : {}),\n // Never prompt (credentials, editors) — a provider runs unattended.\n env: { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_EDITOR: 'true' },\n }, (err, stdout, stderr) => {\n if (err)\n reject(new GitError(args, stderr || err.message, (err as { code?: number | string }).code))\n else\n resolve({ stdout, stderr })\n })\n })\n}\n\n/** `git …` that answers yes/no: exit 0 → true, anything else → false. */\nexport async function gitSucceeds(cwd: string, args: readonly string[], options: { signal?: AbortSignal } = {}): Promise<boolean> {\n try {\n await git(cwd, args, options)\n return true\n }\n catch {\n return false\n }\n}\n\nlet gitAvailable: Promise<boolean> | undefined\n/** Whether a `git` binary runs at all. Cached per process. */\nexport function isGitInstalled(): Promise<boolean> {\n gitAvailable ??= gitSucceeds(process.cwd(), ['--version'])\n return gitAvailable\n}\n","/**\n * Git plumbing for environments that work on a CLONE of the session's repo\n * (remote sandboxes): which remote, which base branch, the token, and the\n * in-sandbox scripts that clone, push and open a pull request.\n *\n * Token resolution (first hit wins): the kind's `gitToken` secret →\n * `GH_TOKEN` / `GITHUB_TOKEN` (github.com only) → `gh auth token --hostname <host>`\n * on this machine. The token is\n * handed to the sandbox as an env var for the clone and each push, and stored\n * in the sandbox's git credential store so the agent's own `git push` works —\n * which also means the agent can read it (documented on the settings field).\n */\nimport type { EnvironmentConfig } from '../environment'\nimport { execFile } from 'node:child_process'\nimport { git, GitError, gitSucceeds } from './git'\n\n/** The session repo's `origin`, parsed. */\nexport interface GitRemote {\n /** `github.com`, or a GitHub Enterprise / GitLab host. */\n host: string\n owner: string\n repo: string\n /** Token-friendly clone URL (`https://host/owner/repo.git`). */\n httpsUrl: string\n}\n\n/**\n * Parse a remote URL — `https://host/owner/repo(.git)`, `git@host:owner/repo(.git)`,\n * `ssh://git@host(:port)/owner/repo(.git)` — into an https clone target.\n * `undefined` for anything else (local paths, file://).\n */\nexport function parseGitRemote(url: string): GitRemote | undefined {\n const trimmed = url.trim()\n let host: string | undefined\n let path: string | undefined\n const scp = /^[\\w.-]+@([\\w.-]+):(?!\\/)(.+)$/.exec(trimmed)\n if (scp) {\n host = scp[1]\n path = scp[2]\n }\n else {\n try {\n const parsed = new URL(trimmed)\n if (!['https:', 'http:', 'ssh:', 'git:'].includes(parsed.protocol))\n return undefined\n host = parsed.hostname\n path = parsed.pathname\n }\n catch {\n return undefined\n }\n }\n const segments = (path ?? '').replace(/^\\/+|\\/+$/g, '').replace(/\\.git$/, '').split('/').filter(Boolean)\n if (!host || segments.length < 2)\n return undefined\n const repo = segments.at(-1)!\n const owner = segments.slice(0, -1).join('/')\n return { host, owner, repo, httpsUrl: `https://${host}/${owner}/${repo}.git` }\n}\n\n/** `origin` of the repo at `cwd`, parsed — throws with a user-facing reason. */\nexport async function readGitRemote(cwd: string): Promise<GitRemote> {\n let url: string\n try {\n url = (await git(cwd, ['remote', 'get-url', 'origin'])).stdout.trim()\n }\n catch {\n throw new Error('The repository has no \"origin\" remote to clone from.')\n }\n const remote = parseGitRemote(url)\n if (!remote)\n throw new Error(`Can't clone \"${url}\" into a sandbox: only https / ssh remotes work.`)\n return remote\n}\n\nexport function isGitHub(remote: Pick<GitRemote, 'host'>): boolean {\n return remote.host === 'github.com'\n}\n\n/**\n * A token for `remote`: config secret → env → `gh auth token`. `undefined` when none.\n * The GitHub fallbacks are host-scoped so a github.com credential never reaches\n * another server: env vars only for github.com, `gh` only for `remote.host`.\n */\nexport async function resolveGitToken(config: EnvironmentConfig, remote: Pick<GitRemote, 'host'>, env: Record<string, string | undefined> = process.env): Promise<string | undefined> {\n const configured = typeof config.gitToken === 'string' ? config.gitToken.trim() : ''\n if (configured)\n return configured\n if (isGitHub(remote)) {\n const fromEnv = env.GH_TOKEN?.trim() || env.GITHUB_TOKEN?.trim()\n if (fromEnv)\n return fromEnv\n }\n return ghAuthToken(remote.host)\n}\n\nfunction ghAuthToken(host: string): Promise<string | undefined> {\n return new Promise((resolve) => {\n execFile('gh', ['auth', 'token', '--hostname', host], { timeout: 5000, encoding: 'utf8' }, (err, stdout) => {\n resolve(err ? undefined : stdout.trim() || undefined)\n })\n })\n}\n\nexport interface BaseBranch {\n /** Branch the session's branch is cut from. */\n name: string\n /** Local commits on it that aren't on the remote (they won't be in the clone). */\n unpushed: number\n}\n\n/**\n * The base for a new sandbox branch: the checkout's current branch when the\n * remote has it, else the remote's default branch. Uses this machine's git\n * credentials (it's the user's own `git ls-remote`).\n */\nexport async function resolveBaseBranch(cwd: string, options: { signal?: AbortSignal } = {}): Promise<BaseBranch> {\n const current = (await git(cwd, ['rev-parse', '--abbrev-ref', 'HEAD'], options).catch(() => ({ stdout: '' }))).stdout.trim()\n if (current && current !== 'HEAD' && await gitSucceeds(cwd, ['ls-remote', '--exit-code', '--heads', 'origin', current], options)) {\n const ahead = await git(cwd, ['rev-list', '--count', `origin/${current}..HEAD`], options).catch(() => ({ stdout: '0' }))\n return { name: current, unpushed: Number.parseInt(ahead.stdout.trim(), 10) || 0 }\n }\n try {\n const { stdout } = await git(cwd, ['ls-remote', '--symref', 'origin', 'HEAD'], { ...options, timeoutMs: 30_000 })\n const match = /^ref: refs\\/heads\\/(\\S+)\\s+HEAD/m.exec(stdout)\n if (match)\n return { name: match[1]!, unpushed: 0 }\n }\n catch (err) {\n throw new Error(`Couldn't reach the \"origin\" remote: ${err instanceof GitError ? err.message : String(err)}`)\n }\n return { name: 'main', unpushed: 0 }\n}\n\n/** This machine's git identity, so sandbox commits are attributed to the user. */\nexport async function readGitIdentity(cwd: string): Promise<{ name?: string, email?: string }> {\n const read = async (key: string) => (await git(cwd, ['config', '--get', key]).catch(() => ({ stdout: '' }))).stdout.trim() || undefined\n const [name, email] = await Promise.all([read('user.name'), read('user.email')])\n return { ...(name ? { name } : {}), ...(email ? { email } : {}) }\n}\n\n/** POSIX single-quote. */\nexport function shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\\\\''`)}'`\n}\n\n/** Env var the scripts read the token from — never baked into a command line. */\nexport const GIT_TOKEN_ENV = 'ZIDANE_GIT_TOKEN'\n\n/** Shell lines that (re)write the sandbox's git credential for `host` from `$ZIDANE_GIT_TOKEN`. */\nfunction credentialLines(host: string): string[] {\n return [\n `if [ -n \"$${GIT_TOKEN_ENV}\" ]; then`,\n ` git config --global credential.helper store`,\n ` umask 077`,\n ` printf 'https://x-access-token:%s@%s\\\\n' \"$${GIT_TOKEN_ENV}\" ${shellQuote(host)} > \"$HOME/.git-credentials\"`,\n `fi`,\n ]\n}\n\n/**\n * Clone `remote` into `dir` and check out `branch` (existing locally, on the\n * remote, or cut from `base`). Idempotent — a retry over a half-done clone\n * fetches instead. Token and identity via env, never on the command line.\n */\nexport function cloneScript(input: { remote: GitRemote, dir: string, branch: string, base: string, identity: { name?: string, email?: string } }): string {\n const { remote, dir, branch, base, identity } = input\n const d = shellQuote(dir)\n const b = shellQuote(branch)\n return [\n 'set -e',\n 'command -v git >/dev/null 2>&1 || { echo \"git is not installed in this sandbox. Use an image / template that has git.\" >&2; exit 127; }',\n 'export GIT_TERMINAL_PROMPT=0',\n ...credentialLines(remote.host),\n ...(identity.name ? [`git config --global user.name ${shellQuote(identity.name)}`] : []),\n ...(identity.email ? [`git config --global user.email ${shellQuote(identity.email)}`] : []),\n `if [ -d ${d}/.git ]; then cd ${d} && git fetch --quiet origin; else git clone --quiet ${shellQuote(remote.httpsUrl)} ${d} && cd ${d}; fi`,\n `if git rev-parse --verify --quiet ${shellQuote(`refs/heads/${branch}`)} >/dev/null; then git checkout --quiet ${b};`,\n `elif git ls-remote --exit-code --heads origin ${b} >/dev/null 2>&1; then git checkout --quiet -b ${b} --track ${shellQuote(`origin/${branch}`)};`,\n `else git checkout --quiet -b ${b} ${shellQuote(`origin/${base}`)}; fi`,\n ].join('\\n')\n}\n\n/** Push the session branch (sets upstream). Refreshes the credential from `$ZIDANE_GIT_TOKEN` first. */\nexport function pushScript(input: { remote: GitRemote, branch: string }): string {\n return [\n 'set -e',\n 'export GIT_TERMINAL_PROMPT=0',\n ...credentialLines(input.remote.host),\n `git push --quiet -u origin ${shellQuote(`HEAD:refs/heads/${input.branch}`)}`,\n ].join('\\n')\n}\n\n/** GitHub REST base for `host` (github.com or Enterprise). */\nfunction githubApi(host: string): string {\n return host === 'github.com' ? 'https://api.github.com' : `https://${host}/api/v3`\n}\n\n/**\n * Open a pull request for `head` → `base`, or return the open one that\n * already exists for `head`. Throws with GitHub's message on failure.\n */\nexport async function openPullRequest(input: {\n remote: GitRemote\n token: string\n head: string\n base: string\n title: string\n body: string\n fetchImpl?: typeof fetch\n}): Promise<{ url: string, created: boolean }> {\n const { remote, token, head, base } = input\n const doFetch = input.fetchImpl ?? fetch\n const api = `${githubApi(remote.host)}/repos/${remote.owner}/${remote.repo}/pulls`\n const headers = {\n 'Accept': 'application/vnd.github+json',\n 'Authorization': `Bearer ${token}`,\n 'X-GitHub-Api-Version': '2022-11-28',\n 'Content-Type': 'application/json',\n }\n const response = await doFetch(api, { method: 'POST', headers, body: JSON.stringify({ title: input.title, body: input.body, head, base }) })\n if (response.ok)\n return { url: ((await response.json()) as { html_url: string }).html_url, created: true }\n const failure = await response.json().catch(() => ({})) as { message?: string, errors?: { message?: string }[] }\n if (response.status === 422) {\n const owner = remote.owner.split('/')[0]\n const existing = await doFetch(`${api}?state=open&head=${encodeURIComponent(`${owner}:${head}`)}`, { headers })\n if (existing.ok) {\n const [pull] = await existing.json() as { html_url: string }[]\n if (pull)\n return { url: pull.html_url, created: false }\n }\n }\n const detail = failure.errors?.map(error => error.message).filter(Boolean).join('; ')\n throw new Error(`GitHub refused the pull request (${response.status}): ${failure.message ?? 'unknown error'}${detail ? `. ${detail}` : ''}`)\n}\n","import type { SandboxProvider } from '../../contexts/sandbox'\nimport type { ExecutionContext, ExecutionHandle, SpawnConfig } from '../../contexts/types'\n/**\n * Remote sandbox environments (e2b, Daytona) — one factory, one driver per\n * vendor. The session gets its own sandbox holding a CLONE of the session's\n * repo on its own branch; the agent's tools run there, and the branch comes\n * back through a push + pull request.\n *\n * prepare → create the sandbox, clone `origin` over https with the git\n * token, check out the session branch from the base, run the\n * setup command. `ref = { sandboxId, remote }`, `execCwd` = the\n * clone. `metadata.cwd` stays the host checkout, so AGENTS.md,\n * skills and MCP config still load from it.\n * execution → attach to the sandbox by id (a paused one resumes). Releasing\n * the context leaves the sandbox alone; the host decides when to\n * pause it (`suspend`, after `idleMinutes`) or delete it.\n * teardown → delete the sandbox. Unpushed work in it is gone — the delete\n * confirmation says so.\n * actions → Push branch; Open pull request (GitHub hosts).\n */\nimport type {\n EnvironmentAction,\n EnvironmentConfig,\n EnvironmentConfigField,\n EnvironmentPrepareResult,\n EnvironmentProvider,\n EnvironmentVerifyResult,\n SessionEnvironment,\n} from '../environment'\nimport type { GitRemote } from './git-remote'\nimport { randomBytes } from 'node:crypto'\nimport { posix } from 'node:path'\nimport { createSandboxContext } from '../../contexts/sandbox'\nimport { findGitRoot } from '../project-root'\nimport { git, gitSucceeds, isGitInstalled } from './git'\nimport {\n cloneScript,\n GIT_TOKEN_ENV,\n isGitHub,\n openPullRequest,\n pushScript,\n readGitIdentity,\n readGitRemote,\n resolveBaseBranch,\n resolveGitToken,\n shellQuote,\n} from './git-remote'\n\n/** What a vendor supplies; everything else is shared. */\nexport interface RemoteSandboxDriver {\n kind: string\n label: string\n description: string\n /** Vendor options (API key first), rendered before the shared ones. */\n fields: readonly EnvironmentConfigField[]\n /** Why it can't be offered with `config` (missing key, missing SDK), or `undefined`. */\n unavailableReason: (config: EnvironmentConfig) => Promise<string | undefined>\n /**\n * A sandbox provider for `config`. `sandboxId` attaches (and resumes) an\n * existing sandbox — attached sandboxes are never deleted by `destroy`.\n */\n provider: (config: EnvironmentConfig, options: { sandboxId?: string, cwd?: string }) => SandboxProvider\n /** Vendor create-time options for a fresh sandbox (lifetime, auto-stop, …) — `SpawnConfig`. */\n spawnConfig?: (config: EnvironmentConfig) => Partial<SpawnConfig>\n pause: (config: EnvironmentConfig, sandboxId: string) => Promise<void>\n remove: (config: EnvironmentConfig, sandboxId: string) => Promise<void>\n verify: (config: EnvironmentConfig) => Promise<EnvironmentVerifyResult>\n}\n\n/** Provider-owned state on `environment.ref`. */\nexport interface RemoteSandboxRef {\n sandboxId: string\n remote: GitRemote\n}\n\nexport function readRemoteSandboxRef(environment: SessionEnvironment): RemoteSandboxRef | undefined {\n const ref = environment.ref as Partial<RemoteSandboxRef> | undefined\n const remote = ref?.remote as Partial<GitRemote> | undefined\n return typeof ref?.sandboxId === 'string' && remote && typeof remote.host === 'string' && typeof remote.owner === 'string'\n && typeof remote.repo === 'string' && typeof remote.httpsUrl === 'string'\n ? { sandboxId: ref.sandboxId, remote: remote as GitRemote }\n : undefined\n}\n\nconst CLONE_TIMEOUT_SECONDS = 15 * 60\nconst SETUP_TIMEOUT_SECONDS = 30 * 60\nconst PUSH_TIMEOUT_SECONDS = 5 * 60\nconst OUTPUT_TAIL = 2000\n\n/** Options every remote kind has, after the vendor's own. */\nexport const SHARED_REMOTE_FIELDS: readonly EnvironmentConfigField[] = [\n {\n key: 'gitToken',\n type: 'secret',\n label: 'Git token',\n // No `env` binding: GH_TOKEN is a github.com credential, so resolveGitToken\n // only falls back to it when origin is github.com.\n description: 'Sent to the host `origin` points at, to clone the repo and push the session branch. Falls back to GH_TOKEN / GITHUB_TOKEN (github.com only), then `gh auth token` for the remote\\'s host. The agent inside the sandbox can read it, so use a token scoped to the repos you work on.',\n placeholder: 'github_pat_…',\n },\n { key: 'branchPrefix', type: 'string', label: 'Branch prefix', description: 'Prefix of the suggested branch name.', default: 'zidane/', placeholder: 'zidane/' },\n { key: 'setupCommand', type: 'string', label: 'Setup command', description: 'Runs in the clone before the session starts (e.g. install dependencies).', placeholder: 'npm ci', default: '' },\n { key: 'idleMinutes', type: 'number', label: 'Pause after idle (minutes)', description: 'The sandbox is paused after this long without a run and resumes on the next prompt. 0 keeps it running.', default: 10 },\n]\n\nfunction tail(text: string): string {\n const trimmed = text.trim()\n return trimmed.length > OUTPUT_TAIL ? `…${trimmed.slice(-OUTPUT_TAIL)}` : trimmed\n}\n\nfunction numberOption(config: EnvironmentConfig, key: string, fallback: number): number {\n const value = config[key]\n return typeof value === 'number' && Number.isFinite(value) ? value : fallback\n}\n\nexport function createRemoteSandboxEnvironmentProvider(driver: RemoteSandboxDriver): EnvironmentProvider {\n const pushAction: EnvironmentAction = {\n id: 'push',\n label: 'Push branch',\n description: 'Push the session branch to origin.',\n available: environment => Boolean(environment.branch && readRemoteSandboxRef(environment)),\n async run({ environment, config, exec }) {\n const ref = readRemoteSandboxRef(environment)!\n const token = await resolveGitToken(config, ref.remote)\n const result = await exec(pushScript({ remote: ref.remote, branch: environment.branch! }), { env: tokenEnv(token), timeoutSeconds: PUSH_TIMEOUT_SECONDS })\n if (result.exitCode !== 0)\n throw new Error(`git push failed: ${tail(result.stderr || result.stdout) || `exit ${result.exitCode}`}${token ? '' : ' (no git token configured)'}`)\n return { message: `Pushed ${environment.branch} to ${ref.remote.owner}/${ref.remote.repo}.` }\n },\n }\n\n const pullRequestAction: EnvironmentAction = {\n id: 'open-pr',\n label: 'Open pull request',\n description: 'Push the branch and open a pull request against its base.',\n available: (environment) => {\n const ref = readRemoteSandboxRef(environment)\n return Boolean(environment.branch && environment.base && ref && isGitHub(ref.remote))\n },\n async run(input) {\n const { environment, config, exec } = input\n const ref = readRemoteSandboxRef(environment)!\n const token = await resolveGitToken(config, ref.remote)\n if (!token)\n throw new Error('Opening a pull request needs a git token (Settings → Environments, or GH_TOKEN).')\n await pushAction.run(input)\n // Title / body from the branch's own commits.\n const log = await exec(`git log --format=%s ${shellQuote(`origin/${environment.base}..HEAD`)}`, { timeoutSeconds: 30 })\n const subjects = log.exitCode === 0 ? log.stdout.split('\\n').map(line => line.trim()).filter(Boolean) : []\n if (subjects.length === 0)\n throw new Error(`${environment.branch} has no commits on top of ${environment.base} yet.`)\n const title = subjects.at(-1)!\n const body = subjects.length > 1 ? subjects.reverse().map(subject => `- ${subject}`).join('\\n') : ''\n const pull = await openPullRequest({ remote: ref.remote, token, head: environment.branch!, base: environment.base!, title, body })\n return { message: pull.created ? `Opened a pull request for ${environment.branch}.` : `A pull request for ${environment.branch} is already open.`, url: pull.url }\n },\n }\n\n return {\n kind: driver.kind,\n label: driver.label,\n description: driver.description,\n offByDefault: true,\n configSchema: [...driver.fields, ...SHARED_REMOTE_FIELDS],\n takesBranch: true,\n suggestBranch: config => suggestBranch(config),\n idleSuspendMinutes: config => numberOption(config, 'idleMinutes', 10),\n actions: [pushAction, pullRequestAction],\n\n async available({ cwd, config }) {\n const vendor = await driver.unavailableReason(config)\n if (vendor)\n return { ok: false, reason: vendor }\n if (!cwd)\n return { ok: false, reason: 'Pick a folder inside a git repository.' }\n if (!await isGitInstalled())\n return { ok: false, reason: 'git is not installed.' }\n const root = findGitRoot(cwd)\n if (!root)\n return { ok: false, reason: 'The folder is not inside a git repository.' }\n try {\n await readGitRemote(root)\n }\n catch (err) {\n return { ok: false, reason: (err as Error).message }\n }\n return { ok: true }\n },\n\n verify: ({ config }) => driver.verify(config),\n\n // Local git only (no network): what the clone will and won't contain.\n async note({ cwd }) {\n const root = findGitRoot(cwd)\n if (!root)\n return undefined\n const remote = await readGitRemote(root)\n const branch = (await git(root, ['rev-parse', '--abbrev-ref', 'HEAD']).catch(() => ({ stdout: '' }))).stdout.trim()\n const ahead = Number.parseInt((await git(root, ['rev-list', '--count', '@{upstream}..HEAD']).catch(() => ({ stdout: '0' }))).stdout.trim(), 10) || 0\n const base = branch && branch !== 'HEAD' ? `, branching off ${branch}` : ''\n const warning = ahead > 0 ? ` ${ahead} local commit${ahead === 1 ? ' isn\\'t' : 's aren\\'t'} pushed and won't be included.` : ''\n return `Clones ${remote.owner}/${remote.repo} from origin${base}.${warning}`\n },\n\n async prepare({ cwd, environment, config, signal }): Promise<EnvironmentPrepareResult> {\n const root = findGitRoot(cwd) ?? cwd\n const remote = await readGitRemote(root)\n const base = environment.base ? { name: environment.base, unpushed: 0 } : await resolveBaseBranch(root, signal ? { signal } : {})\n const branch = environment.branch?.trim() || suggestBranch(config)\n // Before paying for a sandbox; a leading '-' would also read as an option in the clone script.\n if (branch.startsWith('-') || !await gitSucceeds(root, ['check-ref-format', '--branch', branch], signal ? { signal } : {}))\n throw new Error(`\"${branch}\" is not a valid branch name.`)\n const [token, identity] = await Promise.all([resolveGitToken(config, remote), readGitIdentity(root)])\n\n const context = createSandboxContext(driver.provider(config, {}))\n let handle: ExecutionHandle | undefined\n const discard = async () => {\n if (handle)\n await driver.remove(config, handle.id).catch(() => undefined)\n }\n try {\n handle = await context.spawn(driver.spawnConfig?.(config) ?? {})\n signal?.throwIfAborted()\n const dir = posix.join(handle.cwd, remote.repo)\n const clone = await context.exec(handle, cloneScript({ remote, dir, branch, base: base.name, identity }), { env: tokenEnv(token), timeout: CLONE_TIMEOUT_SECONDS })\n if (clone.exitCode !== 0)\n throw new Error(`Cloning ${remote.owner}/${remote.repo} failed: ${tail(clone.stderr || clone.stdout) || `exit ${clone.exitCode}`}${token ? '' : ' (no git token set, and private repos need one)'}`)\n signal?.throwIfAborted()\n const setup = typeof config.setupCommand === 'string' ? config.setupCommand.trim() : ''\n if (setup) {\n const result = await context.exec(handle, setup, { cwd: dir, timeout: SETUP_TIMEOUT_SECONDS })\n if (result.exitCode !== 0)\n throw new Error(`Setup command failed (exit ${result.exitCode}): ${tail(result.stderr || result.stdout)}`)\n }\n signal?.throwIfAborted()\n const ref: RemoteSandboxRef = { sandboxId: handle.id, remote }\n return { environment: { ref: ref as unknown as NonNullable<SessionEnvironment['ref']>, execCwd: dir, branch, base: base.name } }\n }\n catch (err) {\n await discard()\n throw err\n }\n finally {\n // Drop the local connection only: the sandbox is the session's now\n // (or was just removed above).\n if (handle)\n await context.destroy(handle).catch(() => undefined)\n }\n },\n\n execution({ environment, config }) {\n const ref = readRemoteSandboxRef(environment)\n if (!ref)\n throw new Error(`This ${driver.label} session has no sandbox. Retry its environment or delete it.`)\n const cwd = environment.execCwd\n return {\n key: JSON.stringify({ sandboxId: ref.sandboxId, cwd: cwd ?? null, vendor: driver.fields.map(field => field.type === 'secret' ? field.key : `${field.key}=${String(config[field.key] ?? '')}`) }),\n // Spawn attaches by id — a paused sandbox resumes; destroy leaves it.\n create: (): ExecutionContext => createSandboxContext(driver.provider(config, { sandboxId: ref.sandboxId, ...(cwd ? { cwd } : {}) })),\n ...(cwd ? { promptCwd: cwd } : {}),\n }\n },\n\n async suspend(environment, { config }) {\n const ref = readRemoteSandboxRef(environment)\n if (ref)\n await driver.pause(config, ref.sandboxId)\n },\n\n async teardown(environment, { config }) {\n const ref = readRemoteSandboxRef(environment)\n if (!ref)\n return { removed: true }\n try {\n await driver.remove(config, ref.sandboxId)\n return { removed: true }\n }\n catch (err) {\n return { removed: false, reason: `Couldn't delete ${driver.label} sandbox ${ref.sandboxId}: ${(err as Error).message}` }\n }\n },\n }\n}\n\nfunction suggestBranch(config: EnvironmentConfig): string {\n return `${typeof config.branchPrefix === 'string' && config.branchPrefix ? config.branchPrefix : 'zidane/'}${randomBytes(3).toString('hex')}`\n}\n\n/** The token as the scripts' env (never on a command line); empty when there is none. */\nfunction tokenEnv(token: string | undefined): Record<string, string> {\n return token ? { [GIT_TOKEN_ENV]: token } : {}\n}\n","/**\n * Daytona environment — a Daytona sandbox per session (hosted or your own\n * Daytona via `apiUrl`). Shared behaviour (clone, branch, push, PR, idle\n * pause) lives in `remote-sandbox.ts`; this file is the vendor.\n *\n * Daytona's own auto-stop is kept as a safety net (twice the idle window,\n * at least 30 minutes): if the host dies without pausing, the sandbox still\n * stops. Stopped sandboxes keep their disk; attaching starts them again.\n */\nimport type { EnvironmentConfig, EnvironmentProvider } from '../environment'\nimport type { RemoteSandboxDriver } from './remote-sandbox'\nimport { createDaytonaProvider } from '../../contexts/daytona'\nimport { createDebugLog } from '../../debug-log'\nimport { createLogger } from '../../logger'\nimport { createRemoteSandboxEnvironmentProvider } from './remote-sandbox'\n\nexport const DAYTONA_ENVIRONMENT_KIND = 'daytona'\n\nconst debugLog = createDebugLog('environment:daytona')\nconst logger = createLogger({ emit: record => debugLog(record.message, record.attrs) })\n\n/** Structural slice of the `@daytona/sdk` client this driver calls. */\ninterface DaytonaSandboxLike {\n id: string\n stop?: () => Promise<unknown>\n delete: () => Promise<unknown>\n}\n\ninterface DaytonaClientLike {\n get: (idOrName: string) => Promise<DaytonaSandboxLike>\n list: (query?: unknown) => AsyncIterable<unknown> | Promise<unknown>\n}\n\ntype DaytonaCtor = new (config?: { apiKey?: string, apiUrl?: string, target?: string }) => DaytonaClientLike\n\nfunction text(config: EnvironmentConfig, key: string): string | undefined {\n const value = config[key]\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction positive(config: EnvironmentConfig, key: string): number | undefined {\n const value = config[key]\n return typeof value === 'number' && value > 0 ? value : undefined\n}\n\nfunction clientOptions(config: EnvironmentConfig): { apiKey?: string, apiUrl?: string, target?: string } {\n const apiKey = text(config, 'apiKey')\n const apiUrl = text(config, 'apiUrl')\n const target = text(config, 'target')\n return { ...(apiKey ? { apiKey } : {}), ...(apiUrl ? { apiUrl } : {}), ...(target ? { target } : {}) }\n}\n\nasync function loadClient(config: EnvironmentConfig): Promise<DaytonaClientLike> {\n let Daytona: DaytonaCtor\n try {\n Daytona = (await import('@daytona/sdk') as unknown as { Daytona: DaytonaCtor }).Daytona\n }\n catch {\n throw new Error('The @daytona/sdk package is not installed. Install it with: bun add @daytona/sdk')\n }\n return new Daytona(clientOptions(config))\n}\n\nexport const daytonaDriver: RemoteSandboxDriver = {\n kind: DAYTONA_ENVIRONMENT_KIND,\n label: 'Daytona',\n description: 'A Daytona sandbox per session, working on a clone of the repo on its own branch.',\n fields: [\n { key: 'apiKey', type: 'secret', label: 'API key', description: 'From app.daytona.io → Keys.', env: 'DAYTONA_API_KEY', placeholder: 'dtn_…' },\n { key: 'apiUrl', type: 'string', label: 'API URL', description: 'Your own Daytona. Empty = hosted Daytona.', env: 'DAYTONA_API_URL', placeholder: 'https://app.daytona.io/api', default: '' },\n { key: 'target', type: 'string', label: 'Region', description: 'Target region. Empty = the organization default.', env: 'DAYTONA_TARGET', placeholder: 'us', default: '' },\n { key: 'snapshot', type: 'string', label: 'Snapshot', description: 'Snapshot to create sandboxes from (needs git). Empty = Daytona\\'s default.', default: '' },\n { key: 'cpu', type: 'number', label: 'CPUs', description: 'Empty = the snapshot default.' },\n { key: 'memory', type: 'number', label: 'Memory (GiB)', description: 'Empty = the snapshot default.' },\n ],\n\n async unavailableReason(config) {\n try {\n await import('@daytona/sdk')\n }\n catch {\n return 'The @daytona/sdk package is not installed. Install it with: bun add @daytona/sdk'\n }\n return text(config, 'apiKey') ? undefined : 'Needs a Daytona API key.'\n },\n\n provider(config, { sandboxId, cwd }) {\n const snapshot = text(config, 'snapshot')\n const cpu = positive(config, 'cpu')\n const memory = positive(config, 'memory')\n return createDaytonaProvider({\n ...clientOptions(config),\n ...(snapshot ? { snapshot } : {}),\n ...(cpu || memory ? { resources: { ...(cpu ? { cpu } : {}), ...(memory ? { memory } : {}) } } : {}),\n ...(sandboxId ? { sandboxId } : {}),\n ...(cwd ? { cwd } : {}),\n onDestroy: 'leave',\n logger,\n })\n },\n\n spawnConfig(config) {\n const idle = typeof config.idleMinutes === 'number' && config.idleMinutes > 0 ? config.idleMinutes : 0\n return { sandbox: { provider: 'daytona', autoStopInterval: Math.max(30, idle * 2) } }\n },\n\n async pause(config, sandboxId) {\n const sandbox = await (await loadClient(config)).get(sandboxId)\n await sandbox.stop?.()\n },\n\n async remove(config, sandboxId) {\n const sandbox = await (await loadClient(config)).get(sandboxId)\n await sandbox.delete()\n },\n\n async verify(config) {\n if (!text(config, 'apiKey'))\n return { ok: false, reason: 'No API key configured.' }\n const client = await loadClient(config)\n const listed = await client.list()\n let count = 0\n if (listed && typeof (listed as AsyncIterable<unknown>)[Symbol.asyncIterator] === 'function') {\n for await (const _ of listed as AsyncIterable<unknown>) {\n if (++count >= 100)\n break\n }\n }\n else if (Array.isArray((listed as { items?: unknown[] })?.items)) {\n count = (listed as { items: unknown[] }).items.length\n }\n const where = text(config, 'apiUrl') ?? 'app.daytona.io'\n return { ok: true, detail: `Connected to ${where}: ${count} sandbox${count === 1 ? '' : 'es'} in this organization.` }\n },\n}\n\nexport function createDaytonaEnvironmentProvider(): EnvironmentProvider {\n return createRemoteSandboxEnvironmentProvider(daytonaDriver)\n}\n","/**\n * Worktree environment — the session gets its own branch in a linked git\n * worktree, commands run on this machine (under the OS sandbox when Local's\n * sandbox setting is on). Sessions keep their project identity: a worktree\n * resolves to its main checkout (`project-root.ts`), so it lists and groups\n * with the rest of the repo.\n *\n * Options (Settings → Environments → Worktree):\n * - location — `<dataDir>/worktrees/…` (default), next to the repo, or\n * in-repo `.zidane/worktrees/` (git-excluded).\n * - branchPrefix / base / onDelete / setupCommand — see the schema.\n *\n * Safety: teardown only removes a CLEAN worktree (no uncommitted or untracked\n * changes) and never deletes the branch — committed work always survives.\n */\nimport type { EnvironmentConfig, EnvironmentPrepareResult, EnvironmentProvider, EnvironmentTeardownResult, SessionEnvironment } from '../environment'\nimport { execFile } from 'node:child_process'\nimport { createHash, randomBytes } from 'node:crypto'\nimport { appendFileSync, existsSync, mkdirSync, readFileSync, statSync } from 'node:fs'\nimport { basename, dirname, join, relative, resolve } from 'node:path'\nimport { createProcessContext } from '../../contexts/process'\nimport { findGitRoot, mainCheckoutRoot } from '../project-root'\nimport { git, GitError, gitSucceeds, isGitInstalled } from './git'\n\nexport const WORKTREE_ENVIRONMENT_KIND = 'worktree'\n\n/** Provider-owned state on `environment.ref`. */\nexport interface WorktreeRef {\n /** The worktree's directory. */\n path: string\n /** The main checkout it belongs to. */\n repoRoot: string\n}\n\nconst SETUP_TIMEOUT_MS = 10 * 60 * 1000\nconst SETUP_OUTPUT_TAIL = 2000\n\nfunction readWorktreeRef(environment: SessionEnvironment): WorktreeRef | undefined {\n const ref = environment.ref as Partial<WorktreeRef> | undefined\n return ref && typeof ref.path === 'string' && typeof ref.repoRoot === 'string' ? { path: ref.path, repoRoot: ref.repoRoot } : undefined\n}\n\n/** A branch name as a single path segment (`zidane/k3f9` → `zidane-k3f9`). */\nfunction branchSlug(branch: string): string {\n return branch.replace(/[^\\w.-]+/g, '-').replace(/^-+|-+$/g, '') || 'worktree'\n}\n\nfunction short(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 8)\n}\n\n/** Where the worktree for `branch` of `repoRoot` goes under `location`. */\nexport function worktreePath(input: { dataDir: string, repoRoot: string, branch: string, location: unknown }): string {\n const slug = branchSlug(input.branch)\n const repo = basename(input.repoRoot)\n switch (input.location) {\n case 'sibling':\n return join(dirname(input.repoRoot), `${repo}--${slug}`)\n case 'in-repo':\n return join(input.repoRoot, '.zidane', 'worktrees', slug)\n default:\n // Hash of the repo path keeps two repos that share a name apart.\n return join(input.dataDir, 'worktrees', `${repo}-${short(input.repoRoot)}`, slug)\n }\n}\n\n/** The repo's default branch: `origin/HEAD`, else an existing `main` / `master`, else `HEAD`. */\nasync function defaultBranch(repoRoot: string, signal?: AbortSignal): Promise<string> {\n try {\n const { stdout } = await git(repoRoot, ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], { signal })\n if (stdout.trim())\n return stdout.trim()\n }\n catch {}\n for (const candidate of ['main', 'master']) {\n if (await gitSucceeds(repoRoot, ['show-ref', '--verify', '--quiet', `refs/heads/${candidate}`], { signal }))\n return candidate\n }\n return 'HEAD'\n}\n\n/** Keep an in-repo worktree dir out of `git status` without touching tracked files. */\nfunction excludeInRepoWorktrees(repoRoot: string): void {\n const exclude = join(repoRoot, '.git', 'info', 'exclude')\n const line = '/.zidane/worktrees/'\n try {\n const current = existsSync(exclude) ? readFileSync(exclude, 'utf8') : ''\n if (current.split('\\n').includes(line))\n return\n mkdirSync(dirname(exclude), { recursive: true })\n appendFileSync(exclude, `${current && !current.endsWith('\\n') ? '\\n' : ''}${line}\\n`)\n }\n catch {}\n}\n\n/** The worktree git already has at `path`, with its branch — for idempotent retries. */\nasync function existingWorktree(repoRoot: string, path: string, signal?: AbortSignal): Promise<{ branch?: string } | undefined> {\n const { stdout } = await git(repoRoot, ['worktree', 'list', '--porcelain'], { signal })\n const target = resolve(path)\n for (const block of stdout.split('\\n\\n')) {\n const lines = block.split('\\n')\n const worktree = lines.find(l => l.startsWith('worktree '))?.slice('worktree '.length)\n if (!worktree || resolve(worktree) !== target)\n continue\n const branch = lines.find(l => l.startsWith('branch '))?.slice('branch refs/heads/'.length)\n return branch ? { branch } : {}\n }\n return undefined\n}\n\nfunction runSetup(command: string, cwd: string, signal?: AbortSignal): Promise<void> {\n return new Promise((resolvePromise, reject) => {\n execFile('sh', ['-c', command], {\n cwd,\n timeout: SETUP_TIMEOUT_MS,\n maxBuffer: 64 * 1024 * 1024,\n encoding: 'utf8',\n ...(signal ? { signal } : {}),\n }, (err, stdout, stderr) => {\n if (!err)\n return resolvePromise()\n const tail = `${stdout}${stderr}`.trim().slice(-SETUP_OUTPUT_TAIL)\n const code = (err as { code?: number | string }).code\n reject(new Error(`Setup command failed${code !== undefined ? ` (exit ${code})` : ''}${tail ? `:\\n${tail}` : '.'}`))\n })\n })\n}\n\nfunction isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n }\n catch {\n return false\n }\n}\n\n/** The session's directory inside the worktree — same subdirectory it was created in, when that exists there. */\nfunction mapIntoWorktree(cwd: string, checkoutRoot: string, worktree: string): string {\n const inner = relative(checkoutRoot, cwd)\n if (!inner || inner.startsWith('..'))\n return worktree\n const candidate = join(worktree, inner)\n return isDirectory(candidate) ? candidate : worktree\n}\n\n/** Create (or reuse, on a retry) the session's worktree: the provider's `prepare`, also run machine-side for `worktree@<machine>`. */\nexport async function prepareWorktree(\n input: { cwd: string, environment: SessionEnvironment, config: EnvironmentConfig, signal?: AbortSignal },\n dataDir: string,\n): Promise<EnvironmentPrepareResult> {\n const { cwd, environment, config, signal } = input\n const checkoutRoot = findGitRoot(cwd)\n if (!checkoutRoot)\n throw new Error(`${cwd} is not inside a git repository.`)\n const repoRoot = mainCheckoutRoot(checkoutRoot) ?? checkoutRoot\n const branch = environment.branch?.trim()\n if (!branch)\n throw new Error('A worktree session needs a branch name.')\n if (!await gitSucceeds(repoRoot, ['check-ref-format', '--branch', branch], { signal }))\n throw new Error(`\"${branch}\" is not a valid branch name.`)\n\n const path = worktreePath({ dataDir, repoRoot, branch, location: config.location })\n const base = environment.base ?? (config.base === 'default' ? await defaultBranch(repoRoot, signal) : 'HEAD')\n\n const existing = await existingWorktree(repoRoot, path, signal)\n if (existing) {\n // A retry after a failed setup (or a restart mid-provisioning): reuse it,\n // but only if it is ours — the same branch.\n if (existing.branch !== branch)\n throw new Error(`${path} is already a worktree for ${existing.branch ? `branch \"${existing.branch}\"` : 'a detached HEAD'}.`)\n }\n else {\n if (existsSync(path))\n throw new Error(`${path} already exists and is not a worktree of this repository.`)\n if (await gitSucceeds(repoRoot, ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], { signal }))\n throw new Error(`Branch \"${branch}\" already exists. Pick another name.`)\n let baseCommit: string\n try {\n baseCommit = (await git(repoRoot, ['rev-parse', '--verify', `${base}^{commit}`], { signal })).stdout.trim()\n }\n catch {\n throw new Error(`Base \"${base}\" doesn't resolve to a commit${base === 'HEAD' ? '. Does the repository have any commits?' : '.'}`)\n }\n if (config.location === 'in-repo')\n excludeInRepoWorktrees(repoRoot)\n mkdirSync(dirname(path), { recursive: true })\n try {\n await git(repoRoot, ['worktree', 'add', '-b', branch, path, baseCommit], { signal })\n }\n catch (err) {\n throw new Error(err instanceof GitError ? err.message : String(err))\n }\n }\n\n const setup = typeof config.setupCommand === 'string' ? config.setupCommand.trim() : ''\n if (setup)\n await runSetup(setup, path, signal)\n\n return {\n cwd: mapIntoWorktree(cwd, checkoutRoot, path),\n // `WorktreeRef`, spelled as a JSON literal (`ref` is persisted metadata).\n environment: { branch, base, ref: { path, repoRoot } },\n }\n}\n\nexport function createWorktreeEnvironmentProvider(options: { dataDir: string }): EnvironmentProvider {\n return {\n kind: WORKTREE_ENVIRONMENT_KIND,\n label: 'Worktree',\n description: 'A new branch in its own git worktree, commands on this machine.',\n takesBranch: true,\n suggestBranch: config => `${typeof config.branchPrefix === 'string' ? config.branchPrefix : 'zidane/'}${randomBytes(3).toString('hex')}`,\n configSchema: [\n {\n key: 'location',\n type: 'choice',\n label: 'Location',\n description: 'Where new worktrees are created.',\n choices: [\n { value: 'data', label: 'Zidane data folder', description: 'worktrees/<repo>/<branch> in the zidane data directory.' },\n { value: 'sibling', label: 'Next to the repository', description: '<repo>--<branch>, beside the checkout.' },\n { value: 'in-repo', label: 'Inside the repository', description: '.zidane/worktrees/, excluded from git.' },\n ],\n default: 'data',\n },\n { key: 'branchPrefix', type: 'string', label: 'Branch prefix', description: 'Prefix of the suggested branch name.', default: 'zidane/', placeholder: 'zidane/' },\n {\n key: 'base',\n type: 'choice',\n label: 'Base',\n description: 'What a new branch starts from.',\n choices: [\n { value: 'head', label: 'Current HEAD', description: 'Whatever the checkout has checked out right now.' },\n { value: 'default', label: 'Default branch', description: 'origin/HEAD, else main or master.' },\n ],\n default: 'head',\n },\n {\n key: 'onDelete',\n type: 'choice',\n label: 'On session delete',\n description: 'What happens to the worktree folder. The branch itself is never deleted.',\n choices: [\n { value: 'if-clean', label: 'Remove if clean', description: 'Removed unless it has uncommitted changes.' },\n { value: 'never', label: 'Keep', description: 'Left on disk; remove it yourself with git worktree remove.' },\n ],\n default: 'if-clean',\n },\n { key: 'setupCommand', type: 'string', label: 'Setup command', description: 'Run in each new worktree before the session starts (e.g. install dependencies).', placeholder: 'bun install', default: '' },\n ],\n\n async available({ cwd }) {\n if (!cwd)\n return { ok: false, reason: 'Pick a folder inside a git repository.' }\n if (!await isGitInstalled())\n return { ok: false, reason: 'git is not installed.' }\n return findGitRoot(cwd) ? { ok: true } : { ok: false, reason: 'The folder is not inside a git repository.' }\n },\n\n prepare: input => prepareWorktree(input, options.dataDir),\n\n execution: ({ cwd, isolation }) => ({\n key: JSON.stringify({ cwd, isolation: isolation ?? null }),\n create: () => createProcessContext({ cwd, ...(isolation ? { isolation } : {}) }),\n }),\n\n teardown: (environment, { config }) => teardownWorktree(readWorktreeRef(environment), environment.branch, config),\n }\n}\n\n/** Remove a session's worktree when clean (`onDelete`); the branch is always kept. */\nexport async function teardownWorktree(ref: WorktreeRef | undefined, branch: string | undefined, config: EnvironmentConfig): Promise<EnvironmentTeardownResult> {\n if (!ref)\n return { removed: true }\n if (config.onDelete === 'never')\n return { removed: false, reason: `Kept the worktree at ${ref.path} (Settings → Environments → Worktree).` }\n if (!existsSync(ref.path)) {\n await gitSucceeds(ref.repoRoot, ['worktree', 'prune'])\n return { removed: true }\n }\n const { stdout } = await git(ref.path, ['status', '--porcelain'])\n if (stdout.trim())\n return { removed: false, reason: `Kept the worktree at ${ref.path}: it has uncommitted changes. The branch${branch ? ` \"${branch}\"` : ''} is kept too.` }\n await git(ref.repoRoot, ['worktree', 'remove', ref.path])\n return { removed: true }\n}\n","import type { ExecutionContext, ExecutionHandle } from '../../contexts/types'\n/**\n * Docker environment — the session's commands run in a container on this\n * machine, on the session's files through a bind mount (so the Files panel,\n * mentions and diffs keep reading the host copy).\n *\n * Options (Settings → Environments → Docker):\n * - image — any image with `sh` (and `git` if the agent should commit).\n * - workspace — `checkout`: bind-mount the session's folder (edits your\n * working tree); `worktree`: a fresh git worktree on its own\n * branch, provisioned exactly like the Worktree kind, then\n * mounted.\n * - network — `bridge` (default) or `none`.\n * - setupCommand — runs in every new container (they're recreated after an\n * idle release, files persist on the host).\n * - idleMinutes — the container is removed after this long without a run;\n * the next prompt starts a fresh one.\n *\n * The container runs as the host user (`uid:gid`) so files it writes into the\n * bind mount aren't root-owned, with `HOME=/tmp` (that uid rarely has a home in\n * the image). Git hooks / config are mounted read-only (`hostWorkspaceMounts`).\n */\nimport type { EnvironmentConfig, EnvironmentProvider, EnvironmentVerifyResult } from '../environment'\nimport { createDockerContext, hostWorkspaceMounts } from '../../contexts/docker'\nimport { findGitRoot } from '../project-root'\nimport { isGitInstalled } from './git'\nimport { createWorktreeEnvironmentProvider } from './worktree'\n\nexport const DOCKER_ENVIRONMENT_KIND = 'docker'\n\nconst DEFAULT_IMAGE = 'node:22'\nconst SETUP_TIMEOUT_SECONDS = 30 * 60\nconst PING_CACHE_MS = 15_000\n\n/** Structural slice of dockerode this provider calls. */\ninterface DockerodeLike {\n ping: () => Promise<unknown>\n version: () => Promise<{ Version?: string, Os?: string, Arch?: string }>\n getImage: (name: string) => { inspect: () => Promise<unknown> }\n pull: (name: string) => Promise<NodeJS.ReadableStream>\n modem: { followProgress: (stream: NodeJS.ReadableStream, done: (err: Error | null) => void) => void }\n}\n\nasync function loadDocker(): Promise<DockerodeLike> {\n let Dockerode: new () => DockerodeLike\n try {\n Dockerode = (await import('dockerode') as unknown as { default: new () => DockerodeLike }).default\n }\n catch {\n throw new Error('The dockerode package is not installed. Install it with: bun add dockerode')\n }\n return new Dockerode()\n}\n\nlet lastPing: { at: number, result: string | undefined } | undefined\n/** `undefined` when the daemon answers; else why not. Cached briefly — pickers ask often. */\nasync function dockerUnavailableReason(): Promise<string | undefined> {\n if (lastPing && Date.now() - lastPing.at < PING_CACHE_MS)\n return lastPing.result\n let result: string | undefined\n try {\n await (await loadDocker()).ping()\n }\n catch (err) {\n const message = (err as Error).message\n result = message.includes('dockerode') ? message : `Docker isn't reachable: ${message}. Is Docker running?`\n }\n lastPing = { at: Date.now(), result }\n return result\n}\n\nfunction text(config: EnvironmentConfig, key: string, fallback = ''): string {\n const value = config[key]\n return typeof value === 'string' && value.trim() ? value.trim() : fallback\n}\n\nfunction usesWorktree(config: EnvironmentConfig): boolean {\n return config.workspace === 'worktree'\n}\n\nasync function ensureImage(image: string, signal?: AbortSignal): Promise<void> {\n const docker = await loadDocker()\n const present = await docker.getImage(image).inspect().then(() => true, () => false)\n if (present)\n return\n signal?.throwIfAborted()\n const stream = await docker.pull(image)\n await new Promise<void>((resolve, reject) => docker.modem.followProgress(stream, err => err ? reject(err) : resolve()))\n}\n\n/** The host user as `uid:gid` (POSIX hosts), so bind-mounted files stay the user's. */\nfunction hostUser(): string | undefined {\n const uid = process.getuid?.()\n const gid = process.getgid?.()\n return uid === undefined || gid === undefined ? undefined : `${uid}:${gid}`\n}\n\n/** Runs `command` in every container the context spawns, before handing the handle back. */\nfunction withSetupCommand(context: ExecutionContext, command: string, cwd: string): ExecutionContext {\n if (!command)\n return context\n return {\n ...context,\n async spawn(config) {\n const handle: ExecutionHandle = await context.spawn(config)\n const result = await context.exec(handle, command, { cwd, timeout: SETUP_TIMEOUT_SECONDS })\n if (result.exitCode !== 0) {\n await context.destroy(handle).catch(() => undefined)\n throw new Error(`Docker setup command failed (exit ${result.exitCode}): ${(result.stderr || result.stdout).trim().slice(-2000)}`)\n }\n return handle\n },\n }\n}\n\nexport function createDockerEnvironmentProvider(options: { dataDir: string }): EnvironmentProvider {\n // `workspace: worktree` provisions and removes exactly like the Worktree kind.\n const worktree = createWorktreeEnvironmentProvider(options)\n const worktreeConfig = (config: EnvironmentConfig): EnvironmentConfig => ({\n location: 'data',\n base: 'head',\n onDelete: 'if-clean',\n branchPrefix: text(config, 'branchPrefix', 'zidane/'),\n })\n\n return {\n kind: DOCKER_ENVIRONMENT_KIND,\n label: 'Docker',\n description: 'Commands run in a container on this machine, on the session\\'s files.',\n offByDefault: true,\n configSchema: [\n { key: 'image', type: 'string', label: 'Image', description: 'Any image with sh (and git, for commits). Pulled when a session is created.', default: DEFAULT_IMAGE, placeholder: DEFAULT_IMAGE },\n {\n key: 'workspace',\n type: 'choice',\n label: 'Workspace',\n choices: [\n { value: 'checkout', label: 'This checkout', description: 'The session\\'s folder, mounted read-write: edits land in your working tree.' },\n { value: 'worktree', label: 'New worktree', description: 'A git worktree on its own branch, like the Worktree environment.' },\n ],\n default: 'checkout',\n },\n { key: 'branchPrefix', type: 'string', label: 'Branch prefix', description: 'Prefix of the suggested branch name.', default: 'zidane/', placeholder: 'zidane/', when: { key: 'workspace', equals: 'worktree' } },\n {\n key: 'network',\n type: 'choice',\n label: 'Network',\n choices: [{ value: 'bridge', label: 'On' }, { value: 'none', label: 'Off' }],\n default: 'bridge',\n },\n { key: 'setupCommand', type: 'string', label: 'Setup command', description: 'Runs in each new container before the session uses it (e.g. install dependencies). Runs as your user, not root, so bake system packages into the image.', placeholder: 'npm ci', default: '' },\n { key: 'idleMinutes', type: 'number', label: 'Remove container after idle (minutes)', description: 'Files stay on this machine; the next prompt starts a fresh container. 0 keeps it.', default: 30 },\n ],\n takesBranch: usesWorktree,\n suggestBranch: config => worktree.suggestBranch!(worktreeConfig(config)),\n idleSuspendMinutes: config => typeof config.idleMinutes === 'number' ? config.idleMinutes : 30,\n\n async available({ cwd, config }) {\n const reason = await dockerUnavailableReason()\n if (reason)\n return { ok: false, reason }\n if (!cwd)\n return { ok: false, reason: 'Pick a folder to mount into the container.' }\n if (usesWorktree(config)) {\n if (!await isGitInstalled())\n return { ok: false, reason: 'git is not installed.' }\n if (!findGitRoot(cwd))\n return { ok: false, reason: 'A new worktree needs a folder inside a git repository.' }\n }\n return { ok: true }\n },\n\n async verify(): Promise<EnvironmentVerifyResult> {\n const docker = await loadDocker()\n await docker.ping()\n const version = await docker.version()\n lastPing = { at: Date.now(), result: undefined }\n return { ok: true, detail: `Docker ${version.Version ?? '?'}${version.Os ? ` (${version.Os}/${version.Arch ?? '?'})` : ''}` }\n },\n\n // Pull the image up front (the first prompt shouldn't absorb it), then —\n // for a worktree workspace — create the worktree.\n async prepare(input) {\n await ensureImage(text(input.config, 'image', DEFAULT_IMAGE), input.signal)\n return usesWorktree(input.config)\n ? worktree.prepare!({ ...input, config: worktreeConfig(input.config) })\n : {}\n },\n\n execution({ cwd, config }) {\n const image = text(config, 'image', DEFAULT_IMAGE)\n const network = config.network === 'none' ? 'none' : undefined\n const setup = text(config, 'setupCommand')\n const user = hostUser()\n return {\n key: JSON.stringify({ cwd, image, network: network ?? null, setup, user: user ?? null }),\n create: () => withSetupCommand(createDockerContext({\n image,\n cwd,\n mounts: hostWorkspaceMounts(cwd),\n env: { HOME: '/tmp' },\n ...(network ? { network } : {}),\n ...(user ? { user } : {}),\n labels: { 'zidane.environment': 'docker' },\n }), setup, cwd),\n }\n },\n\n teardown: (environment, context) => environment.ref\n ? worktree.teardown!(environment, { ...context, config: worktreeConfig(context.config) })\n : Promise.resolve({ removed: true }),\n }\n}\n","/**\n * e2b environment — a Firecracker micro-VM per session (hosted e2b or a\n * self-hosted cluster via `domain`). Shared behaviour (clone, branch, push,\n * PR, idle pause) lives in `remote-sandbox.ts`; this file is the vendor.\n *\n * Lifetime: sandboxes are created with `onTimeout: 'pause'` + `autoResume`,\n * and every command pushes the timeout out to `lifetimeMinutes` — an active\n * session never times out, an abandoned one pauses (state kept) instead of\n * being killed.\n */\nimport type { EnvironmentConfig, EnvironmentProvider } from '../environment'\nimport type { RemoteSandboxDriver } from './remote-sandbox'\nimport { createE2BProvider } from '../../contexts/e2b'\nimport { createDebugLog } from '../../debug-log'\nimport { createLogger } from '../../logger'\nimport { createRemoteSandboxEnvironmentProvider } from './remote-sandbox'\n\nexport const E2B_ENVIRONMENT_KIND = 'e2b'\n\nconst debugLog = createDebugLog('environment:e2b')\nconst logger = createLogger({ emit: record => debugLog(record.message, record.attrs) })\n\n/** Structural slice of the e2b SDK's static `Sandbox` API this driver calls. */\ninterface E2BStatics {\n kill: (sandboxId: string, opts?: E2BApiOptions) => Promise<boolean>\n pause?: (sandboxId: string, opts?: E2BApiOptions) => Promise<boolean>\n betaPause?: (sandboxId: string, opts?: E2BApiOptions) => Promise<boolean>\n list: (opts?: E2BApiOptions & { limit?: number }) => { nextItems: () => Promise<unknown[]> }\n}\n\ninterface E2BApiOptions {\n apiKey?: string\n domain?: string\n}\n\nfunction text(config: EnvironmentConfig, key: string): string | undefined {\n const value = config[key]\n return typeof value === 'string' && value.trim() ? value.trim() : undefined\n}\n\nfunction apiOptions(config: EnvironmentConfig): E2BApiOptions {\n const apiKey = text(config, 'apiKey')\n const domain = text(config, 'domain')\n return { ...(apiKey ? { apiKey } : {}), ...(domain ? { domain } : {}) }\n}\n\nfunction lifetimeSeconds(config: EnvironmentConfig): number {\n const minutes = typeof config.lifetimeMinutes === 'number' && config.lifetimeMinutes > 0 ? config.lifetimeMinutes : 60\n return Math.round(minutes * 60)\n}\n\nasync function loadStatics(): Promise<E2BStatics> {\n try {\n return (await import('e2b') as unknown as { Sandbox: E2BStatics }).Sandbox\n }\n catch {\n throw new Error('The e2b package is not installed. Install it with: bun add e2b')\n }\n}\n\nexport const e2bDriver: RemoteSandboxDriver = {\n kind: E2B_ENVIRONMENT_KIND,\n label: 'E2B',\n description: 'A cloud micro-VM per session, working on a clone of the repo on its own branch.',\n fields: [\n { key: 'apiKey', type: 'secret', label: 'API key', description: 'From e2b.dev → Dashboard → API keys.', env: 'E2B_API_KEY', placeholder: 'e2b_…' },\n { key: 'domain', type: 'string', label: 'Domain', description: 'Self-hosted cluster domain. Empty = hosted e2b.', env: 'E2B_DOMAIN', placeholder: 'e2b.app', default: '' },\n { key: 'template', type: 'string', label: 'Template', description: 'Sandbox template (needs git). Empty = e2b\\'s base template.', env: 'E2B_TEMPLATE', placeholder: 'base', default: '' },\n { key: 'lifetimeMinutes', type: 'number', label: 'Keep-alive window (minutes)', description: 'Pushed out on every command; when it lapses the sandbox pauses. Hobby plans cap it at 60.', default: 60 },\n ],\n\n async unavailableReason(config) {\n try {\n await loadStatics()\n }\n catch (err) {\n return (err as Error).message\n }\n return text(config, 'apiKey') ? undefined : 'Needs an E2B API key.'\n },\n\n provider(config, { sandboxId, cwd }) {\n const seconds = lifetimeSeconds(config)\n const template = text(config, 'template')\n return createE2BProvider({\n ...apiOptions(config),\n ...(template ? { template } : {}),\n ...(sandboxId ? { sandboxId } : {}),\n ...(cwd ? { cwd } : {}),\n timeoutSeconds: seconds,\n keepAliveSeconds: seconds,\n lifecycle: { onTimeout: 'pause', autoResume: true },\n onDestroy: 'leave',\n logger,\n })\n },\n\n async pause(config, sandboxId) {\n const Sandbox = await loadStatics()\n const pause = Sandbox.pause ?? Sandbox.betaPause\n if (!pause)\n throw new Error('This e2b SDK can\\'t pause sandboxes (needs e2b@^2).')\n await pause.call(Sandbox, sandboxId, apiOptions(config))\n },\n\n async remove(config, sandboxId) {\n const Sandbox = await loadStatics()\n await Sandbox.kill(sandboxId, apiOptions(config))\n },\n\n async verify(config) {\n if (!text(config, 'apiKey'))\n return { ok: false, reason: 'No API key configured.' }\n const Sandbox = await loadStatics()\n const running = await Sandbox.list({ ...apiOptions(config), limit: 100 }).nextItems()\n const where = text(config, 'domain') ?? 'e2b.app'\n return { ok: true, detail: `Connected to ${where}: ${running.length} sandbox${running.length === 1 ? '' : 'es'} in this account.` }\n },\n}\n\nexport function createE2BEnvironmentProvider(): EnvironmentProvider {\n return createRemoteSandboxEnvironmentProvider(e2bDriver)\n}\n","/**\n * Local environment — the current checkout, commands on this machine. Its\n * OS-sandbox options are the pre-existing `sandbox*` settings (bound via\n * `setting`, one source of truth); the host turns them into the `isolation`\n * it passes to `execution`.\n */\nimport type { EnvironmentProvider } from '../environment'\nimport { createProcessContext } from '../../contexts/process'\nimport { LOCAL_ENVIRONMENT } from '../environment'\n\nexport const localEnvironmentProvider: EnvironmentProvider = {\n kind: LOCAL_ENVIRONMENT.kind,\n label: 'Local',\n description: 'The current checkout, commands on this machine.',\n configSchema: [\n {\n key: 'sandbox',\n setting: 'sandbox',\n type: 'boolean',\n label: 'OS sandbox',\n description: 'Shell commands run under Seatbelt (macOS) or bubblewrap (Linux), writing only to the project, temp dirs and the git dir. Worktree sessions use it too.',\n default: false,\n },\n {\n key: 'sandboxNetwork',\n setting: 'sandboxNetwork',\n type: 'choice',\n label: 'Sandbox network',\n description: 'Whether sandboxed commands may reach the network.',\n choices: [{ value: 'allow', label: 'Allow' }, { value: 'deny', label: 'Deny' }],\n default: 'allow',\n when: { key: 'sandbox', equals: true },\n },\n {\n key: 'sandboxAllowWrite',\n setting: 'sandboxAllowWrite',\n type: 'string',\n label: 'Sandbox writable paths',\n description: 'Extra directories sandboxed commands may write to, comma-separated.',\n placeholder: '~/.cache, ~/.bun/install/cache',\n default: '',\n when: { key: 'sandbox', equals: true },\n },\n ],\n execution: ({ cwd, isolation }) => ({\n key: JSON.stringify({ cwd, isolation: isolation ?? null }),\n create: () => createProcessContext({ cwd, ...(isolation ? { isolation } : {}) }),\n }),\n}\n","/**\n * The environment providers zidane ships, `local` first. Hosts register these\n * on their registry (`createEnvironmentRegistry(builtinEnvironmentProviders(…))`).\n */\nimport type { EnvironmentProvider } from '../environment'\nimport { createDaytonaEnvironmentProvider } from './daytona'\nimport { createDockerEnvironmentProvider } from './docker'\nimport { createE2BEnvironmentProvider } from './e2b'\nimport { localEnvironmentProvider } from './local'\nimport { createWorktreeEnvironmentProvider } from './worktree'\n\nexport interface BuiltinEnvironmentOptions {\n /** Host data dir (`~/.zidane`) — default home of worktrees. */\n dataDir: string\n}\n\nexport function builtinEnvironmentProviders(options: BuiltinEnvironmentOptions): EnvironmentProvider[] {\n return [\n localEnvironmentProvider,\n createWorktreeEnvironmentProvider(options),\n createDockerEnvironmentProvider(options),\n createE2BEnvironmentProvider(),\n createDaytonaEnvironmentProvider(),\n ]\n}\n\nexport { createDaytonaEnvironmentProvider, DAYTONA_ENVIRONMENT_KIND, daytonaDriver } from './daytona'\nexport { createDockerEnvironmentProvider, DOCKER_ENVIRONMENT_KIND } from './docker'\nexport { createE2BEnvironmentProvider, E2B_ENVIRONMENT_KIND, e2bDriver } from './e2b'\nexport { localEnvironmentProvider } from './local'\nexport type { RemoteSandboxDriver, RemoteSandboxRef } from './remote-sandbox'\nexport { createRemoteSandboxEnvironmentProvider, readRemoteSandboxRef } from './remote-sandbox'\nexport type { WorktreeRef } from './worktree'\nexport { createWorktreeEnvironmentProvider, prepareWorktree, teardownWorktree, WORKTREE_ENVIRONMENT_KIND, worktreePath } from './worktree'\n","/**\n * `local@<machine>` and `worktree@<machine>`: the local and worktree\n * environments, with their folders and commands on a machine. The host\n * pre-checks a session folder against the machine's declared roots\n * (lexically: the folder is not on this host); the machine re-checks it on\n * its filesystem while the environment provisions (`env.checkFolder` /\n * `env.prepareWorktree`), and on every call after that.\n */\nimport type { EnvironmentProvider, SessionEnvironment } from '../../environment'\nimport type { MachineCapabilities, MachineRoot } from '../../machine-protocol'\nimport type { MachineLink } from './link'\nimport { randomBytes } from 'node:crypto'\nimport { posix } from 'node:path'\nimport { createWorktreeEnvironmentProvider } from '../../environments'\nimport { machineKind } from '../../machine-protocol'\nimport { createMachineContext } from './context'\n\n/** What a machine's providers look the machine up through (it can be forgotten, renamed or offline). */\nexport interface MachineLookup {\n /** The machine holding `name` now. */\n byName: (name: string) => { id: string, roots: readonly MachineRoot[], capabilities?: Partial<MachineCapabilities> } | undefined\n status: (machineId: string) => 'online' | 'offline'\n link: (machineId: string) => MachineLink | undefined\n}\n\ninterface MachineRef {\n machineId: string\n path?: string\n repoRoot?: string\n}\n\nfunction readMachineRef(environment: SessionEnvironment): MachineRef | undefined {\n const ref = environment.ref as Partial<MachineRef> | undefined\n return ref && typeof ref.machineId === 'string' ? ref as MachineRef : undefined\n}\n\n/** Inside a declared root, by the path's own spelling (the machine checks real paths). */\nexport function insideDeclaredRoots(roots: readonly MachineRoot[], cwd: string): boolean {\n if (!cwd.startsWith('/'))\n return false\n const normalized = posix.normalize(cwd)\n return roots.some((root) => {\n const r = posix.normalize(root.path).replace(/\\/+$/, '') || '/'\n return normalized === r || normalized.startsWith(r === '/' ? '/' : `${r}/`)\n })\n}\n\nexport function createMachineProviders(name: string, machines: MachineLookup): EnvironmentProvider[] {\n const unknown = (): Error => new Error(`Unknown machine \"${name}\": it was removed from this host, or never registered.`)\n const machine = () => machines.byName(name)\n\n /** The link for a session's environment: the machine it was created on, still under this name. */\n const linkFor = (environment: SessionEnvironment): MachineLink => {\n const current = machine()\n const ref = readMachineRef(environment)\n if (!current || (ref && ref.machineId !== current.id))\n throw unknown()\n const link = machines.link(current.id)\n if (!link)\n throw unknown()\n return link\n }\n\n const checkFolder = (cwd: string): string => {\n const current = machine()\n if (!current)\n throw unknown()\n if (!insideDeclaredRoots(current.roots, cwd))\n throw new Error(`${cwd || '(no folder)'} is outside ${name}'s roots (${current.roots.map(r => r.path).join(', ')}).`)\n return posix.normalize(cwd)\n }\n\n const describe = (): { id: string, name: string, status: 'online' | 'offline' } | undefined => {\n const current = machine()\n return current ? { id: current.id, name, status: machines.status(current.id) } : undefined\n }\n\n // Not about a folder: pickers ask the kind first, then a folder on the machine (checked at creation).\n const available: EnvironmentProvider['available'] = () => (machine() ? { ok: true } : { ok: false, reason: `${name} is not a machine of this host.` })\n\n const execution: EnvironmentProvider['execution'] = ({ sessionId, cwd, environment }) => {\n const link = linkFor(environment)\n return {\n key: JSON.stringify({ machineId: link.machineId, cwd }),\n create: () => createMachineContext({ link, sessionId, cwd, capabilities: machine()?.capabilities }),\n promptCwd: cwd,\n }\n }\n\n const worktreeSchema = (createWorktreeEnvironmentProvider({ dataDir: '' }).configSchema ?? []).filter(field => field.key !== 'location')\n\n const local: EnvironmentProvider = {\n kind: machineKind('local', name),\n label: `Local @ ${name}`,\n description: `A folder on ${name}; commands run there.`,\n checkFolder,\n machine: describe,\n available,\n async prepare({ sessionId, cwd, signal }) {\n const link = linkFor({ kind: local.kind, state: 'provisioning' })\n const checked = await link.call('env.checkFolder', { cwd }, { sessionId, ...(signal ? { signal } : {}) })\n return { cwd: checked.cwd, environment: { ref: { machineId: link.machineId } } }\n },\n execution,\n }\n\n const worktree: EnvironmentProvider = {\n kind: machineKind('worktree', name),\n label: `Worktree @ ${name}`,\n description: `A new branch in its own git worktree on ${name}; commands run there.`,\n takesBranch: true,\n suggestBranch: config => `${typeof config.branchPrefix === 'string' ? config.branchPrefix : 'zidane/'}${randomBytes(3).toString('hex')}`,\n configSchema: worktreeSchema,\n checkFolder,\n machine: describe,\n available,\n async prepare({ sessionId, cwd, environment, config, signal }) {\n const link = linkFor(environment)\n const branch = environment.branch?.trim()\n if (!branch)\n throw new Error('A worktree session needs a branch name.')\n const prepared = await link.call('env.prepareWorktree', { cwd, branch, ...(environment.base ? { base: environment.base } : {}), config }, { sessionId, ...(signal ? { signal } : {}) })\n return { cwd: prepared.cwd, environment: { branch: prepared.branch, base: prepared.base, ref: { machineId: link.machineId, ...prepared.ref } } }\n },\n execution,\n async teardown(environment, { config }) {\n const ref = readMachineRef(environment)\n if (!ref?.path || !ref.repoRoot)\n return { removed: true }\n const link = machines.link(ref.machineId)\n if (!link?.online())\n return { removed: false, reason: `Kept the worktree at ${ref.path}: ${name} is offline.` }\n return link.call('env.teardownWorktree', { ref: { path: ref.path, repoRoot: ref.repoRoot }, ...(environment.branch ? { branch: environment.branch } : {}), config }, { wait: false })\n },\n }\n\n return [local, worktree]\n}\n","/**\n * A machine session's project files (`docs/MACHINES.md` § Project files):\n * the session folder is on the machine, so its project-scope instructions\n * (`AGENTS.md`, `CLAUDE.md`, `SYSTEM.md`), skills and MCP servers are read\n * THERE, through the session's own machine context (its `fs.read` /\n * `fs.list`, confined to the machine's roots). User scope stays this host's.\n *\n * Never code: project extensions and plugins are not loaded from a machine\n * (the host never runs what a machine provides). A project MCP server is\n * kept only as a stdio server run ON the machine (`scope: 'context'`, over\n * `execStream`), with every `${VAR}` placeholder resolved before this host's\n * environment could fill it; a URL server is dropped with a notice.\n *\n * Bounded: per-file and per-list caps, so a machine can't stall or swell an\n * agent build.\n */\nimport type { ExecutionContext, ExecutionHandle } from '../../../contexts/types'\nimport type { McpServerConfig } from '../../../mcp'\nimport type { SkillConfig } from '../../../skills'\nimport type { AgentsMdFile } from '../../agents-md'\nimport type { MachineRoot } from '../../machine-protocol'\nimport type { DiscoveredMcp } from '../../mcps-discovery'\nimport type { SystemMdFile } from '../../system-md'\nimport { posix } from 'node:path'\nimport { withoutEnvPlaceholders } from '../../../mcp'\nimport { parseSkillContent } from '../../../skills'\nimport { parseMcpsFile } from '../../mcps-discovery'\nimport { insideDeclaredRoots } from './providers'\n\nconst MAX_INSTRUCTION_BYTES = 64 * 1024\nconst MAX_SKILL_BYTES = 256 * 1024\nconst MAX_MCP_BYTES = 256 * 1024\nconst MAX_SKILLS = 64\n\nexport interface MachineProject {\n /** The project root on the machine: its git root when inside the roots, else the session folder. */\n root: string\n /** Project-scope `AGENTS.md` / `CLAUDE.md`, in the order the local discovery loads them. */\n agentsMd: AgentsMdFile[]\n /** `<root>/SYSTEM.md`, when present. */\n systemMd: SystemMdFile | null\n skills: SkillConfig[]\n /** Stdio servers, context-scoped, placeholders resolved. */\n mcps: DiscoveredMcp[]\n /** What was left out, for the session's notices. */\n notices: string[]\n}\n\nexport interface MachineProjectInput {\n context: ExecutionContext\n handle: ExecutionHandle\n cwd: string\n roots: readonly MachineRoot[]\n /** The host's storage prefix (`.zidane`). */\n prefix: string\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max)}\\n\\n[... truncated; ${text.length - max} more bytes in source file ...]` : text\n}\n\n/** A machine's MCP server as this host may run it: on the machine, never reading this host's environment. */\nexport function machineMcpServer(config: McpServerConfig): McpServerConfig | null {\n if (config.transport !== 'stdio')\n return null\n return { ...withoutEnvPlaceholders(config), scope: 'context' }\n}\n\nexport async function readMachineProject(input: MachineProjectInput): Promise<MachineProject> {\n const { context, handle, cwd, roots } = input\n const prefix = input.prefix.replace(/^\\./, '')\n const notices: string[] = []\n\n const read = async (path: string, max: number): Promise<string | undefined> => {\n try {\n const size = context.fileSize ? await context.fileSize(handle, path) : null\n if (size === null && context.fileSize)\n return undefined\n if (size !== null && size > max * 4)\n return undefined\n return await context.readFile(handle, path)\n }\n catch {\n return undefined\n }\n }\n const list = async (dir: string): Promise<string[]> => {\n try {\n return (await context.listFiles(handle, dir)).map(entry => (typeof entry === 'string' ? entry : entry.path))\n }\n catch {\n return []\n }\n }\n\n const root = await (async () => {\n try {\n const result = await context.exec(handle, 'git rev-parse --show-toplevel', { cwd, timeout: 10 })\n const top = result.exitCode === 0 ? result.stdout.trim() : ''\n return top && insideDeclaredRoots(roots, top) ? posix.normalize(top) : cwd\n }\n catch {\n return cwd\n }\n })()\n\n const agentsMd: AgentsMdFile[] = []\n for (const rel of ['AGENTS.md', '.agents/AGENTS.md', `.${prefix}/AGENTS.md`, 'CLAUDE.md']) {\n const path = posix.join(root, rel)\n const text = await read(path, MAX_INSTRUCTION_BYTES)\n if (text && text.trim())\n agentsMd.push({ path, source: 'project', contents: truncate(text, MAX_INSTRUCTION_BYTES) })\n }\n\n const systemPath = posix.join(root, 'SYSTEM.md')\n const systemText = await read(systemPath, MAX_INSTRUCTION_BYTES)\n const systemMd = systemText && systemText.trim() ? { path: systemPath, source: 'project' as const, contents: truncate(systemText, MAX_INSTRUCTION_BYTES) } : null\n\n // First found wins on a name, as on this host: `.agents` before `.<prefix>`.\n const skills: SkillConfig[] = []\n const names = new Set<string>()\n for (const rel of ['.agents/skills', `.${prefix}/skills`]) {\n const dir = posix.join(root, rel)\n for (const entry of (await list(dir)).filter(e => e.endsWith('/'))) {\n if (skills.length >= MAX_SKILLS)\n break\n const location = posix.join(dir, entry, 'SKILL.md')\n const text = await read(location, MAX_SKILL_BYTES)\n const skill = text ? parseSkillContent(text, location, { source: 'project' }) : null\n if (skill && !names.has(skill.name)) {\n names.add(skill.name)\n skills.push(skill)\n }\n }\n }\n\n const mcps: DiscoveredMcp[] = []\n const servers = new Set<string>()\n for (const rel of ['.agents/mcps.json', '.agents/mcp.json', `.${prefix}/mcps.json`, `.${prefix}/mcp.json`]) {\n const path = posix.join(root, rel)\n const text = await read(path, MAX_MCP_BYTES)\n if (!text)\n continue\n let configs: McpServerConfig[]\n try {\n configs = parseMcpsFile(text)\n }\n catch (err) {\n notices.push(`${path}: ${(err as Error).message}`)\n continue\n }\n for (const config of configs) {\n if (servers.has(config.name))\n continue\n servers.add(config.name)\n const server = machineMcpServer(config)\n if (server)\n mcps.push({ config: server, source: 'project', path })\n else\n notices.push(`MCP server \"${config.name}\" (${path}) is a URL server: only stdio servers from a machine run, on the machine.`)\n }\n }\n\n return { root, agentsMd, systemMd, skills, mcps, notices }\n}\n","/**\n * One machine's link: the live connection when it has one, and the offline\n * semantics of `docs/MACHINES.md` § Offline. A call made while offline waits\n * (it was never sent, so sending it later is safe) up to `machineWaitMinutes`;\n * a call sent on a connection that then drops is not re-sent (it may have\n * run) unless it is read-only. The session gets one \"waiting\" notice per\n * outage, \"back\" when the machine returns, \"gave up\" on the timeout.\n */\nimport type { MachineMethodName, MachineParams, MachineResult } from '../../machine-protocol'\nimport { Buffer } from 'node:buffer'\nimport { MACHINE_IDEMPOTENT_METHODS } from '../../machine-protocol'\nimport { MachineLinkLostError, MachineResultLostError, MachineUnavailableError } from './errors'\n\n/** The transport's side of a live machine connection (`src/ipc/daemon/machine-gateway.ts`). */\nexport interface MachineConnection {\n /** Rejects with {@link MachineLinkLostError} when the connection drops before the reply. */\n request: (method: string, params: unknown) => Promise<unknown>\n notify: (method: string, params: unknown) => void\n close: (reason: string) => void\n}\n\nexport interface MachineTimers {\n setTimeout: (fn: () => void, ms: number) => unknown\n clearTimeout: (id: unknown) => void\n}\n\nexport const realTimers: MachineTimers = {\n setTimeout: (fn, ms) => {\n const timer = setTimeout(fn, ms)\n timer.unref?.()\n return timer\n },\n clearTimeout: id => clearTimeout(id as ReturnType<typeof setTimeout>),\n}\n\n/** What the host does when a machine's state touches a session. */\nexport interface MachineEvents {\n status?: (change: { machineId: string, name: string, status: 'online' | 'offline' }) => void\n waiting?: (sessionId: string, name: string) => void\n back?: (sessionId: string, name: string) => void\n gaveUp?: (sessionId: string, name: string, minutes: number) => void\n}\n\nexport interface MachineCallOptions {\n /** The session the call is for: its notices, its give-up. */\n sessionId?: string\n signal?: AbortSignal\n /** Called once when `signal` aborts a call already sent (cancel it machine-side). */\n onAbort?: () => void\n /** `false`: fail at once when offline instead of waiting (teardown, terminal keystrokes). */\n wait?: boolean\n}\n\nexport interface TerminalListener {\n onData: (data: Uint8Array) => void\n exit: (code: number) => void\n /** Bytes received so far: a reattach replays only what came after. */\n seen: number\n}\n\n/** A live `exec.stream` process, as the host side hears it. */\nexport interface StreamListener {\n data: (stream: 'stdout' | 'stderr', bytes: Uint8Array) => void\n exit: (code: number) => void\n}\n\nexport interface MachineLink {\n readonly machineId: string\n name: () => string\n online: () => boolean\n call: <M extends MachineMethodName>(method: M, params: MachineParams<M>, options?: MachineCallOptions) => Promise<MachineResult<M>>\n /** Fire-and-forget; dropped while offline. */\n notify: (method: string, params: unknown) => void\n /** Background task exits by task id (the machine sends `task.exit`). */\n tasks: Map<string, (exit: unknown) => void>\n /** Live terminals by id (the machine sends `terminal.data` / `terminal.exit`). */\n terminals: Map<string, TerminalListener>\n /** Live streams by call id (`exec.stream.data` / `exec.stream.exit`); a dropped link ends them (exit -1). */\n streams: Map<string, StreamListener>\n /** A notification from the machine. */\n deliver: (method: string, params: unknown) => void\n /** The registry swaps the connection (`null`: offline). */\n setConnection: (connection: MachineConnection | null) => void\n connection: () => MachineConnection | null\n /** The host is closing: fail every waiting call, and wait no more. */\n shutdown: () => void\n}\n\ninterface Waiter {\n resolve: (connection: MachineConnection) => void\n reject: (err: unknown) => void\n}\n\nfunction abortReason(signal: AbortSignal): unknown {\n return signal.reason ?? new DOMException('The operation was aborted.', 'AbortError')\n}\n\nexport function createMachineLink(input: { machineId: string, name: () => string, waitMinutes: () => number, timers: MachineTimers, events: MachineEvents }): MachineLink {\n const { machineId, name, timers, events } = input\n let current: MachineConnection | null = null\n const waiters = new Set<Waiter>()\n /** Sessions told \"waiting\" in this outage. */\n const noticed = new Set<string>()\n const tasks = new Map<string, (exit: unknown) => void>()\n const terminals = new Map<string, TerminalListener>()\n const streams = new Map<string, StreamListener>()\n let closed = false\n\n function waitForConnection(options: MachineCallOptions): Promise<MachineConnection> {\n if (options.wait === false || closed)\n return Promise.reject(new MachineUnavailableError(name()))\n const { sessionId, signal } = options\n if (signal?.aborted)\n return Promise.reject(abortReason(signal))\n const minutes = input.waitMinutes()\n return new Promise((resolve, reject) => {\n const pending: { timer?: unknown, onAbort?: () => void } = {}\n const waiter: Waiter = {\n resolve: (connection) => {\n settle()\n resolve(connection)\n },\n reject: (err) => {\n settle()\n reject(err)\n },\n }\n function settle(): void {\n waiters.delete(waiter)\n timers.clearTimeout(pending.timer)\n if (pending.onAbort)\n signal?.removeEventListener('abort', pending.onAbort)\n }\n pending.onAbort = () => waiter.reject(abortReason(signal!))\n pending.timer = timers.setTimeout(() => {\n waiter.reject(new MachineUnavailableError(name(), minutes))\n if (sessionId !== undefined && noticed.delete(sessionId))\n events.gaveUp?.(sessionId, name(), minutes)\n }, minutes * 60_000)\n signal?.addEventListener('abort', pending.onAbort, { once: true })\n waiters.add(waiter)\n if (sessionId !== undefined && !noticed.has(sessionId)) {\n noticed.add(sessionId)\n events.waiting?.(sessionId, name())\n }\n })\n }\n\n /** The reply, or the abort: an aborted call is cancelled machine-side by `onAbort`. */\n function raced<T>(reply: Promise<T>, options: MachineCallOptions): Promise<T> {\n const { signal } = options\n if (!signal)\n return reply\n return new Promise<T>((resolve, reject) => {\n const onAbort = (): void => {\n options.onAbort?.()\n reject(abortReason(signal))\n }\n if (signal.aborted)\n return onAbort()\n signal.addEventListener('abort', onAbort, { once: true })\n reply.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort))\n })\n }\n\n async function call(method: MachineMethodName, params: unknown, options: MachineCallOptions = {}): Promise<unknown> {\n for (;;) {\n const connection = current ?? await waitForConnection(options)\n try {\n return await raced(connection.request(method, params), options)\n }\n catch (err) {\n if (!(err instanceof MachineLinkLostError))\n throw err\n if (!MACHINE_IDEMPOTENT_METHODS.has(method))\n throw new MachineResultLostError(name())\n }\n }\n }\n\n function reattachTerminals(connection: MachineConnection): void {\n for (const [terminalId, listener] of terminals) {\n void connection.request('terminal.attach', { terminalId }).then((reply) => {\n const { attached, backlog, total } = reply as { attached: boolean, backlog: string, total?: number }\n if (!attached) {\n terminals.delete(terminalId)\n listener.exit(-1)\n return\n }\n const bytes = Buffer.from(backlog, 'base64')\n const missed = typeof total === 'number' ? Math.min(Math.max(total - listener.seen, 0), bytes.byteLength) : 0\n if (missed > 0) {\n listener.seen += missed\n listener.onData(bytes.subarray(bytes.byteLength - missed))\n }\n }, () => undefined)\n }\n }\n\n return {\n machineId,\n name,\n online: () => current !== null,\n call: call as MachineLink['call'],\n notify(method, params) {\n try {\n current?.notify(method, params)\n }\n catch {\n // A dying connection; the call it was for fails on its own.\n }\n },\n tasks,\n terminals,\n streams,\n deliver(method, params) {\n const p = (params ?? {}) as Record<string, unknown>\n if (method === 'task.exit' && typeof p.taskId === 'string') {\n tasks.get(p.taskId)?.(p.exit)\n tasks.delete(p.taskId)\n }\n else if (method === 'terminal.data' && typeof p.terminalId === 'string' && typeof p.data === 'string') {\n const listener = terminals.get(p.terminalId)\n if (listener) {\n const bytes = Buffer.from(p.data, 'base64')\n listener.seen += bytes.byteLength\n listener.onData(bytes)\n }\n }\n else if (method === 'terminal.exit' && typeof p.terminalId === 'string') {\n terminals.get(p.terminalId)?.exit(typeof p.code === 'number' ? p.code : -1)\n terminals.delete(p.terminalId)\n }\n else if (method === 'exec.stream.data' && typeof p.callId === 'string' && typeof p.data === 'string') {\n streams.get(p.callId)?.data(p.stream === 'stderr' ? 'stderr' : 'stdout', Buffer.from(p.data, 'base64'))\n }\n else if (method === 'exec.stream.exit' && typeof p.callId === 'string') {\n const listener = streams.get(p.callId)\n streams.delete(p.callId)\n listener?.exit(typeof p.code === 'number' ? p.code : -1)\n }\n },\n setConnection(connection) {\n const wasOnline = current !== null\n current = connection\n if (!connection) {\n // The machine kills its streams when the link drops: output past this point is gone.\n for (const [callId, listener] of [...streams]) {\n streams.delete(callId)\n listener.exit(-1)\n }\n return\n }\n for (const waiter of [...waiters])\n waiter.resolve(connection)\n for (const sessionId of noticed)\n events.back?.(sessionId, name())\n noticed.clear()\n if (wasOnline)\n return\n reattachTerminals(connection)\n },\n connection: () => current,\n shutdown() {\n closed = true\n for (const waiter of [...waiters])\n waiter.reject(new MachineUnavailableError(name()))\n },\n }\n}\n","/**\n * The host's machines: every machine it knows (persisted, so environments\n * reference them while offline) and the links of the ones online. A machine\n * registers on its own connection (`attach`); the transport reports its\n * notifications and its close. See `docs/MACHINES.md` § Host side.\n */\nimport type { EnvironmentRegistry } from '../../environment'\nimport type { MachineCapabilities, MachineInfo, MachineRegisterParams, MachineRegisterResult, MachineRoot } from '../../machine-protocol'\nimport type { MachineConnection, MachineEvents, MachineLink, MachineTimers } from './link'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { writeJsonFileAtomic } from '../../../atomic-write'\nimport { isValidMachineName, MACHINE_PROTOCOL_VERSION, MachineErrorCode } from '../../machine-protocol'\nimport { INVALID_PARAMS, MachineProtocolError, versionSkew } from './errors'\nimport { createMachineLink, realTimers } from './link'\nimport { createMachineProviders } from './providers'\n\nexport const DEFAULT_MACHINE_WAIT_MINUTES = 15\nconst MAX_ROOTS = 32\nconst MACHINES_FILE = 'machines.json'\n\ninterface MachineRecord {\n id: string\n name: string\n roots: MachineRoot[]\n lastSeen?: number\n version?: string\n capabilities?: Partial<MachineCapabilities>\n /**\n * The token it first registered with: the id is bound to it (ids are not\n * secrets). Another token registering this id is refused while this one\n * is live; a revoked one frees the id for the next registration.\n */\n principal?: string\n}\n\n/** A machine the host forgot, and the token it had: that pair never registers again (a new token can). */\ninterface ForgottenBinding {\n machineId: string\n principal: string\n}\n\nconst MAX_FORGOTTEN = 256\n\nexport interface MachineRegistryOptions {\n /** Host data dir: `machines.json` lives there. */\n dataDir: string\n /** The host's environment registry: each known machine adds its kinds. */\n environments: EnvironmentRegistry\n waitMinutes: () => number\n timers?: MachineTimers\n events: MachineEvents\n now?: () => number\n /**\n * Whether a registering token is still valid (a server's token store).\n * Absent: every recorded principal counts as live.\n */\n principalLive?: (principal: string) => boolean\n /** `false`: known machines read as absent (remote hosts turned off since); their kinds stop resolving. */\n active?: () => boolean\n}\n\n/** One registered connection, as the transport drives it. */\nexport interface AttachedMachine {\n result: MachineRegisterResult\n /** A notification the machine sent. */\n notification: (method: string, params: unknown) => void\n /** Its connection closed. */\n closed: () => void\n}\n\nexport interface MachineRegistry {\n list: () => MachineInfo[]\n get: (machineId: string) => MachineInfo | undefined\n link: (machineId: string) => MachineLink | undefined\n attach: (params: MachineRegisterParams, connection: MachineConnection, meta?: { principal?: string }) => AttachedMachine\n /** Forget a machine (it disconnects; its environments stop resolving). */\n forget: (machineId: string) => boolean\n /** A notification for `machineId`'s link (tests drive it directly). */\n deliver: (machineId: string, method: string, params: unknown) => void\n /** The host is draining: calls waiting for an offline machine fail now instead of holding the drain. */\n close: () => void\n /** Run `fn` when the host drains (what keeps links to machines open stops with it). */\n onClose: (fn: () => void) => void\n}\n\nfunction validRoots(value: unknown): MachineRoot[] {\n if (!Array.isArray(value) || value.length === 0 || value.length > MAX_ROOTS)\n throw new MachineProtocolError(INVALID_PARAMS, `machine.register: \"roots\" must list 1 to ${MAX_ROOTS} folders.`)\n return value.map((root) => {\n const r = root as Partial<MachineRoot>\n if (!r || typeof r.path !== 'string' || !r.path.startsWith('/') || r.path.length > 4096 || (r.label !== undefined && typeof r.label !== 'string'))\n throw new MachineProtocolError(INVALID_PARAMS, 'machine.register: each root is { path (absolute), label? }.')\n return { path: r.path, ...(r.label ? { label: r.label.slice(0, 200) } : {}) }\n })\n}\n\n/** Booleans only: what the machine says it can do. */\nfunction capabilitiesOf(value: unknown): Partial<MachineCapabilities> {\n const raw = (value && typeof value === 'object' ? value : {}) as Record<string, unknown>\n const keys = ['shell', 'terminals', 'background', 'worktrees', 'stream', 'sandboxed'] as const\n return Object.fromEntries(keys.filter(key => typeof raw[key] === 'boolean').map(key => [key, raw[key]])) as Partial<MachineCapabilities>\n}\n\nfunction loadFile(file: string): { machines: MachineRecord[], forgotten: ForgottenBinding[] } {\n if (!existsSync(file))\n return { machines: [], forgotten: [] }\n try {\n const parsed = JSON.parse(readFileSync(file, 'utf8')) as { machines?: unknown, forgotten?: unknown }\n return {\n machines: Array.isArray(parsed.machines)\n ? parsed.machines.filter((m): m is MachineRecord => !!m && typeof m.id === 'string' && typeof m.name === 'string' && Array.isArray(m.roots))\n : [],\n forgotten: Array.isArray(parsed.forgotten)\n ? parsed.forgotten.filter((f): f is ForgottenBinding => !!f && typeof f.machineId === 'string' && typeof f.principal === 'string')\n : [],\n }\n }\n catch {\n return { machines: [], forgotten: [] }\n }\n}\n\nconst idBound = (message: string): MachineProtocolError => new MachineProtocolError(MachineErrorCode.IdBound, message)\n\nexport function createMachineRegistry(options: MachineRegistryOptions): MachineRegistry {\n const { environments, events } = options\n const timers = options.timers ?? realTimers\n const now = options.now ?? Date.now\n const file = join(options.dataDir, MACHINES_FILE)\n const loaded = loadFile(file)\n const records = new Map<string, MachineRecord>(loaded.machines.map(record => [record.id, record]))\n let forgotten = loaded.forgotten\n const live = (principal: string): boolean => options.principalLive?.(principal) ?? true\n const active = (): boolean => options.active?.() ?? true\n const links = new Map<string, MachineLink>()\n const registeredNames = new Set<string>()\n const closers: Array<() => void> = []\n\n const save = (): void => {\n try {\n // A revoked token can't come back: its forgotten bindings are moot.\n forgotten = forgotten.filter(f => live(f.principal)).slice(-MAX_FORGOTTEN)\n writeJsonFileAtomic(file, { version: 1, machines: [...records.values()], ...(forgotten.length > 0 ? { forgotten } : {}) }, { ensureDir: true, mode: 0o600 })\n }\n catch {\n // Best effort: a machine still works this run; it is just forgotten on restart.\n }\n }\n\n const byName = (name: string): MachineRecord | undefined => (active() ? [...records.values()].find(record => record.name === name) : undefined)\n\n /** Refuse `principal` registering `machineId` when the id is bound to another live token, or this pair was forgotten. */\n const checkBinding = (machineId: string, principal: string | undefined): void => {\n const bound = records.get(machineId)?.principal\n if (bound && bound !== principal && live(bound))\n throw idBound(`Machine ${machineId} is registered on this host with another token. Use that machine's own token, or revoke it (or forget the machine) first.`)\n if (principal && forgotten.some(f => f.machineId === machineId && f.principal === principal))\n throw idBound(`This host forgot machine ${machineId}: create a new machine token to share it again.`)\n }\n\n const linkOf = (record: MachineRecord): MachineLink => {\n let link = links.get(record.id)\n if (!link) {\n link = createMachineLink({ machineId: record.id, name: () => records.get(record.id)?.name ?? record.name, waitMinutes: options.waitMinutes, timers, events })\n links.set(record.id, link)\n }\n return link\n }\n\n /** The machine's environment kinds, once per name (a registry keeps its first registration; they look the machine up when used). */\n const registerKinds = (name: string): void => {\n if (registeredNames.has(name))\n return\n registeredNames.add(name)\n for (const provider of createMachineProviders(name, { byName, status: id => (links.get(id)?.online() ? 'online' : 'offline'), link: id => (records.has(id) ? linkOf(records.get(id)!) : undefined) }))\n environments.register(provider)\n }\n for (const record of records.values())\n registerKinds(record.name)\n\n const info = (record: MachineRecord): MachineInfo => ({\n id: record.id,\n name: record.name,\n roots: record.roots,\n status: links.get(record.id)?.online() ? 'online' : 'offline',\n ...(record.lastSeen !== undefined ? { lastSeen: record.lastSeen } : {}),\n ...(record.version ? { version: record.version } : {}),\n ...(record.capabilities ? { capabilities: record.capabilities } : {}),\n })\n\n function attach(params: MachineRegisterParams, connection: MachineConnection, meta: { principal?: string } = {}): AttachedMachine {\n if (!active())\n throw new MachineProtocolError(MachineErrorCode.MethodNotAllowed, 'This host takes no machines: remote hosts are off on it.')\n if (params.protocolVersion !== MACHINE_PROTOCOL_VERSION)\n throw versionSkew(params.protocolVersion, MACHINE_PROTOCOL_VERSION)\n if (typeof params.machineId !== 'string' || !/^[\\w-]{1,64}$/.test(params.machineId))\n throw new MachineProtocolError(INVALID_PARAMS, 'machine.register: \"machineId\" must be 1 to 64 letters, digits, \"-\" or \"_\".')\n if (typeof params.name !== 'string' || !isValidMachineName(params.name))\n throw new MachineProtocolError(INVALID_PARAMS, 'machine.register: \"name\" must be 1 to 64 letters, digits, \".\", \"-\" or \"_\".')\n const roots = validRoots(params.roots)\n checkBinding(params.machineId, meta.principal)\n const holder = [...records.values()].find(record => record.name === params.name)\n if (holder && holder.id !== params.machineId)\n throw new MachineProtocolError(MachineErrorCode.NameTaken, `The name \"${params.name}\" belongs to another machine on this host. Pick another name, or forget that machine first.`)\n\n const record: MachineRecord = {\n id: params.machineId,\n name: params.name,\n roots,\n lastSeen: now(),\n ...(typeof params.version === 'string' ? { version: params.version.slice(0, 100) } : {}),\n ...(meta.principal ? { principal: meta.principal } : {}),\n capabilities: capabilitiesOf(params.capabilities),\n }\n records.set(record.id, record)\n if (meta.principal)\n forgotten = forgotten.filter(f => f.machineId !== record.id)\n save()\n registerKinds(record.name)\n const link = linkOf(record)\n // A machine that reconnected before its old connection was noticed dead: the new one wins.\n link.connection()?.close('replaced by a new connection')\n link.setConnection(connection)\n events.status?.({ machineId: record.id, name: record.name, status: 'online' })\n\n let live = true\n return {\n result: { machineId: record.id },\n notification: (method, p) => {\n if (live)\n link.deliver(method, p)\n },\n closed() {\n if (!live)\n return\n live = false\n if (link.connection() !== connection)\n return\n link.setConnection(null)\n const current = records.get(record.id)\n if (current) {\n current.lastSeen = now()\n save()\n }\n events.status?.({ machineId: record.id, name: record.name, status: 'offline' })\n },\n }\n }\n\n return {\n list: () => (active() ? [...records.values()].map(info) : []),\n get: (machineId) => {\n const record = active() ? records.get(machineId) : undefined\n return record ? info(record) : undefined\n },\n link: machineId => (active() && records.has(machineId) ? linkOf(records.get(machineId)!) : undefined),\n attach,\n forget(machineId) {\n const record = records.get(machineId)\n if (!record)\n return false\n records.delete(machineId)\n // Forgetting sticks: the token it had can't register it again (docs/MACHINES.md § Forgetting a machine).\n if (record.principal)\n forgotten = [...forgotten.filter(f => f.machineId !== machineId || f.principal !== record.principal), { machineId, principal: record.principal }]\n save()\n const link = links.get(machineId)\n links.delete(machineId)\n link?.connection()?.close('forgotten by the host')\n link?.setConnection(null)\n return true\n },\n deliver: (machineId, method, params) => links.get(machineId)?.deliver(method, params),\n close() {\n for (const link of links.values())\n link.shutdown()\n for (const fn of closers.splice(0)) {\n try {\n fn()\n }\n catch {\n // One closer's failure never keeps the others open.\n }\n }\n },\n onClose: fn => void closers.push(fn),\n }\n}\n","/**\n * Machines (`docs/MACHINES.md`): the machines that lend this host their\n * execution, their `local@<name>` / `worktree@<name>` environments, and what\n * their being offline does to a session (it waits, then gives up).\n * Transport-free: the WebSocket side (`src/ipc/daemon/machine-gateway.ts`)\n * hands each registered connection to `attach`.\n */\nimport type { EnvironmentRegistry } from '../../environment'\nimport type { MachineRoot } from '../../machine-protocol'\nimport type { WorkspaceConfinement } from '../../workspace-confinement'\nimport type { HostContext } from '../context'\nimport type { ResolvedFolder } from './folders'\nimport type { MachineLink } from './link'\nimport type { MachineProject } from './project-files'\nimport type { MachineRegistry } from './registry'\nimport { mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { remoteHostsGate } from '../../feature-gate'\nimport { MachineErrorCode, parseMachineKind } from '../../machine-protocol'\nimport { emitSessionNotice } from '../notices'\nimport { createMachineContext } from './context'\nimport { MachineProtocolError } from './errors'\nimport { createFolderResolver } from './folders'\nimport { readMachineProject } from './project-files'\nimport { createMachineRegistry, DEFAULT_MACHINE_WAIT_MINUTES } from './registry'\n\nexport { createMachineContext } from './context'\nexport type { MachineContextInput } from './context'\nexport { MachineLinkLostError, MachineProtocolError, MachineResultLostError, MachineUnavailableError } from './errors'\nexport { createFolderResolver } from './folders'\nexport type { FolderResolver, ResolvedFolder } from './folders'\nexport type { MachineCallOptions, MachineConnection, MachineEvents, MachineLink, MachineTimers } from './link'\nexport { readMachineProject } from './project-files'\nexport type { MachineProject } from './project-files'\nexport { insideDeclaredRoots } from './providers'\nexport { createMachineRegistry, DEFAULT_MACHINE_WAIT_MINUTES } from './registry'\nexport type { AttachedMachine, MachineRegistry, MachineRegistryOptions } from './registry'\n\n/**\n * Where this host reads config for a machine's folder (`ActiveRun.discoveryCwd`):\n * a folder of its own with no project, so user scope applies and no\n * project code of this host's (or the machine's) is loaded.\n */\nexport function machineDiscoveryCwd(dataDir: string): string {\n const dir = join(dataDir, 'machine-sessions')\n mkdirSync(dir, { recursive: true })\n return dir\n}\n\n/** `cwd`, or {@link machineDiscoveryCwd} for a machine's environment kind. */\nexport function discoveryCwdFor(kind: string | undefined, cwd: string, dataDir: string): string {\n return kind && parseMachineKind(kind) ? machineDiscoveryCwd(dataDir) : cwd\n}\n\n/** Whether the machine behind a machine kind is connected now (`false` for other kinds). */\nexport function machineOnline(registry: Pick<MachineRegistry, 'list'>, kind: string): boolean {\n const parsed = parseMachineKind(kind)\n return parsed ? registry.list().some(machine => machine.name === parsed.name && machine.status === 'online') : false\n}\n\n/** The declared roots of the machine behind a machine kind, `undefined` for any other kind or a forgotten machine. */\nexport function machineRootsFor(registry: Pick<MachineRegistry, 'list'>, kind: string): readonly MachineRoot[] | undefined {\n const parsed = parseMachineKind(kind)\n return parsed ? registry.list().find(machine => machine.name === parsed.name)?.roots : undefined\n}\n\n/**\n * The host's folder methods over its machines (`ChatHost.resolveFolder` /\n * `verifyFolder` / `folderCatalog`, and the discovery folder of `/` commands).\n */\nexport function createMachineFolders(input: { machines: MachineRegistry, environments: EnvironmentRegistry, workspace: WorkspaceConfinement, dataDir: () => string }) {\n const { machines } = input\n const resolve = createFolderResolver({ environments: input.environments, workspace: input.workspace })\n const linkOf = (name: string): { link: MachineLink, roots: readonly MachineRoot[] } => {\n const info = machines.list().find(machine => machine.name === name)\n const link = info ? machines.link(info.id) : undefined\n if (!info || !link)\n throw new Error(`Unknown machine \"${name}\".`)\n return { link, roots: info.roots }\n }\n const methods = {\n resolve,\n /** Where this host reads runtime config for `cwd`: its own folder for a machine's. */\n discoveryCwd: (cwd: string, kind?: string): string => (cwd && resolve(cwd, kind).machine ? machineDiscoveryCwd(input.dataDir()) : resolve(cwd, kind).cwd),\n async verify(cwd: string, kind?: string): Promise<ResolvedFolder> {\n const folder = resolve(cwd, kind)\n if (!folder.machine || !folder.cwd)\n return folder\n // Never waits for an offline machine: a client is asking now.\n const checked = await linkOf(folder.machine.name).link.call('env.checkFolder', { cwd: folder.cwd }, { wait: false })\n return { ...folder, cwd: checked.cwd }\n },\n async catalog(cwd: string, kind?: string, prefix = '.zidane'): Promise<{ discoveryCwd: string, project?: MachineProject }> {\n const folder = cwd ? resolve(cwd, kind) : { cwd }\n if (!folder.machine)\n return { discoveryCwd: folder.cwd }\n const { link, roots } = linkOf(folder.machine.name)\n const context = createMachineContext({ link, cwd: folder.cwd })\n const handle = await context.spawn({ cwd: folder.cwd })\n try {\n const project = await readMachineProject({ context, handle, cwd: folder.cwd, roots, prefix })\n return { discoveryCwd: machineDiscoveryCwd(input.dataDir()), project }\n }\n finally {\n await context.destroy(handle)\n }\n },\n }\n return {\n ...methods,\n /** `ChatHost.resolveFolder` / `verifyFolder` / `folderCatalog`. */\n hostMethods: { resolveFolder: methods.resolve, verifyFolder: methods.verify, folderCatalog: methods.catalog },\n }\n}\n\n/** `Settings.machineWaitMinutes`, or the default when unset or not a positive number. */\nexport function machineWaitMinutes(settings: { machineWaitMinutes?: unknown }): number {\n const value = settings.machineWaitMinutes\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : DEFAULT_MACHINE_WAIT_MINUTES\n}\n\n/** What agent builds ask about a machine kind (`docs/MACHINES.md` § Project files). */\nexport interface MachineBuilds {\n /** The machine's declared roots; `undefined` for any other kind or a forgotten machine. */\n roots: (kind: string) => readonly MachineRoot[] | undefined\n online: (kind: string) => boolean\n /** Built while its machine was offline (no project files): rebuilt once it is back. */\n skipped: (sessionId: string, machineName: string) => void\n}\n\n/**\n * A registry made on first use while `enabled()` (`ChatHostEnvironment.machineHost`):\n * until then nothing is read (`machines.json`) and no machine kind is registered.\n */\nfunction lazyMachineRegistry(enabled: () => boolean, create: () => MachineRegistry): MachineRegistry {\n let real: MachineRegistry | undefined\n const closers: Array<() => void> = []\n const get = (): MachineRegistry | undefined => {\n if (!real && enabled()) {\n real = create()\n for (const fn of closers.splice(0))\n real.onClose(fn)\n }\n return real\n }\n return {\n list: () => get()?.list() ?? [],\n get: machineId => get()?.get(machineId),\n link: machineId => get()?.link(machineId),\n attach(params, connection, meta) {\n const registry = get()\n if (!registry)\n throw new MachineProtocolError(MachineErrorCode.MethodNotAllowed, 'This host takes no machines: remote hosts are off on it.')\n return registry.attach(params, connection, meta)\n },\n forget: machineId => get()?.forget(machineId) ?? false,\n deliver: (machineId, method, params) => get()?.deliver(machineId, method, params),\n close() {\n if (real)\n return real.close()\n for (const fn of closers.splice(0)) {\n try {\n fn()\n }\n catch {\n // One closer's failure never keeps the others open.\n }\n }\n },\n onClose: fn => (real ? real.onClose(fn) : void closers.push(fn)),\n }\n}\n\nexport function createMachines({ ctx, environments, interrupt, rebuild }: {\n ctx: Pick<HostContext, 'env' | 'broadcast' | 'active'>\n environments: EnvironmentRegistry\n /** Stop a session's run (the machine stayed offline). */\n interrupt: (sessionId: string) => void\n /** Rebuild a session's agent (deferred to run end when busy). */\n rebuild: (sessionId: string) => void\n}): { registry: MachineRegistry, builds: MachineBuilds } {\n const { env, broadcast, active } = ctx\n const notice = (sessionId: string, severity: 'info' | 'warn' | 'error', text: string): void =>\n emitSessionNotice({ sessionId, agent: active.get(sessionId)?.agent, broadcast }, { severity, label: 'machine' }, text)\n const withoutProject = new Map<string, Set<string>>()\n const enabled = (): boolean => env.machineHost !== undefined || remoteHostsGate.isEnabled(env.readSettings())\n const registry = lazyMachineRegistry(enabled, () => createMachineRegistry({\n dataDir: env.userDataDir(),\n environments,\n active: enabled,\n ...(env.machineHost?.principalLive ? { principalLive: env.machineHost.principalLive } : {}),\n waitMinutes: () => machineWaitMinutes(env.readSettings()),\n events: {\n status: (change) => {\n broadcast({ kind: 'machine:status', ...change })\n if (change.status !== 'online')\n return\n for (const sessionId of withoutProject.get(change.name) ?? [])\n rebuild(sessionId)\n withoutProject.delete(change.name)\n },\n waiting: (sessionId, name) => notice(sessionId, 'warn', `waiting for ${name}… it is offline; the run continues when it reconnects.`),\n back: (sessionId, name) => notice(sessionId, 'info', `${name} is back.`),\n gaveUp: (sessionId, name, minutes) => {\n notice(sessionId, 'error', `${name} stayed offline for ${minutes} min: run stopped.`)\n interrupt(sessionId)\n },\n },\n }))\n // On now: known machines' kinds resolve from the start (sessions on them). Turned on later: at first use.\n if (enabled())\n registry.list()\n const builds: MachineBuilds = {\n roots: kind => machineRootsFor(registry, kind),\n online: kind => machineOnline(registry, kind),\n skipped: (sessionId, name) => {\n const sessions = withoutProject.get(name) ?? new Set<string>()\n sessions.add(sessionId)\n withoutProject.set(name, sessions)\n },\n }\n return { registry, builds }\n}\n","import type { Hookable } from 'hookable'\nimport type { WriteStream } from 'node:fs'\nimport type { AgentHooks } from '../agent'\nimport type { Logger } from '../logger'\nimport { createWriteStream, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { consoleSink, createLogger } from '../logger'\n\n/**\n * Subscribe to `mcp:warn`\n * (stdio child stderr lines, see `attachStderrWarnPump` in ./index.ts)\n * and append each to `<dir>/warnings.log`.\n *\n * The stream opens lazily on the first warning so\n * a healthy session never touches disk.\n */\nexport function attachMcpWarnLog(\n hooks: Hookable<AgentHooks>,\n opts: { dir: string },\n): { close: () => Promise<void> } {\n let stream: WriteStream | null = null\n let logger: Logger | null = null\n\n const ensureLogger = (): Logger | null => {\n if (logger)\n return logger\n try {\n // Sync mkdir so the WriteStream's first write never races a\n // missing directory. Runs at most once per session.\n mkdirSync(opts.dir, { recursive: true })\n const s = createWriteStream(join(opts.dir, 'warnings.log'), {\n flags: 'a',\n })\n s.on('error', () => { })\n stream = s\n logger = createLogger(consoleSink({ stream: s, minLevel: 'warn' }))\n return logger\n }\n catch {\n return null\n }\n }\n\n const unhook = hooks.hook('mcp:warn', ({ name, message }) => {\n ensureLogger()?.warn('mcp warn', { server: name, message })\n })\n\n return {\n close: async () => {\n unhook()\n const s = stream\n stream = null\n logger = null\n if (!s)\n return\n await new Promise<void>((resolve) => {\n // `close` fires after the fd is released; safer than `finish` if\n // the stream errored out (handler above swallows so we still resolve).\n s.once('close', () => resolve())\n s.once('error', () => resolve())\n s.end()\n })\n },\n }\n}\n","/**\n * MCP servers for a session's agent: discovery + allowlist, the merged server\n * list (first wins a name collision), the connector bound to the session's\n * cwd and credential store, the per-session warning log, and the status /\n * auth / settled signals windows render as badges.\n */\nimport type { Agent, McpConnector } from '../../../index'\nimport type { McpServerConfig } from '../../../mcp'\nimport type { DiscoveredMcp } from '../../mcps-discovery'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { HostSettings } from '../signals'\nimport type { AgentHookContext } from '../types'\nimport { connectMcpServers, McpOAuthProvider } from '../../../index'\nimport { resolveMcpWarningsDir } from '../../../loop-persistence'\nimport { attachMcpWarnLog } from '../../../mcp/warn-log'\nimport { buildMcpServers, discoverProjectMcps, withSessionStdioCwd } from '../../mcps-discovery'\n\nfunction dedupByName<T extends { name: string }>(entries: readonly T[]): T[] {\n const seen = new Set<string>()\n const out: T[] = []\n for (const entry of entries) {\n if (seen.has(entry.name))\n continue\n seen.add(entry.name)\n out.push(entry)\n }\n return out\n}\n\nexport function discoverSessionMcpServers(cwd: string, prefix: string, settings: HostSettings, machine: readonly DiscoveredMcp[] = []): McpServerConfig[] {\n /*\n * MCP servers: discover from `.zidane/mcps.json` (project + user) and\n * filter by the user's allowlist. A machine session's project servers\n * (`machine`, read there and run there) come first: project beats user.\n */\n const { servers: found } = discoverProjectMcps({\n cwd,\n prefix,\n foreignAgents: settings.importForeignConfigs === true,\n ruler: settings.importRulerConfigs !== false,\n })\n const names = new Set(machine.map(entry => entry.config.name))\n const discoveredMcps = [...machine, ...found.filter(entry => !names.has(entry.config.name))]\n const mcpServers = buildMcpServers({\n discovered: discoveredMcps,\n enabled: settings.enabledMcps,\n ...(settings.disabledMcpTools ? { disabledTools: settings.disabledMcpTools } : {}),\n })\n return mcpServers\n}\n\nexport function sessionMcpServerList(lists: {\n discovered: readonly McpServerConfig[]\n plugin: readonly McpServerConfig[]\n launch: readonly McpServerConfig[] | undefined\n preset: readonly McpServerConfig[] | undefined\n}): McpServerConfig[] {\n // First wins a name collision, in the TUI's order: discovered, plugin,\n // launch (`--mcp`), then the preset's.\n return dedupByName([...lists.discovered, ...lists.plugin, ...(lists.launch ?? []), ...(lists.preset ?? [])])\n}\n\nexport function sessionMcpConnector(\n cwd: string,\n mcpCredentialStore: ChatHostEnvironment['mcpCredentialStore'],\n agent: () => Agent,\n): McpConnector {\n // Forward the agent's execution binding: without it every\n // `scope: 'context'` server fails bootstrap.\n return (configs, _hooks, extras) =>\n connectMcpServers(\n withSessionStdioCwd(configs, cwd),\n undefined,\n agent().hooks,\n {\n ...(extras?.execution ? { execution: extras.execution } : {}),\n ...(mcpCredentialStore\n ? { buildAuthProvider: (config: McpServerConfig) => new McpOAuthProvider({ name: config.name, store: mcpCredentialStore() }) }\n : {}),\n },\n )\n}\n\nexport function attachSessionMcpWarnLog(agent: Agent, artifactsDir: string, sessionId: string): { close: () => Promise<void> } {\n /*\n * MCP warning log — same per-session file the local TUI writes\n * (`resolveMcpWarningsDir`), so daemon-side MCP misbehavior is\n * debuggable from any window's /mcps view or the file itself.\n * Closed with the agent on dispose.\n */\n return attachMcpWarnLog(agent.hooks, {\n dir: resolveMcpWarningsDir({ userDir: artifactsDir, sessionId }),\n })\n}\n\nexport function installMcpStatusHooks({ sessionId, agent, broadcast }: AgentHookContext): void {\n // MCP auth badge — the login flow itself stays window-local (browser +\n // shared credential store); this makes the \"needs login\" state visible.\n agent.hooks.hook('mcp:auth:required', ({ name, reason }) => {\n broadcast({ kind: 'mcp:auth', sessionId, name, reason })\n })\n // Connection outcome per server, so a failed host-side MCP shows a badge.\n // `mcp:bootstrap:end ok:false` fires before `mcp:auth:required`, so a\n // window's last-write-wins reducer still lands on \"needs sign-in\".\n agent.hooks.hook('mcp:bootstrap:end', (ctx) => {\n if (ctx.ok)\n return\n const code = (ctx.error as { code?: unknown }).code\n broadcast({\n kind: 'mcp:status',\n sessionId,\n name: ctx.name,\n status: 'failed',\n transport: ctx.transport,\n error: ctx.error.message,\n ...(typeof code === 'number' ? { code } : {}),\n })\n })\n agent.hooks.hook('mcp:connect', ({ name }) => {\n broadcast({ kind: 'mcp:status', sessionId, name, status: 'connected' })\n })\n agent.hooks.hook('mcp:bootstrap:settled', () => {\n broadcast({ kind: 'mcp:settled', sessionId })\n })\n}\n","import type { SpawnModelEntry, ToolDef } from '../../../index'\n/**\n * Which provider and model a session's agent runs on: the persisted pick\n * (validated against the registry), the restored fallback chain, provider\n * construction (with the auth env re-applied), the provider instances the\n * agent is built with, and the subagent model catalog.\n */\nimport type { Provider } from '../../../providers'\nimport type { ProviderKey } from '../../auth'\nimport type { ResolvedConfig } from '../../config'\nimport type { ModelChainEntry } from '../../model-chain'\nimport type { ProviderDescriptor } from '../../providers'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { HostSettings } from '../signals'\nimport { createModelSearchTool, isSpawnTool } from '../../../index'\nimport { restoreChainFallbacks } from '../../model-chain'\nimport { anthropicDescriptor, BUILTIN_PROVIDERS } from '../../providers'\n\nexport function providerDescriptorFor(\n providers: Readonly<Record<string, ProviderDescriptor>>,\n providerKey: ProviderKey = 'anthropic',\n): ProviderDescriptor {\n return providers[providerKey] ?? providers.anthropic ?? BUILTIN_PROVIDERS.anthropic\n}\n\n/** Read the per-session provider preference off `metadata`. */\nfunction readSessionProvider(\n metadata: Record<string, unknown> | undefined,\n providers: Readonly<Record<string, ProviderDescriptor>>,\n): ProviderKey {\n const raw = metadata?.providerKey\n if (typeof raw === 'string' && raw in providers)\n return raw as ProviderKey\n return 'anthropic'\n}\n\n/**\n * True when the session persisted a `providerKey` that's no longer in the\n * registry — the persisted `modelId` belonged to the now-absent provider,\n * so it must not ride along as a dangling id onto the fallback provider.\n */\nfunction persistedProviderMissing(\n metadata: Record<string, unknown> | undefined,\n providers: Readonly<Record<string, ProviderDescriptor>>,\n): boolean {\n const raw = metadata?.providerKey\n return typeof raw === 'string' && raw.length > 0 && !(raw in providers)\n}\n\nfunction readSessionModel(\n metadata: Record<string, unknown> | undefined,\n providers: Readonly<Record<string, ProviderDescriptor>>,\n): string | undefined {\n if (persistedProviderMissing(metadata, providers))\n return undefined\n const raw = metadata?.modelId\n return typeof raw === 'string' && raw.length > 0 ? raw : undefined\n}\n\n/**\n * Build the active provider from the canonical descriptor. Re-applies the\n * auth env right before construction — belt-and-suspenders against\n * startup ordering edge cases (credentials written after boot, stale\n * inherited env, …).\n */\nexport function createProviderBuilder(env: Pick<ChatHostEnvironment, 'applyAuthEnv'>) {\n return function buildProvider(providers: Readonly<Record<string, ProviderDescriptor>>, providerKey: ProviderKey = 'anthropic') {\n env.applyAuthEnv?.()\n\n const descriptor = providerDescriptorFor(providers, providerKey)\n try {\n return descriptor.factory()\n }\n catch (err) {\n const message = (err as Error).message ?? String(err)\n if (/No API key found|no credential|not authenticated/i.test(message))\n throw new Error(`No credentials for ${descriptor.label}. Sign in to the provider first.`)\n throw err\n }\n }\n}\n\n/**\n * Resolve the canonical model id for a session. Prefers the per-session\n * override when set; otherwise the provider descriptor's default.\n */\nexport function resolveModel(\n providers: Readonly<Record<string, ProviderDescriptor>>,\n providerKey: ProviderKey,\n override: string | undefined,\n): { providerKey: ProviderKey, modelId: string } {\n const descriptor = providerDescriptorFor(providers, providerKey)\n // Last resort for a descriptor with no default: the built-in Anthropic\n // flagship, so the chain never lands on a stale hardcoded id again.\n const modelId = override ?? descriptor.defaultModel ?? anthropicDescriptor.defaultModel ?? 'claude-fable-5-1'\n return { providerKey, modelId }\n}\n\nexport function resolveSessionModel(\n metadata: Record<string, unknown> | undefined,\n providers: Readonly<Record<string, ProviderDescriptor>>,\n): {\n providerKey: ProviderKey\n providerDescriptor: ProviderDescriptor\n modelOverride: string | undefined\n model: string\n modelFallbacks: ModelChainEntry[]\n} {\n const providerKey = readSessionProvider(metadata, providers)\n const providerDescriptor = providerDescriptorFor(providers, providerKey)\n // Validated per-session model pick — undefined when unset OR when the\n // persisted provider was removed (see `readSessionModel`).\n const modelOverride = readSessionModel(metadata, providers)\n const { modelId: model } = resolveModel(providers, providerKey, modelOverride)\n\n /*\n * Model-fallback chain: restore `metadata.modelChain` (TUI-canonical\n * shape). Head must match the resolved primary — a diverging chain\n * (out-of-band primary change) silently degrades to \"no fallbacks\";\n * unregistered providers drop.\n */\n const modelFallbacks = restoreChainFallbacks(\n metadata?.modelChain,\n { provider: providerKey, model },\n k => providers[k] !== undefined,\n )\n return { providerKey, providerDescriptor, modelOverride, model, modelFallbacks }\n}\n\nexport function buildProviderChain(input: {\n providers: Readonly<Record<string, ProviderDescriptor>>\n providerKey: ProviderKey\n modelFallbacks: readonly ModelChainEntry[]\n buildProvider: (providers: Readonly<Record<string, ProviderDescriptor>>, providerKey?: ProviderKey) => Provider\n}): {\n primaryProvider: Provider\n providerNameByKey: Map<ProviderKey, string>\n extraProviders: Provider[]\n seenProviderNames: Set<string>\n} {\n const { providers, providerKey, modelFallbacks, buildProvider } = input\n /*\n * Primary + fallback provider instances — each distinct, registered\n * chain key gets its instance constructed into the agent so run-level\n * pinned targets can resolve. Defensive skips (unregistered key,\n * throwing factory, duplicate instance name) keep a stale persisted\n * chain from ever blocking the agent build.\n */\n const primaryProvider = buildProvider(providers, providerKey)\n const providerNameByKey = new Map<ProviderKey, string>([[providerKey, primaryProvider.name]])\n const extraProviders: Provider[] = []\n const seenProviderNames = new Set([primaryProvider.name])\n for (const entry of modelFallbacks) {\n if (providerNameByKey.has(entry.provider))\n continue\n const descriptor = providers[entry.provider]\n if (!descriptor)\n continue\n let instance: Provider\n try {\n instance = descriptor.factory()\n }\n catch {\n continue\n }\n if (seenProviderNames.has(instance.name))\n continue\n seenProviderNames.add(instance.name)\n providerNameByKey.set(entry.provider, instance.name)\n extraProviders.push(instance)\n }\n return { primaryProvider, providerNameByKey, extraProviders, seenProviderNames }\n}\n\nexport function subagentModelCatalogTools(input: {\n settings: HostSettings\n presetSpawn: ToolDef | undefined\n providerNameByKey: ReadonlyMap<ProviderKey, string>\n runtimeConfig: Pick<ResolvedConfig, 'modelsFor'>\n}): Record<string, ToolDef> {\n const { settings, presetSpawn, providerNameByKey, runtimeConfig } = input\n /*\n * Subagent model catalog (Settings > \"Allow subagents to use different\n * models\"): every model of every provider built into this agent, keyed by\n * the runtime provider name spawn routes on. Off, or a profile without\n * spawn, leaves the spawn schema and tool list as if no catalog existed\n * and children inherit the parent's model. Same rule as the TUI's local\n * `buildAgent`, so a setting means the same thing on every surface.\n */\n const modelCatalogTools: Record<string, ToolDef> = {}\n if (settings.subagentModels && presetSpawn && isSpawnTool(presetSpawn)) {\n const catalog: SpawnModelEntry[] = []\n for (const [key, providerName] of providerNameByKey) {\n for (const info of runtimeConfig.modelsFor(key))\n catalog.push({ provider: providerName, model: info })\n }\n if (catalog.length > 0) {\n modelCatalogTools.spawn = presetSpawn.withModels(catalog)\n modelCatalogTools.model_search = createModelSearchTool(catalog)\n }\n }\n return modelCatalogTools\n}\n","/**\n * Personal instructions discovery — load user + project `AGENTS.md` /\n * `CLAUDE.md` files.\n *\n * Every file that exists is loaded — no shadowing within a scope.\n * Users routinely split doctrine across files (\"`~/.agents/AGENTS.md`\n * for cross-tool portable rules, `~/.zidane/AGENTS.md` for\n * zidane-specific tweaks\") and silently dropping a file they committed\n * is surprising. Empty or whitespace-only files are skipped.\n *\n * Two conventions are supported in each scope:\n * - `AGENTS.md` — Codex / Cursor / agentic-tools convention.\n * - `CLAUDE.md` — Claude Code convention.\n *\n * Search order (broadest scope first; same order in the rendered\n * block, so narrower scopes land closer to the conversation and\n * override broader ones in the model's eyes):\n *\n * user scope:\n * 1. `~/.agents/AGENTS.md` — agnostic\n * 2. `~/.{prefix}/AGENTS.md` — zidane (`.zidane` default)\n * 3. `~/.claude/CLAUDE.md` — Claude Code\n *\n * project scope (anchored at git root, else cwd):\n * 4. `<root>/AGENTS.md` — Codex convention\n * 5. `<root>/.agents/AGENTS.md` — agnostic\n * 6. `<root>/.{prefix}/AGENTS.md` — zidane\n * 7. `<root>/CLAUDE.md` — Claude Code\n *\n * The {@link DiscoverAgentsMdOptions.scope} option restricts which\n * scopes contribute. Defaults to `'both'` (the historical behavior).\n *\n * Each file is rendered as a section with its absolute path as the\n * header so the model can cite the source verbatim when it asks the\n * user about something that came from there.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { resolve } from 'node:path'\nimport { errorMessage } from '../errors'\nimport { findGitRoot } from './project-root'\nimport { isRulerGenerated, rulerInstructionFiles } from './ruler-configs'\n\n/** A single loaded AGENTS.md file. */\nexport interface AgentsMdFile {\n path: string\n source: 'project' | 'user'\n contents: string\n}\n\n/** Result of {@link discoverAgentsMd}. `files` is empty when none were found. */\nexport interface AgentsMdResult {\n /** All loaded files in render order (user first, project last). */\n files: readonly AgentsMdFile[]\n /**\n * Pre-rendered prompt block ready to append to the system prompt, or\n * `null` when no files were loaded. Header + per-file sections with\n * absolute paths.\n */\n block: string | null\n}\n\n/** Sane upper bound per file so a runaway log dumped as AGENTS.md doesn't blow the prompt. */\nconst MAX_BYTES_PER_FILE = 64 * 1024\n\n/**\n * Which scope(s) of personal instructions to load.\n * - `'none'` — skip discovery entirely; no files load. Useful for\n * reproducible reviews, demos, or debugging the base\n * system prompt without any user doctrine bleeding in.\n * - `'user'` — `~/.agents/AGENTS.md`, `~/.{prefix}/AGENTS.md`, `~/.claude/CLAUDE.md`\n * - `'project'` — `<root>/AGENTS.md`, `<root>/.agents/AGENTS.md`, `<root>/.{prefix}/AGENTS.md`, `<root>/CLAUDE.md`\n * - `'both'` — union of user + project (default)\n *\n * Exposed as a user-facing setting so users can scope their instructions\n * to e.g. only the project (when running zidane against an unfamiliar\n * repo and they don't want their global preferences leaking in).\n */\nexport type AgentsMdScope = 'both' | 'none' | 'project' | 'user'\n\nexport interface DiscoverAgentsMdOptions {\n /** Discovery cwd. Default: `process.cwd()`. */\n cwd?: string\n /** User home directory. Default: `os.homedir()`. */\n home?: string\n /** Storage prefix. Leading dot tolerated. Default: `'.zidane'`. */\n prefix?: string\n /** Which scopes to load. Default: `'both'`. */\n scope?: AgentsMdScope\n /**\n * Also load Ruler instruction markdown (`.ruler/*.md`, project and\n * XDG-global) — see `ruler-configs.ts`. Mirrors the\n * `importRulerConfigs` setting. When on, a repo-root `AGENTS.md`\n * that `ruler apply` GENERATED (it aggregates those same sources) is\n * skipped so instructions never load twice.\n */\n ruler?: boolean\n}\n\n/**\n * Walk the candidate paths and load every `AGENTS.md` that exists.\n *\n * Project paths anchor at the git root when one exists above `cwd`,\n * else at `cwd` itself — same anchor logic as `projectUserPaths` so the\n * three discovery surfaces (skills, mcps, AGENTS.md) stay in lock-step.\n *\n * All matching files are loaded (no shadowing within a scope). Empty\n * or whitespace-only files are skipped. Render order matches the\n * search order — broader scopes first, narrower scopes last so the\n * project-specific file lands closest to the conversation.\n *\n * Tolerant on read failures: an unreadable file is skipped silently\n * (logged under `ZIDANE_DEBUG`). The loader never throws — bootstrap\n * paths can't afford to crash on a permission glitch.\n *\n * Defensive dedup: when `<git-root> === ~` (the user launched zidane\n * directly from `$HOME` and `$HOME` happens to be a git repo) the\n * project + user candidate sets would otherwise overlap. We dedup by\n * absolute path so the same file never lands in the block twice.\n */\nexport function discoverAgentsMd(opts: DiscoverAgentsMdOptions = {}): AgentsMdResult {\n const scope: AgentsMdScope = opts.scope ?? 'both'\n // Short-circuit on `'none'` BEFORE touching the filesystem — no\n // existsSync probes, no homedir() / git-root walk. Keeps the\n // explicit opt-out genuinely free.\n if (scope === 'none')\n return { files: [], block: null }\n\n const cwd = opts.cwd ?? process.cwd()\n const home = opts.home ?? homedir()\n const prefix = (opts.prefix ?? '.zidane').replace(/^\\./, '')\n const projectRoot = findGitRoot(cwd) ?? cwd\n\n // Ruler import (behind `importRulerConfigs`): its instruction files\n // join the candidate lists per scope, and the repo-root AGENTS.md is\n // dropped when ruler GENERATED it — the sources are already loading, and\n // they're fresher than the aggregate (which may predate an edit).\n // Forward `home` only when the CALLER supplied one: `rulerRoots` treats\n // an explicit home as \"redirected user scope\" and pins XDG to\n // `<home>/.config`, so passing the defaulted value here would ignore a\n // real `$XDG_CONFIG_HOME` — unlike the MCP/skill surfaces, which omit\n // `home` on the live path and honor the env.\n const rulerFiles = opts.ruler ? rulerInstructionFiles({ cwd, ...(opts.home !== undefined ? { home: opts.home } : {}) }) : []\n\n const userCandidates: { path: string, source: 'user' }[] = [\n { path: resolve(home, `.agents/AGENTS.md`), source: 'user' },\n { path: resolve(home, `.${prefix}/AGENTS.md`), source: 'user' },\n { path: resolve(home, `.claude/CLAUDE.md`), source: 'user' },\n ...rulerFiles.filter(f => f.source === 'user').map(f => ({ path: f.path, source: 'user' as const })),\n ]\n const projectCandidates: { path: string, source: 'project' }[] = [\n { path: resolve(projectRoot, 'AGENTS.md'), source: 'project' },\n { path: resolve(projectRoot, `.agents/AGENTS.md`), source: 'project' },\n { path: resolve(projectRoot, `.${prefix}/AGENTS.md`), source: 'project' },\n { path: resolve(projectRoot, 'CLAUDE.md'), source: 'project' },\n ...rulerFiles.filter(f => f.source === 'project').map(f => ({ path: f.path, source: 'project' as const })),\n ]\n // Ruler-generated aggregates yield to their sources, PER SCOPE, and only\n // when sources for that scope REALLY loaded — a committed generated file\n // whose `.ruler/` sources are gone on this machine (gitignored, deleted)\n // must keep loading, or the user's instructions silently vanish. Applies\n // to EVERY non-ruler candidate, not just the root AGENTS.md: `ruler\n // apply` also generates root `CLAUDE.md` (claude agent), `.agents/\n // AGENTS.md` (goose/codex outputs), and `~/.claude/CLAUDE.md` from a\n // global ruler dir — each aggregates the same sources, so loading any of\n // them alongside the sources would duplicate every instruction.\n const rulerSourcePaths = new Set(rulerFiles.map(f => f.path))\n // Pre-read the ruler sources: the aggregate-skip must key on files that\n // actually LOADED (`readIfPresent` rejects empty / whitespace-only /\n // unreadable files), not on mere existence — a `.ruler/` of empty stubs\n // must not suppress the generated aggregate, or every instruction\n // silently vanishes. The loop below reuses these reads via the map.\n const rulerRead = new Map<string, AgentsMdFile | null>()\n for (const f of rulerFiles) {\n if (!rulerRead.has(f.path))\n rulerRead.set(f.path, readIfPresent(f.path, f.source))\n }\n const rulerLoadedByScope = {\n project: rulerFiles.some(f => f.source === 'project' && rulerRead.get(f.path)),\n user: rulerFiles.some(f => f.source === 'user' && rulerRead.get(f.path)),\n }\n\n const ordered: ({ path: string, source: 'project' | 'user' })[] = []\n if (scope !== 'project')\n ordered.push(...userCandidates)\n if (scope !== 'user')\n ordered.push(...projectCandidates)\n\n const files: AgentsMdFile[] = []\n const seen = new Set<string>()\n for (const c of ordered) {\n if (seen.has(c.path))\n continue\n const file = rulerSourcePaths.has(c.path)\n ? rulerRead.get(c.path) ?? null\n : readIfPresent(c.path, c.source)\n if (file) {\n seen.add(c.path)\n if (!rulerSourcePaths.has(c.path) && rulerLoadedByScope[c.source] && isRulerGenerated(file.contents))\n continue // ruler-generated aggregate — the .ruler sources load instead\n files.push(file)\n }\n }\n\n if (files.length === 0)\n return { files, block: null }\n\n return { files, block: renderAgentsMdBlock(files) }\n}\n\n/**\n * Render one or more `AgentsMdFile` into a system-prompt block.\n *\n * Top header tells the model what's coming + that it's user-authored\n * (so it's treated as guidance, not as a system constraint that can't\n * be questioned). Each file becomes a sub-section with its absolute\n * path so the model can cite it back when asking follow-up questions.\n *\n * Exported separately so callers building custom profiles can inject\n * their own discovery list (e.g. an SDK consumer pulling AGENTS.md\n * from a remote source) without re-implementing the rendering.\n */\nexport function renderAgentsMdBlock(files: readonly AgentsMdFile[]): string {\n if (files.length === 0)\n return ''\n const sections = files.map((f) => {\n const scope = f.source === 'project' ? 'project' : 'user'\n return `## ${f.path} (${scope})\\n\\n${f.contents.trim()}`\n })\n return [\n '# User instructions',\n 'The following sections come from `AGENTS.md` files the user authored. Treat them as durable preferences and context that apply for this session — they extend, and where they conflict take precedence over, the doctrine above.',\n ...sections,\n ].join('\\n\\n')\n}\n\nfunction readIfPresent(path: string, source: 'project' | 'user'): AgentsMdFile | null {\n // Returns null when the file is absent, empty, or unreadable.\n // The caller (discoverAgentsMd) iterates candidates and pushes\n // every non-null hit — so multiple files per scope concatenate\n // naturally and a stub doesn't shadow a real file underneath.\n if (!existsSync(path))\n return null\n let raw: string\n try {\n raw = readFileSync(path, 'utf8')\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] agents-md: failed to read \"${path}\": ${errorMessage(err)}\\n`)\n return null\n }\n // Truncate gigantic files defensively — the model still sees the\n // path, so the user can pare the file down themselves.\n const contents = raw.length > MAX_BYTES_PER_FILE\n ? `${raw.slice(0, MAX_BYTES_PER_FILE)}\\n\\n[... truncated; ${raw.length - MAX_BYTES_PER_FILE} more bytes in source file ...]`\n : raw\n if (contents.trim().length === 0)\n return null\n return { path, source, contents }\n}\n","/**\n * The agent's `browser_*` tools: a dev browser the user can see (the GUI's\n * Browser tab). The tools only describe and forward; the page lives in the\n * process that owns it, reached through `request` (the host's browser hub).\n *\n * Results are written for the model: short, explicit about what changed,\n * and pointing at the next useful step (refs expire → snapshot again).\n */\nimport type { ToolDef } from '../../tools/types'\nimport type { ToolResultContent } from '../../types'\nimport type {\n BrowserChange,\n BrowserConsoleEntry,\n BrowserOp,\n BrowserOpInputs,\n BrowserOpResults,\n BrowserResponse,\n BrowserSnapshot,\n BrowserStatus,\n} from './protocol'\n\nexport type BrowserRequestFn = <O extends BrowserOp>(\n op: O,\n input: BrowserOpInputs[O],\n signal: AbortSignal,\n) => Promise<BrowserResponse<O>>\n\nexport const BROWSER_TOOL_NAMES = [\n 'browser_open',\n 'browser_navigate',\n 'browser_snapshot',\n 'browser_screenshot',\n 'browser_click',\n 'browser_type',\n 'browser_press',\n 'browser_scroll',\n 'browser_wait_for',\n 'browser_evaluate',\n 'browser_console',\n] as const\n\n/** Guidance the host adds to the system prompt when these tools are present. */\nexport const BROWSER_TOOLS_GUIDANCE = [\n 'You have a dev browser the user can watch (the Browser tab). Use it to check your work in the running app.',\n 'Start with browser_open (a URL or a bare port such as 5173), then browser_snapshot to get the page outline with refs.',\n 'Act with refs from the latest snapshot. Actions report what changed; take a new snapshot when they say refs are stale or the page navigated.',\n 'Use browser_screenshot only when the visual result matters. Check browser_console when something fails.',\n].join(' ')\n\nconst target = {\n ref: { type: 'string', description: 'A ref from the latest browser_snapshot, e.g. \"e12\". Preferred.' },\n selector: {\n type: 'string',\n description: 'A CSS selector, or `text=Save` / `role=button[name=\"Save\"]`. Use when no ref fits.',\n },\n x: { type: 'number', description: 'Viewport x in CSS pixels (with y), as a last resort.' },\n y: { type: 'number', description: 'Viewport y in CSS pixels (with x).' },\n} as const\n\nconst timeoutMs = {\n type: 'number',\n description: 'How long to wait for the target to become actionable (default 5000, max 30000).',\n} as const\n\nexport function createBrowserTools(request: BrowserRequestFn): Record<(typeof BROWSER_TOOL_NAMES)[number], ToolDef> {\n const call = async <O extends BrowserOp>(op: O, input: BrowserOpInputs[O], signal: AbortSignal) => {\n const res = await request(op, input, signal)\n if (!res.ok)\n throw new Error(`${res.error.message} [${res.error.code}]`)\n return res.result as BrowserOpResults[O]\n }\n const tool = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n execute: ToolDef['execute'],\n required: string[] = [],\n ): ToolDef => ({\n spec: {\n name,\n description,\n inputSchema: { type: 'object', properties, ...(required.length ? { required } : {}), additionalProperties: false },\n },\n execute,\n })\n\n return {\n browser_open: tool(\n 'browser_open',\n 'Open the dev browser for this session, optionally at a URL (http(s), `localhost:5173`, or a bare port). The page stays open between calls. The Browser tab opens for the user when you use the browser; `show: false` keeps it in the background.',\n { url: { type: 'string' }, show: { type: 'boolean' } },\n async (input, ctx) => statusText(await call('open', pick(input, ['url', 'show']), ctx.signal)),\n ),\n browser_navigate: tool(\n 'browser_navigate',\n 'Go to a URL, or `action: back | forward | reload`. Waits for the page to load (`waitUntil`: load, domcontentloaded or none).',\n {\n url: { type: 'string' },\n action: { type: 'string', enum: ['back', 'forward', 'reload'] },\n waitUntil: { type: 'string', enum: ['load', 'domcontentloaded', 'none'] },\n timeoutMs: { type: 'number' },\n },\n async (input, ctx) =>\n statusText(await call('navigate', pick(input, ['url', 'action', 'waitUntil', 'timeoutMs']), ctx.signal)),\n ),\n browser_snapshot: tool(\n 'browser_snapshot',\n 'Read the page: URL, title, an outline of its interactive and landmark elements with refs (`[ref=e5]`) to act on, the visible text, and recent errors. Text only; cheap. Refs last until the page changes.',\n {},\n async (_input, ctx) => snapshotText(await call('snapshot', {}, ctx.signal)),\n ),\n browser_screenshot: tool(\n 'browser_screenshot',\n 'Take a JPEG of the viewport, or of one element (`ref`). Use it when the look matters; for reading and acting, browser_snapshot is cheaper.',\n { ref: target.ref },\n async (input, ctx): Promise<ToolResultContent[]> => {\n const shot = await call('screenshot', pick(input, ['ref']), ctx.signal)\n return [\n {\n type: 'text',\n text: `Screenshot ${shot.width}×${shot.height}. Scale ${shot.scale} image pixels per CSS pixel: divide image coordinates by it to click by x/y.`,\n },\n { type: 'image', mediaType: shot.mediaType, data: shot.data },\n ]\n },\n ),\n browser_click: tool(\n 'browser_click',\n 'Click an element, after waiting until it is visible, enabled, stable and not covered. Reports what changed.',\n { ...target, timeoutMs },\n async (input, ctx) => {\n const res = await call('click', pick(input, ['ref', 'selector', 'x', 'y', 'timeoutMs']), ctx.signal)\n return actionText(res.target ? `Clicked \"${res.target}\".` : 'Clicked.', res)\n },\n ),\n browser_type: tool(\n 'browser_type',\n 'Type text into a field (or pick an option of a <select> by its label). Without a target it types into the focused element. `clear` empties the field first; `submit` presses Enter after.',\n {\n ...target,\n text: { type: 'string' },\n clear: { type: 'boolean' },\n submit: { type: 'boolean' },\n timeoutMs,\n },\n async (input, ctx) => {\n const res = await call(\n 'type',\n pick(input, ['ref', 'selector', 'x', 'y', 'text', 'clear', 'submit', 'timeoutMs']) as BrowserOpInputs['type'],\n ctx.signal,\n )\n const text = String(input.text ?? '')\n const quoted = `\"${text.length > 60 ? `${text.slice(0, 59)}…` : text}\"`\n return actionText(res.target ? `Typed ${quoted} into \"${res.target}\".` : `Typed ${quoted}.`, res)\n },\n ['text'],\n ),\n browser_press: tool(\n 'browser_press',\n 'Press a key in the page: Enter, Tab, Escape, Backspace, ArrowDown, a letter, … with optional modifiers.',\n {\n key: { type: 'string' },\n modifiers: { type: 'array', items: { type: 'string', enum: ['Alt', 'Control', 'Meta', 'Shift'] } },\n },\n async (input, ctx) => {\n const res = await call('press', pick(input, ['key', 'modifiers']) as BrowserOpInputs['press'], ctx.signal)\n const mods = Array.isArray(input.modifiers) && input.modifiers.length ? `${(input.modifiers as string[]).join('+')}+` : ''\n return actionText(`Pressed ${mods}${String(input.key)}.`, res)\n },\n ['key'],\n ),\n browser_scroll: tool(\n 'browser_scroll',\n 'Scroll the page, or a scrollable element (ref / selector), by dx / dy CSS pixels.',\n { ref: target.ref, selector: target.selector, dx: { type: 'number' }, dy: { type: 'number' } },\n async (input, ctx) => {\n const res = await call('scroll', pick(input, ['ref', 'selector', 'dx', 'dy']), ctx.signal)\n const position = res.scrollY !== undefined ? `Scrolled to ${res.scrollX ?? 0}, ${res.scrollY}.` : 'Scrolled.'\n return `${position}${changeLines(res)}`\n },\n ),\n browser_wait_for: tool(\n 'browser_wait_for',\n 'Wait until the page shows some text, an element matches a selector, and/or the URL contains a string (default 10 s, max 30 s).',\n {\n text: { type: 'string' },\n selector: { type: 'string' },\n urlIncludes: { type: 'string' },\n timeoutMs: { type: 'number' },\n },\n async (input, ctx) =>\n statusText(await call('wait_for', pick(input, ['text', 'selector', 'urlIncludes', 'timeoutMs']), ctx.signal)),\n ),\n browser_evaluate: tool(\n 'browser_evaluate',\n 'Run a JavaScript expression in the page (awaits promises) and return its JSON value, up to 64 KB. For reading app state the outline cannot show.',\n { expression: { type: 'string' } },\n async (input, ctx) => {\n const { value } = await call('evaluate', pick(input, ['expression']) as BrowserOpInputs['evaluate'], ctx.signal)\n const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2)\n return text ?? 'undefined'\n },\n ['expression'],\n ),\n browser_console: tool(\n 'browser_console',\n 'Console messages and failed requests of the page. `level`: error, warning or all (default all). Pass `since` (the `next` of the previous call) to get only newer entries.',\n { since: { type: 'number' }, level: { type: 'string', enum: ['error', 'warning', 'all'] } },\n async (input, ctx) => consoleText(await call('console', pick(input, ['since', 'level']), ctx.signal)),\n ),\n }\n}\n\nfunction pick<T extends object>(input: Record<string, unknown>, keys: string[]): T {\n const out: Record<string, unknown> = {}\n for (const k of keys) {\n if (input[k] !== undefined && input[k] !== null)\n out[k] = input[k]\n }\n return out as T\n}\n\nexport function statusText(s: BrowserStatus): string {\n const lines = [`Page: ${s.title || '(untitled)'}`, `URL: ${s.url || 'about:blank'}`]\n if (s.loading)\n lines.push('Still loading.')\n return lines.join('\\n')\n}\n\nexport function snapshotText(s: BrowserSnapshot): string {\n const parts = [statusText(s.status), '', 'Outline:', s.outline || '(no interactive elements)']\n if (s.truncated > 0)\n parts.push(`(+${s.truncated} more elements not shown; scroll or narrow down with a selector)`)\n if (s.text)\n parts.push('', 'Text:', s.text)\n if (s.errors.length)\n parts.push('', 'Recent errors:', ...s.errors.map(e => `- ${e}`))\n return parts.join('\\n')\n}\n\nfunction changeLines(c: BrowserChange): string {\n const lines: string[] = []\n if (c.url)\n lines.push(`URL → ${c.url}`)\n if (c.title)\n lines.push(`Title → ${c.title}`)\n if (c.dialog)\n lines.push(`The page opened a ${c.dialog.type} dialog (\"${c.dialog.message}\"); it was ${c.dialog.handled}.`)\n if (c.errors?.length)\n lines.push('New errors:', ...c.errors.map(e => `- ${e}`))\n if (c.refsStale)\n lines.push('The page changed: take a new snapshot before using refs.')\n return lines.length ? `\\n${lines.join('\\n')}` : ''\n}\n\n/** First line says what was done (the transcript reads it); the rest, what changed. */\nexport function actionText(head: string, c: BrowserChange): string {\n const lines = changeLines(c)\n return lines ? `${head}${lines}` : `${head} No navigation, dialog or error.`\n}\n\nfunction consoleText(r: { entries: BrowserConsoleEntry[], next: number }): string {\n if (r.entries.length === 0)\n return `No entries. next: ${r.next}`\n const lines = r.entries.map(e => `[${e.level}] ${e.text}${e.url ? ` (${e.url})` : ''}`)\n return `${lines.join('\\n')}\\nnext: ${r.next}`\n}\n","/**\n * Named keys → the bytes a terminal sends for them (xterm conventions), for\n * typing into a PTY on someone's behalf (`terminal_write`).\n */\nconst KEYS: Record<string, string> = {\n 'enter': '\\r',\n 'return': '\\r',\n 'tab': '\\t',\n 'escape': '\\x1B',\n 'esc': '\\x1B',\n 'backspace': '\\x7F',\n 'delete': '\\x1B[3~',\n 'space': ' ',\n 'up': '\\x1B[A',\n 'down': '\\x1B[B',\n 'right': '\\x1B[C',\n 'left': '\\x1B[D',\n 'home': '\\x1B[H',\n 'end': '\\x1B[F',\n 'pageup': '\\x1B[5~',\n 'pagedown': '\\x1B[6~',\n 'shift-tab': '\\x1B[Z',\n}\n\n/** `Enter`, `C-c`, `ctrl-d`, `up`, … → bytes; `null` when unknown. */\nexport function keyBytes(key: string): string | null {\n const k = key.trim().toLowerCase()\n if (k in KEYS)\n return KEYS[k]!\n const ctrl = /^(?:c|ctrl|control)[-+](.)$/.exec(k)\n if (ctrl) {\n const code = ctrl[1]!.toUpperCase().charCodeAt(0)\n if (code >= 0x40 && code <= 0x5F)\n return String.fromCharCode(code - 0x40)\n }\n return null\n}\n","/**\n * The agent's `terminal_*` tools: the session's terminals, the same ones the\n * user sees in the Terminal drawer and tab. Reading is free; typing is\n * gated like `shell` (and always asks on a terminal the user opened).\n *\n * The tools only format; the terminals live in the host's manager.\n */\nimport type { ToolDef } from '../../tools/types'\nimport type { TerminalManager } from '../host/terminal'\nimport type { TerminalInfo } from './protocol'\nimport { keyBytes } from '../../contexts/terminal-keys'\n\nexport const TERMINAL_TOOL_NAMES = ['terminal_list', 'terminal_read', 'terminal_write'] as const\n\n/** Guidance the host adds to the system prompt when these tools are present. */\nexport const TERMINAL_TOOLS_GUIDANCE = [\n 'The user can open terminals next to this chat, in the same environment as your shell.',\n 'terminal_list shows them; terminal_read gives their recent output (a dev server log, a failing command the user ran).',\n 'Your own background shell tasks also show up there as terminals.',\n 'Use terminal_write only to answer an interactive prompt or drive a program that needs a real terminal; run ordinary commands with shell.',\n].join(' ')\n\nfunction describe(t: TerminalInfo): string {\n const bits = [\n t.id,\n `\"${t.label}\"`,\n t.status === 'exited' ? `exited${t.exitCode !== undefined ? ` (${t.exitCode})` : ''}` : t.status,\n t.owner === 'agent' ? `your task${t.taskId ? ` ${t.taskId}` : ''}` : 'opened by the user',\n t.environment,\n ...(t.program ? [`running ${t.program}`] : []),\n ...(t.title && t.title !== t.label ? [`title \"${t.title}\"`] : []),\n `cwd ${t.cwd}`,\n ]\n return bits.join(' · ')\n}\n\nexport function createTerminalTools(terminals: TerminalManager, sessionId: string): Record<(typeof TERMINAL_TOOL_NAMES)[number], ToolDef> {\n return {\n terminal_list: {\n spec: {\n name: 'terminal_list',\n description: 'List the terminals of this session (the user\\'s and your background tasks\\'), with their status, program and working directory.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n isConcurrencySafe: true,\n async execute() {\n const list = await terminals.list(sessionId)\n if (list.length === 0)\n return 'No terminals are open in this session.'\n return list.map(t => `- ${describe(t)}`).join('\\n')\n },\n },\n terminal_read: {\n spec: {\n name: 'terminal_read',\n description: 'Read a terminal\\'s recent output as plain text (colors and redraws removed), up to 16 KB. Pass `since` (the `next` of the previous read) to get only newer lines.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Terminal id from terminal_list.' },\n since: { type: 'number', description: 'Line cursor from a previous read.' },\n lines: { type: 'number', description: 'How many recent lines when `since` is not given (default 200).' },\n },\n required: ['id'],\n additionalProperties: false,\n },\n },\n isConcurrencySafe: true,\n async execute(input) {\n const r = await terminals.read(sessionId, String(input.id), {\n ...(typeof input.since === 'number' ? { since: input.since } : {}),\n ...(typeof input.lines === 'number' ? { lines: input.lines } : {}),\n })\n const head = describe(r.terminal)\n const cut = r.truncated > 0 ? `\\n(${r.truncated} earlier lines left out by the 16 KB cap and not recoverable by this read; only the most recent output is shown)` : ''\n return `${head}${cut}\\n\\n${r.text || '(no output)'}\\n\\nnext: ${r.next}`\n },\n },\n terminal_write: {\n spec: {\n name: 'terminal_write',\n description: 'Type into a terminal: `text` as typed, then `keys` (`Enter`, `Tab`, `Escape`, `Up`, `C-c`, `C-d`, …). Waits for the output to settle and returns what appeared. Needs approval; on a terminal the user opened, every time.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'Terminal id from terminal_list.' },\n text: { type: 'string', description: 'Text to type (no Enter added).' },\n keys: { type: 'array', items: { type: 'string' }, description: 'Keys pressed after the text, in order.' },\n waitMs: { type: 'number', description: 'Longest wait for output to settle (default 3000, max 30000).' },\n },\n required: ['id'],\n additionalProperties: false,\n },\n },\n async execute(input, ctx) {\n const id = String(input.id)\n const text = typeof input.text === 'string' ? input.text : ''\n const keys = Array.isArray(input.keys) ? input.keys.map(String) : []\n const bytes: string[] = []\n for (const key of keys) {\n const b = keyBytes(key)\n if (b === null)\n throw new Error(`Unknown key \"${key}\". Use names like Enter, Tab, Escape, Up, Down, Backspace, C-c.`)\n bytes.push(b)\n }\n if (!text && bytes.length === 0)\n throw new Error('Nothing to type: pass `text` and/or `keys`.')\n const before = await terminals.read(sessionId, id, { lines: 1 })\n await terminals.write(id, text + bytes.join(''))\n const waitMs = Math.min(Math.max(typeof input.waitMs === 'number' ? input.waitMs : 3000, 0), 30_000)\n await terminals.settle(id, { quietMs: 500, maxMs: waitMs, signal: ctx.signal })\n const after = await terminals.read(sessionId, id, { since: Math.max(0, before.next) })\n return `${describe(after.terminal)}\\n\\n${after.text || '(no new output yet)'}\\n\\nnext: ${after.next}`\n },\n },\n }\n}\n","/**\n * The session's system prompt: built-in doctrine with AGENTS.md rules and a\n * `SYSTEM.md` override (`systemFor`), orchestration and surface fragments,\n * the `system-md` signal, and the host methods that explain the assembly\n * (context breakdown, Instructions segments, override seeding).\n */\nimport type { SystemMdFile } from '../../system-md'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { ChatHost } from '../host-api'\nimport type { MachineProject } from '../machines'\nimport type { ActiveRun, AgentHookContext } from '../types'\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { effectiveContextWindow, OUTPUT_RESERVE_TOKENS } from '../../../compact/policy'\nimport { splitSystemPrompt } from '../../../system-prompt'\nimport { buildBuildSystem, buildPlanSystem } from '../../agent-prompt'\nimport { discoverAgentsMd, renderAgentsMdBlock } from '../../agents-md'\nimport { BROWSER_TOOLS_GUIDANCE } from '../../browser/tools'\nimport { orchestratedBy, WORKER_REPORT_FRAGMENT } from '../../orchestration'\nimport { findGitRoot } from '../../project-root'\nimport { BUILTIN_PROVIDERS, getContextWindow } from '../../providers'\nimport { discoverSystemMd, renderSystemMdSeed, userScopeOverridesLoad, userSystemMdPath } from '../../system-md'\nimport { TERMINAL_TOOLS_GUIDANCE } from '../../terminal/tools'\n\nexport type BuiltInSystem = ReturnType<typeof systemFor>\n\nfunction appendSystemFragments(system: string | undefined, fragments: readonly string[]): string | undefined {\n if (fragments.length === 0)\n return system\n const suffix = fragments.join('\\n\\n')\n return system ? `${system}\\n\\n${suffix}` : suffix\n}\n\n/**\n * Compose a built-in agent's system prompt, folding in AGENTS.md/CLAUDE.md\n * rules (project + user scope). Returns the rendered system plus the rules\n * block + source files for the context breakdown.\n */\n/**\n * `cwd` is the host directory discovery reads (AGENTS.md, SYSTEM.md);\n * `promptCwd` is where the model is told it works — the sandbox path for a\n * remote environment, `cwd` otherwise.\n */\nexport function systemFor(env: Pick<ChatHostEnvironment, 'readSettings'>, agentId: string, cwd: string, prefix: string, promptCwd: string = cwd, machineProject?: Pick<MachineProject, 'agentsMd' | 'systemMd'> & { root?: string }): {\n system: string\n rulesBlock?: string\n rulesFiles?: { path: string, source: string, contents: string }[]\n systemFile?: SystemMdFile\n shadowedSystemFiles?: readonly SystemMdFile[]\n} {\n const settings = env.readSettings()\n // `interactionMode` replaced the `allowInteraction` boolean upstream\n // (config.ts migrates the old key); only 'disabled' removes the doctrine.\n const allowInteraction = settings.interactionMode !== 'disabled'\n const scope = settings.userInstructionsScope ?? 'both'\n /*\n * A machine session (`docs/MACHINES.md` § Project files): the user scope\n * is read here (`cwd` is a folder with no project of its own), the project\n * scope was read on the machine; the same scope setting filters both.\n */\n const projectFromMachine = machineProject !== undefined\n const localScope = projectFromMachine ? (scope === 'both' || scope === 'user' ? 'user' : 'none') : scope\n const takesProject = projectFromMachine && (scope === 'both' || scope === 'project')\n const discovered = discoverAgentsMd({\n cwd,\n prefix,\n scope: localScope,\n // Ruler instruction markdown rides the same gate as ruler MCPs/skills.\n ruler: settings.importRulerConfigs !== false,\n })\n const ruleFiles = takesProject ? [...discovered.files, ...machineProject.agentsMd] : discovered.files\n const rules = { files: ruleFiles, block: ruleFiles.length > 0 ? renderAgentsMdBlock(ruleFiles) : null }\n const userInstructions = rules.block ?? undefined\n /*\n * `SYSTEM.md` REPLACES the built-in doctrine (it does not append like\n * AGENTS.md), so it must be discovered wherever the prompt is composed —\n * here, not just in the TUI's local path. Without this the daemon and the\n * GUI silently ran built-in doctrine while the user believed their file\n * was in force, and the safety guidance a `SYSTEM.md` is meant to replace\n * stayed armed.\n *\n * Scoped by the SAME `userInstructionsScope` as AGENTS.md: passing the\n * scope through (rather than a boolean) is what makes `'user'` actually\n * ignore the repo's file, which is the case that setting exists for — an\n * override is the most invasive form of repo-supplied doctrine there is.\n *\n * No profile guard is needed here: the only call site (`buildActiveRun`)\n * already restricts this to the built-in `build`/`plan` profiles, since a\n * host-supplied preset keeps its own `system` and has no built-in doctrine\n * for an override to replace.\n */\n const localSystemMd = discoverSystemMd({\n cwd,\n prefix,\n scope: localScope,\n })\n // The project's file wins over the user's, as on this host.\n const machineSystem = takesProject ? machineProject.systemMd : null\n const systemMd = machineSystem\n ? { file: machineSystem, shadowed: [...(localSystemMd.file ? [localSystemMd.file] : []), ...localSystemMd.shadowed] }\n : localSystemMd\n const systemOverride = systemMd.file?.contents\n /*\n * Working in a subfolder of a checkout: name the project root too, so the\n * model resolves `@`-referenced paths (project-root relative) correctly,\n * as the TUI's local agent always has. Only on this machine: a remote\n * environment's prompt cwd is a path inside it.\n */\n const checkoutRoot = machineProject?.root ?? (promptCwd === cwd ? findGitRoot(cwd) ?? cwd : promptCwd)\n const location = { cwd: promptCwd, ...(checkoutRoot !== promptCwd ? { projectRoot: checkoutRoot } : {}) }\n const system = agentId === 'plan'\n ? buildPlanSystem({ ...location, userInstructions, allowInteraction, ...(systemOverride ? { systemOverride } : {}) })\n : buildBuildSystem({ ...location, userInstructions, allowInteraction, ...(systemOverride ? { systemOverride } : {}) })\n return {\n system,\n ...(rules.block ? { rulesBlock: rules.block } : {}),\n // Full shape retained: the Instructions tab renders each file's contents\n // as a segment, and it is already in memory here.\n ...(rules.files.length > 0 ? { rulesFiles: rules.files.map(f => ({ path: f.path, source: f.source, contents: f.contents })) } : {}),\n ...(systemMd.file ? { systemFile: systemMd.file } : {}),\n ...(systemMd.shadowed.length > 0 ? { shadowedSystemFiles: systemMd.shadowed } : {}),\n }\n}\n\nexport function composeSystem(input: {\n /** Launch `--system`, else the built-in prompt, else the profile's own. */\n base: string | undefined\n metadata: Record<string, unknown>\n extensionSystemFragments: readonly string[]\n mainFragments: readonly string[]\n browserTools: boolean\n terminalTools: boolean\n}): string | undefined {\n const { metadata, mainFragments } = input\n /*\n * A worker's last message becomes its main's `summary`, so it must be a\n * report the main can act on, not a sign-off. Appended as a system\n * fragment (like extension fragments) rather than spliced into the user\n * prompt, so it applies to every run of the worker, not only the first.\n */\n return appendSystemFragments(\n input.base,\n [\n ...(orchestratedBy(metadata)\n ? [...input.extensionSystemFragments, WORKER_REPORT_FRAGMENT]\n : [...input.extensionSystemFragments, ...mainFragments]),\n ...(input.browserTools ? [BROWSER_TOOLS_GUIDANCE] : []),\n ...(input.terminalTools ? [TERMINAL_TOOLS_GUIDANCE] : []),\n ],\n )\n}\n\nexport function broadcastSystemMd({ sessionId, broadcast }: Pick<AgentHookContext, 'sessionId' | 'broadcast'>, builtInSystem: BuiltInSystem | null): void {\n /*\n * Tell windows which `SYSTEM.md` (if any) this prompt was composed with.\n * Emitted once per agent build — the same moment the override was read —\n * so a window can distinguish \"no file on disk\" from \"file in force\"\n * without probing a filesystem that may not be the daemon's.\n */\n broadcast({\n kind: 'system-md',\n sessionId,\n file: builtInSystem?.systemFile ?? null,\n shadowed: builtInSystem?.shadowedSystemFiles ?? [],\n })\n}\n\nexport function createPromptMethods({ env, active, ensureAgent }: {\n env: ChatHostEnvironment\n active: Map<string, ActiveRun>\n ensureAgent: (sessionId: string) => Promise<ActiveRun>\n}): Pick<ChatHost, 'sessionSystemMd' | 'getContextBreakdown' | 'getContextSegments' | 'createSystemOverride'> {\n return {\n sessionSystemMd(sessionId) {\n return active.get(sessionId)?.systemMd ?? null\n },\n\n /**\n * On-demand context-usage breakdown for the session's live agent.\n * Materializes the agent if needed so the breakdown is available before\n * the first message.\n */\n async getContextBreakdown(sessionId) {\n let entry = active.get(sessionId)\n if (!entry) {\n try {\n entry = await ensureAgent(sessionId)\n }\n catch {\n return null\n }\n }\n entry.lastUsedAt = Date.now()\n\n const modelId = entry.model\n const descriptor = entry.providerDescriptor ?? BUILTIN_PROVIDERS.anthropic\n const effWindow = effectiveContextWindow(getContextWindow(descriptor, modelId))\n\n const settings = env.readSettings()\n return entry.agent.getContextBreakdown({\n model: modelId,\n ...(effWindow !== null ? { effectiveWindow: effWindow } : {}),\n autocompactBuffer: OUTPUT_RESERVE_TOKENS,\n ...(settings.autoCompact && settings.autoCompactThreshold\n ? { compactThreshold: settings.autoCompactThreshold }\n : {}),\n })\n },\n\n async getContextSegments(sessionId) {\n let entry = active.get(sessionId)\n if (!entry) {\n try {\n entry = await ensureAgent(sessionId)\n }\n catch {\n return null\n }\n }\n entry.lastUsedAt = Date.now()\n\n const segments = await entry.agent.getContextSegments({\n ...(entry.rules?.rulesFiles ? { rulesFiles: entry.rules.rulesFiles } : {}),\n ...(entry.rules?.rulesBlock ? { rulesBlock: entry.rules.rulesBlock } : {}),\n ...(entry.systemMd.file ? { systemPath: entry.systemMd.file.path } : {}),\n })\n\n /*\n * Two independent reasons an override cannot apply, named separately\n * because the fix differs: the profile supplies its own prompt (only the\n * built-in `build` / `plan` accept `SYSTEM.md`), or `userInstructionsScope`\n * excludes user-scope files. Profile is reported first — it is the more\n * fundamental of the two. Same derivation as the TUI's `getContextSegments`.\n */\n const agentId = entry.agent.session?.agentId\n const supportsOverride = agentId === 'build' || agentId === 'plan'\n const scopeLoadsUserOverride = userScopeOverridesLoad(env.readSettings().userInstructionsScope)\n const canOverrideSystem = supportsOverride && scopeLoadsUserOverride\n const overrideBlockedBy = !supportsOverride\n ? 'profile' as const\n : !scopeLoadsUserOverride ? 'scope' as const : undefined\n const shadowedSystemPath = entry.systemMd.shadowed[0]?.path\n\n return {\n segments: segments ?? [],\n live: true,\n canOverrideSystem,\n ...(overrideBlockedBy ? { overrideBlockedBy } : {}),\n ...(shadowedSystemPath ? { shadowedSystemPath } : {}),\n }\n },\n\n async createSystemOverride(sessionId) {\n const entry = await ensureAgent(sessionId)\n const settings = env.readSettings()\n const agentId = entry.agent.session?.agentId\n /*\n * Refuse rather than write a doctrine-free file. On a host-supplied\n * profile there is no built-in prompt to seed from; the result would be a\n * comment-only override — still VALID, so switching to build/plan later\n * would silently reduce the entire doctrine to an HTML comment. Same\n * silent-no-op guard on the scope axis: under `'project'` / `'none'` the\n * file would be written, edited, and never read. Same two guards, same\n * wording, as the TUI's `onCreateSystemPrompt`.\n */\n if (agentId !== 'build' && agentId !== 'plan')\n throw new Error(`the \"${agentId ?? 'unknown'}\" profile supplies its own system prompt, so a SYSTEM.md override would not apply`)\n if (!userScopeOverridesLoad(settings.userInstructionsScope))\n throw new Error(`userInstructionsScope is \"${settings.userInstructionsScope ?? 'both'}\", so a SYSTEM.md in your home directory would not be loaded`)\n\n const runtimeConfig = await env.runtimeConfig(entry.discoveryCwd)\n const path = userSystemMdPath({ prefix: runtimeConfig.prefix })\n if (existsSync(path))\n return { path, created: false }\n\n /*\n * Seed from the DOCTRINE-ONLY prompt — built without `userInstructions`\n * and without an override. The live `system` already has the AGENTS.md\n * block folded in, and an override composes ABOVE a freshly-appended copy\n * of that block, so seeding from it would duplicate every instruction on\n * the next session.\n */\n const allowInteraction = settings.interactionMode !== 'disabled'\n const doctrineOnly = agentId === 'plan'\n ? buildPlanSystem({ cwd: entry.cwd, allowInteraction })\n : buildBuildSystem({ cwd: entry.cwd, allowInteraction })\n const doctrine = splitSystemPrompt(doctrineOnly).static\n if (doctrine.trim().length === 0)\n throw new Error('could not compose a system prompt to seed the override from')\n\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, renderSystemMdSeed(doctrine, settings.userInstructionsScope), 'utf8')\n return { path, created: true }\n },\n }\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../../agent'\nimport { sanitizeProviderDiagnosticMetadata } from '../../providers/diagnostic'\n\nexport type ProviderDiagnostic = Pick<\n Parameters<AgentHooks['provider:diagnostic']>[0],\n 'requestId' | 'stage' | 'event' | 'elapsedMs' | 'stageElapsedMs' | 'attempt' | 'runId' | 'turnId' | 'httpStatus' | 'upstreamRequestId' | 'transportAttempt' | 'networkCode' | 'retryAfter'\n>\n\nexport function installProviderDiagnosticHook(\n hooks: Hookable<AgentHooks>,\n emit: (diagnostic: ProviderDiagnostic) => void,\n): () => void {\n return hooks.hook('provider:diagnostic', ({ requestId, stage, event, elapsedMs, stageElapsedMs, attempt, runId, turnId, httpStatus, upstreamRequestId, transportAttempt, networkCode, retryAfter }) => {\n // Keep future provider payload additions out of host logs and the wire.\n emit({ requestId, stage, event, elapsedMs, stageElapsedMs, attempt, runId, turnId, ...sanitizeProviderDiagnosticMetadata({ httpStatus, upstreamRequestId, transportAttempt, networkCode, retryAfter }) })\n })\n}\n","import type { SessionStore } from '../session'\nimport type { SessionContentBlock, SessionTurn } from '../types'\nimport type { ToolContext, ToolDef } from './types'\nimport { chatReferenceTokensFromText } from '../chat/completion-chats'\nimport { deriveSessionTitle } from '../chat/store'\nimport { toolPrompts } from './prompts'\n\nconst DEFAULT_TURN_LIMIT = 12\nconst MAX_TURN_LIMIT = 50\nconst DEFAULT_MAX_CHARS = 20_000\nconst HARD_MAX_CHARS = 60_000\n\nexport interface ChatTurnsReadToolOptions {\n store: SessionStore\n getAllowedTokens: () => readonly string[]\n}\n\nexport function createChatTurnsReadTool(options: ChatTurnsReadToolOptions): ToolDef {\n return {\n isConcurrencySafe: true,\n spec: {\n name: 'read_chat_turns',\n description: toolPrompts.read_chat_turns,\n inputSchema: {\n type: 'object',\n properties: {\n session_id: {\n type: 'string',\n description: 'The referenced chat id or `#` token, e.g. \"abc123\" from `#abc123`.',\n },\n from: {\n type: 'integer',\n description: '1-indexed turn number to start at. Default: 1.',\n },\n limit: {\n type: 'integer',\n description: `Maximum turns to return. Default: ${DEFAULT_TURN_LIMIT}. Hard cap: ${MAX_TURN_LIMIT}.`,\n },\n max_chars: {\n type: 'integer',\n description: `Maximum characters to return. Default: ${DEFAULT_MAX_CHARS}. Hard cap: ${HARD_MAX_CHARS}.`,\n },\n },\n required: ['session_id'],\n additionalProperties: false,\n },\n },\n async execute(input, _ctx: ToolContext) {\n const rawSessionId = typeof input.session_id === 'string' ? input.session_id.trim().replace(/^#/, '') : ''\n if (!rawSessionId)\n return 'Read chat error: `session_id` is required.'\n\n const allowedTokens = options.getAllowedTokens()\n const allowed = normalizeTokens(allowedTokens)\n if (allowed.length === 0) {\n return [\n 'Read chat blocked: no previous chat was referenced in the current user prompt.',\n 'Ask the user to reference a chat with `#<chat>` first.',\n ].join(' ')\n }\n\n const resolved = await resolveAllowedSessionId(options.store, rawSessionId, allowed)\n if (resolved.kind === 'error')\n return resolved.message\n\n const data = await options.store.load(resolved.sessionId)\n if (!data)\n return `Read chat error: session \"${resolved.sessionId}\" was not found.`\n\n const from = clampInt(input.from, 1, Number.MAX_SAFE_INTEGER, 1)\n const limit = clampInt(input.limit, 1, MAX_TURN_LIMIT, DEFAULT_TURN_LIMIT)\n const maxChars = clampInt(input.max_chars, 1, HARD_MAX_CHARS, DEFAULT_MAX_CHARS)\n const start = Math.max(0, from - 1)\n const turns = await options.store.getTurns(resolved.sessionId, start, limit)\n const title = deriveSessionTitle(data.turns, data.metadata)\n const header = [\n `<chat id=\"${escapeAttr(data.id)}\" title=\"${escapeAttr(title)}\"${data.projectRoot ? ` project=\"${escapeAttr(data.projectRoot)}\"` : ''}>`,\n `<range from=\"${start + 1}\" returned=\"${turns.length}\" total=\"${data.turns.length}\" />`,\n ]\n const body = renderTurns(turns, start)\n const rendered = `${header.join('\\n')}\\n${body}\\n</chat>`\n if (rendered.length <= maxChars)\n return rendered\n return `${rendered.slice(0, maxChars)}\\n\\n...truncated at ${maxChars} characters. Re-read with a narrower range or higher max_chars.`\n },\n }\n}\n\nexport function chatReferenceTokensForPrompt(prompt: string): string[] {\n return chatReferenceTokensFromText(prompt)\n}\n\nfunction normalizeToken(token: string): string {\n return token.replace(/^#/, '').replace(/-/g, '').toLowerCase()\n}\n\nfunction normalizeTokens(tokens: readonly string[]): string[] {\n const out: string[] = []\n const seen = new Set<string>()\n for (const token of tokens) {\n const normalized = normalizeToken(token)\n if (!normalized || seen.has(normalized))\n continue\n seen.add(normalized)\n out.push(normalized)\n }\n return out\n}\n\nasync function resolveAllowedSessionId(\n store: SessionStore,\n requested: string,\n allowedTokens: readonly string[],\n): Promise<{ kind: 'ok', sessionId: string } | { kind: 'error', message: string }> {\n const requestedNorm = normalizeToken(requested)\n const ids = await store.list()\n const allowedIds = ids.filter((id) => {\n const normalizedId = normalizeToken(id)\n return allowedTokens.some(token => normalizedId.startsWith(token) || token.startsWith(normalizedId))\n })\n const matches = allowedIds.filter((id) => {\n const normalizedId = normalizeToken(id)\n return normalizedId === requestedNorm\n || normalizedId.startsWith(requestedNorm)\n || requestedNorm.startsWith(normalizedId)\n })\n\n if (matches.length === 1)\n return { kind: 'ok', sessionId: matches[0] }\n if (matches.length > 1) {\n return {\n kind: 'error',\n message: `Read chat error: \"${requested}\" is ambiguous among ${matches.length} referenced chats. Use a longer # token.`,\n }\n }\n\n return {\n kind: 'error',\n message: `Read chat blocked: \"${requested}\" was not one of the chats referenced in the current user prompt.`,\n }\n}\n\nfunction clampInt(value: unknown, min: number, max: number, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value))\n return fallback\n return Math.max(min, Math.min(max, Math.floor(value)))\n}\n\nfunction renderTurns(turns: readonly SessionTurn[], startIndex: number): string {\n return turns.map((turn, idx) => {\n const content = turn.content.map(renderBlock).filter(Boolean).join('\\n\\n')\n return `<turn index=\"${startIndex + idx + 1}\" id=\"${escapeAttr(turn.id)}\" role=\"${turn.role}\">\\n${content}\\n</turn>`\n }).join('\\n')\n}\n\nfunction renderBlock(block: SessionContentBlock): string {\n if (block.type === 'text')\n return block.text\n if (block.type === 'thinking')\n return `[thinking]\\n${block.text}`\n if (block.type === 'tool_call')\n return `[tool call: ${block.name}]\\n${stringify(block.input)}`\n if (block.type === 'tool_result')\n return `[tool result]\\n${typeof block.output === 'string' ? block.output : stringify(block.output)}`\n if (block.type === 'compact-summary')\n return `[compaction summary]\\n${block.summary}`\n return ''\n}\n\nfunction stringify(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2)\n }\n catch {\n return String(value)\n }\n}\n\nfunction escapeAttr(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<')\n}\n","/**\n * An attached file as a prompt part, the same on every surface: images as\n * images; text (`text/*`, or unrecognized bytes that decode as text, e.g. a\n * `.asm` file typed `application/octet-stream`) as an inline text document,\n * which costs no base64 overhead and keeps the attachment's line-paged read\n * path; anything else as an opaque base64 document.\n */\nimport type { PromptPart } from '../types'\nimport { Buffer } from 'node:buffer'\nimport { looksBinary } from '../tools/binary-detect'\n\nexport interface AttachmentInput {\n mediaType: string\n /** The file's bytes, base64-encoded (the wire form of `PromptAttachment`). */\n data: string\n name?: string\n}\n\nexport function attachmentPromptPart(attachment: AttachmentInput): PromptPart {\n const { mediaType, data, name } = attachment\n const named = name ? { name } : {}\n if (mediaType.startsWith('image/'))\n return { type: 'image', mediaType, data, ...named }\n if (mediaType.startsWith('text/'))\n return { type: 'document', mediaType, data: Buffer.from(data, 'base64').toString('utf-8'), encoding: 'text', ...named }\n if (mediaType === 'application/octet-stream') {\n const decoded = Buffer.from(data, 'base64').toString('utf-8')\n if (!looksBinary(decoded))\n return { type: 'document', mediaType: 'text/plain', data: decoded, encoding: 'text', ...named }\n }\n return { type: 'document', mediaType, data, encoding: 'base64', ...named }\n}\n","/**\n * Chat-layer auto-compaction helpers.\n *\n * The decision policy itself moved to `src/compact/policy.ts` (core, no chat\n * dependency) so the agent loop's loop-native auto-compaction shares the exact\n * same predicate as the chat hosts; this module re-exports it for back-compat\n * and adds the host-side glue that maps chat settings + a model window into\n * the SDK's `behavior.autoCompact` value.\n */\n\nimport type { Provider } from '../providers'\nimport type { AutoCompact } from '../types'\n\nexport {\n AUTO_COMPACT_MIN_GROWTH_FRACTION,\n type AutoCompactDecision,\n type AutoCompactInput,\n shouldAutoCompact,\n} from '../compact/policy'\n\n/**\n * Build the per-run `behavior.autoCompact` a chat host passes to `agent.run`.\n *\n * Loop-native auto-compaction is the single mechanism now; the TUI + GUI just\n * translate the user's enable/threshold settings plus the picked model's raw\n * context window (the SDK core has no model catalog) into the config the loop\n * consumes. Returns `false` when disabled. `rawContextWindow: null` (unknown\n * model) still enables it but leaves the trigger inert — the loop skips with\n * `unknown-window` rather than guessing.\n */\nexport function chatAutoCompactBehavior(opts: {\n enabled: boolean\n threshold: number\n rawContextWindow: number | null\n /**\n * Summarizer override — run the summary call on a different\n * provider/model than the main one (the user's \"compaction model\"\n * setting). Omitted = summarize on the run's main provider/model.\n * `rawContextWindow` above stays the MAIN model's window: the trigger\n * measures the live conversation, not the summarizer.\n */\n summarizer?: { provider: Provider, model: string }\n}): AutoCompact {\n if (!opts.enabled)\n return false\n const contextWindow = typeof opts.rawContextWindow === 'number'\n && Number.isFinite(opts.rawContextWindow)\n && opts.rawContextWindow > 0\n ? opts.rawContextWindow\n : null\n return {\n threshold: opts.threshold,\n ...(contextWindow ? { contextWindow } : {}),\n ...(opts.summarizer ? { provider: opts.summarizer.provider, model: opts.summarizer.model } : {}),\n // Chat hosts are long-lived processes with a persist dir always\n // configured, so trade inline transcript fidelity of compacted-away\n // turns (recoverable via each stub's persisted path) for bounded\n // memory. Headless/SDK runs keep the lossless default.\n releaseReplacedTurns: true,\n }\n}\n\n/**\n * The per-run window knobs a chat host spreads into `agent.run`'s `behavior`:\n * the auto-compaction config from {@link chatAutoCompactBehavior} PLUS the\n * picked model's raw window as `behavior.contextWindow`, so window-relative\n * wire budgets (`compactThresholdWindowFraction`) see the window even when the\n * user has auto-compaction switched off. Both hosts go through this so they\n * cannot drift: the TUI and the GUI/daemon engine hand the loop the same\n * shape for the same settings.\n */\nexport function chatWindowBehavior(opts: Parameters<typeof chatAutoCompactBehavior>[0]): {\n autoCompact: AutoCompact\n contextWindow?: number\n} {\n const autoCompact = chatAutoCompactBehavior(opts)\n const contextWindow = typeof opts.rawContextWindow === 'number'\n && Number.isFinite(opts.rawContextWindow)\n && opts.rawContextWindow > 0\n ? opts.rawContextWindow\n : undefined\n return { autoCompact, ...(contextWindow !== undefined ? { contextWindow } : {}) }\n}\n","import type { Settings } from './types'\nimport process from 'node:process'\nimport { THINKING_BINDING_SETTING_ENV } from '../providers/anthropic'\n\n/**\n * Publish the user's `thinkingBinding` setting to the Anthropic provider.\n *\n * The chat runtimes build `anthropic()` through a no-arg factory, so the\n * setting travels through the environment: the provider resolves\n * `param > ZIDANE_THINKING_BINDING (shell) > ZIDANE_THINKING_BINDING_SETTING\n * (this) > 'drop_block'` on every request. Writing a DISTINCT variable keeps\n * the shell override authoritative without any launch-time capture — a host\n * or window created later in the same process cannot read this write back\n * as a shell value.\n *\n * Called by every runtime that starts runs: the chat host's send path\n * (daemon, GUI) and the in-process TUI on setting change. Process-global by\n * nature; matches settings being shared across windows today. Inert on\n * non-Anthropic providers.\n */\nexport function applyThinkingBindingSetting(value: Settings['thinkingBinding'] | undefined): void {\n process.env[THINKING_BINDING_SETTING_ENV] = value ?? 'drop_block'\n}\n","/**\n * `ctx.workspace` / `ctx.runtime` / `ctx.sessions` for ONE session of a\n * multi-session host. The TUI attaches an impl for its single active\n * session at mount; the daemon and the GUI's embedded host scope this impl\n * onto the extension bridge (`env.hostRuntime.runWith`) around each `/`\n * command and each agent run, so an extension command, tool or hook that\n * fires for session X talks to X's execution context — never \"detached\",\n * never another session's.\n *\n * Mirrors the TUI's `bridge.attach({...})` in `useHostRuntimeBridge`\n * (`src/tui/host/use-host-runtime-bridge.ts`), minus what has no\n * meaning without a window: `switchSession` / `createSession` answer\n * `false` (an extension cannot steer which session a daemon client is\n * looking at); `setThinking` is a session-metadata write the next run picks\n * up.\n */\nimport type { ExtensionHostRuntimeImpl } from '../../extensions/host-runtime'\nimport type { CommandOutputBlock } from '../commands'\nimport type { ChatHostEnvironment } from './environment'\nimport type { ActiveRun } from './types'\nimport { listSessionMeta } from '../store'\nimport { isThinkingLevel } from './helpers'\n\nexport interface SessionHostRuntimeDeps {\n /**\n * Where `ctx.appendNote` blocks go. Inside a `/` command: the command's own\n * persisted turn. Inside an agent run: a fresh `command` turn broadcast to\n * every window (the engine wires that).\n */\n appendNote: (blocks: readonly CommandOutputBlock[]) => void\n}\n\nexport function sessionHostRuntime(run: ActiveRun, env: ChatHostEnvironment, deps: SessionHostRuntimeDeps): ExtensionHostRuntimeImpl {\n return {\n model: () => run.modelOverride ?? run.model,\n models: () => [],\n thinking: () => {\n const effort = run.agent.session?.metadata?.effort\n return typeof effort === 'string' && isThinkingLevel(effort) ? effort : null\n },\n setThinking: (level) => {\n const session = run.agent.session\n if (!session)\n return false\n session.setMeta('effort', level)\n void session.save().catch(() => undefined)\n return true\n },\n listSessions: async () => {\n const rows = await listSessionMeta(env.store)\n return rows.map(s => ({ id: s.id, ...(s.title ? { title: s.title } : {}), ...(s.updatedAt ? { updatedAt: s.updatedAt } : {}) }))\n },\n switchSession: async () => false,\n createSession: async () => false,\n appendNote: (blocks) => {\n if (blocks.length === 0)\n return false\n deps.appendNote(blocks)\n return true\n },\n // The session's execution pair, spawning the handle on first use — the\n // agent is live for the scope's whole duration. Spawn failures propagate\n // so extensions see the real cause, not a generic \"detached\".\n workspace: async () => {\n const handle = await run.agent.ensureExecution()\n return { execution: run.agent.execution, handle }\n },\n workspaceAvailable: () => true,\n artifacts: () => {\n // Master switch: detached scope → reads answer `[]`, `record` no-ops.\n if (env.readSettings().artifacts === false)\n return null\n const session = run.agent.session\n return {\n store: env.store,\n ...(session ? { sessionId: session.id } : {}),\n ...(session?.projectRoot ? { projectRoot: session.projectRoot } : {}),\n // Host-side writes (`/pr`, `/commit`) bypass the loop, so fan the\n // change out ourselves — same signal the `artifacts.upsert` RPC emits.\n record: async (artifact) => {\n if (!env.store.upsertArtifact)\n return null\n const stored = await env.store.upsertArtifact(artifact)\n if (stored)\n env.broadcast({ kind: 'artifact:changed', sessionId: stored.sessionId, op: 'upsert', artifactId: stored.id, artifact: stored })\n return stored\n },\n }\n },\n }\n}\n","/**\n * Built-in `/` commands every surface ships regardless of extensions. Kept as\n * a factory so `/help` can enumerate the *live* merged command list (built-ins\n * + extension-contributed) without a circular import.\n *\n * Lives in `chat/` (not `tui/`) because the shared chat host runs slash\n * commands for the GUI and for daemon-attached windows; a `/help` that only\n * the TUI's local path knew about was a command that silently did not exist on\n * every other surface.\n *\n * (Extension install/update/remove deliberately have no commands — that\n * lifecycle lives in `Settings → Extensions`: `ctrl+g` install, `ctrl+u`\n * update, `ctrl+x` remove.)\n */\n\nimport type { Command } from './commands'\n\nexport function createBuiltinCommands(opts: {\n /** The full merged command list (built-ins + extensions), read live. */\n getCommands: () => readonly Command[]\n /**\n * Hot-reload the extension registry (re-discover, re-setup, dispose the\n * old instance). Omit on hosts without one — `/reload` then isn't offered.\n */\n reloadExtensions?: () => Promise<{ active: number, inactive: number }>\n}): Command[] {\n const commands: Command[] = [\n {\n name: 'help',\n description: 'List the available / commands',\n run: (ctx) => {\n const all = [...opts.getCommands()].sort((a, b) => a.name.localeCompare(b.name))\n const body = all.length === 0\n ? '_No commands are registered._'\n : all.map(c => `- **/${c.name}**: ${c.description}`).join('\\n')\n ctx.emit({ text: `### Commands\\n\\n${body}` })\n },\n },\n ]\n if (opts.reloadExtensions) {\n const reload = opts.reloadExtensions\n commands.push({\n name: 'reload',\n description: 'Reload extensions (re-discover, re-run setup, tear down the old instances)',\n run: async (ctx) => {\n ctx.emit({ text: '', detail: { label: 'reloading extensions…' } })\n const { active, inactive } = await reload()\n ctx.emit({ text: `Reloaded: **${active}** active${inactive > 0 ? `, ${inactive} inactive` : ''}. Agent-side contributions apply on the next run.` })\n },\n })\n }\n return commands\n}\n","/**\n * Skills discovery + persisted enabled-state for the chat layer.\n *\n * Walks project + storage-dir scan paths, returns each skill's parsed\n * metadata, and folds the user's enabled-toggle list into a `SkillsConfig`\n * the agent picks up at construction time.\n *\n * Pattern mirrors what `createAgent` already supports (`SkillsConfig.scan`\n * + `enabled`), so the agent receives the same shape it always did — the\n * chat layer just owns the discovery + UI plumbing.\n */\n\nimport type { SkillConfig, SkillsConfig, SourcedScanPath } from '../skills'\nimport { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { discoverSkills } from '../skills'\nimport { foreignSkillScanPaths } from './foreign-configs'\nimport { projectUserPaths } from './project-user-paths'\nimport { rulerSkillScanPaths } from './ruler-configs'\n\n/**\n * Resolve the default skill scan paths for a project. First-found wins on\n * collision; earlier entries take precedence.\n *\n * Search order — see {@link projectUserPaths}. Non-existent paths are\n * returned so downstream code can choose whether to create them;\n * `discoverSkills` itself skips missing dirs without error.\n */\nexport function defaultSkillScanPaths(opts: {\n cwd?: string\n home?: string\n prefix?: string\n /**\n * Also scan the skill directories other agents maintain (Claude Code,\n * Codex, Pi) — see `foreign-configs.ts`. Mirrors the\n * `importForeignConfigs` setting. Appended AFTER the native paths so\n * first-found-wins keeps zidane's own copies authoritative on name\n * collisions.\n */\n foreignAgents?: boolean\n /**\n * Also scan Ruler skill directories (`.ruler/skills`, project and\n * XDG-global) — see `ruler-configs.ts`. Mirrors the\n * `importRulerConfigs` setting; appended last so first-found-wins\n * keeps both zidane's own and foreign copies authoritative.\n */\n ruler?: boolean\n} = {}): SourcedScanPath[] {\n const native = projectUserPaths({ subPath: 'skills', ...opts })\n return [\n ...native,\n ...(opts.foreignAgents ? foreignSkillScanPaths(opts) : []),\n ...(opts.ruler ? rulerSkillScanPaths(opts) : []),\n ]\n}\n\n/**\n * Does an enabled skill answer `/<name>` for this folder? Used to drop a\n * markdown file command that shares a skill's name (skills win, as in Claude\n * Code). A cheap probe rather than a full scan: it checks\n * `<scan path>/<name>/SKILL.md` over the same paths a session scans, so a\n * skill in a nested category folder or one renamed by frontmatter is not\n * seen. `extraNames` are skills that bypass `enabledSkills` (extension and\n * plugin skills).\n */\nexport function createSkillNameProbe(opts: {\n cwd: string\n home?: string\n prefix?: string\n settings: { importForeignConfigs?: boolean, importRulerConfigs?: boolean, enabledSkills?: readonly string[] }\n extraNames?: readonly string[]\n}): (name: string) => boolean {\n const extra = new Set(opts.extraNames ?? [])\n const enabled = opts.settings.enabledSkills === undefined ? null : new Set(opts.settings.enabledSkills)\n const scan = defaultSkillScanPaths({\n cwd: opts.cwd,\n ...(opts.home !== undefined ? { home: opts.home } : {}),\n ...(opts.prefix !== undefined ? { prefix: opts.prefix } : {}),\n foreignAgents: opts.settings.importForeignConfigs === true,\n ruler: opts.settings.importRulerConfigs !== false,\n })\n return (name) => {\n if (extra.has(name))\n return true\n if (name.includes(':') || name.includes('/') || (enabled !== null && !enabled.has(name)))\n return false\n return scan.some(p => existsSync(join(p.path, name, 'SKILL.md')))\n }\n}\n\n/**\n * Discover every skill reachable from the default scan paths. Returns\n * parsed `SkillConfig`s with `name`, `description`, frontmatter, and\n * lenient-load diagnostics. Pure I/O — does not activate or write.\n *\n * `signal` is forwarded to `discoverSkills` so the TUI's directory-watch\n * effect can cancel a long scan when the user switches `cwd` rapidly.\n *\n * Errors during parse are surfaced as `diagnostics` on the returned\n * skill, not thrown — keeps the picker usable even when a single\n * SKILL.md is malformed.\n */\nexport async function discoverProjectSkills(opts: {\n cwd?: string\n home?: string\n prefix?: string\n /** See {@link defaultSkillScanPaths}. */\n foreignAgents?: boolean\n /** See {@link defaultSkillScanPaths}. */\n ruler?: boolean\n signal?: AbortSignal\n} = {}): Promise<SkillConfig[]> {\n const paths = defaultSkillScanPaths(opts).filter(p => existsSync(p.path))\n return discoverSkills(paths, opts.signal)\n}\n\n/**\n * Map a user-toggled enable list onto the format `createAgent` expects.\n *\n * Conventions:\n * - `enabled === undefined` → all discovered skills enabled (default).\n * - `enabled === []` → fully off; the agent will not scan or\n * inject the skills tools.\n * - `enabled === [names]` → allowlist; skills not in the list are\n * left out of the catalog.\n *\n * `scan` is the resolved scan-path list (passed through verbatim). Pass\n * `defaultSkillScanPaths()` for the standard project + user paths, or\n * supply a host-specific list.\n */\nexport function buildSkillsConfig(opts: {\n scan: SourcedScanPath[]\n enabled?: readonly string[]\n}): SkillsConfig {\n // Keep the source tags (a project under $HOME would otherwise infer as\n // 'user') and skip the library defaults: they resolve against\n // `process.cwd()`, which in the daemon/GUI is unrelated to the session\n // and in the TUI can differ from the session cwd. `opts.scan` is already\n // the complete project + user list for the session's cwd.\n const scan = opts.scan.map(p => ({ path: p.path, source: p.source }))\n // NB: pre-resolved skills (e.g. Agent Plugin skills) deliberately do NOT\n // go through here. `composePresets` is last-wins on the whole `skills`\n // object, so a `catalog` set at this level is replaced outright as soon as\n // an extension contributes skills. Hosts must concatenate onto the FINAL\n // merged skills instead — see `composeSessionSkills` in `chat/host/skills/index.ts`.\n // Empty allowlist must disable the system outright — the loop checks for\n // `enabled === false || enabled.length === 0` to short-circuit catalog\n // assembly. Passing `[]` here used to leak through as \"no allowlist\n // entries, so include nothing\" which the loop treats as \"off\" anyway,\n // but being explicit prevents future loop refactors from drifting.\n if (opts.enabled !== undefined && opts.enabled.length === 0) {\n return { scan, skipDefaultPaths: true, enabled: false }\n }\n return {\n scan,\n skipDefaultPaths: true,\n ...(opts.enabled ? { enabled: [...opts.enabled] } : {}),\n }\n}\n","/**\n * The command catalog a session's `/` resolves against — the shared\n * built-ins, extension commands and markdown file commands — and the wire projections of it for a client's\n * completion popover.\n */\nimport type { Command } from '../../../index'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { CommandArgSuggestionSummary, CommandSummary } from '../signals'\nimport { loadMarkdownCommands } from '../../../markdown-defs'\nimport { createBuiltinCommands } from '../../builtin-commands'\nimport { mergeCommands } from '../../commands'\nimport { createSkillNameProbe } from '../../skills-discovery'\nimport { hostDebug } from '../debug'\n\nexport function createCommandCatalog(env: ChatHostEnvironment): {\n mergedCommands: (extensionCommands: readonly Command[], cwd: string, prefix: string | undefined, extensionSkillNames?: readonly string[]) => Command[]\n listCommands: (cwd: string) => Promise<CommandSummary[]>\n completeCommandArgs: (cwd: string, name: string, argsPrefix: string) => Promise<CommandArgSuggestionSummary[]>\n} {\n /**\n * Builtins (`/help`; `/reload` is omitted because the host has no\n * hot-reload seam), extension commands, then markdown file commands, via\n * the shared `mergeCommands` so every surface resolves a name the same way.\n */\n function mergedCommands(extensionCommands: readonly Command[], cwd: string, prefix: string | undefined, extensionSkillNames: readonly string[] = []): Command[] {\n let merged: Command[] = []\n // `/help` enumerates the LIVE merged list, so the closure reads `merged`\n // after it is assigned below.\n const builtins = createBuiltinCommands({ getCommands: () => merged })\n const settings = env.readSettings()\n const file = loadMarkdownCommands({\n cwd,\n prefix,\n includeForeign: settings.importForeignConfigs === true,\n isSkillName: createSkillNameProbe({ cwd, prefix, settings, extraNames: extensionSkillNames }),\n })\n for (const d of file.diagnostics)\n hostDebug('markdown command', d.path, d.message)\n merged = mergeCommands({ builtins, extension: extensionCommands, file: file.commands }, (dropped, layer) => {\n hostDebug('command dropped (name taken)', layer, dropped.name)\n })\n return merged\n }\n\n async function listCommands(cwd: string): Promise<CommandSummary[]> {\n try {\n const runtimeConfig = await env.runtimeConfig(cwd)\n\n return mergedCommands(runtimeConfig.extensions.commands, cwd, runtimeConfig.prefix, runtimeConfig.extensions.skills.map(skill => skill.name)).map(command => ({\n name: command.name,\n description: command.description,\n ...(command.aliases && command.aliases.length > 0 ? { aliases: [...command.aliases] } : {}),\n ...(command.group ? { group: command.group } : {}),\n ...(command.completeArgs ? { hasArgCompletion: true } : {}),\n }))\n }\n catch {\n return []\n }\n }\n\n /**\n * Forward to the command's `completeArgs` for a client's argument\n * completion. Best-effort by contract — extension code runs here, so any\n * throw degrades to \"no suggestions\" rather than an IPC error.\n */\n async function completeCommandArgs(\n cwd: string,\n name: string,\n argsPrefix: string,\n ): Promise<CommandArgSuggestionSummary[]> {\n try {\n const runtimeConfig = await env.runtimeConfig(cwd)\n const command = mergedCommands(runtimeConfig.extensions.commands, cwd, runtimeConfig.prefix, runtimeConfig.extensions.skills.map(skill => skill.name)).find(\n c => c.name === name || (c.aliases?.includes(name) ?? false),\n )\n\n if (!command?.completeArgs)\n return []\n\n const suggestions = (await command.completeArgs(argsPrefix)) ?? []\n\n return suggestions.map(s => ({\n value: s.value,\n ...(s.label ? { label: s.label } : {}),\n ...(s.description ? { description: s.description } : {}),\n }))\n }\n catch {\n return []\n }\n }\n\n return { mergedCommands, listCommands, completeCommandArgs }\n}\n","export function errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n","/**\n * Interactions — plan approvals and Q&A clarifications between the agent\n * and the user.\n *\n * Renderer-agnostic by design: this module owns the tool factories, the\n * pending-state derivation from `session.turns`, the response serializer,\n * and a tiny React queue context. The TUI / GUI consume the queue and\n * provide the actual picker UI; the same data plumbing works for both.\n *\n * Persistence model — the call IS the persisted state:\n *\n * - The agent emits `present_plan` / `ask_user` as a regular tool call.\n * The `tool_call` block lands in `session.turns` like any other tool.\n * When the user responds, the corresponding `tool_result` block follows\n * in the next user turn. Standard tool-call/tool-result contract — no\n * parallel store, no extra schema.\n *\n * - \"Pending\" = the trailing assistant turn has a `tool_call` to one of\n * the interaction tools with no matching `tool_result` in a later\n * user turn. Derived at load time via\n * {@link pendingInteractionsFromTurns}; no parallel bookkeeping.\n *\n * - Resumed sessions land in the same UI as live ones. The host only\n * swaps the resolver:\n * - **Live**: the tool's `execute()` is awaiting a Promise; the\n * resolver resolves that Promise. The agent loop persists the\n * tool_result naturally on its next iteration.\n * - **Resumed**: no Promise exists (the prior run was destroyed).\n * The resolver appends a synthetic user turn with the tool_result\n * block and triggers a follow-up `agent.run()` so the model\n * continues from where it left off.\n *\n * No OpenTUI imports — a GUI consumer can ship its own renderer and reuse\n * this module verbatim.\n */\nimport type { ReactNode } from 'react'\nimport type { ToolDef } from '../tools/types'\nimport type { SessionContentBlock, SessionTurn } from '../types'\nimport { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'\n\n// ---------------------------------------------------------------------------\n// Tool identities — canonical names persisted in `session.turns`. Stable\n// across the lifetime of the project; renaming would break resume.\n// ---------------------------------------------------------------------------\n\nexport const PRESENT_PLAN_TOOL = 'present_plan'\nexport const ASK_USER_TOOL = 'ask_user'\n\n/** True when `name` is one of the interaction tool canonical names. */\nexport function isInteractionTool(name: string): boolean {\n return name === PRESENT_PLAN_TOOL || name === ASK_USER_TOOL\n}\n\n// ---------------------------------------------------------------------------\n// Payload shapes — parsed views of each tool's `input` blob.\n// ---------------------------------------------------------------------------\n\nexport interface PlanStep {\n id: string\n title: string\n description?: string\n}\n\nexport interface PlanPayload {\n /** Short headline summary — used as the modal title. */\n title: string\n /** Full plan body. Markdown. */\n plan: string\n /** Optional structured step list — surfaced as a checklist preview. */\n steps?: readonly PlanStep[]\n}\n\nexport interface QuestionChoice {\n id: string\n label: string\n description?: string\n /**\n * Open a `multi` select with this choice already ticked. Ignored by\n * single selects (which position the cursor from the carried answer\n * instead) and overridden by a carried answer on re-entry, so resuming a\n * question keeps what the user had rather than snapping back to the\n * defaults.\n *\n * Exists because the alternative for an opt-out list is N keystrokes to\n * accept N items: a caller offering \"which of these 20 findings do you\n * want to send\" wants them pre-ticked and the user deselecting a few.\n */\n selected?: boolean\n}\n\n/**\n * One question in an `ask_user` batch. Discriminated by `type`:\n *\n * - `text` — single-line free-text answer (rendered via `<input>`).\n * - `textarea` — multi-line free-text answer (rendered via `<textarea>`).\n * - `select` — single pick from a fixed set of `choices`.\n * - `confirm` — yes/no boolean (rendered as a 2-option select).\n *\n * The model batches related clarifications into one tool call instead of\n * pinging the user N times with N round-trips.\n */\nexport type QuestionType = 'text' | 'textarea' | 'select' | 'confirm'\n\ninterface BaseQuestion {\n /** Stable id — keys the response back to the model. */\n id: string\n /** Question text shown above the input (Markdown allowed). */\n prompt: string\n /** Optional helper text under the prompt. */\n description?: string\n /**\n * Whether the answer is required (non-empty). Default: `true` for\n * `select` / `confirm` (no sensible empty), `false` for free-text\n * (skipping = empty string). Free-text questions still accept an\n * answer; the flag only gates submission.\n */\n required?: boolean\n}\n\nexport interface TextQuestion extends BaseQuestion {\n type: 'text' | 'textarea'\n /** Placeholder shown when the input is empty. */\n placeholder?: string\n /** Pre-fill the input with this value (still editable). */\n default?: string\n}\n\nexport interface SelectQuestion extends BaseQuestion {\n type: 'select'\n choices: readonly QuestionChoice[]\n /**\n * Allow picking MORE than one choice. The answer becomes a\n * `readonly string[]` of choice ids (space toggles, ↵ commits in the\n * TUI). `required` (default `true`) demands at least one selection.\n */\n multi?: boolean\n}\n\nexport interface ConfirmQuestion extends BaseQuestion {\n type: 'confirm'\n /** Label for the affirmative option. Default: `'yes'`. */\n affirmLabel?: string\n /** Label for the negative option. Default: `'no'`. */\n denyLabel?: string\n}\n\nexport type Question = TextQuestion | SelectQuestion | ConfirmQuestion\n\nexport interface QuestionPayload {\n /** Optional intro / context shown above every question (Markdown). */\n intro?: string\n /** One or more questions for the user to answer in one form. */\n questions: readonly Question[]\n}\n\n/** Per-question answer value — `string` for text/textarea/select, `boolean` for confirm, `string[]` for multi-select. */\nexport type AnswerValue = string | boolean | readonly string[]\n\n/**\n * Who raised a request. `model` is a tool call awaiting a `tool_result`;\n * `host` is a slash command or extension prompt whose consumer is local\n * code. Automatic mode may only answer on the model's behalf, so this is\n * carried as data rather than inferred from the id — a missing value is a\n * compile error at the construction site instead of a silent mis-answer.\n */\nexport type InteractionOrigin = 'model' | 'host'\n\ninterface BaseRequest {\n /** Stable id — the `tool_call.id` from the model. */\n id: string\n /** Whether the model or the host raised this request. */\n origin: InteractionOrigin\n /** Tool canonical name. */\n tool: string\n /** Run that emitted the call, when known. */\n runId?: string\n /** Turn id the call lives in. */\n turnId?: string\n /** Unix ms when the request was raised. */\n createdAt: number\n}\n\nexport interface PlanRequest extends BaseRequest {\n kind: 'plan'\n tool: typeof PRESENT_PLAN_TOOL\n payload: PlanPayload\n}\n\nexport interface QuestionRequest extends BaseRequest {\n kind: 'question'\n tool: typeof ASK_USER_TOOL\n payload: QuestionPayload\n}\n\nexport type InteractionRequest = PlanRequest | QuestionRequest\n\n// ---------------------------------------------------------------------------\n// Response shapes — what the user gives back. Serialized as JSON below so\n// the model parses a stable, explicit envelope.\n// ---------------------------------------------------------------------------\n\nexport type PlanDecision = 'approve' | 'reject' | 'revise'\n\nexport interface PlanResponse {\n kind: 'plan'\n decision: PlanDecision\n /** Optional free-text feedback — shown to the model verbatim. */\n comment?: string\n /**\n * Resolved by automatic mode rather than by a person. Serialized so the\n * model can tell a real decision from a default it is free to override.\n */\n automatic?: boolean\n}\n\nexport interface QuestionResponse {\n kind: 'question'\n /**\n * Map of `Question.id → AnswerValue` for every question the user\n * answered. Missing keys = question skipped (only possible when\n * `required: false`).\n */\n answers: Readonly<Record<string, AnswerValue>>\n /**\n * Free text the user attached to the whole form — every ask_user surface\n * offers it unconditionally, so the user can always refine or override\n * the questions instead of being boxed into the model's choices. Parallel\n * to {@link PlanResponse.comment}; absent when left empty.\n */\n instructions?: string\n /** See {@link PlanResponse.automatic}. */\n automatic?: boolean\n}\n\nexport type InteractionResponse = PlanResponse | QuestionResponse\n\nexport const AUTOMATIC_INTERACTION_INSTRUCTION\n = 'Automatic mode is enabled. Make the best choice from the repository and current task, then continue without asking for this input again.'\n\n/**\n * Id prefix for interactions the HOST synthesizes — slash commands and\n * extension `ctx.interaction.*` share the prompt slot with the tools but\n * never pass through {@link createInteractionTools}. Model-originated\n * requests carry the provider's `tool_call.id` instead. Naming only:\n * origin policy reads {@link BaseRequest.origin}, never the id.\n */\nexport const HOST_INTERACTION_ID_PREFIX = 'command_'\n\n/**\n * Whether a queued request came from a model tool call. Automatic mode\n * answers on the model's behalf, so it must leave host-originated prompts\n * alone: their consumer is local code awaiting a real decision, with no\n * model on the other end to act on an instruction sentence.\n */\nexport function isModelInteraction(request: InteractionRequest): boolean {\n return request.origin === 'model'\n}\n\n/**\n * Stand-in for a free-text answer nobody typed. Deliberately NOT the\n * instruction sentence: {@link serializeInteractionResponse} already leads\n * the envelope with it once, so repeating it per answer only restates the\n * same disclosure — four times over on a three-question form.\n */\nconst AUTOMATIC_FREE_TEXT_ANSWER = '(no answer, automatic mode)'\n\n/**\n * Automatic answer for one question, in the shape its `type` promises:\n * `confirm` declares a boolean and `select` declares one of its own choice\n * ids, so a free-text placeholder would be out of contract there.\n *\n * These are defaults, not decisions — nobody chose them. The response\n * carries `automatic: true` so the model reads them as such and overrides\n * whatever doesn't fit; see {@link serializeInteractionResponse}.\n */\nfunction automaticAnswerFor(question: Question): AnswerValue {\n switch (question.type) {\n // Proceed, consistent with auto-approving plans.\n case 'confirm':\n return true\n // Nothing marks a choice as recommended, so the first one is an\n // arbitrary placeholder the model is expected to reconsider.\n case 'select': {\n const picked = question.choices[0]?.id ?? ''\n return question.multi ? (picked ? [picked] : []) : picked\n }\n default:\n return AUTOMATIC_FREE_TEXT_ANSWER\n }\n}\n\n/** Build the deterministic response used when the host skips interaction UI. */\nexport function createAutomaticInteractionResponse(request: InteractionRequest): InteractionResponse {\n if (request.kind === 'plan') {\n // No `comment`: that field is the user's own free-text feedback, shown to\n // the model verbatim. Harness text belongs in the envelope's `note`, which\n // serialization adds once for every automatic response.\n return {\n kind: 'plan',\n decision: 'approve',\n automatic: true,\n }\n }\n const answers: Record<string, AnswerValue> = {}\n for (const question of request.payload.questions)\n answers[question.id] = automaticAnswerFor(question)\n return { kind: 'question', answers, automatic: true }\n}\n\n// ---------------------------------------------------------------------------\n// Serialization — what the model sees as the tool_result `output`.\n// ---------------------------------------------------------------------------\n\n/**\n * Format an {@link InteractionResponse} as the tool_result content. JSON\n * keeps the envelope parseable and explicit. Empty fields are stripped so\n * the model doesn't waste tokens reading absent values.\n */\nexport function serializeInteractionResponse(response: InteractionResponse): string {\n // Leads the envelope so the model reads \"nobody answered this\" before the\n // values themselves. Absent on user-submitted responses, which cost the\n // same tokens they always did.\n const automatic: Record<string, unknown> = response.automatic\n ? { automatic: true, note: AUTOMATIC_INTERACTION_INSTRUCTION }\n : {}\n if (response.kind === 'plan') {\n const body: Record<string, unknown> = { ...automatic, decision: response.decision }\n if (response.comment && response.comment.trim().length > 0)\n body.comment = response.comment.trim()\n return JSON.stringify(body)\n }\n // Normalize answer values: trim strings, drop empty / undefined entries\n // so the model sees a tight payload of only the meaningful answers.\n const answers: Record<string, AnswerValue> = {}\n for (const [id, value] of Object.entries(response.answers)) {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed.length > 0)\n answers[id] = trimmed\n }\n else if (typeof value === 'boolean') {\n answers[id] = value\n }\n else if (Array.isArray(value)) {\n // Multi-select — keep non-empty trimmed ids, drop empty selections.\n const picked = value.map(v => String(v).trim()).filter(v => v.length > 0)\n if (picked.length > 0)\n answers[id] = picked\n }\n }\n const body: Record<string, unknown> = { ...automatic, answers }\n const instructions = response.instructions?.trim()\n if (instructions)\n body.instructions = instructions\n return JSON.stringify(body)\n}\n\n// ---------------------------------------------------------------------------\n// Resumed-flow turn builder — batches every pending interaction's response\n// into ONE matched user turn.\n//\n// Why a dedicated builder: the agent loop's history-validation contract\n// requires every `tool_use` block in an assistant turn to be followed by\n// EXACTLY ONE matched `tool_result` block in the very next user turn.\n// When a session was killed mid-batch — say the model emitted both\n// `present_plan` and `ask_user` in parallel and the process died before\n// either Promise resolved — naively writing one `tool_result` per UI\n// submission would persist a user turn missing the sibling's match, and\n// the next `agent.run()` would reject the history on the API side.\n//\n// The wizard UI accumulates answers across submissions; this helper\n// converts the accumulated map back into a protocol-valid user turn\n// containing one `tool_result` per pending request, in pending order.\n// ---------------------------------------------------------------------------\n\n/**\n * Build a protocol-valid user `SessionTurn` that closes a batch of\n * resumed pending interactions.\n *\n * - `requests` MUST be the same list returned by\n * {@link pendingInteractionsFromTurns} for the session, in order.\n * - `responses` MUST contain an entry for every request id; throws\n * otherwise (caller bug — flush before all answers collected).\n *\n * Pure / total. Tested in isolation so the batching invariant doesn't\n * regress without the resumed-flow integration noticing.\n */\nexport function buildResumedToolResultsTurn(\n requests: readonly InteractionRequest[],\n responses: ReadonlyMap<string, InteractionResponse>,\n options: {\n /** Turn id minted by the session store. */\n turnId: string\n /**\n * Run id that emitted the pending tool calls — when known, attaching\n * it ties the resumed turn back to the originating `SessionRun` row\n * so consumers grouping turns by run keep clean ancestry across the\n * close/reopen boundary.\n */\n runId?: string\n /** `createdAt` timestamp. Defaults to `Date.now()`. */\n createdAt?: number\n },\n): SessionTurn {\n if (requests.length === 0)\n throw new Error('buildResumedToolResultsTurn: at least one request is required')\n\n const content: SessionContentBlock[] = requests.map((req) => {\n const response = responses.get(req.id)\n if (!response) {\n throw new Error(\n `buildResumedToolResultsTurn: missing response for request \"${req.id}\". `\n + `All ${requests.length} pending interactions must be resolved before flushing.`,\n )\n }\n return {\n type: 'tool_result',\n callId: req.id,\n output: serializeInteractionResponse(response),\n }\n })\n\n return {\n id: options.turnId,\n role: 'user',\n content,\n createdAt: options.createdAt ?? Date.now(),\n ...(options.runId ? { runId: options.runId } : {}),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Pending-state derivation — pure, store-agnostic.\n//\n// The single source of truth for \"what is the session waiting on?\". Used by\n// the chat layer on session activation to decide whether to render the\n// resumed-interaction UI instead of the prompt textarea.\n// ---------------------------------------------------------------------------\n\n/**\n * Scan `turns` and return every interaction tool call without a matching\n * `tool_result`, ordered by turn appearance. Works equally for live mid-run\n * inspection and reload-from-disk.\n *\n * Malformed payloads (input that doesn't match the tool's schema) are\n * skipped silently — the call still lives in the persisted history, but\n * the renderer wouldn't know how to display it. The next `agent.run()` on\n * the session will see the orphan and synthesize an error tool_result via\n * the loop's normal recovery path.\n */\nexport function pendingInteractionsFromTurns(turns: readonly SessionTurn[]): InteractionRequest[] {\n interface CallInfo {\n callId: string\n tool: string\n input: Record<string, unknown>\n runId?: string\n turnId: string\n createdAt: number\n }\n const calls: CallInfo[] = []\n const resultIds = new Set<string>()\n\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'tool_call' && isInteractionTool(block.name)) {\n calls.push({\n callId: block.id,\n tool: block.name,\n input: block.input,\n ...(turn.runId ? { runId: turn.runId } : {}),\n turnId: turn.id,\n createdAt: turn.createdAt,\n })\n }\n else if (block.type === 'tool_result') {\n resultIds.add(block.callId)\n }\n }\n }\n\n const pending: InteractionRequest[] = []\n for (const call of calls) {\n if (resultIds.has(call.callId))\n continue\n if (call.tool === PRESENT_PLAN_TOOL) {\n const payload = parsePlanPayload(call.input)\n if (!payload)\n continue\n pending.push({\n id: call.callId,\n // Reconstructed from an unmatched `tool_use` block, so model by\n // construction — host prompts never reach the transcript.\n origin: 'model',\n kind: 'plan',\n tool: PRESENT_PLAN_TOOL,\n payload,\n ...(call.runId ? { runId: call.runId } : {}),\n turnId: call.turnId,\n createdAt: call.createdAt,\n })\n }\n else if (call.tool === ASK_USER_TOOL) {\n const payload = parseQuestionPayload(call.input)\n if (!payload)\n continue\n pending.push({\n id: call.callId,\n origin: 'model',\n kind: 'question',\n tool: ASK_USER_TOOL,\n payload,\n ...(call.runId ? { runId: call.runId } : {}),\n turnId: call.turnId,\n createdAt: call.createdAt,\n })\n }\n }\n return pending\n}\n\n/**\n * Defensive parsers — tools validate via JSON Schema before `execute`, but\n * persisted turns can carry malformed input (model regressions, schema\n * migrations). We accept what we recognize and drop what we don't.\n */\nfunction parsePlanPayload(input: Record<string, unknown>): PlanPayload | null {\n const title = typeof input.title === 'string' ? input.title.trim() : ''\n const plan = typeof input.plan === 'string' ? input.plan : ''\n if (!title || !plan)\n return null\n const stepsRaw = Array.isArray(input.steps) ? input.steps : undefined\n const steps: PlanStep[] = []\n if (stepsRaw) {\n for (const s of stepsRaw) {\n if (!s || typeof s !== 'object')\n continue\n const cast = s as { id?: unknown, title?: unknown, description?: unknown }\n if (typeof cast.id !== 'string' || typeof cast.title !== 'string')\n continue\n steps.push({\n id: cast.id,\n title: cast.title,\n ...(typeof cast.description === 'string' ? { description: cast.description } : {}),\n })\n }\n }\n return {\n title,\n plan,\n ...(steps.length > 0 ? { steps } : {}),\n }\n}\n\n/**\n * Defensive parser for an `ask_user` request. Accepts BOTH the new\n * multi-question shape and the legacy single-question shape (kept so\n * sessions created before the multi-question rework still surface\n * correctly on resume).\n *\n * - New: `{ intro?, questions: [...] }`.\n * - Legacy: `{ question, choices?, allowComment? }` → wrapped into a\n * single `select` (if choices) or `textarea` (otherwise) question\n * keyed by the synthetic id `'answer'`.\n */\nfunction parseQuestionPayload(input: Record<string, unknown>): QuestionPayload | null {\n const intro = typeof input.intro === 'string' && input.intro.trim().length > 0\n ? input.intro\n : undefined\n\n // New shape — explicit `questions` array. Parse each entry; drop\n // malformed ones rather than the whole payload so a single bad\n // question doesn't make the entire batch invisible on reload.\n //\n // Dedup by id (first wins). React would warn on the duplicate `key`\n // anyway, but more importantly the response `answers` map is keyed\n // by id — duplicates would silently collapse to a single value the\n // model would receive for every question that shared the id. First-\n // occurrence-wins keeps the form predictable; the model's own\n // schema validation should have caught it earlier.\n if (Array.isArray(input.questions)) {\n const questions: Question[] = []\n const seen = new Set<string>()\n for (const raw of input.questions) {\n const q = parseQuestion(raw)\n if (!q)\n continue\n if (seen.has(q.id))\n continue\n seen.add(q.id)\n questions.push(q)\n }\n if (questions.length === 0)\n return null\n return { ...(intro ? { intro } : {}), questions }\n }\n\n // Legacy shape — flatten to a one-question payload so resumed sessions\n // created before the multi-question rework still render.\n const question = typeof input.question === 'string' ? input.question.trim() : ''\n if (!question)\n return null\n const choices = parseChoices(input.choices)\n const legacy: Question = choices.length > 0\n ? { id: 'answer', prompt: question, type: 'select', choices }\n : { id: 'answer', prompt: question, type: 'textarea' }\n return { ...(intro ? { intro } : {}), questions: [legacy] }\n}\n\nfunction parseQuestion(raw: unknown): Question | null {\n if (!raw || typeof raw !== 'object')\n return null\n const cast = raw as {\n id?: unknown\n prompt?: unknown\n type?: unknown\n description?: unknown\n required?: unknown\n placeholder?: unknown\n default?: unknown\n choices?: unknown\n multi?: unknown\n affirmLabel?: unknown\n denyLabel?: unknown\n }\n if (typeof cast.id !== 'string' || !cast.id)\n return null\n if (typeof cast.prompt !== 'string' || !cast.prompt.trim())\n return null\n const type = cast.type\n if (type !== 'text' && type !== 'textarea' && type !== 'select' && type !== 'confirm')\n return null\n\n const base = {\n id: cast.id,\n prompt: cast.prompt,\n ...(typeof cast.description === 'string' ? { description: cast.description } : {}),\n ...(typeof cast.required === 'boolean' ? { required: cast.required } : {}),\n }\n\n if (type === 'text' || type === 'textarea') {\n return {\n ...base,\n type,\n ...(typeof cast.placeholder === 'string' ? { placeholder: cast.placeholder } : {}),\n ...(typeof cast.default === 'string' ? { default: cast.default } : {}),\n }\n }\n\n if (type === 'select') {\n const choices = parseChoices(cast.choices)\n if (choices.length === 0)\n return null // a select with zero choices is unusable\n return { ...base, type, choices, ...(cast.multi === true ? { multi: true } : {}) }\n }\n\n // type === 'confirm'\n return {\n ...base,\n type,\n ...(typeof cast.affirmLabel === 'string' ? { affirmLabel: cast.affirmLabel } : {}),\n ...(typeof cast.denyLabel === 'string' ? { denyLabel: cast.denyLabel } : {}),\n }\n}\n\nfunction parseChoices(raw: unknown): QuestionChoice[] {\n if (!Array.isArray(raw))\n return []\n const choices: QuestionChoice[] = []\n for (const c of raw) {\n if (!c || typeof c !== 'object')\n continue\n const cast = c as { id?: unknown, label?: unknown, description?: unknown, selected?: unknown }\n if (typeof cast.id !== 'string' || typeof cast.label !== 'string')\n continue\n choices.push({\n id: cast.id,\n label: cast.label,\n ...(typeof cast.description === 'string' ? { description: cast.description } : {}),\n // Preserved through the sanitizer, not just accepted at the type\n // level: a question rehydrated from a persisted session would\n // otherwise reopen with every pre-tick silently dropped.\n ...(cast.selected === true ? { selected: true } : {}),\n })\n }\n return choices\n}\n\n// ---------------------------------------------------------------------------\n// Tool factory — builds `present_plan` and `ask_user` ToolDefs bound to a\n// host-provided async resolver. Used by `buildAgent` in the TUI; a GUI\n// consumer wires its own React resolver the same way.\n// ---------------------------------------------------------------------------\n\nexport interface CreateInteractionToolsOptions {\n /**\n * Called when the agent invokes one of the interaction tools. Resolves\n * with the user's response (forwarded to the model as the tool_result);\n * reject to signal denial / abort (the model receives\n * `Tool error: <message>` as the result).\n */\n requestInteraction: (request: InteractionRequest) => Promise<InteractionResponse>\n /** Evaluated at invocation time so hosts can switch modes without rebuilding the agent. */\n shouldSkipInteractions?: () => boolean\n}\n\n/**\n * Create the `present_plan` and `ask_user` tools as a record, ready to\n * spread into `createAgent({ tools })` or composed into a {@link Preset}.\n */\nexport function createInteractionTools(opts: CreateInteractionToolsOptions): Record<string, ToolDef> {\n return {\n [PRESENT_PLAN_TOOL]: createPlanTool(opts),\n [ASK_USER_TOOL]: createQuestionTool(opts),\n }\n}\n\nconst PLAN_DESCRIPTION\n = 'Present a multi-step plan to the user for approval BEFORE executing it. '\n + 'Use this when you have a concrete proposal that materially changes the workspace '\n + 'and want explicit confirmation. The user can approve, reject, or request revisions; '\n + 'revisions come back as a comment alongside a `revise` decision.'\n\nconst QUESTION_DESCRIPTION\n = 'Ask the user one or more clarifying questions and pause until they answer. '\n + 'Batch related questions into a single call instead of asking one at a time — '\n + 'every call pauses the conversation. '\n + 'Each question carries a `type`: '\n + '`text` (single line), `textarea` (multi-line), `select` (one of `choices`), or '\n + '`confirm` (yes/no). Use sparingly: only when explicit user input materially '\n + 'changes the next steps. The response may carry `instructions`: free text the '\n + 'user added alongside their answers. It refines or overrides the questions and is '\n + 'authoritative.'\n\nfunction createPlanTool({ requestInteraction, shouldSkipInteractions }: CreateInteractionToolsOptions): ToolDef {\n return {\n spec: {\n name: PRESENT_PLAN_TOOL,\n description: PLAN_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: {\n title: { type: 'string', description: 'Short headline summary of the plan.' },\n plan: { type: 'string', description: 'Full plan body, written as Markdown.' },\n steps: {\n type: 'array',\n description: 'Optional structured step list. Each step has an `id`, `title`, and optional `description`.',\n items: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n title: { type: 'string' },\n description: { type: 'string' },\n },\n required: ['id', 'title'],\n },\n },\n },\n required: ['title', 'plan'],\n },\n },\n async execute(input, ctx) {\n const payload = parsePlanPayload(input)\n if (!payload)\n throw new Error('present_plan: invalid input, expected non-empty `title` and `plan` strings.')\n const request: PlanRequest = {\n id: ctx.callId,\n origin: 'model',\n kind: 'plan',\n tool: PRESENT_PLAN_TOOL,\n payload,\n ...(ctx.runId ? { runId: ctx.runId } : {}),\n turnId: ctx.turnId,\n createdAt: Date.now(),\n }\n const response = shouldSkipInteractions?.()\n ? createAutomaticInteractionResponse(request)\n : await requestInteraction(request)\n if (response.kind !== 'plan')\n throw new Error(`present_plan: unexpected response kind \"${response.kind}\".`)\n return serializeInteractionResponse(response)\n },\n }\n}\n\nfunction createQuestionTool({ requestInteraction, shouldSkipInteractions }: CreateInteractionToolsOptions): ToolDef {\n return {\n spec: {\n name: ASK_USER_TOOL,\n description: QUESTION_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: {\n intro: {\n type: 'string',\n description: 'Optional context shown above the questions (Markdown).',\n },\n questions: {\n type: 'array',\n description: 'One or more questions for the user to answer in a single form.',\n minItems: 1,\n items: {\n type: 'object',\n properties: {\n id: {\n type: 'string',\n description: 'Stable identifier — keys the answer back to the model.',\n },\n prompt: {\n type: 'string',\n description: 'The question to display.',\n },\n type: {\n type: 'string',\n enum: ['text', 'textarea', 'select', 'confirm'],\n description: '`text` = single line, `textarea` = multi-line, `select` = pick from `choices`, `confirm` = yes/no.',\n },\n description: {\n type: 'string',\n description: 'Optional helper text shown under the prompt.',\n },\n required: {\n type: 'boolean',\n description: 'Whether a non-empty answer is required.',\n },\n placeholder: {\n type: 'string',\n description: 'For `text` / `textarea`: placeholder shown when the input is empty.',\n },\n default: {\n type: 'string',\n description: 'For `text` / `textarea`: pre-fill the input with this value.',\n },\n choices: {\n type: 'array',\n description: 'The available choices. Required when `type` is `select`; omit for other types.',\n items: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n label: { type: 'string' },\n description: { type: 'string' },\n selected: {\n type: 'boolean',\n description: 'For a `multi` select: open with this choice already ticked (opt-out lists).',\n },\n },\n required: ['id', 'label'],\n },\n },\n affirmLabel: {\n type: 'string',\n description: 'For `confirm`: label for the affirmative option. Default: `\"yes\"`.',\n },\n denyLabel: {\n type: 'string',\n description: 'For `confirm`: label for the negative option. Default: `\"no\"`.',\n },\n },\n required: ['id', 'prompt', 'type'],\n },\n },\n },\n required: ['questions'],\n },\n },\n async execute(input, ctx) {\n const payload = parseQuestionPayload(input)\n if (!payload)\n throw new Error('ask_user: invalid input, expected a non-empty `questions` array.')\n const request: QuestionRequest = {\n id: ctx.callId,\n origin: 'model',\n kind: 'question',\n tool: ASK_USER_TOOL,\n payload,\n ...(ctx.runId ? { runId: ctx.runId } : {}),\n turnId: ctx.turnId,\n createdAt: Date.now(),\n }\n const response = shouldSkipInteractions?.()\n ? createAutomaticInteractionResponse(request)\n : await requestInteraction(request)\n if (response.kind !== 'question')\n throw new Error(`ask_user: unexpected response kind \"${response.kind}\".`)\n return serializeInteractionResponse(response)\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// React context — FIFO queue of pending requests + resolver callbacks.\n//\n// Two contexts on purpose (mirrors `safe-mode-context.tsx`):\n// - `InteractionsQueueContext` carries the live queue. Consumers re-render\n// on every push/pop.\n// - `InteractionsActionsContext` carries `{ enqueue, resolveHead, … }` and\n// never changes identity, so callbacks that depend on these don't\n// re-bind on every queue churn.\n// ---------------------------------------------------------------------------\n\nexport interface PendingInteractionEntry {\n request: InteractionRequest\n /** The user picked something — forward to the live tool Promise or the resumed tool_result writer. */\n resolve: (response: InteractionResponse) => void\n /**\n * The user / system cancelled — distinct from `resolve` so renderers can\n * differentiate \"user picked something\" from \"user gave up / aborted\".\n * Live entries reject the tool's Promise; resumed entries decide what\n * to persist as the cancelled tool_result.\n */\n cancel: (reason?: string) => void\n}\n\nexport interface InteractionsActions {\n /** Add a request to the FIFO queue. */\n enqueue: (entry: PendingInteractionEntry) => void\n /** Resolve the head request with `response`. */\n resolveHead: (response: InteractionResponse) => void\n /**\n * Cancel the head request. Reserved for future per-call cancel\n * affordances (a \"skip this\" button, a GUI's close-modal-X) — the\n * built-in TUI currently cancels via the run-level `cancelAll` path\n * only. Kept on the public API so consumer renderers can wire it\n * without a follow-up surface change.\n */\n cancelHead: (reason?: string) => void\n /** Cancel every queued request. Used by abort / session teardown. */\n cancelAll: (reason?: string) => void\n /**\n * Remove the queued entry whose `request.id` matches, WITHOUT settling\n * it locally — used by the daemon runtime when ANOTHER window resolved\n * the same shared interaction. No-op when absent.\n */\n dropById: (requestId: string) => void\n}\n\nconst InteractionsQueueContext = createContext<readonly PendingInteractionEntry[]>([])\nconst InteractionsActionsContext = createContext<InteractionsActions | null>(null)\n\nexport function InteractionsProvider({ children }: { children: ReactNode }) {\n const [queue, setQueue] = useState<readonly PendingInteractionEntry[]>([])\n\n // Mirror the live queue so the unmount cleanup can settle whatever is\n // pending without re-subscribing the effect on every queue change.\n const queueRef = useRef<readonly PendingInteractionEntry[]>([])\n queueRef.current = queue\n\n // Provider unmount is a teardown path too: React drops the queue state\n // outright, so any in-flight `requestInteraction` Promise would hang\n // forever (its tool body never settles → the run's `running` gate never\n // clears). Cancel every pending entry on unmount so the resolver can't be\n // silently dropped. (#4)\n useEffect(() => () => {\n for (const entry of queueRef.current)\n entry.cancel('Interactions provider unmounted')\n }, [])\n\n const enqueue = useCallback((entry: PendingInteractionEntry) => {\n setQueue(prev => [...prev, entry])\n }, [])\n\n const resolveHead = useCallback((response: InteractionResponse) => {\n setQueue((prev) => {\n const [head, ...rest] = prev\n if (head)\n head.resolve(response)\n return rest\n })\n }, [])\n\n const cancelHead = useCallback((reason?: string) => {\n setQueue((prev) => {\n const [head, ...rest] = prev\n if (head)\n head.cancel(reason)\n return rest\n })\n }, [])\n\n const cancelAll = useCallback((reason?: string) => {\n setQueue((prev) => {\n for (const entry of prev) entry.cancel(reason)\n return []\n })\n }, [])\n\n const dropById = useCallback((requestId: string) => {\n // Remove WITHOUT settling: the daemon already resolved this in the\n // window that answered it. Neither resolve nor cancel — both would\n // reach back toward the (no-op) daemon callback needlessly.\n setQueue(prev => prev.filter(entry => entry.request.id !== requestId))\n }, [])\n\n // Stable actions identity — every member is `useCallback`'d with `[]`\n // deps. `useRef` captures the first-render identity and we hand the\n // same object out forever, so consumers calling `useInteractionsActions()`\n // never re-render purely because of queue state.\n const actionsRef = useRef<InteractionsActions | null>(null)\n if (!actionsRef.current)\n actionsRef.current = { enqueue, resolveHead, cancelHead, cancelAll, dropById }\n\n return (\n <InteractionsActionsContext.Provider value={actionsRef.current}>\n <InteractionsQueueContext.Provider value={queue}>\n {children}\n </InteractionsQueueContext.Provider>\n </InteractionsActionsContext.Provider>\n )\n}\n\n/** Read the live queue (re-renders on every push/pop). */\nexport function useInteractionsQueue(): readonly PendingInteractionEntry[] {\n return useContext(InteractionsQueueContext)\n}\n\n/** Read the stable actions object. */\nexport function useInteractionsActions(): InteractionsActions {\n const ctx = useContext(InteractionsActionsContext)\n if (!ctx)\n throw new Error('useInteractionsActions must be used inside <InteractionsProvider>')\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Live-tool binding helper — wraps the queue actions into a Promise-shaped\n// `requestInteraction` that {@link createInteractionTools} expects.\n// ---------------------------------------------------------------------------\n\n/**\n * Build the `requestInteraction` callback for `createInteractionTools` from\n * the React-side {@link InteractionsActions}. Each call adds a fresh entry\n * to the queue whose `resolve` / `cancel` route back to one Promise that\n * the tool's `execute` awaits.\n */\nexport function makeRequestInteraction(\n actions: InteractionsActions,\n): CreateInteractionToolsOptions['requestInteraction'] {\n return request => new Promise<InteractionResponse>((resolve, reject) => {\n actions.enqueue({\n request,\n resolve,\n cancel: reason => reject(new Error(reason ?? 'Interaction cancelled')),\n })\n })\n}\n","/**\n * `ctx.interaction` for a running command: confirm / askUser / presentPlan,\n * bridged onto the host's interaction queue and cancelled with the command.\n */\nimport type { CommandStepContext } from '../../../index'\nimport type { InteractionRequest, InteractionResponse } from '../../interactions'\nimport type { InteractionHub } from '../interactions'\nimport { randomUUID } from 'node:crypto'\nimport { ASK_USER_TOOL, HOST_INTERACTION_ID_PREFIX, PRESENT_PLAN_TOOL } from '../../interactions'\n\nexport function createCommandInteractionBridge({ interactions, sessionId, controller }: {\n interactions: InteractionHub\n sessionId: string\n controller: AbortController\n}): (request: InteractionRequest) => Promise<InteractionResponse> {\n const requestInteraction = interactions.requestInteractionFor(sessionId)\n\n /*\n * Promise-shaped bridge into the interaction queue — the same\n * `interactions.*` surface the ask_user / present_plan TOOLS ride,\n * minus the tool call (synthetic id, no turns, nothing to resume after\n * a reload). An abort cancels the pending request so every client's\n * modal dismisses and the awaiting Promise rejects.\n */\n const requestCommandInteraction = (request: InteractionRequest): Promise<InteractionResponse> => {\n if (controller.signal.aborted)\n return Promise.reject(new Error('command aborted'))\n\n const promise = requestInteraction(request)\n const onAbort = (): void => {\n interactions.cancel(request.id, 'command aborted')\n }\n controller.signal.addEventListener('abort', onAbort, { once: true })\n\n return promise.finally(() => controller.signal.removeEventListener('abort', onAbort))\n }\n\n return requestCommandInteraction\n}\n\nexport function createCommandInteraction(\n requestCommandInteraction: (request: InteractionRequest) => Promise<InteractionResponse>,\n): CommandStepContext['interaction'] {\n return {\n confirm: async (confirmPrompt, confirmOpts) => {\n const response = await requestCommandInteraction({\n id: `${HOST_INTERACTION_ID_PREFIX}${randomUUID()}`,\n origin: 'host',\n kind: 'question',\n tool: ASK_USER_TOOL,\n createdAt: Date.now(),\n payload: {\n ...(confirmOpts?.intro ? { intro: confirmOpts.intro } : {}),\n questions: [\n {\n id: 'confirm',\n type: 'confirm',\n prompt: confirmPrompt,\n ...(confirmOpts?.affirmLabel ? { affirmLabel: confirmOpts.affirmLabel } : {}),\n ...(confirmOpts?.denyLabel ? { denyLabel: confirmOpts.denyLabel } : {}),\n },\n ],\n },\n })\n\n if (response.kind !== 'question')\n throw new Error('confirm: unexpected interaction response kind')\n\n return response.answers.confirm === true\n },\n askUser: async (form) => {\n const response = await requestCommandInteraction({\n id: `${HOST_INTERACTION_ID_PREFIX}${randomUUID()}`,\n origin: 'host',\n kind: 'question',\n tool: ASK_USER_TOOL,\n createdAt: Date.now(),\n payload: form,\n })\n\n if (response.kind !== 'question')\n throw new Error('askUser: unexpected interaction response kind')\n\n return response.answers\n },\n presentPlan: async (plan) => {\n const response = await requestCommandInteraction({\n id: `${HOST_INTERACTION_ID_PREFIX}${randomUUID()}`,\n origin: 'host',\n kind: 'plan',\n tool: PRESENT_PLAN_TOOL,\n createdAt: Date.now(),\n payload: plan,\n })\n\n if (response.kind !== 'plan')\n throw new Error('presentPlan: unexpected interaction response kind')\n\n return response\n },\n }\n}\n","/**\n * A running command's display-only output: blocks stream live and buffer\n * into one `role: 'command'` turn per ordering boundary; a failure persists\n * as a notice turn.\n */\nimport type { CommandOutputBlock } from '../../../index'\nimport type { Session } from '../../../session'\nimport type { StreamEvent } from '../../types'\nimport { randomUUID } from 'node:crypto'\nimport { commandBlocksToContent, commandBlockToEvent } from '../../../index'\nimport { noticeTurnContent } from '../../store'\n\nexport interface CommandOutput {\n /*\n * Display-only blocks accrue here and flush as one `command` turn at\n * each ordering boundary. `pendingTurnId` is minted at the batch's\n * first emit so live events and the eventually-persisted turn share\n * one id.\n */\n state: { pending: CommandOutputBlock[], pendingTurnId: string | null }\n flushCommandTurn: () => Promise<void>\n emitBlock: (block: CommandOutputBlock) => void\n emitCommandError: (text: string) => Promise<void>\n}\n\nexport function createCommandOutput({ session, emitEvent }: {\n session: Session\n emitEvent: (event: StreamEvent) => void\n}): CommandOutput {\n const state: CommandOutput['state'] = { pending: [], pendingTurnId: null }\n\n const flushCommandTurn = async (): Promise<void> => {\n if (state.pending.length === 0)\n return\n\n const content = commandBlocksToContent(state.pending)\n const turnId = state.pendingTurnId ?? randomUUID()\n state.pending = []\n state.pendingTurnId = null\n await session.appendTurns([{ id: turnId, role: 'command', createdAt: Date.now(), content }]).catch(() => undefined)\n }\n\n const emitBlock = (block: CommandOutputBlock): void => {\n state.pendingTurnId ??= randomUUID()\n state.pending.push(block)\n emitEvent({ ...commandBlockToEvent(block), turnId: state.pendingTurnId })\n }\n\n /*\n * A command failure is the one line the user needs to read after the\n * fact, so it is persisted as a notice turn (same shape the TUI-local\n * host and the engine's cache-break notice write), not just broadcast\n * live — a live-only `error` event vanishes on the next re-converge,\n * which the `finally` of `runSlashCommand`'s completion (`./index`)\n * triggers immediately. Flushes pending output\n * first so the notice lands after the blocks the step emitted.\n */\n const emitCommandError = async (text: string): Promise<void> => {\n await flushCommandTurn()\n const notice = { severity: 'error' as const, label: 'command' }\n const turnId = randomUUID()\n await session\n .appendTurns([{ id: turnId, role: 'command', createdAt: Date.now(), content: noticeTurnContent(notice, text) }])\n .catch(() => undefined)\n emitEvent({ kind: 'error', text, notice, turnId })\n }\n\n return { state, flushCommandTurn, emitBlock, emitCommandError }\n}\n","/**\n * `ctx.runAgent` for a running command: one agent sub-run on the session,\n * tagged as command-driven so a reload renders it the same way.\n */\nimport type { CommandStepContext } from '../../../index'\nimport type { Session } from '../../../session'\nimport type { StreamEvent } from '../../types'\nimport type { startRunHeartbeat } from '../helpers'\nimport type { HostSignal } from '../signals'\nimport type { ActiveRun } from '../types'\nimport type { CommandRunSettings } from './run-settings'\nimport { randomUUID } from 'node:crypto'\nimport { commandStepLabel } from '../../command-notes'\nimport { errorMessage } from './errors'\n\nexport function createCommandRunAgent({ run, session, sessionId, controller, heartbeat, broadcast, emitEvent, flushCommandTurn, resolveRunSettings }: {\n run: ActiveRun\n session: Session\n sessionId: string\n controller: AbortController\n heartbeat: ReturnType<typeof startRunHeartbeat>\n broadcast: (signal: HostSignal) => void\n emitEvent: (event: StreamEvent) => void\n flushCommandTurn: () => Promise<void>\n resolveRunSettings: (run: ActiveRun) => Promise<CommandRunSettings>\n}): CommandStepContext['runAgent'] {\n return async (agentPrompt: string, agentOpts?: { readonly display?: string }) => {\n if (controller.signal.aborted)\n throw new Error('runAgent: command aborted')\n\n // Persist output emitted so far so it lands BEFORE the sub-run's\n // user/assistant turns in the transcript order.\n await flushCommandTurn()\n\n // Re-assert host-driven skill activation (same invariant sendPrompt\n // protects) — the agent's run-end pass deactivates everything.\n for (const name of run.autoActivateSkills ?? []) {\n try {\n await run.agent.activateSkill(name)\n }\n catch {\n // skill not resolvable — best-effort, matches sendPrompt.\n }\n }\n\n // A step of the command, not a new prompt: its short `display` as\n // the label, the full prompt tucked underneath. The model still\n // receives it verbatim.\n emitEvent({\n kind: 'command-detail',\n label: agentOpts?.display ? commandStepLabel(agentOpts.display) : 'prompt',\n text: agentPrompt,\n })\n\n const before = session.turns.length\n const beforeRuns = session.runs.length\n const { thinking, modelOptions, autoCompact, caps } = await resolveRunSettings(run)\n const runId = randomUUID()\n\n // Fresh runId per sub-run so clients paint streaming state.\n broadcast({ kind: 'run:start', sessionId, runId })\n\n try {\n await run.agent.run({\n prompt: agentPrompt,\n signal: controller.signal,\n behavior: { autoCompact, ...caps },\n ...(run.modelOverride ? { model: run.modelOverride } : {}),\n ...(thinking ? { thinking } : {}),\n ...(modelOptions ? { modelOptions } : {}),\n })\n broadcast({ kind: 'run:end', sessionId, runId, ok: true })\n }\n catch (err) {\n broadcast({ kind: 'run:end', sessionId, runId, ok: false, error: errorMessage(err) })\n throw err\n }\n finally {\n // The loop just settled the marker; the command is still going.\n heartbeat.beat()\n }\n\n await session.save().catch(() => undefined)\n\n // Tag the sub-run(s) as command-driven so a reload renders the\n // injected prompt the same minimal way. Presentation-only.\n for (const sessionRun of session.runs.slice(beforeRuns)) {\n if (sessionRun.parentRunId)\n continue\n\n sessionRun.origin = { kind: 'command', ...(agentOpts?.display ? { display: agentOpts.display } : {}) }\n await session.updateRun(sessionRun).catch(() => undefined)\n }\n\n const text = session.turns\n .slice(before)\n .filter(t => t.role === 'assistant')\n .flatMap(t => t.content.flatMap(b => (b.type === 'text' ? [b.text] : [])))\n .join('\\n')\n\n return { text }\n }\n}\n","/**\n * Per-run settings shared by prompt runs and command-driven sub-runs: the\n * settings hard caps, and a sub-run's model / effort / auto-compact.\n */\nimport type { Provider } from '../../../providers'\nimport type { AgentBehavior, ThinkingLevel } from '../../../types'\nimport type { ProviderKey } from '../../auth'\nimport type { ProviderDescriptor } from '../../providers'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { HostSettings } from '../signals'\nimport type { ActiveRun } from '../types'\nimport { chatAutoCompactBehavior } from '../../auto-compact'\nimport { BUILTIN_PROVIDERS, enabledModelOptions, getContextWindow, restoreModelOptions } from '../../providers'\nimport { isThinkingLevel, resolveCompactionSummarizer } from '../helpers'\n\n/**\n * Hard-cap settings → per-run `AgentBehavior` overrides. Empty when every cap sits\n * at its \"unlimited\" default (0 / off), so out of the box nothing is\n * forwarded and the run stays model-driven and unbounded. Spread into\n * `behavior` on every `agent.run()` (prompt runs and command sub-runs\n * alike).\n */\nexport function runCapsFromSettings(settings: HostSettings): Partial<AgentBehavior> {\n const caps: Partial<AgentBehavior> = {}\n\n if (settings.resumeOnMaxTokens)\n caps.resumeOnMaxTokens = true\n if (settings.maxOutputTokens > 0)\n caps.maxTokens = settings.maxOutputTokens\n if (settings.maxTurns > 0)\n caps.maxTurns = settings.maxTurns\n if (settings.maxCostUsd > 0)\n caps.maxCostUsd = settings.maxCostUsd\n if (settings.maxTotalTokens > 0)\n caps.maxTotalTokens = settings.maxTotalTokens\n if (settings.maxWallMinutes > 0)\n caps.maxWallMs = settings.maxWallMinutes * 60_000\n if (settings.retryMaxAttempts > 0)\n caps.retry = { maxAttempts: settings.retryMaxAttempts }\n\n return caps\n}\n\nexport interface CommandRunSettings {\n thinking?: ThinkingLevel\n modelOptions?: Record<string, boolean>\n autoCompact: ReturnType<typeof chatAutoCompactBehavior>\n caps: Partial<AgentBehavior>\n}\n\nexport function createRunSettingsResolver({ env, buildProvider }: {\n env: ChatHostEnvironment\n buildProvider: (providers: Readonly<Record<string, ProviderDescriptor>>, providerKey?: ProviderKey) => Provider\n}): (run: ActiveRun) => Promise<CommandRunSettings> {\n /**\n * Per-session model/effort derivation for command-driven sub-runs —\n * mirrors `sendPrompt`'s resolution (metadata effort, model options,\n * auto-compact from settings + model context window) so a `ctx.runAgent`\n * call behaves exactly like a user-sent prompt.\n */\n return async function resolveRunSettings(run: ActiveRun): Promise<CommandRunSettings> {\n let thinking: ThinkingLevel | undefined\n let modelOptions: Record<string, boolean> | undefined\n\n try {\n const data = await env.store.load(run.sessionId)\n const rawEffort = data?.metadata?.effort\n\n if (typeof rawEffort === 'string' && isThinkingLevel(rawEffort))\n thinking = rawEffort\n\n const descriptor = run.providerDescriptor ?? BUILTIN_PROVIDERS.anthropic\n const modelId = run.modelOverride ?? run.model\n const enabled = enabledModelOptions(data?.metadata?.modelOptions)\n modelOptions = restoreModelOptions(descriptor, modelId, { [modelId]: enabled })\n }\n catch {\n // Reading metadata is best-effort; absence just means defaults.\n }\n\n const settings = env.readSettings()\n const descriptor = BUILTIN_PROVIDERS[run.providerKey] ?? BUILTIN_PROVIDERS.anthropic\n // Same dedicated `compactionModel` summarizer as `sendPrompt` resolves\n // for prompt runs — a sub-run's auto-compact must not silently fall\n // back to the main model when the user pinned a cheaper one.\n // (Sub-runs also carry the same cross-process run heartbeat as prompt\n // runs — see `ctx.runAgent`.)\n const runtime = await env.runtimeConfig(run.discoveryCwd)\n const summarizer = resolveCompactionSummarizer(\n settings.compactionModel,\n key => buildProvider(runtime.providers, key),\n { providerKey: run.providerKey, model: run.modelOverride ?? run.model },\n )\n const autoCompact = chatAutoCompactBehavior({\n enabled: settings.autoCompact,\n threshold: settings.autoCompactThreshold,\n rawContextWindow: getContextWindow(descriptor, run.modelOverride ?? run.model),\n ...(summarizer ? { summarizer } : {}),\n })\n\n // Same hard-cap overrides as prompt runs — a command-driven sub-run must\n // not escape the user's turn/cost/token/time budgets.\n return {\n ...(thinking ? { thinking } : {}),\n ...(modelOptions ? { modelOptions } : {}),\n autoCompact,\n caps: runCapsFromSettings(settings),\n }\n }\n}\n","import type { CommandSpawnResult, CommandStepContext, ToolContext } from '../../../index'\nimport type { Session } from '../../../session'\n/**\n * `ctx.spawnAgents` for a running command: isolated child agents through the\n * agent's spawn tool, in a worker pool under the tool's concurrency cap.\n */\nimport type { CommandInvocation, CommandRunRecord } from '../../commands'\nimport type { startRunHeartbeat } from '../helpers'\nimport type { ActiveRun } from '../types'\nimport { randomUUID } from 'node:crypto'\nimport { isSpawnTool } from '../../../index'\nimport { nonOwningMcpView } from '../../../mcp/index'\nimport { errorMessage } from './errors'\n\nexport function createSpawnAgents({ run, session, invocation, controller, commandRun, heartbeat, flushCommandTurn }: {\n run: ActiveRun\n session: Session\n invocation: CommandInvocation\n controller: AbortController\n commandRun: CommandRunRecord\n heartbeat: ReturnType<typeof startRunHeartbeat>\n flushCommandTurn: () => Promise<void>\n}): CommandStepContext['spawnAgents'] {\n return async (tasks, spawnOpts) => {\n const seam = run.commandSeam?.()\n const agent = run.agent\n\n if (!seam || !isSpawnTool(seam.spawnTool))\n throw new Error('spawnAgents: no spawn tool available for this agent')\n\n if (controller.signal.aborted)\n throw new Error('spawnAgents: command aborted')\n\n if (tasks.length === 0)\n return []\n\n await flushCommandTurn()\n\n const commandRunId = await commandRun.ensure()\n const handle = await agent.ensureExecution()\n\n // Bind the parent's MCP connection BEFORE spawning so children get\n // the live view instead of re-bootstrapping every server. Raced\n // against the command's abort signal — a full MCP bootstrap can\n // take seconds and an abort must not block on it.\n let onAbort: (() => void) | undefined\n\n try {\n await Promise.race([\n agent.warmup(),\n new Promise<void>((resolveAbort) => {\n if (controller.signal.aborted) {\n resolveAbort()\n\n return\n }\n\n onAbort = () => resolveAbort()\n controller.signal.addEventListener('abort', onAbort, { once: true })\n }),\n ])\n }\n catch {\n // warmup failed — children fall back to config bootstrap (degraded, not dead).\n }\n finally {\n if (onAbort)\n controller.signal.removeEventListener('abort', onAbort)\n }\n\n if (controller.signal.aborted)\n throw new Error('spawnAgents: command aborted')\n\n const parentMcp = agent.mcpConnection\n const results: CommandSpawnResult[] = tasks.map((task, i) => ({\n label: task.label ?? `task-${i + 1}`,\n ...(task.model !== undefined ? { model: task.model } : {}),\n status: 'aborted' as const,\n text: '',\n message: 'spawnAgents: batch aborted before this task ran',\n }))\n\n // Simple worker pool — capped at the spawn tool's own concurrency\n // limit so a task the pool admitted starts at once instead of\n // queuing for a slot. `runTask` reports child failures in its outcome; the\n // per-task catch only guards infrastructure throws.\n let cursor = 0\n const worker = async (): Promise<void> => {\n while (cursor < tasks.length && !controller.signal.aborted) {\n const index = cursor++\n const spawnTask = tasks[index]!\n\n try {\n const outcome = await seam.spawnTool.runTask(\n {\n task: spawnTask.prompt,\n ...(spawnTask.system !== undefined ? { system: spawnTask.system } : {}),\n ...(spawnTask.model !== undefined ? { model: spawnTask.model } : {}),\n },\n {\n provider: seam.provider,\n providers: seam.providers,\n ...(seam.name !== undefined ? { name: seam.name } : {}),\n model: run.modelOverride ?? run.model,\n signal: controller.signal,\n execution: agent.execution,\n handle,\n hooks: agent.hooks,\n ...(seam.system !== undefined ? { system: seam.system } : {}),\n tools: seam.tools,\n mcpServers: [...agent.mcpServers],\n ...(parentMcp ? { mcpConnection: nonOwningMcpView(parentMcp) } : {}),\n skills: seam.skills,\n behavior: seam.behavior,\n turnId: `command_${invocation.name}`,\n runId: commandRunId,\n callId: `command_spawn_${randomUUID()}`,\n session,\n } satisfies ToolContext,\n )\n\n results[index] = {\n label: spawnTask.label ?? outcome.id ?? `task-${index + 1}`,\n ...(spawnTask.model !== undefined ? { model: spawnTask.model } : {}),\n status: outcome.status,\n text: outcome.text,\n message: outcome.message,\n }\n }\n catch (err) {\n results[index] = {\n label: spawnTask.label ?? `task-${index + 1}`,\n ...(spawnTask.model !== undefined ? { model: spawnTask.model } : {}),\n status: 'error',\n text: '',\n message: `spawnAgents: ${errorMessage(err)}`,\n }\n }\n }\n }\n\n const cap = seam.spawnTool.maxConcurrent\n const width = Math.max(1, Math.min(spawnOpts?.maxConcurrent ?? cap, cap, tasks.length))\n await Promise.all(Array.from({ length: width }, () => worker()))\n heartbeat.beat()\n await session.save().catch(() => undefined)\n\n return results\n }\n}\n","/**\n * `/` command host for the shared chat host, transport-agnostic (the GUI\n * main process and the TUI both run commands through it). A command is\n * an extension-contributed workflow invoked by typing `/<name> [args]` as\n * the whole prompt; steps emit display-only blocks (persisted as\n * `role: 'command'` turns, never sent to the model) and can drive the agent\n * mid-flight via `ctx.runAgent` / `ctx.spawnAgents` / `ctx.generateData`.\n *\n * The host supplies the side-effecting capabilities on the step context;\n * the canonical model (`executeCommand`, `parseCommandInvocation`, the\n * block↔content/event mappers) lives in the library core and is shared\n * with the TUI/GUI so live and reloaded transcripts render identically in\n * every surface.\n *\n * Seam adaptations vs. the GUI module: `broadcast` / `ensureAgent` /\n * `buildProvider` are host-closure values injected through the factory;\n * the interaction bridge rides the host's `InteractionHub`; settings /\n * runtime config / session store come from the `ChatHostEnvironment`.\n */\nimport type { Command, CommandGenerateDataOptions, CommandStepContext } from '../../../index'\nimport type { Provider } from '../../../providers'\nimport type { ProviderKey } from '../../auth'\nimport type { CommandExecution } from '../../commands'\nimport type { ProviderDescriptor } from '../../providers'\nimport type { StreamEvent } from '../../types'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { InteractionHub } from '../interactions'\nimport type { CommandArgSuggestionSummary, CommandSummary, HostSignal, SendOptions } from '../signals'\nimport type { ActiveRun } from '../types'\nimport { randomUUID } from 'node:crypto'\nimport { createLogger, executeCommand, generateStructuredData, parseCommandInvocation } from '../../../index'\nimport { withExtensionSession } from '../../../session'\nimport { commandHeaderBlock, commandNoteText, noteDisplay } from '../../command-notes'\nimport { createCommandRunRecord } from '../../commands'\nimport { startRunHeartbeat } from '../helpers'\nimport { sessionHostRuntime } from '../host-runtime'\nimport { createCommandCatalog } from './catalog'\nimport { errorMessage } from './errors'\nimport { createCommandInteraction, createCommandInteractionBridge } from './interaction'\nimport { createCommandOutput } from './output'\nimport { createCommandRunAgent } from './run-agent'\nimport { createRunSettingsResolver } from './run-settings'\nimport { createSpawnAgents } from './spawn-agents'\n\nexport { runCapsFromSettings } from './run-settings'\n\nexport interface CommandModule {\n /** Wire-safe command catalog for a client's `/` completion popover. */\n listCommands: (cwd: string) => Promise<CommandSummary[]>\n /** Argument suggestions for `/name <prefix>` — best-effort, empty on failure. */\n completeCommandArgs: (cwd: string, name: string, argsPrefix: string) => Promise<CommandArgSuggestionSummary[]>\n /**\n * Try the prompt as a `/` command invocation. `{ ran: false }` when the\n * prompt isn't one (caller falls through to the model run). `{ ran: true }`\n * as soon as the command is ACCEPTED: `completion` settles when it\n * finishes (success or step error — errors surface as transcript events,\n * not rejections). The caller must hold the session busy until then.\n *\n * Resolving at accept is load-bearing: a command runs for minutes\n * (`/review`'s reviewer fan-out, an `askUser` wait), and the dispatch RPCs\n * that land here (`chat.send`, `chat.pushQueued`, `queue.*`) sit behind a\n * 30 s client deadline that tears the socket down on expiry.\n */\n runSlashCommand: (opts: SendOptions, assertOpen?: () => void) => Promise<{ ran: false } | { ran: true, runId: string, completion: Promise<void> }>\n}\n\nexport function createCommandModule(deps: {\n env: ChatHostEnvironment\n broadcast: (signal: HostSignal) => void\n ensureAgent: (sessionId: string) => Promise<ActiveRun>\n buildProvider: (providers: Readonly<Record<string, ProviderDescriptor>>, providerKey?: ProviderKey) => Provider\n interactions: InteractionHub\n}): CommandModule {\n const { env, broadcast, ensureAgent, buildProvider, interactions } = deps\n const { mergedCommands, listCommands, completeCommandArgs } = createCommandCatalog(env)\n const resolveRunSettings = createRunSettingsResolver({ env, buildProvider })\n\n /**\n * Mirrors the TUI's `runCommand`: display-only blocks buffer and flush\n * as ONE `role: 'command'` turn per ordering boundary (before each\n * sub-run / spawn / context note, and at the end), each block ALSO\n * streams live via `commandBlockToEvent`, and sub-runs are tagged with\n * `origin: { kind: 'command' }` so reloads render identically.\n */\n async function runSlashCommand(opts: SendOptions, assertOpen?: () => void): Promise<{ ran: false } | { ran: true, runId: string, completion: Promise<void> }> {\n const prompt = opts.prompt.trim()\n\n if (!prompt.startsWith('/'))\n return { ran: false }\n\n const run = await ensureAgent(opts.sessionId)\n const runtimeConfig = await env.runtimeConfig(run.discoveryCwd)\n const commands: readonly Command[] = mergedCommands(runtimeConfig.extensions.commands, run.discoveryCwd, runtimeConfig.prefix, runtimeConfig.extensions.skills.map(skill => skill.name))\n const invocation = parseCommandInvocation(prompt, commands)\n\n if (!invocation)\n return { ran: false }\n\n const command = commands.find(c => c.name === invocation.name)\n\n if (!command)\n return { ran: false }\n\n // The awaits above can outlive the dispatch generation (dispose/drain):\n // bail before any side effect, so no detached body starts on it.\n assertOpen?.()\n\n if (run.agent.isRunning)\n throw new Error(`/${invocation.name}: a run is in progress. Wait for it to finish.`)\n\n const session = run.agent.session\n\n if (!session)\n throw new Error(`/${invocation.name}: session is not available`)\n\n const sessionId = opts.sessionId\n const controller = new AbortController()\n // Parent run for this command's spawn children (see `createCommandRunRecord`).\n const commandRun = createCommandRunRecord(session, invocation)\n let commandError: string | undefined\n run.commandAbort = controller\n\n /*\n * Mark the session busy for every window NOW, not at the first\n * `ctx.runAgent`. A command can stream for minutes through `emit` and\n * `spawnAgents` (e.g. /review's reviewer fan-out) without ever starting\n * a parent run; without this signal the windows' run gate stays idle,\n * so any `sessions:changed` in that span re-syncs the transcript from\n * the store mid-stream and the live blocks vanish. The dispatch layer\n * in `sendPrompt` pairs this with the final `run:end` at release and\n * folds the sub-run pairs in between.\n */\n const dispatchRunId = randomUUID()\n broadcast({ kind: 'run:start', sessionId, runId: dispatchRunId })\n\n /*\n * One cross-process marker for the WHOLE command, not per sub-run: a\n * spawn fan-out or an `askUser` wait runs no parent loop, so without it\n * the session reads idle on disk and another process (the GUI's\n * in-process fallback, a non-daemon TUI) could start a concurrent run.\n * Each sub-run's loop settles the marker at its end; `beat()` after\n * each one re-asserts it. No-op when `useDaemon` is off.\n */\n const heartbeat = startRunHeartbeat({ env, sessionId, isRunning: () => true, immediate: true })\n\n const requestCommandInteraction = createCommandInteractionBridge({ interactions, sessionId, controller })\n\n const emitEvent = (event: StreamEvent): void => {\n broadcast({ kind: 'event', sessionId, event })\n }\n\n const output = createCommandOutput({ session, emitEvent })\n const { flushCommandTurn, emitBlock, emitCommandError } = output\n const invocationText = `/${invocation.name}${invocation.args ? ` ${invocation.args}` : ''}`\n\n const ctx: CommandStepContext = {\n args: invocation.args,\n argv: invocation.argv,\n ...(invocation.invokedAs ? { invokedAs: invocation.invokedAs } : {}),\n ...(opts.attachments && opts.attachments.length > 0\n ? {\n attachments: opts.attachments.map(a => ({\n name: a.name ?? 'attachment',\n mediaType: a.mediaType,\n data: a.data,\n })),\n }\n : {}),\n data: {},\n emit: emitBlock,\n runAgent: createCommandRunAgent({ run, session, sessionId, controller, heartbeat, broadcast, emitEvent, flushCommandTurn, resolveRunSettings }),\n // Single implementation behind the overloaded contract (zod-inferred\n // vs. explicit-generic) — the cast is the standard TS pattern for\n // implementing an overload set with one function.\n generateData: (async (dataOpts: CommandGenerateDataOptions) => {\n if (controller.signal.aborted)\n throw new Error('generateData: command aborted')\n\n // Side-channel one-shot: fresh provider instance, schema-pinned,\n // no session writes, no transcript events.\n const provider = buildProvider(runtimeConfig.providers, run.providerKey)\n\n return generateStructuredData({\n provider,\n model: dataOpts.model ?? run.modelOverride ?? run.model,\n prompt: dataOpts.prompt,\n schema: dataOpts.schema,\n ...(dataOpts.system ? { system: dataOpts.system } : {}),\n ...(dataOpts.includeConversation ? { turns: session.turns } : {}),\n signal: controller.signal,\n })\n }) as CommandStepContext['generateData'],\n logger: createLogger({ emit() {} }, { command: invocation.name }),\n signal: controller.signal,\n cwd: run.cwd,\n // Read-only live view — getters, so turns/runs appended mid-workflow\n // are visible on re-read. Projection only: no mutators cross into\n // extension code.\n session: {\n get id() {\n return session.id\n },\n get turns() {\n return session.turns\n },\n get runs() {\n return session.runs\n },\n get metadata() {\n return session.metadata\n },\n },\n interaction: createCommandInteraction(requestCommandInteraction),\n // Isolated child agents — the spawn tool driven host-side via the\n // build-time seam (`run.commandSeam`), so command children get the\n // exact model routing, persistence, and concurrency accounting of\n // model-initiated spawns.\n spawnAgents: createSpawnAgents({ run, session, invocation, controller, commandRun, heartbeat, flushCommandTurn }),\n // Model-visible context note — a plain user turn appended straight to\n // the session (no run). The next `agent.run` rebuilds conversation\n // from `session.turns`, so the note reaches the wire on the next\n // prompt. The transcript shows it as the command's receipt line; the\n // turn always carries a `display` so a reload can tell it from a\n // typed prompt.\n appendContext: async (text, noteOpts) => {\n if (controller.signal.aborted)\n throw new Error('appendContext: command aborted')\n\n const trimmed = text.trim()\n\n if (!trimmed)\n return\n\n await flushCommandTurn()\n // A model-only note (`display: false`) persists as `''`: no receipt, live or on reload.\n const display = noteDisplay(noteOpts?.display, trimmed)\n const turnId = await session.generateTurnId()\n if (display)\n emitEvent({ kind: 'command-note', text: commandNoteText(display, trimmed, invocationText), turnId })\n await session.appendTurns([\n {\n id: turnId,\n role: 'user',\n content: [{ type: 'text', text: trimmed }],\n createdAt: Date.now(),\n display,\n },\n ])\n },\n }\n\n /*\n * `ctx.workspace` / `ctx.runtime` / `ctx.sessions` for THIS session,\n * scoped onto the host-runtime bridge for the command's duration. The\n * TUI attaches an impl for its one active session at mount; a\n * multi-session host has to say which session a command belongs to —\n * without this every extension command over the daemon or in the GUI\n * saw \"ctx.workspace is detached\".\n */\n /*\n * `ext.session.get/set/delete` resolve their target through the same\n * AsyncLocalStorage binding `agent.run` establishes. A command body runs\n * OUTSIDE any agent run (its sub-runs bind their own child sessions),\n * so without this wrapper every `ext.session.set` in a command is a\n * silent no-op — `/review` lost its resumable state and `/review\n * continue` reported \"no unfinished review\" after every interruption.\n */\n const execute = (): Promise<CommandExecution> => withExtensionSession(session, () => executeCommand(command, ctx))\n const executeScoped = env.hostRuntime\n ? () => env.hostRuntime!.runWith(sessionHostRuntime(run, env, { appendNote: blocks => blocks.forEach(emitBlock) }), execute)\n : execute\n\n // Delimit from the prior exchange (matches the reload rendering in\n // eventsFromTurns), then show the invocation as the user's prompt.\n // Emitted during accept so it precedes anything the body streams.\n try {\n if (session.turns.length > 0)\n emitEvent({ kind: 'separator', text: '' })\n\n // Persisted as the header block of a display-only `command` turn: a\n // `user`-role turn would leak `/cmd` into model context.\n output.state.pendingTurnId = randomUUID()\n output.state.pending.push({ text: commandHeaderBlock(invocationText) })\n emitEvent({ kind: 'user-prompt', text: invocationText, synthetic: true, turnId: output.state.pendingTurnId })\n }\n catch (err) {\n // No detached completion exists yet to release these — do it here or\n // the heartbeat keeps the session marked busy forever.\n if (run.commandAbort === controller)\n delete run.commandAbort\n\n await heartbeat.end('idle')\n throw err\n }\n\n /*\n * The body runs detached from the dispatch RPC (see `runSlashCommand`\n * on `CommandModule`); the caller tracks `completion` as the dispatch\n * settlement. Never rejects: errors become persisted notices.\n */\n const completion = (async (): Promise<void> => {\n try {\n const result = await executeScoped()\n\n if (result.error) {\n commandError = errorMessage(result.error)\n await emitCommandError(`/${invocation.name}: ${commandError}`)\n }\n }\n catch (err) {\n // executeCommand isolates step errors, so this only fires on an\n // unexpected host failure — surface it as a transcript notice.\n commandError = errorMessage(err)\n await emitCommandError(`/${invocation.name}: ${errorMessage(err)}`).catch(() => undefined)\n }\n finally {\n if (run.commandAbort === controller)\n delete run.commandAbort\n\n await flushCommandTurn().catch(() => undefined)\n await commandRun.finish({ aborted: controller.signal.aborted, ...(commandError !== undefined ? { error: commandError } : {}) })\n await session.save().catch(() => undefined)\n run.lastUsedAt = Date.now()\n // Settle the command-wide marker (chained behind any in-flight\n // beat), then stamp the run end, which arms the engine's own-marker\n // exemption so a straggler marker this host wrote can't block its\n // own next send for the 5-minute freshness window.\n // Same mapping the agent loop uses: abort settles to 'idle'.\n await heartbeat.end(controller.signal.aborted ? 'idle' : commandError !== undefined ? 'error' : 'completed')\n run.lastRunEndedAt = Date.now()\n }\n })()\n\n // Same id as the dispatch `run:start` so the final `run:end` pairs with\n // it when the command ran no sub-run.\n return { ran: true, runId: dispatchRunId, completion }\n }\n\n return { listCommands, completeCommandArgs, runSlashCommand }\n}\n","/**\n * Host-domain wire shapes — the JSON-serializable types the chat host\n * (`createChatHost`) emits and consumes, independent of any transport.\n *\n * These used to live in `src/ipc/protocol.ts`; they moved here so the host\n * (`src/chat/host/**`) has zero dependency on `src/ipc/**`. The IPC layer\n * re-exports them from `src/ipc/protocol.ts` alongside its transport-only\n * contract (method map, handshake, protocol version), so `zidane/ipc`\n * consumers are unaffected.\n *\n * Everything in this file is JSON-serializable: it must survive Electron's\n * structured clone AND a JSON-RPC socket hop unchanged. Canonical agent\n * types (`StreamEvent`, `InteractionRequest`, …) are re-used where they are\n * already wire-safe; host-only shapes (live `resolve` callbacks, `Map`s)\n * never appear here.\n */\nimport type { CacheBreakInfo } from '../../cache-telemetry'\nimport type { SessionArtifact } from '../../session/artifacts'\nimport type { JsonValue, TurnUsage } from '../../types'\nimport type { BrowserRequest } from '../browser/protocol'\nimport type { HunkResolution } from '../edit-diff'\nimport type { InteractionRequest } from '../interactions'\nimport type { MachineLinksStatus, MachineStatusChange } from '../machine-protocol'\nimport type { ApprovalDecision, ApprovalRequest } from '../safe-mode-context'\nimport type { SystemMdFile } from '../system-md'\nimport type { TerminalInfo } from '../terminal/protocol'\nimport type { ActiveTodosState, TodoItem, TodoTally } from '../todos'\nimport type { PromptTurnRef } from '../turn-selection'\nimport type { EditPayload, Settings, StreamEvent } from '../types'\nimport type { ProviderDiagnostic } from './provider-diagnostic'\n\n/** Caller attribution for approvals raised by subagents. */\nexport type ApprovalOriginator = { kind: 'parent' } | { kind: 'child', label: string }\n\n/**\n * Serializable mirror of canonical `ActiveTodosState` — plain arrays so the\n * payload survives structured clone / JSON without `readonly` friction.\n */\nexport interface TodosSnapshot {\n runId: string | null\n todos: TodoItem[]\n archive: TodoItem[]\n inProgress: TodoItem | null\n tally: TodoTally\n}\n\n/**\n * Project canonical `ActiveTodosState` onto its wire mirror.\n *\n * One implementation because the copy is load-bearing, not cosmetic: the arrays\n * must be detached from the live session's before they cross a process boundary\n * (or reach another window in-process), and a site that forgot to copy would\n * hand out a reference that mutates under its reader. Previously open-coded at\n * each of the broadcast and RPC sites.\n */\nexport function toTodosSnapshot(state: ActiveTodosState): TodosSnapshot {\n return {\n runId: state.runId,\n todos: [...state.todos],\n archive: [...state.archive],\n inProgress: state.inProgress,\n tally: state.tally,\n }\n}\n\n/** Parent-level cancellable tool call or background task. */\nexport interface RunningWorkItem {\n kind: 'tool' | 'task'\n id: string\n label: string\n startedAt: number\n childId?: string\n}\n\n/**\n * Serializable mirror of `PreviewResult` — `readonly` arrays widened so the\n * payload round-trips without TypeScript friction on the client side.\n */\nexport interface SerializedPreview {\n diffText: string\n perHunkDiff: readonly string[]\n resolution: readonly HunkResolution[]\n resolvedPayload: EditPayload\n}\n\n/**\n * Wire-safe approval request. Canonical `ApprovalRequest` minus its live\n * `resolve` callback (kept host-side, keyed by `id`), plus the context a\n * remote approval surface needs: owning session, safelist cwd, precomputed\n * safelist suggestions, and the edit preview byproducts.\n */\nexport interface WireApprovalRequest extends Omit<ApprovalRequest, 'resolve'> {\n sessionId: string\n cwd: string\n suggestedSafelistEntries: string[]\n edit?: EditPayload\n priorContent?: string | null\n preview?: SerializedPreview\n}\n\n/** Attachment carried alongside the prompt text (base64, no data-URL prefix). */\nexport interface PromptAttachment {\n mediaType: string\n data: string\n name?: string\n}\n\n/** `chat.send` options. */\nexport interface SendOptions {\n sessionId: string\n prompt: string\n /** Skill names picked via `/` completion — activated before the run. */\n activatedSkills?: string[]\n attachments?: PromptAttachment[]\n /**\n * Host-internal wake run: delivers pending background-task notifications\n * to the model with an empty prompt. Skips the `user-prompt` broadcast\n * (there is no user message) — mirrors the local TUI's wake semantics.\n */\n wake?: boolean\n /**\n * The client resolved this text as the `/` command of this name in ITS\n * registry. The host re-resolves against the SESSION's registry (its cwd,\n * its extensions) and refuses when that misses, instead of sending\n * `/fix comments` to the model as prose — the two registries can disagree\n * (extension installed after the runtime cache was built, different cwd),\n * and a silent prose send is indistinguishable from a broken command.\n */\n asCommand?: string\n /**\n * Sent from outside the composer (Continue, Retry, a palette prompt): the\n * shared draft was not consumed, so the daemon leaves it alone instead of\n * clearing it in every other window.\n */\n keepDraft?: boolean\n}\n\n/**\n * Wire-safe summary of an extension-contributed `/` command — the\n * projection of canonical `Command` (src/chat/commands.ts) minus its\n * function-valued fields (steps, completeArgs).\n */\nexport interface CommandSummary {\n name: string\n description: string\n aliases?: string[]\n\n /** Grouping label — defaults to the contributing extension's name. */\n group?: string\n\n /**\n * `true` when the canonical command declares `completeArgs` — lets a\n * client wire an arg-completion shim only for commands that actually\n * complete, instead of firing blind RPCs on every `/name <prefix>`.\n */\n hasArgCompletion?: boolean\n}\n\n/** Wire-safe projection of canonical `CommandArgSuggestion`. */\nexport interface CommandArgSuggestionSummary {\n /** Text inserted after `/<name> ` on accept. */\n value: string\n\n /** Display label. Defaults to `value`. */\n label?: string\n description?: string\n}\n\n/** Host settings — canonical `Settings` plus the extension allowlist. */\nexport type HostSettings = Settings & {\n enabledExtensions?: readonly string[]\n}\n\n/** One entry in the shared type-ahead queue. */\nexport interface QueuedItem {\n id: string\n text: string\n /**\n * What rides with the text, WITHOUT the bytes — enough for a queue row to\n * show \"+2 attachments\" chips the way the echoed prompt will. The payload\n * itself stays host-side until the entry is sent.\n */\n attachments?: QueuedAttachment[]\n}\n\nexport interface QueuedAttachment {\n mediaType: string\n name?: string\n}\n\n/**\n * Live per-session presence — which sessions have attached windows and\n * what state they're in. Drives the session list's \"active\" scope and\n * per-row status icons. A session appears here when it has ≥1 attached\n * window, a run in flight, or pending HITL state.\n */\nexport interface SessionPresence {\n sessionId: string\n /** Number of windows currently attached (watching) this session. */\n windows: number\n /** A run is executing right now. */\n running: boolean\n /** Pending approval or interaction — awaiting user input somewhere. */\n attention: boolean\n}\n\n/** Pending interaction row as returned by `interactions.list`. */\nexport interface PendingInteraction {\n sessionId: string\n request: InteractionRequest\n live: boolean\n}\n\n/**\n * The single push channel. Chat stream signals mirror the agent loop hooks;\n * interaction/approval signals carry the HITL queues so every window renders\n * the same pending state; `sessions:changed` keeps session lists in sync\n * across windows.\n */\n/** Payload of the `stream:progress` signal — see the variant's doc. */\nexport interface StreamProgressInfo {\n turnId: string\n outputTokens: number\n estimated: boolean\n elapsedMs: number\n estCostUsd?: number\n}\n\nexport type HostSignal\n = | { kind: 'run:start', sessionId: string, runId: string }\n | { kind: 'run:end', sessionId: string, runId: string, ok: boolean, error?: string }\n /**\n * A turn finished. `usage` carries the loop-reported token/cost figures\n * that drive footer gauges (context size = prompt-side tokens of the\n * LAST parent turn; cost accrues across parent + child turns).\n */\n | { kind: 'turn:end', sessionId: string, turnId: string, childId?: string, depth?: number, usage?: TurnUsage }\n /**\n * `echo: true` marks host-generated SEND/STEER echoes of the user's own\n * message. Clients that already render the prompt locally (the GUI's\n * enriched append) drop echo-tagged signals; command-module\n * user-prompts are never echoes and always render.\n */\n | { kind: 'event', sessionId: string, event: StreamEvent, echo?: boolean }\n | { kind: 'compacting:start', sessionId: string }\n /**\n * Live token estimate for an in-flight compaction summary. Throttled by the\n * loop, so this is a low-rate progress tick rather than a stream.\n *\n * Without it a daemon-mode window shows a static \"Compacting…\" with no\n * indication of progress — a compaction of a large transcript can run for\n * minutes, which is indistinguishable from a hang.\n */\n | { kind: 'compacting:progress', sessionId: string, estOutputTokens: number }\n /**\n * Live counters for the parent turn currently streaming — the loop's\n * `stream:progress` (throttled ~4/s, one final tick before `stream:end`).\n * `outputTokens` is provider-counted unless `estimated`; `estCostUsd` is\n * the running catalog-rate estimate for THIS turn (absent for unpriced\n * models and flat-rate subscription traffic). Clients add it to the settled\n * session figure while streaming and drop it when the matching `turn:end`\n * brings the real `usage.cost`.\n */\n | ({ kind: 'stream:progress', sessionId: string } & StreamProgressInfo)\n /**\n * Prompt turns that just persisted, reduced to the fields needed to bind a\n * live `user-prompt` event to its turn id (see {@link PromptTurnRef}).\n *\n * Deliberately NOT the full `SessionTurn`: those carry every content block,\n * including base64 image/document payloads, which would be megabytes per\n * prompt to ship for the sake of an id. Without this a prompt sent from a\n * daemon-attached window is unselectable — no hover, edit, or delete — until\n * the run-end transcript replace.\n */\n | { kind: 'prompt-turns', sessionId: string, refs: readonly PromptTurnRef[] }\n /**\n * `effectiveTokens` (success only) is the loop's post-compact context\n * estimate — windows drop their footer ctx gauge to it immediately\n * instead of waiting for the next turn's usage.\n */\n | { kind: 'compacting:end', sessionId: string, ok: boolean, effectiveTokens?: number }\n | {\n kind: 'model:fallback'\n sessionId: string\n from: { provider: string, model: string }\n to: { provider: string, model: string }\n }\n | { kind: 'work:snapshot', sessionId: string, items: RunningWorkItem[] }\n | { kind: 'todos:snapshot', sessionId: string, snapshot: TodosSnapshot }\n /**\n * The session recorded an artifact (PR, branch, commit, file, extension\n * kind — see `session/artifacts.ts`). Carries the stored row so a window\n * can badge / list without a round-trip; `sessions.artifacts` is the\n * authoritative query. Additive — older clients ignore unknown kinds.\n */\n | { kind: 'artifact:recorded', sessionId: string, artifact: SessionArtifact }\n /**\n * An artifact was removed or refreshed through the host (`artifacts.delete`\n * / `artifacts.upsert`) — windows re-query. Carries the row for `upsert`.\n */\n | { kind: 'artifact:changed', sessionId: string, op: 'delete' | 'upsert', artifactId: string, artifact?: SessionArtifact }\n | { kind: 'interaction:request', sessionId: string, request: InteractionRequest, live: boolean }\n | { kind: 'interaction:resolved', sessionId: string, requestId: string }\n /**\n * Dev browser (`browser.ts` hub): a tool call for the page, addressed to\n * the registered browser host (`hostId`); other clients ignore it. The\n * host answers through `browser.respond`. `browser:cancel` withdraws it.\n */\n | { kind: 'browser:request', sessionId: string, hostId: string, request: BrowserRequest }\n | { kind: 'browser:cancel', sessionId: string, hostId: string, requestId: string }\n /**\n * Terminals (`terminal.ts` manager). `changed` carries the session's full\n * list; `output` is a batch starting at `offset` (clients drop what they\n * already have and `terminal.ack` what they wrote); `reset` replaces a\n * view's content with history after a client fell too far behind.\n */\n | { kind: 'terminal:changed', sessionId: string, terminals: TerminalInfo[] }\n | { kind: 'terminal:output', sessionId: string, terminalId: string, offset: number, data: string }\n | { kind: 'terminal:reset', sessionId: string, terminalId: string, offset: number, data: string }\n /**\n * A streamed workspace command (`sessions.workspaceExecStream`): its output\n * in arrival order, then exactly one `exit`. Sent to the connection that\n * started it only, never fanned out or replayed. `code` is `null` and\n * `signal` set when the host killed it (`cancelled`: the client asked;\n * `truncated`: the output cap was reached).\n */\n | { kind: 'workspace:exec:data', execId: string, stream: 'stdout' | 'stderr', chunk: string }\n | { kind: 'workspace:exec:exit', execId: string, code: number | null, signal: string | null, truncated?: true, cancelled?: true }\n /**\n * A client installed, updated or removed something on the host\n * (`catalog.install` / `remove` / `update`, `mcp.upsert` / `remove`): every\n * window re-reads that catalog.\n */\n | { kind: 'catalog:changed', catalog: 'skills' | 'mcps' | 'extensions' | 'plugins' }\n /** A server's settings-sync record changed (a claim, a push, an override, a reset): settings UIs re-read `sync.status`. */\n | { kind: 'sync:changed' }\n | { kind: 'approval:request', request: WireApprovalRequest }\n /**\n * An approval left the pending queue (answered or denied in bulk) — every\n * OTHER window clears its surface. The window that resolved it already\n * knows; the signal makes the queue converge everywhere else.\n */\n | { kind: 'approval:resolved', sessionId: string, requestId: string, decision: ApprovalDecision }\n | { kind: 'sessions:changed', op: 'create' | 'update' | 'delete', sessionId: string }\n /**\n * Settings were written through the host (`settings.set`) — every window\n * applies the new state so settings UIs converge without a restart.\n * Windows that persist settings themselves must treat this as\n * authoritative for the delivered snapshot.\n */\n | { kind: 'settings:changed', settings: HostSettings }\n /**\n * Another window edited the session's shared prompt draft. The daemon\n * EXCLUDES the originating peer from this fan-out, so applying it can\n * never fight the local cursor — clients apply unconditionally\n * (last-writer-wins whole-text replacement). Empty `text` clears the\n * draft (broadcast when any window submits the prompt).\n */\n | { kind: 'draft:changed', sessionId: string, text: string, shell?: boolean }\n /**\n * The shared draft's composing ATTACHMENTS changed (paste/drop/remove in\n * any window). Payloads ride along so a remote window can submit the\n * shared draft attachments-and-all. Same origin-exclusion as text.\n */\n | { kind: 'draft:attachments', sessionId: string, attachments: PromptAttachment[] }\n /**\n * The session's shared transcript-search state changed (mode entered /\n * exited, query edited) in another window. Same origin-exclusion and\n * last-writer-wins contract as the draft — every window on the session\n * shows the same filtered transcript.\n */\n | { kind: 'search:changed', sessionId: string, active: boolean, query: string }\n /**\n * The daemon resolved another window's inline-autocomplete query\n * (`suggest.resolve`). Excludes the requesting peer (it already has\n * the result from its RPC reply). Receivers mirror the ghost ONLY\n * when their live buffer still equals `basis` — the standard\n * staleness guard; otherwise discard.\n */\n | { kind: 'suggest:changed', sessionId: string, seq: number, basis: string, caret: number, suggestion: string | null, candidates?: string[] }\n /**\n * The daemon-side agent's active-skill set changed (`skills_use` /\n * run-end deactivation). Windows mirror it into their skill chips.\n */\n | { kind: 'skills:snapshot', sessionId: string, active: string[] }\n /**\n * A daemon-side MCP server needs (re-)authentication. Windows surface\n * the badge; the interactive login flow itself runs in whichever window\n * the user triggers it from (tokens land in the shared credential\n * store; the daemon reconnects on the next agent rebuild).\n */\n | { kind: 'mcp:auth', sessionId: string, name: string, reason: string }\n /**\n * The session agent's MCP bootstrap finished: every server has its\n * outcome (`mcp:status` / `mcp:auth` came first). A window's deadline for\n * the one-shot auto-login it arms when the user adds a server.\n */\n | { kind: 'mcp:settled', sessionId: string }\n /**\n * A host-side MCP server connected, or failed to. Windows feed it to the\n * same status reducer the in-process path uses (badges: connected, signed\n * in, needs sign-in, key refused, couldn't connect). `error` is the\n * failure's message and `code` its HTTP-ish code when it had one, enough\n * for the shared classifier (`classifyMcpTest`) to read it the same way.\n */\n | { kind: 'mcp:status', sessionId: string, name: string, status: 'connected' }\n | { kind: 'mcp:status', sessionId: string, name: string, status: 'failed', transport: string, error: string, code?: number }\n /**\n * Provider retry in progress (rate-limit / overload / silent stall) —\n * drives the footer's \"retrying n/m\" indicator. `source` is `'parent'`\n * or the retrying child's id; the indicator clears when that source\n * streams again or the run ends.\n */\n | { kind: 'stream:retry', sessionId: string, attempt: number, max: number, source: string }\n /**\n * A retried stream reached a terminal state for `source` (`'parent'` or a\n * child id) — clear that source's retry indicator.\n *\n * Distinct kind rather than a nullable `attempt` so the two states stay\n * unambiguous on the wire. Consumers also clear at run end as a backstop;\n * this exists for the mid-run case, where a subagent's stream fails while\n * the parent run continues and the indicator would otherwise stick.\n */\n | { kind: 'stream:retry:cleared', sessionId: string, source: string }\n /**\n * Which `SYSTEM.md` override (if any) the host folded into this session's\n * system prompt, emitted at agent-build time.\n *\n * The prompt is composed where the agent is built — in the daemon, not in\n * the window — so a window cannot derive this by probing its own disk: it\n * may have a different cwd, and `userInstructionsScope` is the daemon's.\n * Windows need it to tell \"no override on disk\" apart from \"override in\n * force\", which is the difference between doctrine the user wrote and\n * doctrine they think they replaced. `shadowed` carries precedence losers\n * so the Instructions surface can mark them inactive.\n */\n | { kind: 'system-md', sessionId: string, file: SystemMdFile | null, shadowed: readonly SystemMdFile[] }\n /**\n * A cache-prefix break was detected for this session's last request — the\n * footer chip names the culprit dimension and the re-billed prefix size.\n * Detection is per-agent closure state inside the loop, so in daemon mode\n * only the daemon can observe it. Cost pricing stays window-side (it needs\n * only the provider key and the token count).\n */\n | { kind: 'cache:break', sessionId: string, info: CacheBreakInfo }\n | { kind: 'provider:diagnostic', sessionId: string, diagnostic: ProviderDiagnostic }\n\n /**\n * Presence snapshot — recomputed and fanned out whenever a window\n * attaches/detaches or any tracked session's run/HITL state changes.\n * Full snapshot (the set is small: only live sessions appear).\n */\n | { kind: 'presence:changed', sessions: SessionPresence[] }\n /** A machine of this host came online or went offline (`docs/MACHINES.md`). */\n | ({ kind: 'machine:status' } & MachineStatusChange)\n /** This local host's machine links changed (`machines.links.status`): shares of this computer, servers used as machines. */\n | { kind: 'machine:links', links: MachineLinksStatus }\n /**\n * A server lending itself as a machine to the local host on this\n * connection (`machine.attach`): one of its machine notifications\n * (`terminal.data`, `task.exit`, `exec.stream.*`). Sent to that\n * connection only, never broadcast.\n */\n | { kind: 'machine:notification', method: string, params: JsonValue }\n /**\n * Daemon-side extension HUD snapshot (status lines + banners). Extension\n * hooks run in the daemon in daemon mode, so their `ctx.tui.setStatus` /\n * `setBanner` writes happen there — windows overlay this state under\n * their local HUD (local entries win per extension name).\n */\n | { kind: 'hud:state', statuses: Record<string, { text: string, loader: boolean }>, banners: Record<string, string[]> }\n /** Daemon-side extension `ctx.tui.notify` — a one-shot transcript line. */\n | { kind: 'hud:notify', extension: string, text: string, tone: 'info' | 'warn' | 'error' }\n /**\n * The session's type-ahead queue changed (message queued while a run is\n * in flight, drained by the host on run end, pushed early, or dropped).\n * Broadcast to EVERY peer including the origin — the queue box is shared\n * state and all windows render the same list.\n */\n | { kind: 'queue:changed', sessionId: string, items: QueuedItem[] }\n /**\n * Extension bus message (`ctx.bus.emit`, `'ipc'` permission). PRIVATE\n * per `extensionId`: receivers re-inject into the SAME extension's local\n * subscribers only and drop ids they haven't registered. `extensionId`\n * is stamped by the emitting host from the registration identity —\n * never caller-supplied. `payload` is capped at 64 KiB serialized\n * (enforced at emit and again at the daemon boundary); `(nonce, seq)`\n * feeds the receivers' per-extension dedupe window (self-echo through a\n * second connection of the same process, duplicate deliveries). `nonce`\n * is the emitter's per-process random id (additive — absent from older\n * peers, which dedupe on seq alone).\n */\n | { kind: 'extension:signal', extensionId: string, sessionId?: string, payload: JsonValue, seq: number, nonce?: string }\n","/**\n * Session todos as the host serves them: the `todos:snapshot` broadcast and\n * the host methods that read and (user-)edit the live agent's todo bag.\n */\nimport type { Agent } from '../../../index'\nimport type { ChatHost } from '../host-api'\nimport type { HostSignal } from '../signals'\nimport type { ActiveRun } from '../types'\nimport { sanitizeTodoItems, selectActiveTodos, setTodosForRun } from '../../todos'\nimport { toTodosSnapshot } from '../signals'\n\nexport function broadcastTodosSnapshot(broadcast: (signal: HostSignal) => void, entry: { sessionId: string, agent: Agent }): void {\n const session = entry.agent.session\n if (!session)\n return\n broadcast({\n kind: 'todos:snapshot',\n sessionId: entry.sessionId,\n snapshot: toTodosSnapshot(selectActiveTodos(session)),\n })\n}\n\nexport function createTodoMethods({ active, broadcast }: {\n active: Map<string, ActiveRun>\n broadcast: (signal: HostSignal) => void\n}): Pick<ChatHost, 'getTodosSnapshot' | 'setTodos'> {\n return {\n /**\n * Initial fetch for todos indicators. `null` when no agent is live —\n * the slot may exist on disk but `pickActiveRunId` needs the in-memory\n * `Session.runs` list to choose it; the `run:start` snapshot broadcast\n * catches clients up after the first send.\n */\n getTodosSnapshot(sessionId) {\n const entry = active.get(sessionId)\n if (!entry)\n return null\n entry.lastUsedAt = Date.now()\n const session = entry.agent.session\n return session ? selectActiveTodos(session) : null\n },\n\n /**\n * Apply a user todo edit to the session that the model actually reads.\n *\n * The invariant this restores: **whichever process owns the agent owns the\n * todo bag.** Todos live in `session.metadata`, and `todowrite` reads them\n * off `entry.agent.session` — so a window that called `setTodosForRun` on\n * its OWN `Session` instance wrote behind the daemon's back. The edit\n * persisted, rendered, and looked applied, then the model's next\n * `todowrite` read its stale in-memory bag and overwrote it. The user's\n * edit vanished and the model never learned it happened.\n *\n * Same live-vs-idle split as {@link patchLiveSessionMeta}, for the same\n * reason: routing through the live `Session` keeps `save()` re-persisting\n * the CURRENT turns instead of a stale snapshot.\n *\n * Returns the resulting snapshot when handled here, or `null` when no\n * agent is live and the caller should apply its own store-level write\n * (race-free, since nothing is appending turns).\n *\n * The run id is resolved HERE rather than accepted from the caller:\n * `pickActiveRunId` needs the in-memory `Session.runs` list, and a\n * window-supplied id could already be stale by the time it arrives.\n */\n async setTodos(sessionId, items) {\n const entry = active.get(sessionId)\n const session = entry?.agent.session\n if (!session)\n return null\n entry!.lastUsedAt = Date.now()\n const runId = selectActiveTodos(session).runId\n if (!runId)\n return null\n /*\n * Validate before writing. This is the LEAST trusted todo boundary —\n * anything that can reach the socket can call it — and it was the only\n * one left unguarded: `setTodosForRun`'s `normalizeItem` picks id /\n * content / status without checking them, so an invalid `status` was\n * written and then silently dropped by the read validation, making the\n * edit vanish with nothing reported. Same validator and same cap as the\n * model's `todowrite`, so a user edit cannot do what the tool cannot.\n */\n const sanitized = sanitizeTodoItems(items)\n /*\n * A caller that sent rows and had ALL of them rejected is sending\n * malformed data — writing the empty result would delete the user's list\n * on their behalf. No-op, returning current state so the caller sees its\n * edit didn't apply (distinct from `null`, which means \"no live agent,\n * fall back to a store write\"). An intentional clear sends `[]` and still\n * works, because nothing was rejected.\n */\n if (items.length > 0 && sanitized.length === 0)\n return selectActiveTodos(session)\n // `clearArchive` because every write arriving here is user-initiated —\n // matching the modal's local path, where keeping the archive makes a\n // confirmed deletion re-render as a no-op.\n setTodosForRun(session, runId, sanitized, { clearArchive: true })\n await session.save()\n // Fans out to every attached window, including the one that sent this.\n broadcastTodosSnapshot(broadcast, entry!)\n return selectActiveTodos(session)\n },\n }\n}\n","import type { ChatHostEnvironment } from '../environment'\nimport type { ActiveRun } from '../types'\n\n/**\n * How long a persisted `status: 'running'` marker from another process is\n * trusted as live. Turn persistence keeps `updatedAt` moving during real\n * runs; a marker older than this is treated as the residue of a crashed\n * process and does not block new runs.\n */\nexport const STALE_RUN_MARKER_MS = 5 * 60 * 1000\n\n/**\n * CROSS-PROCESS run guard probe: the loop persists session-level `status`\n * through the shared store ('running' at run start, settled at run\n * end), so a session being driven by ANOTHER process (an in-process\n * TUI window on the same sessions.db) is visible here. Freshness\n * bound guards against a crashed process leaving 'running' behind\n * forever — a live run keeps `updatedAt` moving via turn persistence.\n *\n * GATED on the shared `useDaemon` setting (read fresh per call): with\n * IPC disabled there is exactly one writer per surface — the pre-IPC\n * assumption — so the guard's only purpose (daemon/multi-process\n * coexistence) doesn't apply, and ungated it would lock the user out of\n * a session for up to `STALE_RUN_MARKER_MS` after a crash mid-run.\n */\nexport async function foreignRunActive(\n env: ChatHostEnvironment,\n sessionId: string,\n run: ActiveRun,\n internal?: { ownMarkerExempt?: boolean },\n): Promise<boolean> {\n if (!env.multiProcess && env.readSettings().useDaemon !== true)\n return false\n\n // Header-only read where the store supports it — the guard needs two\n // scalar fields; loading a long session's full turn array per send\n // would make send latency scale with history size.\n const persisted = env.store.getMeta\n ? await env.store.getMeta(sessionId)\n : await env.store.load(sessionId)\n if (persisted?.status !== 'running' || Date.now() - persisted.updatedAt >= STALE_RUN_MARKER_MS)\n return false\n\n /*\n * OWN-marker exemption: a marker whose write time is explained by\n * this host's just-finished run is OURS (settle-lagged heartbeat /\n * loop persistence), not another process's — refusing it would\n * strand queued messages and wake runs behind a misleading error.\n * A FOREIGN run started after ours beats `updatedAt` past the\n * epsilon and is still refused. Truly concurrent local runs are\n * caught by the caller's `isRunning` check.\n */\n const ownRunEnded = run.lastRunEndedAt\n const exemptionAllowed = internal?.ownMarkerExempt !== false\n const explainedByOwnRun\n = exemptionAllowed && ownRunEnded !== undefined && persisted.updatedAt <= ownRunEnded + 2000\n return !explainedByOwnRun\n}\n","import type { Agent } from '../../../index'\nimport type { HostSignal } from '../signals'\nimport { formatRunReceiptLine, hasRunReceipt, runReceiptFromRun } from '../../run-receipt'\n\n/**\n * The per-run receipt (`run-summary`) for the run that just ended, read off\n * the session's latest TOP-LEVEL run record. Emitted BEFORE `run:end` so it\n * is the last transcript row of the run, not the first of the idle state.\n * Not persisted as a turn — replay synthesizes it from the same record in\n * `eventsFromTurns`, so live and reloaded transcripts match.\n */\nexport function broadcastRunReceipt(broadcast: (signal: HostSignal) => void, entry: { sessionId: string, agent: Agent }): void {\n const session = entry.agent.session\n if (!session)\n return\n const record = [...session.runs].reverse().find(r => r.parentRunId === undefined)\n if (!record)\n return\n const receipt = runReceiptFromRun(record)\n if (!hasRunReceipt(receipt))\n return\n // Tagged with the run's last turn so a client can dock the receipt onto\n // that turn's row (the GUI merges it into the turn's action strip).\n const lastTurnId = session.turns.at(-1)?.id\n broadcast({\n kind: 'event',\n sessionId: entry.sessionId,\n event: { kind: 'run-summary', text: formatRunReceiptLine(receipt), runSummary: receipt, ...(lastTurnId ? { turnId: lastTurnId } : {}) },\n })\n}\n","/**\n * Preparing one prompt dispatch: the guards, `/` command routing, the\n * user-prompt echo, the compaction barrier, skill activation, the per-run\n * model / effort / window / caps, and the agent run itself.\n */\nimport type { PromptPart } from '../../../index'\nimport type { ThinkingLevel } from '../../../types'\nimport type { CommandOutputBlock } from '../../commands'\nimport type { ResolvedConfig } from '../../config'\nimport type { CommandModule } from '../commands'\nimport type { HostContext } from '../context'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { createProviderBuilder } from '../models'\nimport type { HostSettings, HostSignal, SendOptions } from '../signals'\nimport type { ActiveRun } from '../types'\nimport { randomUUID } from 'node:crypto'\nimport { chatReferenceTokensForPrompt } from '../../../tools/read-chat-turns'\nimport { attachmentPromptPart } from '../../attachment-part'\nimport { chatWindowBehavior } from '../../auto-compact'\nimport { buildRunModel } from '../../model-chain'\nimport { inferPromptRefs } from '../../prompt-segments'\nimport { BUILTIN_PROVIDERS, enabledModelOptions, getContextWindow, restoreModelOptions } from '../../providers'\nimport { applyThinkingBindingSetting } from '../../thinking-binding'\nimport { runCapsFromSettings } from '../commands'\nimport { isThinkingLevel, resolveCompactionSummarizer, startRunHeartbeat } from '../helpers'\nimport { sessionHostRuntime } from '../host-runtime'\nimport { broadcastTodosSnapshot } from '../todos'\nimport { foreignRunActive } from './guard'\nimport { broadcastRunReceipt } from './receipt'\n\n/**\n * Cap on how long `sendPrompt` waits for an in-flight manual compaction\n * before proceeding. Sized above `compactConversation`'s 5-minute\n * inactivity watchdog so a healthy long-running summary finishes behind\n * the barrier instead of racing the new prompt; a genuinely hung stream\n * self-terminates well before this cap.\n */\nconst COMPACTION_BARRIER_TIMEOUT_MS = 10 * 60 * 1000\n\nexport function createPromptPreparer({ ctx, ensureAgent, commands, buildProvider, applyPendingDispose, pruneIdleAgents, appendNoteTurn }: {\n ctx: HostContext\n ensureAgent: (sessionId: string) => Promise<ActiveRun>\n commands: Pick<CommandModule, 'runSlashCommand'>\n buildProvider: ReturnType<typeof createProviderBuilder>\n applyPendingDispose: (sessionId: string) => void\n pruneIdleAgents: () => void\n appendNoteTurn: (run: ActiveRun, blocks: readonly CommandOutputBlock[]) => Promise<void>\n}) {\n const { env, broadcast, suppressedWake, lifecycle, assertDispatchOpen } = ctx\n\n async function preparePrompt(\n opts: SendOptions,\n /**\n * Host-internal dispatch context. Post-settle callers (queue drain,\n * wake runs — sequenced AFTER the settled status landed on disk) set\n * `ownMarkerExempt: false`: any fresh 'running' marker they see is\n * genuinely foreign, and exempting it would open a double-run window\n * exactly when drains fire (at run end). Direct client sends keep the\n * exemption — they can arrive in the run-end → settle gap where the\n * host's own heartbeat marker is still on disk.\n */\n internal: { ownMarkerExempt?: boolean, onCommand?: () => void, onForeignRun?: () => void } | undefined,\n trackSettlement: (completion: Promise<unknown>) => void,\n ): Promise<{ runId: string }> {\n const generation = lifecycle.teardownGeneration\n const settings = env.readSettings()\n // Setting → provider, live on this run (daemon + GUI path; the in-process\n // TUI does the same on setting change). See `applyThinkingBindingSetting`.\n applyThinkingBindingSetting(settings.thinkingBinding)\n const run = await ensureAgent(opts.sessionId)\n assertDispatchOpen(generation)\n\n /*\n * Multi-window guard: two windows racing `chat.send` on one session\n * must not stack `agent.run()` calls. The loser gets an explicit,\n * actionable error — `pushQueued` is the race-free spelling (steers\n * into the live run instead).\n */\n if (run.agent.isRunning) {\n throw new Error(\n `Session \"${opts.sessionId}\" already has a run in flight. Use steer/followUp (or pushQueued) to feed the active run.`,\n )\n }\n\n // CROSS-PROCESS run guard — see `foreignRunActive` (daemon-mode only).\n if (await foreignRunActive(env, opts.sessionId, run, internal)) {\n internal?.onForeignRun?.()\n throw new Error(\n `Session \"${opts.sessionId}\" is running in another process (an in-process zidane window?). `\n + `Wait for that run to finish or interrupt it there.`,\n )\n }\n\n /*\n * Un-latch wake suppression once the dispatch passed the guards — any\n * user-initiated dispatch (plain prompt OR /command) re-engages the\n * session, so pending background-task notifications may deliver\n * again. A REFUSED send must not re-arm a wake the user just\n * interrupted away, hence after the guards.\n */\n if (!opts.wake)\n suppressedWake.delete(opts.sessionId)\n\n /*\n * `/` commands run host-side and never reach the model as a user\n * prompt. Routed AFTER the in-flight and cross-process guards — a\n * command appends command turns and can drive full agent sub-runs\n * via ctx.runAgent, so interleaving with a foreign process's run is\n * exactly what the guard exists to prevent — and BEFORE the\n * user-prompt echo (commands emit their own transcript blocks).\n * Return shape stays `{ runId }` (mirrors the GUI's `chat:send`).\n */\n assertDispatchOpen(generation)\n const commandResult = await commands.runSlashCommand(opts, () => assertDispatchOpen(generation))\n if (commandResult.ran) {\n // The command body continues after accept; its completion is this\n // dispatch's settlement, so the session stays busy (queue, wake,\n // cross-window guards) and the final `run:end` fires at release.\n trackSettlement(commandResult.completion)\n internal?.onCommand?.()\n return { runId: commandResult.runId }\n }\n assertDispatchOpen(generation)\n\n // Declared as a command by the client but unknown here (see\n // `SendOptions.asCommand`). Refusing is the whole point: the fallthrough\n // below would hand the model `/fix comments` as a user message.\n if (opts.asCommand !== undefined) {\n throw new Error(\n `unknown command: /${opts.asCommand}. No extension or markdown command in this session provides it (different working directory, or the extension or command file is not installed for it).`,\n )\n }\n\n /*\n * The user message is part of the shared transcript — broadcast it as\n * soon as the send is accepted (BEFORE the compaction barrier, which\n * can block for minutes). Clients render the prompt from this event\n * rather than appending locally, so the sender's message appears\n * immediately instead of vanishing until the barrier clears.\n */\n if (!opts.wake)\n broadcastPromptEcho(broadcast, opts)\n\n /*\n * Wait for any in-flight manual compaction before kicking off the next\n * run, so `agent.run()` sees the post-compaction turn history rather\n * than racing it. Bounded so a stalled post-compact file read can't\n * keep `sendPrompt` from ever reaching `agent.run()` — on timeout we\n * abort the compaction and proceed.\n */\n if (run.compacting)\n await awaitCompactionBarrier(run.compacting, run, broadcast, opts.sessionId)\n\n /*\n * Re-assert host-driven skill activation before each run. The agent's\n * run-end pass deactivates everything, so an edit/create-extension\n * session's docs skill must be re-activated on every send. Best-effort\n * + idempotent — a resolution hiccup must not abort the run.\n */\n /*\n * Force-activate BOTH the session's auto-activated skills and the\n * caller's pinned/referenced ones. This is gate-relevant, not just a\n * nudge: a pinned `read-only` skill's allowed-tools union only holds\n * if the activation bit is actually set before the run — the same\n * invariant the local TUI's `runSingleMessage` protects.\n */\n for (const name of new Set([...(run.autoActivateSkills ?? []), ...(opts.activatedSkills ?? [])])) {\n try {\n await run.agent.activateSkill(name)\n }\n catch {\n // skill not resolvable (disabled / unknown) — fall back to the nudge\n }\n }\n\n const runId = randomUUID()\n\n /*\n * Skills picked via `/` completion plus session-auto-activated skills:\n * nudge the model to load them via `skills_use` before responding —\n * `agent.activateSkill` flips the activation bit but doesn't make the\n * body visible to the model.\n */\n const requestedSkills = Array.from(\n new Set([...(opts.activatedSkills ?? []), ...(run.autoActivateSkills ?? [])]),\n )\n\n const systemNudge\n = requestedSkills.length > 0\n ? `The user invoked the following skill(s) via the \\`/<name>\\` syntax: ${requestedSkills\n .map(n => `\\`${n}\\``)\n .join(', ')}.\\nCall \\`skills_use({ name: ... })\\` for each one before responding, then follow the returned instructions strictly when composing your reply.`\n : undefined\n\n /*\n * Per-session reasoning effort + model override + custom model options.\n * Only forwarded when explicitly set — absent means \"let the agent /\n * provider pick its own default\".\n */\n let thinking: ThinkingLevel | undefined\n const modelOverride = run.modelOverride\n let modelOptions: Record<string, boolean> | undefined\n\n try {\n const data = await env.store.load(opts.sessionId)\n const rawEffort = data?.metadata?.effort\n\n if (typeof rawEffort === 'string' && isThinkingLevel(rawEffort))\n thinking = rawEffort\n\n const descriptor = run.providerDescriptor ?? BUILTIN_PROVIDERS.anthropic\n const modelId = modelOverride ?? run.model\n const enabled = enabledModelOptions(data?.metadata?.modelOptions)\n modelOptions = restoreModelOptions(descriptor, modelId, { [modelId]: enabled })\n }\n catch {\n // Reading metadata is best-effort; absence just means defaults.\n }\n\n /*\n * Build the canonical prompt. With attachments, `prompt` becomes a\n * `PromptPart[]`; text-only sends keep the plain-string fast path.\n */\n const promptValue: string | PromptPart[]\n = opts.attachments && opts.attachments.length > 0\n ? [\n ...(opts.prompt.length > 0 ? [{ type: 'text' as const, text: opts.prompt }] : []),\n ...opts.attachments.map(attachmentPromptPart),\n ]\n : opts.prompt\n\n /*\n * Dedicated compaction summarizer (cheap-model summaries) — resolved\n * per run against the session's runtime providers so provider\n * removal degrades silently to the main model.\n */\n const sendRuntime = await env.runtimeConfig(run.discoveryCwd)\n // Window source for this run's auto-compaction + window-relative wire\n // budgets: the session's runtime registry first — it carries\n // extension-contributed providers and host catalog overrides the builtin\n // table doesn't know — then the builtin descriptor, matching how the TUI\n // resolves it (`providerRegistryRef`). Falling back straight to the\n // builtin left every non-builtin provider without a window (autocompact\n // inert, tail compaction on the byte rule).\n const autoCompactDescriptor = sendRuntime.providers[run.providerKey] ?? BUILTIN_PROVIDERS[run.providerKey] ?? BUILTIN_PROVIDERS.anthropic\n assertDispatchOpen(generation)\n const summarizer = resolveCompactionSummarizer(\n settings.compactionModel,\n key => buildProvider(sendRuntime.providers, key),\n { providerKey: run.providerKey, model: modelOverride ?? run.model },\n )\n const windowRun = chatWindowBehavior({\n enabled: settings.autoCompact,\n threshold: settings.autoCompactThreshold,\n rawContextWindow: getContextWindow(autoCompactDescriptor, modelOverride ?? run.model),\n ...(summarizer ? { summarizer } : {}),\n })\n\n launchRun({ env, broadcast, assertDispatchOpen, applyPendingDispose, pruneIdleAgents, appendNoteTurn }, {\n opts,\n run,\n runId,\n generation,\n settings,\n promptValue,\n systemNudge,\n windowRun,\n modelOverride,\n sendRuntime,\n thinking,\n modelOptions,\n trackSettlement,\n })\n\n return { runId }\n }\n\n return preparePrompt\n}\n\n/** Echo the accepted user prompt to every window, with its file and attachment chips. */\nfunction broadcastPromptEcho(broadcast: (signal: HostSignal) => void, opts: SendOptions): void {\n const promptRefs = inferPromptRefs(opts.prompt)\n broadcast({\n kind: 'event',\n sessionId: opts.sessionId,\n // Send-path ECHO: clients that already render the prompt locally\n // (the GUI's enriched append) drop echo-tagged signals; command\n // module user-prompts are NOT echoes and always render.\n echo: true,\n event: {\n kind: 'user-prompt',\n text: opts.prompt,\n // Other windows (and the TUI) get the sender's file chips too.\n ...(promptRefs.length > 0 ? { refs: promptRefs } : {}),\n // Attachment metadata (not payloads) so every window renders the\n // same chips the sender's transcript shows. Base64 → raw bytes.\n ...(opts.attachments?.length\n ? {\n attachments: opts.attachments.map(a => ({\n name: a.name ?? 'attachment',\n mediaType: a.mediaType,\n // Exact decoded size from base64 length minus padding.\n size: (a.data.length / 4) * 3 - (a.data.endsWith('==') ? 2 : a.data.endsWith('=') ? 1 : 0),\n })),\n }\n : {}),\n },\n })\n}\n\n/** Wait (bounded) for an in-flight manual compaction; on timeout abort it and say so. */\nasync function awaitCompactionBarrier(\n compacting: Promise<unknown>,\n run: ActiveRun,\n broadcast: (signal: HostSignal) => void,\n sessionId: string,\n): Promise<void> {\n let barrierTimer: ReturnType<typeof setTimeout> | undefined\n const timedOut = await Promise.race([\n compacting.then(\n () => false,\n () => false, // errors already surfaced through the stream; proceed.\n ),\n new Promise<boolean>((resolve) => {\n barrierTimer = setTimeout(resolve, COMPACTION_BARRIER_TIMEOUT_MS, true)\n }),\n ])\n if (barrierTimer)\n clearTimeout(barrierTimer)\n if (timedOut) {\n run.compactionController?.abort()\n broadcast({\n kind: 'event',\n sessionId,\n event: {\n kind: 'error',\n text: `Compaction timed out after ${COMPACTION_BARRIER_TIMEOUT_MS}ms; continuing with your prompt.`,\n },\n })\n }\n}\n\ninterface LaunchDeps {\n env: ChatHostEnvironment\n broadcast: (signal: HostSignal) => void\n assertDispatchOpen: (generation?: number) => number\n applyPendingDispose: (sessionId: string) => void\n pruneIdleAgents: () => void\n appendNoteTurn: (run: ActiveRun, blocks: readonly CommandOutputBlock[]) => Promise<void>\n}\n\n/** Start the accepted prompt's agent run and track its settlement (receipt, cleanup, marker, `run:end`). */\nfunction launchRun(deps: LaunchDeps, input: {\n opts: SendOptions\n run: ActiveRun\n runId: string\n generation: number\n settings: HostSettings\n promptValue: string | PromptPart[]\n systemNudge: string | undefined\n windowRun: ReturnType<typeof chatWindowBehavior>\n modelOverride: string | undefined\n sendRuntime: ResolvedConfig\n thinking: ThinkingLevel | undefined\n modelOptions: Record<string, boolean> | undefined\n trackSettlement: (completion: Promise<unknown>) => void\n}): void {\n const { env, broadcast, assertDispatchOpen, applyPendingDispose, pruneIdleAgents, appendNoteTurn } = deps\n const { opts, run, runId, generation, settings, promptValue, systemNudge, windowRun, modelOverride, sendRuntime, thinking, modelOptions, trackSettlement } = input\n /*\n * Settings-driven run ceilings — the SAME caps the local TUI applies\n * (`runCaps`): max turns, USD budget, token/wall-clock ceilings,\n * provider retry budget. Read fresh per run; zero means \"unbounded /\n * library default\" and passes nothing. Shared with command-driven\n * sub-runs (`runSlashCommand`'s `resolveRunSettings`).\n */\n const caps = runCapsFromSettings(settings)\n\n run.chatReferenceTokens.current = chatReferenceTokensForPrompt(opts.prompt)\n\n /*\n * Fresh AbortController PER RUN: `interrupt()` aborts the current\n * controller, and an aborted controller can never be un-aborted — if\n * the build-time controller were reused, one esc would leave every\n * subsequent send on this session born-aborted (instant\n * run:start/run:end) until the agent happened to be rebuilt.\n */\n run.controller = new AbortController()\n\n // Keep the cross-process run marker fresh through long quiet tool\n // calls (no-op when `useDaemon` is off — see startRunHeartbeat for the\n // straggler-settle contract shared with command sub-runs).\n const heartbeat = startRunHeartbeat({\n env,\n sessionId: opts.sessionId,\n isRunning: () => run.agent.isRunning,\n })\n\n /*\n * Extension tools and hooks that fire during the run reach\n * `ctx.workspace` / `ctx.runtime` through the host-runtime bridge; scope\n * THIS session's impl around the run so they resolve to it (see\n * `sessionHostRuntime`). Without a bridge (bare harness) the surfaces\n * stay detached, as before.\n */\n const runAgent = (): Promise<unknown> => run.agent\n .run({\n prompt: promptValue,\n system: systemNudge && run.system ? `${run.system}\\n\\n${systemNudge}` : systemNudge,\n signal: run.controller.signal,\n behavior: { ...windowRun, ...caps },\n // Attribute the Rules bucket only when the agent's composed system\n // is actually in use — a `systemNudge` override replaces it.\n ...(run.rules && !systemNudge ? { contextSections: run.rules } : {}),\n\n /*\n * Only forward `model` when the session has an explicit override —\n * forwarding the provider default every run would shadow the\n * agent's own per-turn model-selection logic. With a fallback\n * chain, expand into pinned {provider, model} targets WITH\n * per-target context windows so the loop re-bases the\n * auto-compact trigger when it advances down the chain.\n */\n ...(modelOverride\n ? {\n model: run.modelFallbacks.length > 0\n ? buildRunModel(\n [{ provider: run.providerKey, model: modelOverride }, ...run.modelFallbacks],\n k => run.providerNameByKey.get(k),\n (entry) => {\n const d = sendRuntime.providers[entry.provider]\n return d ? (getContextWindow(d, entry.model) ?? undefined) : undefined\n },\n )\n : modelOverride,\n }\n : {}),\n ...(thinking ? { thinking } : {}),\n ...(modelOptions ? { modelOptions } : {}),\n })\n broadcast({ kind: 'run:start', sessionId: opts.sessionId, runId })\n broadcastTodosSnapshot(broadcast, run)\n const scopedRun = Promise.resolve().then(() => {\n assertDispatchOpen(generation)\n return env.hostRuntime\n ? env.hostRuntime.runWith(sessionHostRuntime(run, env, { appendNote: (blocks) => { void appendNoteTurn(run, blocks) } }), runAgent)\n : runAgent()\n })\n let outcome: { ok: boolean, error?: string } = { ok: true }\n trackSettlement(scopedRun\n .catch((err) => {\n outcome = { ok: false, error: err instanceof Error ? err.message : String(err) }\n })\n .then(async () => {\n run.lastRunEndedAt = Date.now()\n // Capture status before a deferred rebuild destroys the live agent.\n const settle = heartbeat.end(run.agent.session?.status)\n try {\n try {\n broadcastRunReceipt(broadcast, run)\n }\n finally {\n run.chatReferenceTokens.current = []\n run.lastUsedAt = Date.now()\n // Apply deferred model changes before draining on the fresh agent.\n applyPendingDispose(opts.sessionId)\n pruneIdleAgents()\n }\n }\n finally {\n // Receipt/cleanup errors must not skip the final marker write.\n await settle\n }\n broadcast({ kind: 'run:end', sessionId: opts.sessionId, runId, ...outcome })\n broadcastTodosSnapshot(broadcast, run)\n }))\n}\n","import type { ApprovalHub } from '../approvals'\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport type { InteractionHub } from '../interactions'\n\n/** Interrupt / steer / follow-up on a session's live run. */\nexport function createRunControls(\n { active, suppressedWake }: Pick<HostContext, 'active' | 'suppressedWake'>,\n hitl: { approvals: Pick<ApprovalHub, 'denyAll'>, interactions: Pick<InteractionHub, 'list' | 'cancel'> },\n): Pick<ChatHost, 'interrupt' | 'steer' | 'followUp'> {\n function interruptSession(sessionId: string): void {\n suppressedWake.add(sessionId)\n const entry = active.get(sessionId)\n if (entry) {\n entry.commandAbort?.abort()\n entry.controller.abort()\n entry.agent.abort()\n }\n /*\n * After the abort, so the call they unblock sees an aborted run and the\n * loop stops instead of carrying on with a denied result. The approval\n * gate and the interaction tools await these with no abort signal:\n * left pending, the run never ended (approval) or its modal outlived it\n * (interaction), and answering it later aborted the NEXT run.\n */\n hitl.approvals.denyAll(sessionId)\n for (const pending of hitl.interactions.list(sessionId)) {\n if (pending.live)\n hitl.interactions.cancel(pending.request.id, 'Run interrupted.')\n }\n }\n\n function steerSession(sessionId: string, message: string): boolean {\n const entry = active.get(sessionId)\n // Broadcast happens at DELIVERY time via the `steer:inject` hook —\n // registering here only marks the text as a real user message.\n if (!entry?.agent.steer(message))\n return false\n entry.pendingInjections.push(message)\n return true\n }\n\n return {\n interrupt: interruptSession,\n steer: steerSession,\n\n followUp(sessionId, message) {\n const entry = active.get(sessionId)\n if (!entry?.agent.followUp(message))\n return false\n entry.pendingInjections.push(message)\n return true\n },\n }\n}\n","import type { ActiveRun, AgentHookContext } from '../types'\n\nexport function installSteerDelivery({ sessionId, agent, broadcast }: AgentHookContext, run: ActiveRun): void {\n /*\n * Registered AFTER `run` exists (hooks only fire during runs, long\n * after construction — the ordering is for the linter). Delivery-time\n * user-prompt broadcast for steers/follow-ups: fires when the loop\n * actually injects the message, so every window's live transcript\n * matches the canonical `eventsFromTurns` order (an accept-time\n * broadcast would render steered text before the turn it lands\n * after). Accepted-but-never-delivered injections die with the run.\n */\n agent.hooks.hook('steer:inject', ({ message }) => {\n const index = run.pendingInjections.indexOf(message)\n if (index < 0)\n return\n run.pendingInjections.splice(index, 1)\n broadcast({ kind: 'event', sessionId, echo: true, event: { kind: 'user-prompt', text: message } })\n })\n agent.hooks.hook('agent:done', () => {\n run.pendingInjections.length = 0\n })\n}\n","/**\n * Runs: the controls on a live run (interrupt, steer, follow-up), the\n * dispatch of a prompt (`sendPrompt` → guards, `/` command routing, user-\n * prompt echo, compaction barrier, skill activation, per-run model/effort/\n * caps, settlement), the cross-process run guard, and the per-run receipt.\n */\nimport type { CommandOutputBlock } from '../../commands'\nimport type { DispatchSignals } from '../broadcast'\nimport type { CommandModule } from '../commands'\nimport type { HostContext } from '../context'\nimport type { createProviderBuilder } from '../models'\nimport type { HostSignal, SendOptions } from '../signals'\nimport type { ActiveRun } from '../types'\nimport { randomUUID } from 'node:crypto'\nimport { createPromptPreparer } from './prepare'\n\nexport { createRunControls } from './controls'\nexport { STALE_RUN_MARKER_MS } from './guard'\nexport { installSteerDelivery } from './steer'\n\nexport function createRuns({ ctx, dispatchSignals, ensureAgent, commands, buildProvider, applyPendingDispose, pruneIdleAgents, drainQueue, appendNoteTurn }: {\n ctx: HostContext\n dispatchSignals: DispatchSignals\n ensureAgent: (sessionId: string) => Promise<ActiveRun>\n commands: Pick<CommandModule, 'runSlashCommand'>\n buildProvider: ReturnType<typeof createProviderBuilder>\n applyPendingDispose: (sessionId: string) => void\n pruneIdleAgents: () => void\n drainQueue: (sessionId: string) => void\n appendNoteTurn: (run: ActiveRun, blocks: readonly CommandOutputBlock[]) => Promise<void>\n}) {\n const { broadcast, dispatches, lifecycle, assertDispatchOpen, isSessionBusy } = ctx\n const preparePrompt = createPromptPreparer({ ctx, ensureAgent, commands, buildProvider, applyPendingDispose, pruneIdleAgents, appendNoteTurn })\n\n async function sendPrompt(\n opts: SendOptions,\n internal?: { ownMarkerExempt?: boolean, onCommand?: () => void, onForeignRun?: () => void },\n ): Promise<{ runId: string }> {\n assertDispatchOpen()\n if (isSessionBusy(opts.sessionId)) {\n throw new Error(`Session \"${opts.sessionId}\" already has a run in flight. Use steer/followUp (or pushQueued) to feed the active run.`)\n }\n const generation = lifecycle.teardownGeneration\n const finished = Promise.withResolvers<void>()\n dispatches.set(opts.sessionId, finished.promise)\n let settlement: Promise<unknown> | undefined\n let accepted = false\n const signals = { runId: randomUUID() } as { runId: string, end?: Extract<HostSignal, { kind: 'run:end' }> }\n dispatchSignals.set(opts.sessionId, signals)\n let outcome: { ok: boolean, error?: string } = { ok: true }\n const release = () => {\n if (dispatches.get(opts.sessionId) === finished.promise)\n dispatches.delete(opts.sessionId)\n dispatchSignals.delete(opts.sessionId)\n // Every dispatch kind (prompt, `/` command, refused send) ends here, so\n // a rebuild deferred while it was busy lands now — not at some later\n // prompt run. Without this a `runtime.reload` during `/review` never\n // resolved and the old extension registries were never disposed.\n if (!isSessionBusy(opts.sessionId))\n applyPendingDispose(opts.sessionId)\n try {\n broadcast({ kind: 'run:end', sessionId: opts.sessionId, runId: signals.runId, ...(signals.end ?? outcome), ...(!outcome.ok ? outcome : {}) })\n }\n finally {\n finished.resolve()\n }\n }\n try {\n const result = await preparePrompt(opts, internal, (completion) => { settlement = completion })\n if (!signals.end)\n signals.runId = result.runId\n accepted = true\n return result\n }\n catch (err) {\n outcome = { ok: false, error: err instanceof Error ? err.message : String(err) }\n throw err\n }\n finally {\n const drain = () => {\n if (!lifecycle.closed && generation === lifecycle.teardownGeneration)\n drainQueue(opts.sessionId)\n }\n if (settlement) {\n void settlement.catch((err) => {\n outcome = { ok: false, error: err instanceof Error ? err.message : String(err) }\n }).finally(release).then(drain).catch(() => undefined)\n }\n else {\n release()\n if (accepted)\n setTimeout(drain, 0)\n }\n }\n }\n\n return { sendPrompt }\n}\n","/**\n * The user's \"pinned\" active skills, persisted on the session: the set\n * toggled on via `/skill-name` that must stay active across run boundaries\n * and restarts. Shared by the TUI and the host, which both maintain it.\n *\n * Separate from the agent's `skillActivationState` for two reasons:\n * 1. The framework's run-end pass deactivates everything; the pinned set\n * survives that pass so the next prompt can re-activate.\n * 2. The agent's session-resume rehydrator only sees `skills_use`\n * `tool_call` blocks in history. Slash-command activations bypass that\n * path; this metadata key is the system of record for them.\n */\n\n/** Session-metadata key of the pinned-skills list. */\nexport const PINNED_SKILLS_META_KEY = 'zidane.activeSkills'\n\n/**\n * The pinned set from session metadata. Tolerant by design: older sessions,\n * hand-edited metadata or type drift degrade to \"no pins\", never throw.\n * Returns a fresh Set so callers can mutate it without aliasing the input.\n */\nexport function readPinnedSkills(raw: unknown): Set<string> {\n if (!Array.isArray(raw))\n return new Set<string>()\n return new Set(raw.filter((v): v is string => typeof v === 'string' && v.length > 0))\n}\n\n/** The pinned set as stored: sorted, for stable on-disk ordering. */\nexport function pinnedSkillsValue(pins: ReadonlySet<string>): string[] {\n return Array.from(pins).sort()\n}\n\n/**\n * Whether a skill deactivation releases the pin. The framework's `'run-end'`\n * pass is mechanical per-run cleanup (the pin re-activates on the next\n * prompt); a model, explicit or reset deactivation is intent.\n */\nexport function deactivationReleasesPin(reason: string): boolean {\n return reason !== 'run-end'\n}\n","/**\n * Skills for a session's agent: the extension / skill-edit session markers,\n * the merged skills config (disk scan, extension and plugin skills, preset\n * catalog, injected authoring skills), and the activation hooks that keep\n * pins on the session and windows' chips in sync.\n */\nimport type { filterRegistryPlugins } from '../../../extensions'\nimport type { SkillConfig } from '../../../skills'\nimport type { buildPluginContributions } from '../../plugins-discovery'\nimport type { HostSettings } from '../signals'\nimport type { AgentHookContext } from '../types'\nimport { EXTENSION_EDIT_METADATA_KEY, extensionDirForCwd, readSkillEditMarker, SKILL_EDIT_METADATA_KEY, withZidaneExtensionSkill, withZidaneSkillEditSkill } from '../../../index'\nimport { deactivationReleasesPin, PINNED_SKILLS_META_KEY, pinnedSkillsValue, readPinnedSkills } from '../../pinned-skills'\nimport { buildSkillsConfig, defaultSkillScanPaths } from '../../skills-discovery'\nimport { hostDebug } from '../debug'\n\nexport function readSessionSkillMarkers(metadata: Record<string, unknown> | undefined): {\n isExtensionEdit: boolean\n skillEditMarker: ReturnType<typeof readSkillEditMarker>\n} {\n /*\n * \"Edit / create extension\" sessions carry the marker stamped at\n * session-creation time. When present we inject the `zidane-extension`\n * docs skill into the FINAL merged skills (below) and auto-activate it\n * each run so the authoring guidance is live from turn one.\n */\n const extensionEditMarker = metadata?.[EXTENSION_EDIT_METADATA_KEY]\n const isExtensionEdit = typeof extensionEditMarker === 'object' && extensionEditMarker !== null\n\n /*\n * \"Edit skill\" sessions carry the skill counterpart of the marker\n * above. The preset skill embeds the target's name + directory, so\n * the marker payload matters — `readSkillEditMarker` degrades\n * malformed metadata to null.\n */\n const skillEditMarker = readSkillEditMarker(metadata?.[SKILL_EDIT_METADATA_KEY])\n return { isExtensionEdit, skillEditMarker }\n}\n\nexport function composeSessionSkills(input: {\n cwd: string\n prefix: string\n settings: HostSettings\n liveExtensions: ReturnType<typeof filterRegistryPlugins>\n pluginContributions: ReturnType<typeof buildPluginContributions>\n presetSkills: ReturnType<typeof buildSkillsConfig> | undefined\n isExtensionEdit: boolean\n skillEditMarker: ReturnType<typeof readSkillEditMarker>\n /** A machine session's project skills, read on the machine (`docs/MACHINES.md` § Project files). */\n machineSkills?: readonly SkillConfig[]\n}): ReturnType<typeof buildSkillsConfig> {\n const { cwd, settings, liveExtensions, pluginContributions, isExtensionEdit, skillEditMarker } = input\n /*\n * Skills catalog: scan `.claude/skills` (project + home) so all zidane\n * surfaces share the user's existing skill library. Allowlist via\n * settings; extension-contributed skills are always allowed.\n */\n const extensionSkillNames = liveExtensions.skills.map(skill => skill.name)\n /*\n * Plugin skill names are force-included for the same reason as extension\n * skills — a user's `enabledSkills` only covers what was on disk when they\n * last toggled — but keyed to the PLUGIN's toggle: enabling the plugin IS\n * the consent, and `enabledPlugins` is the affordance for withholding it.\n */\n const pluginSkillNames = pluginContributions.skills.map(skill => skill.name)\n const mergedEnabledSkills = settings.enabledSkills === undefined\n ? undefined\n : Array.from(new Set([...settings.enabledSkills, ...extensionSkillNames, ...pluginSkillNames]))\n const skillsConfig = buildSkillsConfig({\n // Native scan under the host's own prefix (`.zidane/skills`);\n // other agents' skill dirs (`.claude`, `.codex`, `.pi`) are the\n // FOREIGN set, gated behind the `importForeignConfigs` opt-in —\n // same convention as the TUI's discovery shell.\n scan: defaultSkillScanPaths({\n cwd,\n prefix: input.prefix,\n foreignAgents: settings.importForeignConfigs === true,\n ruler: settings.importRulerConfigs !== false,\n }),\n enabled: mergedEnabledSkills,\n })\n\n /*\n * Merge skills (preset last-wins on `catalog`), THEN inject the\n * extension docs skill — injecting before the merge would be dropped\n * whenever a preset also contributes skills.\n */\n const mergedSkills = { ...skillsConfig, ...(input.presetSkills ?? {}) }\n const injectExtensionSkill = isExtensionEdit || extensionDirForCwd(cwd) !== null\n const withExtensionSkill = injectExtensionSkill ? withZidaneExtensionSkill(mergedSkills, { cwd }) : mergedSkills\n // Skill-edit sessions get their preset skill the same way (post-merge).\n const withSkillEdit = skillEditMarker\n ? withZidaneSkillEditSkill(withExtensionSkill, skillEditMarker, { cwd })\n : withExtensionSkill\n /*\n * Plugin skills ride `catalog`, never `scan`: handing a plugin's `skills/`\n * to the recursive disk scanner would bypass the strict loader (depth-1\n * discovery, package boundary, per-skill isolation) that is what makes\n * reading a third-party package safe.\n */\n // A machine's project skills ride `catalog` too (they are not on this filesystem), ahead of the rest: project beats user.\n const extraCatalog = [...(input.machineSkills ?? []), ...pluginContributions.skills]\n const finalSkills = extraCatalog.length > 0\n ? { ...withSkillEdit, catalog: [...extraCatalog, ...(withSkillEdit.catalog ?? [])] }\n : withSkillEdit\n return finalSkills\n}\n\nexport function installSkillHooks({ sessionId, agent, broadcast }: AgentHookContext): void {\n /*\n * Active-skill chips — snapshot on every activation change so windows\n * mirror the daemon agent's live skill state.\n */\n const broadcastSkills = (): void => {\n broadcast({\n kind: 'skills:snapshot',\n sessionId,\n active: agent.activeSkills.map(entry => entry.skill.name),\n })\n }\n /*\n * Pins on the session (`PINNED_SKILLS_META_KEY`), so a restart re-activates\n * them; the same rule as the TUI's local agent.\n */\n // Pins changed during a run: saved once at its end, not on every activation.\n let pinsDirty = false\n const savePins = (): void => {\n pinsDirty = false\n void agent.session?.save().catch(err => hostDebug('skills', `pin save failed: ${String(err)}`))\n }\n agent.hooks.hook('agent:done', () => {\n if (pinsDirty)\n savePins()\n })\n const updatePins = (skill: string, pinned: boolean): void => {\n const session = agent.session\n if (!session)\n return\n const pins = readPinnedSkills(session.metadata[PINNED_SKILLS_META_KEY])\n if (pins.has(skill) === pinned)\n return\n if (pinned)\n pins.add(skill)\n else\n pins.delete(skill)\n session.setMeta(PINNED_SKILLS_META_KEY, pinnedSkillsValue(pins))\n if (agent.isRunning)\n pinsDirty = true\n else\n savePins()\n }\n agent.hooks.hook('skills:activate', ({ skill }) => {\n updatePins(skill.name, true)\n broadcastSkills()\n })\n agent.hooks.hook('skills:deactivate', ({ skill, reason }) => {\n /*\n * `'run-end'` is the framework's mechanical per-run cleanup: the pin\n * (and the windows' chips, re-asserted on the next send) survives it.\n * User / model intent ('model' / 'explicit' / 'reset') releases it.\n */\n if (!deactivationReleasesPin(reason))\n return\n updatePins(skill.name, false)\n broadcastSkills()\n })\n}\n","/**\n * The `ActiveRun` record `buildActiveRun` hands the host: the built agent plus\n * everything later sends, rebuilds and teardown read back off it.\n */\nimport type { BuiltInSystem } from '../prompt'\nimport type { ActiveRun, CommandSpawnSeam } from '../types'\nimport { ZIDANE_EXTENSION_SKILL_NAME, ZIDANE_SKILL_EDIT_SKILL_NAME } from '../../../index'\n\nexport function assembleActiveRun(input: Pick<ActiveRun, 'sessionId' | 'cwd' | 'discoveryCwd' | 'sessionFolder' | 'movableCwd' | 'agent' | 'providerKey' | 'providerDescriptor' | 'model' | 'modelOverride' | 'ledger' | 'work' | 'chatReferenceTokens' | 'warnLog' | 'modelFallbacks' | 'providerNameByKey' | 'system'> & {\n builtInSystem: BuiltInSystem | null\n isExtensionEdit: boolean\n skillEditMarker: unknown\n commandSeam: (() => CommandSpawnSeam) | undefined\n}): ActiveRun {\n const { sessionId, cwd, discoveryCwd, sessionFolder, movableCwd, agent, providerKey, providerDescriptor, model, modelOverride, ledger, work, chatReferenceTokens, warnLog, modelFallbacks, providerNameByKey, system, builtInSystem, isExtensionEdit, skillEditMarker, commandSeam } = input\n return {\n sessionId,\n cwd,\n discoveryCwd,\n sessionFolder,\n movableCwd,\n agent,\n controller: new AbortController(),\n providerKey,\n providerDescriptor,\n model,\n ...(modelOverride ? { modelOverride } : {}),\n ledger,\n work,\n chatReferenceTokens,\n warnLog,\n modelFallbacks,\n providerNameByKey,\n systemMd: {\n file: builtInSystem?.systemFile ?? null,\n shadowed: builtInSystem?.shadowedSystemFiles ?? [],\n },\n pendingInjections: [],\n lastUsedAt: Date.now(),\n ...(system ? { system } : {}),\n ...(isExtensionEdit || skillEditMarker\n ? {\n autoActivateSkills: [\n ...(isExtensionEdit ? [ZIDANE_EXTENSION_SKILL_NAME] : []),\n ...(skillEditMarker ? [ZIDANE_SKILL_EDIT_SKILL_NAME] : []),\n ],\n }\n : {}),\n ...(commandSeam ? { commandSeam } : {}),\n ...((builtInSystem?.rulesBlock || builtInSystem?.rulesFiles)\n ? { rules: { rulesBlock: builtInSystem.rulesBlock, rulesFiles: builtInSystem.rulesFiles } }\n : {}),\n }\n}\n","import type { SpawnModelEntry, ToolDef } from '../../../index'\nimport type { Provider } from '../../../providers'\nimport type { ProviderKey } from '../../auth'\nimport type { ResolvedConfig } from '../../config'\nimport type { ProviderDescriptor } from '../../providers'\nimport type { CommandSpawnSeam } from '../types'\nimport { isSpawnTool } from '../../../index'\nimport { detectAuth } from '../../auth'\nimport { hostDebug } from '../debug'\n\nexport function createCommandSeam(input: {\n spawnCandidate: ToolDef | undefined\n primaryProvider: Provider\n extraProviders: readonly Provider[]\n providerNameByKey: ReadonlyMap<ProviderKey, string>\n seenProviderNames: ReadonlySet<string>\n providers: Readonly<Record<string, ProviderDescriptor>>\n runtimeConfig: Pick<ResolvedConfig, 'modelsFor'>\n userDataDir: string\n system: string | undefined\n tools: CommandSpawnSeam['tools']\n skills: CommandSpawnSeam['skills']\n behavior: CommandSpawnSeam['behavior']\n name: string\n}): (() => CommandSpawnSeam) | undefined {\n const { spawnCandidate, primaryProvider, extraProviders, providerNameByKey, seenProviderNames, providers, runtimeConfig, system } = input\n /*\n * Capture the spawn seam for `/` command `ctx.spawnAgents`: the exact\n * inputs the agent was built with, so command children get the same\n * model routing, tools, skills, and behavior as model-initiated spawns.\n */\n /*\n * The seam's catalog and providers span EVERY credentialed provider, not\n * just the run's chain: extension pickers offer the full\n * `ctx.runtime.models()` catalog, so a session on one provider can pin a\n * review child to another. Those extra providers exist only for child\n * routing; the agent's chain and the model-facing spawn catalog stay\n * chain-scoped. Same rule as the TUI's local `buildAgent`.\n *\n * Built on first use and memoized: only a `/` command that spawns\n * children needs it, so an ordinary agent build never reads credentials\n * or constructs providers for it. Unlike the GUI's always-spawn-capable\n * preset, host presets may omit `spawn` entirely.\n */\n let builtSeam: CommandSpawnSeam | undefined\n return spawnCandidate && isSpawnTool(spawnCandidate)\n ? (): CommandSpawnSeam => {\n if (builtSeam)\n return builtSeam\n const seamProviders: Provider[] = [primaryProvider, ...extraProviders]\n const seamCatalog: SpawnModelEntry[] = []\n for (const [key, providerName] of providerNameByKey) {\n for (const info of runtimeConfig.modelsFor(key))\n seamCatalog.push({ provider: providerName, model: info })\n }\n for (const auth of detectAuth(input.userDataDir, providers)) {\n const descriptor = providers[auth.key]\n if (!auth.available || providerNameByKey.has(auth.key) || !descriptor)\n continue\n const models = runtimeConfig.modelsFor(auth.key)\n if (models.length === 0)\n continue\n try {\n const extra = descriptor.factory()\n if (seenProviderNames.has(extra.name))\n continue\n seamProviders.push(extra)\n for (const info of models)\n seamCatalog.push({ provider: extra.name, model: info })\n }\n catch (err) {\n // Credentialed but unconstructable (corrupt key file, …): skip;\n // pinning one of its models rejects with the usual catalog error.\n hostDebug(`seam provider \"${auth.key}\" construction failed`, err)\n }\n }\n builtSeam = {\n spawnTool: seamCatalog.length === 0 ? spawnCandidate : spawnCandidate.withModels(seamCatalog),\n provider: primaryProvider,\n providers: seamProviders,\n ...(system ? { system } : {}),\n tools: input.tools,\n skills: input.skills,\n behavior: input.behavior,\n name: input.name,\n }\n return builtSeam\n }\n : undefined\n}\n","/**\n * A window's overrides for a host-built session agent: the `zidane run`\n * launch flags (`--system / --mcp / --context …`) and a working directory\n * picked mid-session. Owned by the window (never persisted). Dependency-free\n * so the TUI, the daemon dispatcher, and the host share one rule without\n * importing the engine.\n */\nimport type { McpServerConfig } from '../../mcp'\nimport type { StartLocalOptions } from '../../start/shared-options'\n\n/** `zidane run --context …`: the execution this launch runs in, overriding the session's environment. */\nexport interface LaunchExecution {\n /** Execution context kind (`docker`, `e2b`, `daytona`). `process` is the default and not an override. */\n context: string\n image?: string\n env?: Record<string, string>\n pregame?: { name: string, content: string }\n sandboxId?: string\n sandboxOnDestroy?: 'kill' | 'pause' | 'leave'\n}\n\n/** `ChatHost.setLaunchOverrides`: what the window overrides on a session's agent. */\nexport interface SessionLaunchOverrides {\n /** Replaces the base system prompt (extension fragments still append). */\n system?: string\n /** Extra MCP servers, after the discovered and plugin ones (which win a name collision). */\n mcp?: readonly McpServerConfig[]\n execution?: LaunchExecution\n /**\n * Working directory picked mid-session (the TUI's cwd picker), instead of\n * the session's folder: the live agent's tools move at once, its prompt on\n * the next turn, and later builds use it. Not persisted.\n */\n cwd?: string\n}\n\n/**\n * The overrides that shape an agent, or `null` when none do (no `system`,\n * no MCP server, no non-`process` context, no cwd). The one rule for \"are launch\n * overrides set\", shared by the host, the daemon dispatcher, and the TUI.\n */\nexport function normalizeLaunchOverrides(overrides: SessionLaunchOverrides | null | undefined): SessionLaunchOverrides | null {\n if (!overrides)\n return null\n const mcp = overrides.mcp && overrides.mcp.length > 0 ? overrides.mcp : undefined\n const execution = overrides.execution && overrides.execution.context !== 'process' ? overrides.execution : undefined\n const cwd = overrides.cwd || undefined\n if (overrides.system === undefined && !mcp && !execution && !cwd)\n return null\n return {\n ...(overrides.system !== undefined ? { system: overrides.system } : {}),\n ...(mcp ? { mcp } : {}),\n ...(execution ? { execution } : {}),\n ...(cwd ? { cwd } : {}),\n }\n}\n\n/**\n * A window's overrides for a session (see {@link normalizeLaunchOverrides}):\n * what its `zidane run` launch carries, plus its cwd when that is not the\n * session's own folder (picked mid-session).\n */\nexport function launchOverridesFrom(\n launch: Partial<StartLocalOptions> | null | undefined,\n location?: { cwd: string, sessionFolder: string },\n): SessionLaunchOverrides | null {\n return normalizeLaunchOverrides({\n ...(location && location.cwd !== location.sessionFolder ? { cwd: location.cwd } : {}),\n ...fromLaunch(launch),\n })\n}\n\nfunction fromLaunch(launch: Partial<StartLocalOptions> | null | undefined): SessionLaunchOverrides {\n if (!launch)\n return {}\n return {\n ...(launch.system !== undefined ? { system: launch.system } : {}),\n ...(launch.mcp ? { mcp: launch.mcp } : {}),\n ...(launch.context\n ? {\n execution: {\n context: launch.context,\n ...(launch.image !== undefined ? { image: launch.image } : {}),\n ...(launch.env !== undefined ? { env: launch.env } : {}),\n ...(launch.pregame !== undefined ? { pregame: launch.pregame } : {}),\n ...(launch.sandboxId !== undefined ? { sandboxId: launch.sandboxId } : {}),\n ...(launch.sandboxOnDestroy !== undefined ? { sandboxOnDestroy: launch.sandboxOnDestroy } : {}),\n },\n }\n : {}),\n }\n}\n","/**\n * Where a session's agent works, and moving it live: the session cwd\n * (launch override else folder), the movable-cwd rule, the hooks that keep a\n * live agent's handle and env block on a cwd picked mid-session, and\n * `setLaunchOverrides` (a cwd-only change moves the agent in place).\n */\nimport type { ExecutionContext } from '../../../contexts/types'\nimport type { SessionData } from '../../../session/index'\nimport type { WorkspaceConfinement } from '../../workspace-confinement'\nimport type { SessionLaunchOverrides } from '../launch-overrides'\nimport type { ActiveRun, AgentHookContext } from '../types'\nimport { stableStringify } from '../../../behaviors/repeat-guard'\nimport { replaceDynamicSection } from '../../../system-prompt'\nimport { envSection } from '../../agent-prompt'\nimport { findGitRoot } from '../../project-root'\nimport { resolveSessionCwd } from '../../session-cwd'\nimport { hostDebug } from '../debug'\nimport { normalizeLaunchOverrides } from '../launch-overrides'\n\nexport function createSessionCwd(launchOverrides: Map<string, SessionLaunchOverrides>, folderlessCwd: () => string | undefined = () => undefined): (sessionId: string, data: SessionData) => string {\n /**\n * Where a session's agent works: a cwd the window picked mid-session, else\n * the session's folder. Canonical folder semantics (`session-cwd.ts`): an\n * empty `metadata.cwd` counts as unset (directory-less forks persist\n * `''`), and the anchor for a folderless session is the user's HOME, never\n * `process.cwd()` (which in a daemon or packaged app points nowhere the\n * user chose). On a confined host (a server) it is the first workspace\n * root instead: the server user's home is outside them.\n */\n function sessionCwd(sessionId: string, data: SessionData): string {\n const override = launchOverrides.get(sessionId)?.cwd\n if (override !== undefined)\n return override\n const recorded = typeof data.metadata?.cwd === 'string' ? data.metadata.cwd : ''\n const anchor = recorded || data.projectRoot ? undefined : folderlessCwd()\n return anchor ?? resolveSessionCwd({ metadata: data.metadata, projectRoot: data.projectRoot ?? undefined })\n }\n return sessionCwd\n}\n\n/*\n * Commands run in this machine's folders (a process context, not a\n * sandbox's clone or a container): a cwd picked mid-session can move the\n * live agent (`setLaunchOverrides`).\n */\nexport function isMovableCwd(promptCwd: string | undefined, context: ExecutionContext): boolean {\n return promptCwd === undefined && context.type === 'process'\n}\n\nexport function installCwdHooks(\n { sessionId, agent }: AgentHookContext,\n input: {\n active: Map<string, ActiveRun>\n launchOverrides: Map<string, SessionLaunchOverrides>\n cwd: string\n sessionFolder: string\n movableCwd: boolean\n /** The agent runs a built-in prompt with no launch `--system` replacement. */\n builtInPrompt: boolean\n },\n): void {\n const { active, launchOverrides, cwd, sessionFolder, movableCwd } = input\n /*\n * A cwd picked mid-session (`setLaunchOverrides({ cwd })`) moves the live\n * handle without a rebuild, so the prompt's env block follows here, per\n * turn, below the cache boundary (the doctrine above stays byte-stable).\n * Same as the TUI's local agent. Only for the built-in prompts the env\n * block belongs to, on this machine (a remote environment's prompt cwd\n * is a path inside it), and not under a `--system` replacement.\n */\n if (movableCwd) {\n // A cwd picked before the execution started: it starts there.\n agent.hooks.hook('execution:ready', ({ handle }) => {\n const live = active.get(sessionId)\n if (live?.agent === agent && handle.cwd !== live.cwd)\n handle.cwd = live.cwd\n })\n }\n if (input.builtInPrompt && movableCwd) {\n agent.hooks.hook('system:transform', (ctx) => {\n const live = launchOverrides.get(sessionId)?.cwd ?? sessionFolder\n if (live === cwd)\n return\n const projectRoot = findGitRoot(live) ?? live\n ctx.system = replaceDynamicSection(ctx.system, envSection({\n cwd: live,\n ...(projectRoot !== live ? { projectRoot } : {}),\n }))\n })\n }\n}\n\nexport function createLaunchOverridesSetter(input: {\n launchOverrides: Map<string, SessionLaunchOverrides>\n active: Map<string, ActiveRun>\n disposeAgentForRebuild: (sessionId: string) => Promise<void>\n workspace: Pick<WorkspaceConfinement, 'checkFolder'>\n}): (sessionId: string, overrides: SessionLaunchOverrides | null) => void {\n const { launchOverrides, active, disposeAgentForRebuild, workspace } = input\n /**\n * A confined host (a server) drops a `cwd` outside its workspace roots and\n * applies the rest: a window's own folder is a path on ITS machine, which\n * the session must not move to (the session keeps its folder).\n */\n const allowedCwd = (sessionId: string, cwd: string | undefined): string | undefined => {\n if (!cwd)\n return cwd\n try {\n return workspace.checkFolder(cwd)\n }\n catch (err) {\n // Diagnosable, not silent: which session, which path, why (`ZIDANE_DEBUG`).\n hostDebug(`launch overrides for session ${sessionId}: cwd ${JSON.stringify(cwd)} dropped, the session keeps its folder`, err)\n return undefined\n }\n }\n return function setLaunchOverrides(sessionId, overrides) {\n const { cwd, ...rest } = overrides ?? {}\n const allowed = allowedCwd(sessionId, cwd)\n const next = normalizeLaunchOverrides(overrides ? { ...rest, ...(allowed !== undefined ? { cwd: allowed } : {}) } : null)\n // Key-order-insensitive: windows re-send on every activation, and an\n // equal set must not cost a rebuild.\n const previous = launchOverrides.get(sessionId) ?? null\n if (stableStringify(previous) === stableStringify(next))\n return\n if (next)\n launchOverrides.set(sessionId, next)\n else\n launchOverrides.delete(sessionId)\n const { cwd: _previousCwd, ...previousShape } = previous ?? {}\n const { cwd: _nextCwd, ...nextShape } = next ?? {}\n if (stableStringify(previousShape) !== stableStringify(nextShape)) {\n void disposeAgentForRebuild(sessionId)\n return\n }\n /*\n * Only the cwd moved (the window's cwd picker): like the TUI's local\n * agent, re-point the live execution handle so tools resolve against\n * it at once, mid-run included, and let the prompt follow per turn\n * (the `system:transform` in `installCwdHooks`); commands and the\n * context panel read `run.cwd`. No rebuild, so running background\n * tasks keep their execution. Only where commands run on this machine:\n * a sandbox's working directory is a path inside it.\n */\n const run = active.get(sessionId)\n if (!run?.movableCwd)\n return\n run.cwd = next?.cwd ?? run.sessionFolder\n // Not spawned yet: the `execution:ready` hook applies it.\n if (run.agent.handle)\n run.agent.handle.cwd = run.cwd\n }\n}\n","/**\n * Edit tools as the host shows and annotates them: the pre-edit file read\n * that gives tool cards real line numbers, the `<edit-outcomes>` annotation\n * the approval pipeline's ledger feeds into tool results, and the run-boundary\n * cleanup of that ledger.\n */\nimport type { Agent } from '../../../index'\nimport type { EditOutcomeLedger } from '../edit-outcome-ledger'\nimport { buildEditOutcomesAnnotation, mergeApprovalAndBodyOutcomes, parseEditOutcomesFromResult, rewriteMultiEditHeader, stripEditOutcomesAnnotation } from '../../edit-approval'\nimport { pruneTodosByRun } from '../../todos'\nimport { EDIT_TOOL_NAMES } from '../../turn-selection'\nimport { hostDebug } from '../debug'\n\n/** Largest file whose pre-edit content rides a tool card to the windows (see `readPriorContent`). */\nconst PRIOR_CONTENT_MAX_BYTES = 512 * 1024\n\nexport function createPriorContentReader(agent: Agent): (name: string, input: Record<string, unknown>) => Promise<string | undefined> {\n /*\n * The file as it is before an edit tool runs, so the card's diff shows\n * real line numbers. The loop awaits this hook, so the read happens\n * before the write. Capped, since the content rides a live event to every\n * window: past the cap an edit's diff has no line numbers and a\n * `write_file` over the file renders as a new file.\n */\n const readPriorContent = async (name: string, input: Record<string, unknown>): Promise<string | undefined> => {\n const handle = agent.handle\n if (!EDIT_TOOL_NAMES.has(name) || !handle || typeof input.path !== 'string')\n return undefined\n try {\n const size = await agent.execution.fileSize?.(handle, input.path)\n if (size !== undefined && size !== null && size > PRIOR_CONTENT_MAX_BYTES)\n return undefined\n return await agent.execution.readFile(handle, input.path)\n }\n catch {\n // A new file (`write_file`) or a wrong path: the diff renders without it.\n return undefined\n }\n }\n return readPriorContent\n}\n\nexport function installEditAnnotationHooks(agent: Agent, ledger: EditOutcomeLedger): void {\n /**\n * `tool:transform` runs AFTER the tool body returns its result and\n * BEFORE the result is sent back to the model — the seam the\n * `<edit-outcomes>` annotation rides in on. Registered on both the\n * parent and child transforms so subagent edits get the annotation too.\n */\n const annotateEditResult = (\n callId: string,\n toolName: string,\n result: string | readonly unknown[],\n ): string | unknown[] | undefined => {\n const stashed = ledger.drain(callId)\n if (!stashed)\n return undefined\n\n /*\n * Canonical merge path: peel the body's `<edit-outcomes>` block (if\n * the tool body emitted one — multi_edit does on partial failures),\n * merge it into the approval-side outcomes, then re-append exactly\n * one annotation.\n */\n const bodyOutcomes = parseEditOutcomesFromResult(result as Parameters<typeof parseEditOutcomesFromResult>[0])\n const merged = mergeApprovalAndBodyOutcomes(stashed.outcomes, bodyOutcomes)\n const annotation = buildEditOutcomesAnnotation(merged)\n\n if (typeof result === 'string') {\n let body = stripEditOutcomesAnnotation(result)\n\n /*\n * Multi-edit header rewrite — the tool body counts only the\n * approved subset; the canonical transcript should reflect the\n * original edit list size so clients and the model see consistent\n * totals.\n */\n if (toolName === 'multi_edit') {\n // multi_edit's schema key is `path` — and when it resolves\n // empty, skip the rewrite entirely.\n const rawPath = (stashed.originalInput as { path?: unknown }).path\n const path = typeof rawPath === 'string' ? rawPath : ''\n if (path)\n body = rewriteMultiEditHeader(body, merged, path)\n }\n\n return body.length === 0 ? annotation : `${body}\\n\\n${annotation}`\n }\n\n /*\n * Structured content — peel + re-append from the text segments only;\n * image/document blocks pass through.\n */\n const peeled = (result as readonly { type: string, text?: string }[]).map(block =>\n block.type === 'text' && typeof block.text === 'string'\n ? { ...block, text: stripEditOutcomesAnnotation(block.text) }\n : block,\n )\n return [...peeled, { type: 'text', text: `\\n${annotation}` }]\n }\n\n agent.hooks.hook('tool:transform', (ctx) => {\n const next = annotateEditResult(ctx.callId, ctx.name, ctx.result)\n if (next !== undefined)\n ctx.result = next as typeof ctx.result\n })\n\n agent.hooks.hook('child:tool:transform', (ctx) => {\n const next = annotateEditResult(ctx.callId, ctx.name, ctx.result)\n if (next !== undefined)\n ctx.result = next as typeof ctx.result\n })\n}\n\nexport function installRunBoundaryCleanup(agent: Agent, { ledger, manuallyEmittedGateBlocks }: { ledger: EditOutcomeLedger, manuallyEmittedGateBlocks: Set<string> }): void {\n /**\n * Memory hardening: clear the entire stash on every run boundary.\n * Catches any entry whose `tool:transform` never fired so the Map stays\n * bounded by run lifetime rather than session lifetime.\n */\n agent.hooks.hook('agent:done', () => {\n ledger.clear()\n manuallyEmittedGateBlocks.clear()\n // GC per-subagent todo slots whose run is no longer in `session.runs`\n // (fork / restore / hand-edited sessions strand them otherwise), as the\n // TUI's local agent does. Saved through the live session, like every\n // other host-side todo write.\n const session = agent.session\n if (session && pruneTodosByRun(session).dropped.length > 0)\n void session.save().catch(err => hostDebug('todos', `prune save failed: ${String(err)}`))\n })\n}\n","/**\n * Subagent lifecycle markers (spawn start / end / error).\n */\nimport type { ChildRunStats, SpawnHookContext } from '../../../types'\nimport type { SpawnStartRecord } from '../../spawn-markers'\nimport type { EmitNotice } from '../notices'\nimport type { AgentHookContext } from '../types'\nimport { buildSpawnEndEvent, buildSpawnQueuedEvent, buildSpawnStartEvent } from '../../spawn-markers'\n\n/** What a start / end / error handler reads — `spawn:*` and nested `child:spawn:*` alike. */\ntype StartCtx = Omit<SpawnHookContext, 'tracingContext'> & { parentChildId?: string }\ntype EndCtx = ChildRunStats & { parentChildId?: string }\n\nexport function installSpawnHooks({ sessionId, agent, broadcast }: AgentHookContext, emitNotice: EmitNotice): void {\n /*\n * Subagent lifecycle banners — same StreamEvent shapes `eventsFromTurns`\n * produces on reload, so the live spawn tree renders identically in\n * every window (child tool events already carry childId/depth; these\n * add the start/end markers between them).\n *\n * Direct children arrive as `spawn:*`; a spawn run BY a subagent arrives\n * as `child:spawn:*` with the spawner in `parentChildId`. Both build the\n * same markers — the marker's `childId` / `depth` are the spawned\n * worker's (what its own rows carry), and `spawn.parentChildId` names the\n * spawner so clients nest the worker under it.\n */\n // Wall-clock start + task/model per in-flight child — drives the\n // structured `spawn` lifecycle metadata and the elapsed segment on the\n // spawn-end marker. Same bookkeeping as the local TUI hooks.\n const spawnStartedAt = new Map<string, SpawnStartRecord>()\n const onStart = (ctx: StartCtx): void => {\n /*\n * Canonical (unit-tested) marker builders — shared with the GUI so\n * live markers match replay byte-for-byte, `resumes child-N` prefix\n * for resumed children included.\n */\n const startedAt = Date.now()\n spawnStartedAt.set(ctx.id, {\n startedAt,\n task: ctx.task,\n ...(ctx.model ? { model: ctx.model } : {}),\n })\n broadcast({ kind: 'event', sessionId, event: buildSpawnStartEvent(ctx, startedAt) })\n }\n const onComplete = (ctx: EndCtx): void => {\n const record = spawnStartedAt.get(ctx.id)\n spawnStartedAt.delete(ctx.id)\n broadcast({ kind: 'event', sessionId, event: buildSpawnEndEvent(ctx, record) })\n }\n const onError = ({ id, depth, error }: StartCtx & { error: Error }): void => {\n // Drop the start record — the completion that would consume it\n // never fires on the error path.\n spawnStartedAt.delete(id)\n // Attributed to the failing worker itself (its own lane), at any depth.\n emitNotice({ severity: 'error', label: 'subagent' }, `[${id}] ${error.message}`, { childId: id, depth: depth ?? 1 })\n }\n // Live only: the call starts (`spawn:before`) once a slot frees, and a replay has no waiting.\n agent.hooks.hook('spawn:queued', ctx => broadcast({ kind: 'event', sessionId, event: buildSpawnQueuedEvent(ctx) }))\n agent.hooks.hook('spawn:before', onStart)\n agent.hooks.hook('spawn:complete', onComplete)\n agent.hooks.hook('spawn:error', onError)\n agent.hooks.hook('child:spawn:before', onStart)\n agent.hooks.hook('child:spawn:complete', onComplete)\n agent.hooks.hook('child:spawn:error', onError)\n}\n","/**\n * Stream deltas (parent and subagent prose/reasoning) and the provider-retry\n * indicator they clear.\n */\nimport type { StreamEvent } from '../../types'\nimport type { AgentHookContext } from '../types'\n\n/** Installs the delta hooks; returns the retrying-sources set `installRetryHooks` shares. */\nexport function installStreamHooks({ sessionId, agent, broadcast }: AgentHookContext): Set<string> {\n /*\n * ---- Hook → HostSignal forwarding -------------------------------------\n * Same merge semantics as `useStreamBuffer`: same-owner same-kind deltas\n * coalesce on the client reducer side; everything else appends.\n */\n\n /*\n * Sources (`'parent'` or a child id) with a provider-retry indicator up.\n * The first delta after a retry means the stream resumed: clear the\n * indicator for every window here, once, instead of leaving each client\n * to infer it (the TUI's daemon path never did, so the chip hung on).\n */\n const retrying = new Set<string>()\n const resumed = (source: string): void => {\n if (retrying.delete(source))\n broadcast({ kind: 'stream:retry:cleared', sessionId, source })\n }\n\n agent.hooks.hook('stream:text', (ctx) => {\n resumed('parent')\n const event: StreamEvent = { kind: 'markdown', text: ctx.delta, streaming: true, turnId: ctx.turnId }\n broadcast({ kind: 'event', sessionId, event })\n })\n\n agent.hooks.hook('stream:thinking', (ctx) => {\n resumed('parent')\n const event: StreamEvent = { kind: 'thinking', text: ctx.delta, turnId: ctx.turnId }\n broadcast({ kind: 'event', sessionId, event })\n })\n\n /*\n * Subagent prose. `childId` + `depth` are what put the delta in the\n * child's lane in the transcript, and windows already key their stream\n * buffer on that owner — so these are the parent handlers above with the\n * owner threaded through, nothing more.\n *\n * Previously absent: the host forwarded child TOOL activity and spawn\n * markers but not child text, so in daemon mode a subagent's reasoning\n * and answer never streamed. It reappeared in one block whenever the\n * run-end `loadEvents` replace converged the transcript, which reads as\n * a stalled subagent for the whole run.\n */\n agent.hooks.hook('child:stream:text', (ctx) => {\n resumed(ctx.childId)\n const event: StreamEvent = {\n kind: 'markdown',\n text: ctx.delta,\n streaming: true,\n turnId: ctx.turnId,\n childId: ctx.childId,\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n }\n broadcast({ kind: 'event', sessionId, event })\n })\n\n agent.hooks.hook('child:stream:thinking', (ctx) => {\n resumed(ctx.childId)\n const event: StreamEvent = {\n kind: 'thinking',\n text: ctx.delta,\n turnId: ctx.turnId,\n childId: ctx.childId,\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n }\n broadcast({ kind: 'event', sessionId, event })\n })\n return retrying\n}\n\nexport function installRetryHooks({ sessionId, agent, broadcast }: AgentHookContext, retrying: Set<string>): void {\n /*\n * Provider retries — footer indicator in every window. `source` keys\n * the clear: the source's next delta (`resumed`, above), a terminal\n * stream failure (below), or the run end (busy backstop).\n */\n agent.hooks.hook('stream:retry', ({ nextAttempt, maxAttempts }) => {\n retrying.add('parent')\n broadcast({ kind: 'stream:retry', sessionId, attempt: nextAttempt, max: maxAttempts, source: 'parent' })\n })\n agent.hooks.hook('child:stream:retry', ({ nextAttempt, maxAttempts, childId }) => {\n retrying.add(childId)\n broadcast({ kind: 'stream:retry', sessionId, attempt: nextAttempt, max: maxAttempts, source: childId })\n })\n /*\n * Terminal stream failure clears that source's indicator. Windows also\n * clear at run end, but a SUBAGENT stream can fail while the parent run\n * continues — without this the \"retrying n/m\" chip sticks for the rest of\n * the run, describing a stream that is already dead.\n */\n agent.hooks.hook('stream:error', () => {\n retrying.delete('parent')\n broadcast({ kind: 'stream:retry:cleared', sessionId, source: 'parent' })\n })\n agent.hooks.hook('child:stream:error', ({ childId }) => {\n retrying.delete(childId)\n broadcast({ kind: 'stream:retry:cleared', sessionId, source: childId })\n })\n // Windows clear every indicator at run end; forget them here too, so an\n // aborted retry doesn't send a stray clear on the next run's first delta.\n agent.hooks.hook('agent:done', () => {\n retrying.clear()\n })\n}\n","/**\n * Tool calls as transcript rows: the `tool` card (with the edit payload, the\n * approval ledger's original intent winning), the results of calls that never\n * reach `tool:after` (gate block, invalid input, unknown tool), and the\n * `tool-result` rows, artifacts and todo refresh of the ones that do.\n */\nimport type { AgentHooks } from '../../../index'\nimport type { EditPayload, StreamEvent } from '../../types'\nimport type { EditOutcomeLedger } from '../edit-outcome-ledger'\nimport type { AgentHookContext } from '../types'\nimport type { WorkTracker } from '../work'\nimport { extractEditPayload } from '../../edit-diff'\nimport { stripSpawnTokensLine, toolCallPreview, toolResultText } from '../../store'\nimport { isTodoTool } from '../../todos'\n\n/**\n * Coerce a tool result (`string | ToolResultContent[]`) to plain text for\n * clients.\n */\nfunction resultToText(result: unknown): string {\n if (typeof result === 'string')\n return result\n try {\n return toolResultText(result as Parameters<typeof toolResultText>[0])\n }\n catch {\n return JSON.stringify(result)\n }\n}\n\nexport function installToolCardHooks(\n { sessionId, broadcast, agent }: AgentHookContext,\n input: {\n ledger: EditOutcomeLedger\n manuallyEmittedGateBlocks: Set<string>\n work: WorkTracker\n readPriorContent: (name: string, input: Record<string, unknown>) => Promise<string | undefined>\n },\n): { toolErrorMessages: Map<string, string> } {\n const { ledger, manuallyEmittedGateBlocks, readPriorContent } = input\n const { registerWork, dropWork } = input.work\n /**\n * Emit the canonical `tool` stream event. Centralized so `tool:before`\n * and `child:tool:before` route through identical logic.\n *\n * When the gate stashed a `PendingAnnotation` for this `callId`\n * (`partial` decision), the stashed `originalInput` / `originalPayload`\n * win over the live `ctx.input` — by `tool:before`, `ctx.input.edits`\n * has been REDUCED to the approved subset; the stash carries the\n * model's full intent so clients can paint every hunk with its badge.\n */\n const emitToolEvent = (\n callId: string,\n name: string,\n liveInput: Record<string, unknown>,\n priorContent: string | undefined,\n turnId: string | undefined,\n ownership?: { childId: string, depth: number },\n ): void => {\n const stashed = ledger.peek(callId)\n\n let inputForEvent: Record<string, unknown>\n let edit: EditPayload | undefined\n\n if (stashed) {\n inputForEvent = stashed.originalInput\n edit = { ...stashed.originalPayload, outcomes: stashed.outcomes.slice() }\n }\n else {\n inputForEvent = liveInput\n if (name === 'write_file')\n edit = extractEditPayload(name, liveInput, priorContent ?? '')\n else if (name === 'edit' || name === 'multi_edit')\n edit = extractEditPayload(name, liveInput, priorContent)\n }\n\n const event: StreamEvent = {\n kind: 'tool',\n text: toolCallPreview(name, inputForEvent),\n tool: name,\n callId,\n input: inputForEvent,\n ...(turnId ? { turnId } : {}),\n ...(ownership ? { childId: ownership.childId, depth: ownership.depth } : {}),\n ...(edit ? { edit } : {}),\n }\n broadcast({ kind: 'event', sessionId, event })\n }\n\n // Nested calls (`ToolContext.callTool`, codemode) never land in\n // `session.turns`, so a reload would not show them: keep live rows the same.\n agent.hooks.hook('tool:before', async (ctx) => {\n if (ctx.parentToolCallId !== undefined)\n return\n registerWork({ kind: 'tool', id: ctx.callId, label: ctx.name, startedAt: Date.now() })\n const input = ctx.input as Record<string, unknown>\n const priorContent = ctx.priorContent ?? await readPriorContent(ctx.name, input)\n emitToolEvent(ctx.callId, ctx.name, input, priorContent, ctx.turnId)\n })\n\n agent.hooks.hook('child:tool:before', (ctx) => {\n if (ctx.parentToolCallId !== undefined)\n return\n registerWork({\n kind: 'tool',\n id: ctx.callId,\n label: ctx.name,\n startedAt: Date.now(),\n childId: ctx.childId,\n })\n emitToolEvent(ctx.callId, ctx.name, ctx.input as Record<string, unknown>, ctx.priorContent, ctx.turnId, {\n childId: ctx.childId,\n depth: ctx.depth,\n })\n })\n\n /*\n * Calls that never reach `tool:after` still resolve live with the result\n * the loop persists, so the card reads the way it replays:\n * - gate-block: `Blocked: <reason>`;\n * - invalid-input: `Validation error: <reason>` (`validation:reject`);\n * - unknown tool: whatever `tool:unknown` substituted (parent calls\n * only; the hook doesn't bubble from children), else\n * `Tool error: <tool:error message>`, else (a hook suppressed the\n * error without substituting) `Tool error: Unknown tool: <name>`.\n * `tool:dispatched` fires last, so all of these are captured by then.\n * Gate-block and invalid-input calls get no `tool:before` either, so\n * their card is emitted here too; an unknown tool's came from\n * `tool:before`, and its work item ends here.\n */\n const unknownToolCalls = new Map<string, { result?: unknown }>()\n const toolErrorMessages = new Map<string, string>()\n const validationReasons = new Map<string, string>()\n agent.hooks.hook('tool:unknown', (ctx) => {\n unknownToolCalls.set(ctx.callId, ctx)\n })\n agent.hooks.hook('validation:reject', (ctx) => {\n validationReasons.set(ctx.callId, ctx.reason)\n })\n agent.hooks.hook('child:validation:reject', (ctx) => {\n validationReasons.set(ctx.callId, ctx.reason)\n })\n const undispatchedResult = (ctx: Parameters<AgentHooks['tool:dispatched']>[0]): { text: string, isError: boolean } | undefined => {\n const substituted = unknownToolCalls.get(ctx.callId)?.result\n const message = toolErrorMessages.get(ctx.callId)\n const invalid = validationReasons.get(ctx.callId)\n unknownToolCalls.delete(ctx.callId)\n toolErrorMessages.delete(ctx.callId)\n validationReasons.delete(ctx.callId)\n switch (ctx.outcome) {\n // The same error bit the loop puts on the persisted result; a gate\n // block reads as a plain result, as it always has.\n case 'unknown':\n if (substituted !== undefined)\n return { text: resultToText(substituted), isError: false }\n return { text: `Tool error: ${message ?? `Unknown tool: ${ctx.name}`}`, isError: true }\n case 'gate-block':\n return ctx.reason ? { text: `Blocked: ${ctx.reason}`, isError: false } : undefined\n case 'invalid-input':\n return invalid !== undefined ? { text: `Validation error: ${invalid}`, isError: true } : undefined\n default:\n return undefined\n }\n }\n const onDispatched = (\n ctx: Parameters<AgentHooks['tool:dispatched']>[0],\n ownership?: { childId: string, depth: number },\n ): void => {\n if (ctx.outcome === 'execute' || ctx.parentToolCallId !== undefined)\n return\n dropWork(ctx.callId)\n const manualGateBlock = ctx.outcome === 'gate-block' && manuallyEmittedGateBlocks.delete(ctx.callId)\n const result = undispatchedResult(ctx)\n if (manualGateBlock)\n return\n if (ctx.outcome !== 'unknown')\n emitToolEvent(ctx.callId, ctx.name, ctx.input as Record<string, unknown>, undefined, ctx.turnId, ownership)\n if (result === undefined)\n return\n const event: StreamEvent = {\n kind: 'tool-result',\n text: result.text,\n tool: ctx.name,\n callId: ctx.callId,\n ...(ctx.turnId ? { turnId: ctx.turnId } : {}),\n ...(ownership ? { childId: ownership.childId, depth: ownership.depth } : {}),\n ...(result.isError ? { isError: true as const } : {}),\n }\n broadcast({ kind: 'event', sessionId, event })\n }\n agent.hooks.hook('tool:dispatched', ctx => onDispatched(ctx))\n agent.hooks.hook('child:tool:dispatched', ctx => onDispatched(ctx, { childId: ctx.childId, depth: ctx.depth }))\n return { toolErrorMessages }\n}\n\nexport function installToolResultHooks(\n { sessionId, broadcast, agent }: AgentHookContext,\n input: {\n ledger: EditOutcomeLedger\n work: WorkTracker\n toolErrorMessages: Map<string, string>\n broadcastTodosSnapshot: (entry: { sessionId: string, agent: AgentHookContext['agent'] }) => void\n },\n): void {\n const { ledger, toolErrorMessages, broadcastTodosSnapshot } = input\n const { dropWork } = input.work\n /*\n * A tool result as the transcript shows it. A spawn's `Tokens: …` line\n * repeats the spawn-end marker right above it, and the reloaded row\n * (`eventsFromTurns`) drops it, so the live row does too.\n */\n const displayedResult = (tool: string, result: unknown): string => {\n const text = resultToText(result)\n return tool === 'spawn' ? stripSpawnTokensLine(text) : text\n }\n\n agent.hooks.hook('tool:after', (ctx) => {\n if (ctx.parentToolCallId !== undefined)\n return\n dropWork(ctx.callId)\n toolErrorMessages.delete(ctx.callId)\n const event: StreamEvent = {\n kind: 'tool-result',\n text: displayedResult(ctx.name, ctx.result),\n tool: ctx.name,\n callId: ctx.callId,\n turnId: ctx.turnId,\n ...(ctx.isError ? { isError: true as const } : {}),\n }\n broadcast({ kind: 'event', sessionId, event })\n /*\n * Todos state is mutated by `todowrite` (and sometimes refreshed by\n * `todoread`) — recompute + broadcast only when a todo tool fires.\n */\n if (isTodoTool(ctx.name))\n broadcastTodosSnapshot({ sessionId, agent })\n })\n\n // Artifacts (PRs / branches / commits / files) are already persisted by\n // the loop; the signal lets windows refresh badges and an open\n // artifacts rail live. Shared-session subagents bubble theirs as\n // `child:artifact:recorded`.\n agent.hooks.hook('artifact:recorded', (ctx) => {\n broadcast({ kind: 'artifact:recorded', sessionId, artifact: ctx.artifact })\n })\n agent.hooks.hook('child:artifact:recorded', (ctx) => {\n broadcast({ kind: 'artifact:recorded', sessionId, artifact: ctx.artifact })\n })\n\n agent.hooks.hook('child:tool:after', (ctx) => {\n if (ctx.parentToolCallId !== undefined)\n return\n dropWork(ctx.callId)\n toolErrorMessages.delete(ctx.callId)\n const event: StreamEvent = {\n kind: 'tool-result',\n text: displayedResult(ctx.name, ctx.result),\n tool: ctx.name,\n callId: ctx.callId,\n turnId: ctx.turnId,\n childId: ctx.childId,\n depth: ctx.depth,\n ...(ctx.isError ? { isError: true as const } : {}),\n }\n broadcast({ kind: 'event', sessionId, event })\n // Subagent todo writes route to a per-run slot via the same helper.\n if (isTodoTool(ctx.name))\n broadcastTodosSnapshot({ sessionId, agent })\n })\n\n agent.hooks.hook('tool:error', (ctx) => {\n dropWork(ctx.callId)\n /*\n * `tool:transform` doesn't fire on the throw path — drop any stash\n * entry so the Map doesn't leak past the run.\n */\n ledger.discard(ctx.callId)\n // No event of its own: `tool:after` follows with the error as the\n // tool's result, which is how the failure replays from the store. An\n // extra live `error` row here vanished on the run-end resync. The\n // exception, an unknown tool, resolves at `tool:dispatched`.\n if (ctx.parentToolCallId === undefined)\n toolErrorMessages.set(ctx.callId, ctx.error.message)\n })\n\n agent.hooks.hook('child:tool:error', (ctx) => {\n dropWork(ctx.callId)\n ledger.discard(ctx.callId)\n if (ctx.parentToolCallId === undefined)\n toolErrorMessages.set(ctx.callId, ctx.error.message)\n })\n\n agent.hooks.hook('tool:cancelled', (ctx) => {\n dropWork(ctx.callId)\n toolErrorMessages.delete(ctx.callId)\n })\n\n agent.hooks.hook('child:tool:cancelled', (ctx) => {\n dropWork(ctx.callId)\n toolErrorMessages.delete(ctx.callId)\n })\n}\n","/**\n * Turn-level signals: native server tools, prompt-turn refs, live progress\n * counters, and turn ends (parent and subagent).\n */\nimport type { AgentHookContext } from '../types'\nimport { serverToolResultSummary, toolCallPreview } from '../../store'\nimport { promptTurnRefs } from '../../turn-selection'\n\nexport function installTurnHooks({ sessionId, agent, broadcast }: AgentHookContext): void {\n /*\n * Native provider server tools (e.g. Anthropic `web_search`) execute\n * upstream and bypass the tool loop — surface them as the same\n * synthetic `tool` / `tool-result` events the local TUI and the\n * `eventsFromTurns` replay produce.\n */\n agent.hooks.hook('stream:server_tool_use', ({ id, name, input, turnId }) => {\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'tool', text: toolCallPreview(name, input), tool: name, input, callId: id, turnId },\n })\n })\n agent.hooks.hook('stream:server_tool_result', ({ toolUseId, toolName, content, turnId }) => {\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'tool-result', text: serverToolResultSummary(content), tool: toolName, callId: toolUseId, turnId },\n })\n })\n agent.hooks.hook('child:stream:server_tool_use', ({ id, name, input, childId, depth, turnId }) => {\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'tool', text: toolCallPreview(name, input), tool: name, input, callId: id, childId, depth, turnId },\n })\n })\n agent.hooks.hook('child:stream:server_tool_result', ({ toolUseId, toolName, content, childId, depth, turnId }) => {\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'tool-result', text: serverToolResultSummary(content), tool: toolName, callId: toolUseId, childId, depth, turnId },\n })\n })\n\n agent.hooks.hook('session:turns', ({ turns: appended }) => {\n const refs = promptTurnRefs(appended)\n if (refs.length > 0)\n broadcast({ kind: 'prompt-turns', sessionId, refs })\n })\n\n // Throttled by the loop — live footer counters, not a stream.\n agent.hooks.hook('stream:progress', ({ turnId, outputTokens, estimated, elapsedMs, estCostUsd }) => {\n broadcast({\n kind: 'stream:progress',\n sessionId,\n turnId,\n outputTokens,\n estimated,\n elapsedMs,\n ...(estCostUsd !== undefined ? { estCostUsd } : {}),\n })\n })\n\n agent.hooks.hook('turn:after', (ctx) => {\n broadcast({\n kind: 'turn:end',\n sessionId,\n turnId: ctx.turnId,\n ...(ctx.usage ? { usage: ctx.usage } : {}),\n })\n })\n\n // Child turns carry their own usage — clients accrue subagent spend\n // live (context gauges only track PARENT turns; cost tracks both).\n agent.hooks.hook('child:turn:after', (ctx) => {\n broadcast({\n kind: 'turn:end',\n sessionId,\n turnId: ctx.turnId,\n childId: ctx.childId,\n depth: ctx.depth,\n ...(ctx.usage ? { usage: ctx.usage } : {}),\n })\n })\n}\n","/**\n * Parent-level running work (cancellable tool calls, background tasks): the\n * per-build work map tracker, the background-task hooks with their exit\n * banner, the `work:snapshot` broadcast, and the running-work host methods.\n */\nimport type { ChatHost } from '../host-api'\nimport type { HostSignal, RunningWorkItem } from '../signals'\nimport type { ActiveRun, AgentHookContext } from '../types'\nimport { formatTaskSummary, previewLine } from '../../format'\n\nexport interface WorkTracker {\n registerWork: (item: RunningWorkItem) => void\n dropWork: (id: string) => void\n}\n\nexport function visibleWorkItems(entry: { work: Map<string, RunningWorkItem> }): RunningWorkItem[] {\n return [...entry.work.values()].filter(item => item.childId === undefined)\n}\n\nexport function broadcastWorkSnapshot(broadcast: (signal: HostSignal) => void, entry: { sessionId: string, work: Map<string, RunningWorkItem> }): void {\n broadcast({ kind: 'work:snapshot', sessionId: entry.sessionId, items: visibleWorkItems(entry) })\n}\n\nexport function createWorkTracker({ sessionId, broadcast }: Pick<AgentHookContext, 'sessionId' | 'broadcast'>, work: Map<string, RunningWorkItem>): WorkTracker {\n const registerWork = (item: RunningWorkItem): void => {\n work.set(item.id, item)\n broadcast({ kind: 'work:snapshot', sessionId, items: visibleWorkItems({ work }) })\n }\n\n const dropWork = (id: string): void => {\n if (!work.delete(id))\n return\n broadcast({ kind: 'work:snapshot', sessionId, items: visibleWorkItems({ work }) })\n }\n return { registerWork, dropWork }\n}\n\nexport function installBackgroundTaskHooks(\n { sessionId, agent, broadcast }: AgentHookContext,\n { work, tracker, maybeWake }: { work: Map<string, RunningWorkItem>, tracker: WorkTracker, maybeWake: (sessionId: string) => void },\n): void {\n const { registerWork, dropWork } = tracker\n const registerBackgroundTask = (ctx: { taskId: string, command: string, startedAt: number, childId?: string }): void => {\n registerWork({\n kind: 'task',\n id: ctx.taskId,\n label: `shell (background): ${previewLine(ctx.command, 60)}`,\n startedAt: ctx.startedAt,\n ...(ctx.childId ? { childId: ctx.childId } : {}),\n })\n }\n\n const dropBackgroundTaskAndEmitBanner = (ctx: {\n taskId: string\n status: 'exited' | 'killed'\n exitCode: number\n signal?: NodeJS.Signals\n outputPath: string\n durationMs: number\n command: string\n childId?: string\n depth?: number\n }): void => {\n dropWork(ctx.taskId)\n broadcast({\n kind: 'event',\n sessionId,\n event: {\n kind: 'task-notification',\n text: formatTaskSummary(ctx),\n task: {\n taskId: ctx.taskId,\n status: ctx.status,\n exitCode: ctx.exitCode,\n outputPath: ctx.outputPath,\n command: ctx.command,\n durationMs: ctx.durationMs,\n },\n ...(ctx.childId ? { childId: ctx.childId } : {}),\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n },\n })\n }\n\n agent.hooks.hook('background:start', ctx => registerBackgroundTask(ctx))\n // Still running from the previous agent on this session's handle.\n agent.hooks.hook('background:adopt', ctx => registerBackgroundTask(ctx))\n agent.hooks.hook('background:exit', (ctx) => {\n dropBackgroundTaskAndEmitBanner(ctx)\n // Idle-path delivery — a task that finished mid-run is delivered by\n // the run-end drain instead.\n maybeWake(sessionId)\n })\n agent.hooks.hook('background:reassign', (ctx) => {\n const existing = work.get(ctx.taskId)\n if (!existing)\n return\n work.set(ctx.taskId, { kind: 'task', id: existing.id, label: existing.label, startedAt: existing.startedAt })\n broadcast({ kind: 'work:snapshot', sessionId, items: visibleWorkItems({ work }) })\n })\n agent.hooks.hook('child:background:start', ctx => registerBackgroundTask(ctx))\n agent.hooks.hook('child:background:exit', ctx => dropBackgroundTaskAndEmitBanner(ctx))\n}\n\nexport function createWorkMethods(active: Map<string, ActiveRun>): Pick<ChatHost, 'listRunningWork' | 'cancelRunningWork'> {\n return {\n listRunningWork(sessionId) {\n const entry = active.get(sessionId)\n if (entry)\n entry.lastUsedAt = Date.now()\n return entry ? visibleWorkItems(entry) : []\n },\n\n async cancelRunningWork(sessionId, id, reason) {\n const entry = active.get(sessionId)\n if (!entry)\n return false\n entry.lastUsedAt = Date.now()\n\n const targets = id === 'all' ? visibleWorkItems(entry) : visibleWorkItems(entry).filter(item => item.id === id)\n let cancelled = false\n\n for (const item of targets) {\n if (item.kind === 'task')\n cancelled = (await entry.agent.killBackgroundTask(item.id)) || cancelled\n else\n cancelled = entry.agent.cancelTool(item.id, reason ?? 'user-cancelled-tool') || cancelled\n }\n\n return cancelled\n },\n }\n}\n","import type { ExecutionContext } from '../../../contexts/types'\n/**\n * The per-agent hook pipeline of `buildActiveRun`: every feature installer,\n * in the one order the host depends on.\n */\nimport type { Agent } from '../../../index'\nimport type { ApprovalHub } from '../approvals'\nimport type { EditOutcomeLedger } from '../edit-outcome-ledger'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { SessionLaunchOverrides } from '../launch-overrides'\nimport type { BuiltInSystem } from '../prompt'\nimport type { HostSignal, RunningWorkItem } from '../signals'\nimport type { TerminalManager } from '../terminal'\nimport type { ActiveRun, AgentHookContext, CommandSpawnSeam } from '../types'\nimport { installApprovalGate } from '../approval-gate'\nimport { installAutoCompactionHooks } from '../compaction'\nimport { installCwdHooks, isMovableCwd } from '../cwd'\nimport { createPriorContentReader, installEditAnnotationHooks, installRunBoundaryCleanup } from '../edits'\nimport { attachSessionMcpWarnLog, installMcpStatusHooks } from '../mcp'\nimport { broadcastSandboxWarning, installNotices, installRecoveryNotices, installRunEndNotice } from '../notices'\nimport { broadcastSystemMd } from '../prompt'\nimport { installSkillHooks } from '../skills'\nimport { broadcastTodosSnapshot } from '../todos'\nimport { installRetryHooks, installSpawnHooks, installStreamHooks, installToolCardHooks, installToolResultHooks, installTurnHooks } from '../transcript'\nimport { createWorkTracker, installBackgroundTaskHooks } from '../work'\n\nexport interface SessionHooksInput {\n sessionId: string\n agent: Agent\n broadcast: (signal: HostSignal) => void\n env: ChatHostEnvironment\n active: Map<string, ActiveRun>\n launchOverrides: Map<string, SessionLaunchOverrides>\n approvals: ApprovalHub\n terminals: TerminalManager\n artifactsDir: () => string\n maybeWake: (sessionId: string) => void\n cwd: string\n sessionFolder: string\n promptCwd: string | undefined\n executionContext: ExecutionContext\n builtInSystem: BuiltInSystem | null\n launch: SessionLaunchOverrides | undefined\n sandbox: { warning?: string }\n ledger: EditOutcomeLedger\n work: Map<string, RunningWorkItem>\n readSessionFile: (path: string) => Promise<string>\n sessionSafelist: Set<string>\n /** Captures the `/` command spawn seam; called at its place in the pipeline. */\n createCommandSeam: () => (() => CommandSpawnSeam) | undefined\n}\n\n/**\n * Install the feature hooks on a freshly created session agent. Returns what\n * the `ActiveRun` keeps from the pipeline, and the hook context for the hooks\n * installed after it exists.\n */\nexport function installSessionHooks(input: SessionHooksInput): {\n hookContext: AgentHookContext\n movableCwd: boolean\n commandSeam: (() => CommandSpawnSeam) | undefined\n warnLog: { close: () => Promise<void> }\n} {\n const { sessionId, agent, broadcast, env, active, launchOverrides, approvals, terminals, artifactsDir, maybeWake, cwd, sessionFolder, promptCwd, builtInSystem, launch, sandbox, ledger, work, readSessionFile, sessionSafelist } = input\n /*\n * ---- Per-agent hooks ---------------------------------------------------\n * Installed in the original registration order: handlers of the same\n * event (`agent:done`, `session:turns`) run in registration order, and\n * library installers (MCP tools cache, cache-break logger, MCP warn log,\n * `instrumentAgent`) precede the host's own handlers of their events.\n */\n const hookContext: AgentHookContext = { sessionId, agent, broadcast }\n const movableCwd = isMovableCwd(promptCwd, input.executionContext)\n installCwdHooks(hookContext, {\n active,\n launchOverrides,\n cwd,\n sessionFolder,\n movableCwd,\n builtInPrompt: builtInSystem !== null && launch?.system === undefined,\n })\n const emitNotice = installNotices(hookContext)\n broadcastSystemMd(hookContext, builtInSystem)\n broadcastSandboxWarning(hookContext, sandbox)\n\n const commandSeam = input.createCommandSeam()\n const warnLog = attachSessionMcpWarnLog(agent, artifactsDir(), sessionId)\n\n const retrying = installStreamHooks(hookContext)\n const manuallyEmittedGateBlocks = new Set<string>()\n const workTracker = createWorkTracker(hookContext, work)\n const readPriorContent = createPriorContentReader(agent)\n const { toolErrorMessages } = installToolCardHooks(hookContext, { ledger, manuallyEmittedGateBlocks, work: workTracker, readPriorContent })\n installEditAnnotationHooks(agent, ledger)\n installToolResultHooks(hookContext, {\n ledger,\n work: workTracker,\n toolErrorMessages,\n broadcastTodosSnapshot: entry => broadcastTodosSnapshot(broadcast, entry),\n })\n installBackgroundTaskHooks(hookContext, { work, tracker: workTracker, maybeWake })\n installRunBoundaryCleanup(agent, { ledger, manuallyEmittedGateBlocks })\n installRunEndNotice(agent, emitNotice)\n installApprovalGate(hookContext, {\n env,\n approvals,\n terminals,\n cwd,\n readSessionFile,\n sessionSafelist,\n ledger,\n manuallyEmittedGateBlocks,\n })\n installSpawnHooks(hookContext, emitNotice)\n installSkillHooks(hookContext)\n installMcpStatusHooks(hookContext)\n installRetryHooks(hookContext, retrying)\n installTurnHooks(hookContext)\n installAutoCompactionHooks(hookContext, emitNotice)\n installRecoveryNotices(hookContext, emitNotice)\n\n return { hookContext, movableCwd, commandSeam, warnLog }\n}\n","import type { Preset } from '../../../presets'\nimport type { AgentProfile } from '../../agents'\nimport type { ResolvedConfig } from '../../config'\nimport type { DiscoveredPlugin } from '../../plugins-discovery'\nimport type { HostSettings } from '../signals'\nimport { filterRegistryPlugins } from '../../../extensions'\nimport { artifactsPreset, composeExtensionPreset, composePresets, withIsolatedSpawnTool } from '../../../index'\nimport { applyMarkdownSubagents, loadMarkdownAgents } from '../../../markdown-defs'\nimport { hostDebug } from '../debug'\n\n/** The live extension registry (plugin-gated) and the preset the agent is composed from. */\nexport function composeSessionPreset({ settings, runtimeConfig, profile, pluginCatalog }: {\n settings: HostSettings\n runtimeConfig: ResolvedConfig\n profile: AgentProfile\n pluginCatalog: readonly DiscoveredPlugin[]\n}) {\n /*\n * Second plugin gate. `enabledExtensions` (applied by whoever built this\n * registry) drops whole extensions; this drops the contributions of\n * plugins an extension pulled in via `ctx.loadAgentPlugin`. Both are\n * needed because plugin skills / servers are fanned into the LOADING\n * extension's sinks, so filtering by extension name alone cannot express\n * \"this extension runs, but the plugin it pulled in does not\" — without\n * this pass a plugin the user explicitly switched off still contributed\n * skills and still had its stdio MCP servers configured, which makes\n * `enabledPlugins` a consent gate that only the TUI honoured.\n *\n * The third argument keeps this in step with the settings list, which\n * dedupes a plugin present both on disk and inside an extension to a\n * single row preferring the disk copy — otherwise that one checkbox\n * governs two live copies and which one survives is decided by merge\n * order rather than by anything the user chose.\n */\n const liveExtensions = filterRegistryPlugins(\n runtimeConfig.extensions,\n settings.enabledPlugins,\n new Set(pluginCatalog.map(p => p.name)),\n )\n // Built-in artifact detection (PRs / branches / commits) + the\n // `record_artifact` tool compose UNDER the profile so hosts get them\n // without touching `basic`; extension-registered kinds ride the\n // registry's hooks. `Settings.artifacts` off drops the preset entirely\n // (no detectors, no tool) and the agent-level switch below silences the\n // loop for anything an extension might still emit.\n const artifactsEnabled = settings.artifacts !== false\n const composedPreset = withIsolatedSpawnTool(composeExtensionPreset(\n liveExtensions,\n artifactsEnabled ? composePresets(artifactsPreset, profile.preset) : profile.preset,\n ))\n return { liveExtensions, artifactsEnabled, composedPreset }\n}\n\n/**\n * Markdown + builtin subagents fill the spawn registry's gaps AFTER\n * composition: extension agents keep their names (builtin < file <\n * extension). Separate from `composeSessionPreset` because Claude model\n * aliases (`sonnet`, `haiku`) resolve against the session's provider.\n */\nexport function withMarkdownSubagents(preset: Preset, { cwd, prefix, settings, providerKey }: {\n cwd: string\n prefix: string | undefined\n settings: HostSettings\n providerKey: string\n}): Preset {\n const markdownAgents = loadMarkdownAgents({\n cwd,\n prefix,\n includeForeign: settings.importForeignConfigs === true,\n modelContext: { parentProvider: providerKey },\n })\n for (const d of markdownAgents.diagnostics)\n hostDebug('markdown subagent', d.path, d.message)\n return applyMarkdownSubagents(preset, markdownAgents.subagents)\n}\n","/**\n * Delivery: a worker event is displayed on the main at once and buffered for\n * the model until the main is idle, then flushed as `user` turns (and a wake).\n */\nimport type { SessionTurn } from '../../../types'\nimport type { SessionEvent } from '../../orchestration'\nimport type { OrchestrationState } from './state'\nimport type { OrchestrationDeps } from './types'\nimport { randomUUID } from 'node:crypto'\nimport { loadSession } from '../../../session/index'\nimport { renderSessionEventXml, sessionEventLabel } from '../../orchestration'\n\n/**\n * How long to wait for a burst of worker events to settle before waking the\n * main. Short enough to feel immediate, long enough that several workers\n * finishing together cost one run instead of one each.\n */\nconst FLUSH_DEBOUNCE_MS = 150\n\nexport function createDelivery(deps: OrchestrationDeps, state: OrchestrationState) {\n // ---------------------------------------------------------------------------\n // Delivery\n // ---------------------------------------------------------------------------\n\n const nextSeq = (main: string): number => {\n const n = (state.seqByMain.get(main) ?? 0) + 1\n state.seqByMain.set(main, n)\n return n\n }\n\n /**\n * `wake` = start a run so the model reacts now. True for the main's OWN\n * workers and for anything blocked on a decision; false for an ordinary\n * session finishing, which is appended as context and read on the main's\n * next natural turn. Waking on every unrelated chat would cost a run each\n * time the human finishes a conversation somewhere else.\n */\n function deliver(main: string, rawEvent: SessionEvent, wake: boolean): void {\n const event: SessionEvent = { ...rawEvent, seq: nextSeq(main) }\n // 1. Display, now. A pure transcript row — nothing here touches the\n // model's generation, so this is safe mid-stream by construction.\n deps.broadcast({\n kind: 'event',\n sessionId: main,\n event: { kind: 'session-event', text: sessionEventLabel(event), sessionEvent: event },\n })\n // 2. Context, at the boundary.\n const queue = state.pending.get(main) ?? []\n queue.push({ event, wake })\n state.pending.set(main, queue)\n scheduleFlush(main)\n }\n\n /** Coalesce a burst of events into one wake run. */\n function scheduleFlush(main: string): void {\n if (state.flushTimers.has(main))\n return\n const timer = setTimeout(() => {\n state.flushTimers.delete(main)\n void flush(main)\n }, FLUSH_DEBOUNCE_MS)\n // Never let a pending debounce hold the process open — this is a\n // best-effort coalesce, not work the runtime must wait for.\n timer.unref?.()\n state.flushTimers.set(main, timer)\n }\n\n async function flush(main: string): Promise<void> {\n if (state.flushing.has(main) || deps.isRunning(main))\n return\n const events = state.pending.get(main)\n if (!events || events.length === 0)\n return\n state.flushing.add(main)\n state.pending.delete(main)\n /*\n * Set the moment the turns are durably appended — NOT when the wake run\n * succeeds. Once appended they are in the session's history, so a failed\n * wake only delays when the model reads them; requeueing at that point\n * would append the same events twice.\n */\n let appended = false\n try {\n /*\n * Write to the live agent's `Session` when one is hosted — the same\n * invariant as todos: the model reads the instance the agent holds, and\n * a store-level write behind it would be overwritten by the next save.\n * Idle-with-no-agent falls back to the store, which the next `sendPrompt`\n * builds an agent from.\n */\n const live = deps.liveSession(main)\n const session = live ?? await loadSession(deps.store, main)\n if (!session)\n return\n /*\n * Re-check AFTER the awaits above. The guard at the top of this function\n * is stale by now: a user prompt can start a run while we were loading,\n * and appending a user turn into a mid-run session is precisely the\n * malformed-conversation case this buffering exists to prevent (a user\n * turn landing between an assistant `tool_call` and its `tool_result`).\n * Yield — the run-end edge will flush.\n */\n if (deps.isRunning(main))\n return\n const now = Date.now()\n const turns: SessionTurn[] = events.map(({ event }, i) => ({\n id: randomUUID(),\n role: 'user',\n createdAt: now + i,\n content: [{ type: 'text', text: renderSessionEventXml(event) }],\n }))\n await session.appendTurns(turns)\n /*\n * Persist unconditionally. Writing through the LIVE session keeps the\n * model reading the instance the agent holds, but it does not make the\n * turns durable — and a batch with nothing to wake for (the\n * human-started-session-finished case) starts no run, so nothing else\n * would ever save them. An idle teardown or a model-change rebuild\n * between now and the main's next run would drop the events silently,\n * and unlike the requeue below there would be nothing left to recover.\n */\n await session.save()\n appended = true\n /*\n * Wake only when something in the batch warrants a reaction (own worker,\n * or a session blocked on a decision). Otherwise the turns sit as context\n * for the main's next natural turn. Empty prompt + trailing user turn =\n * the designed wake path; the `user-prompt` echo is suppressed since the\n * `session-event` row already painted in `deliver`.\n *\n * `deps.wake` may decline (the user pressed esc on the main, or a queued\n * message is about to drain). That is fine and deliberate: the turns are\n * already appended and saved above, so declining only delays when the\n * model reads them — the same fallback as a batch with nothing to wake\n * for. Starting a run against an explicit stop would be the worse bug.\n */\n if (events.some(e => e.wake))\n await deps.wake(main)\n }\n catch {\n // Swallowed deliberately: callers invoke this as `void flush(...)`, so a\n // rejection here would be an unhandled rejection. Recovery is the\n // requeue in `finally`, which also covers the early returns above.\n }\n finally {\n /*\n * Every non-delivering exit path restores the buffer — the `!session`\n * and mid-run returns as well as a throw. Dropping an event silently is\n * the one outcome worse than delivering it late, and an early `return`\n * walks around a `catch`.\n */\n if (!appended) {\n const again = state.pending.get(main) ?? []\n state.pending.set(main, [...events, ...again])\n }\n state.flushing.delete(main)\n }\n }\n\n return { deliver, flush }\n}\n\nexport type Delivery = ReturnType<typeof createDelivery>\n","/**\n * Who is who: the feature gate, the main (found, cached, or created), session\n * metadata and lineage, and where a session's events report.\n */\nimport type { OrchestrationState } from './state'\nimport type { OrchestrationDeps } from './types'\nimport { loadSession } from '../../../session/index'\nimport { isMainSession, MAIN_SESSION_TITLE, orchestratedBy, SESSION_ROLE_KEY } from '../../orchestration'\n\nexport interface ScanRow { id: string, metadata: Record<string, unknown>, updatedAt: number, turns: number, projectRoot?: string }\n\nexport function createDirectory(deps: OrchestrationDeps, state: OrchestrationState) {\n const enabled = (): boolean => deps.readSettings().orchestration === true\n\n /**\n * The feature gate, on every verb and not just on discovery.\n *\n * `mainId` / `ensureMain` returning `null` while the setting is off is not\n * enough: the main is PERSISTED, so its id survives the toggle, and anything\n * holding it (resume-on-launch, an IPC client, an extension) could otherwise\n * still spawn sessions and start runs that cost money — with no events\n * delivered, since `onSignal` bails. Off means off for every caller.\n */\n function requireEnabled(): void {\n if (!enabled())\n throw new Error('orchestration is disabled')\n }\n\n /**\n * The CALLER check, shared by every verb that takes a `mainId`. That id\n * arrives over the wire, so an unchecked one would make orchestration an\n * open remote-control API for any client that guesses a session id.\n */\n async function requireMainCaller(main: string): Promise<void> {\n requireEnabled()\n if (!isMainSession((await metadataOf(main)) ?? undefined))\n throw new Error('only a main session may orchestrate')\n }\n\n async function metadataOf(sessionId: string): Promise<Record<string, unknown> | null> {\n const live = deps.liveSession(sessionId)\n if (live)\n return live.metadata\n const data = await deps.store.load(sessionId)\n return data?.metadata ?? null\n }\n\n async function mainOf(sessionId: string): Promise<string | null> {\n if (state.lineage.has(sessionId))\n return state.lineage.get(sessionId)!\n const meta = await metadataOf(sessionId)\n const main = orchestratedBy(meta ?? undefined)\n state.lineage.set(sessionId, main)\n return main\n }\n\n /**\n * Where a session's events go. EVERY non-main session reports to the main —\n * the main is an observer of the whole store, not only of the sessions it\n * created — so a chat the human runs elsewhere still shows up in the main's\n * history. Returns `null` for the main itself and for unknown ids.\n */\n async function reportsTo(sessionId: string): Promise<{ main: string, worker: boolean, wake: boolean } | null> {\n const main = await mainId()\n if (!main || sessionId === main)\n return null\n const meta = await metadataOf(sessionId)\n if (!meta || isMainSession(meta))\n return null\n const worker = (await mainOf(sessionId)) === main\n return { main, worker, wake: state.wakePolicy.get(sessionId) ?? worker }\n }\n\n /**\n * Every session's `{ id, metadata }`.\n *\n * Prefers the store's indexed metadata query — one round-trip on sqlite —\n * because the fan-out alternative materializes the FULL turn history of\n * every session on disk, and `list()` runs this on every `sessions list`\n * the model issues. Degrades to the fan-out when the store has no index or\n * the index throws, mirroring how `listSessionMeta` degrades.\n *\n * Live metadata wins over the stored row: an agent that has set\n * `orchestratedBy` but not yet saved is still a worker.\n */\n async function scan(): Promise<ScanRow[]> {\n if (deps.store.listMeta) {\n try {\n const rows = await deps.store.listMeta()\n return rows.map((row) => {\n const live = deps.liveSession(row.id)\n return {\n id: row.id,\n // Live wins: an agent that has set a pointer but not yet saved is\n // still a worker.\n metadata: live?.metadata ?? row.metadata,\n updatedAt: row.updatedAt,\n turns: live?.turns.length ?? row.turnCount,\n ...(row.projectRoot !== undefined ? { projectRoot: row.projectRoot } : {}),\n }\n })\n }\n catch {\n // Fall through to the fan-out below.\n }\n }\n const ids = await deps.store.list()\n const rows = await Promise.all(ids.map(async (id): Promise<ScanRow | null> => {\n const live = deps.liveSession(id)\n if (live)\n return { id, metadata: live.metadata, updatedAt: Date.now(), turns: live.turns.length, ...(live.projectRoot !== undefined ? { projectRoot: live.projectRoot } : {}) }\n const data = await deps.store.load(id)\n return data ? { id, metadata: data.metadata, updatedAt: data.updatedAt, turns: data.turns.length, ...(data.projectRoot !== undefined ? { projectRoot: data.projectRoot } : {}) } : null\n }))\n return rows.filter((r): r is ScanRow => r !== null)\n }\n\n async function mainId(): Promise<string | null> {\n if (!enabled())\n return null\n if (state.cachedMain !== undefined)\n return state.cachedMain\n const found = (await scan()).find(row => isMainSession(row.metadata))\n state.cachedMain = found?.id ?? null\n return state.cachedMain\n }\n\n async function ensureMain(): Promise<string | null> {\n if (!enabled())\n return null\n if (state.creating)\n return state.creating\n /*\n * Assigned with no `await` between the check above and the assignment\n * below, so a second caller on this event-loop turn cannot slip past.\n */\n const inflight = (async (): Promise<string | null> => {\n const existing = await mainId()\n if (existing) {\n await unbindMainFromProject(existing)\n return existing\n }\n // Directory-less: no cwd, no project. See `createMainSession` for why.\n const id = await deps.createSession({ cwd: '', title: MAIN_SESSION_TITLE })\n const session = await loadSession(deps.store, id)\n if (!session)\n throw new Error(`main session ${id} vanished after creation`)\n session.setMeta(SESSION_ROLE_KEY, 'main')\n await session.save()\n state.cachedMain = id\n // `create`, not `update`: clients have never seen this id, and a list that\n // only appends on `create` would otherwise never show the main until reload.\n deps.broadcast({ kind: 'sessions:changed', op: 'create', sessionId: id })\n return id\n })()\n state.creating = inflight\n try {\n return await inflight\n }\n finally {\n state.creating = undefined\n }\n }\n\n /**\n * One-time repair for mains created before they were directory-less: clear\n * the recorded cwd and drop the project so the row moves to the \"Chats\"\n * bucket. Store-level, so only while no agent is live for it — the live\n * `Session` would overwrite a behind-its-back write on its next save.\n */\n async function unbindMainFromProject(main: string): Promise<void> {\n if (deps.liveSession(main))\n return\n const data = await deps.store.load(main)\n if (!data)\n return\n const cwd = data.metadata.cwd\n if ((typeof cwd !== 'string' || cwd === '') && data.projectRoot === undefined)\n return\n data.metadata.cwd = ''\n delete data.projectRoot\n await deps.store.save(data)\n deps.broadcast({ kind: 'sessions:changed', op: 'update', sessionId: main })\n }\n\n return { enabled, requireEnabled, requireMainCaller, metadataOf, mainOf, reportsTo, scan, mainId, ensureMain }\n}\n\nexport type Directory = ReturnType<typeof createDirectory>\n","import type { SessionRun } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { SessionEvent } from '../../orchestration'\nimport type { HostSignal } from '../signals'\n\n/**\n * The receipt for one run, read off the persisted run RECORD — the loop already\n * totals turns / tokens / cost there, so this is exact and needs no rescan of\n * the transcript.\n *\n * `run:end` is broadcast a beat before the record is finalized, so the record\n * may still be `running` with no `endedAt` when this runs: fall back to the\n * turn-level usage the loop has already attached, and to \"now\" for the end\n * time (the run IS ending). Every cell is omitted rather than zeroed when\n * genuinely unknown — a `0 tok` cell is a claim, and an untrue one.\n */\nexport function runMetrics(\n data: { runs: readonly SessionRun[], turns: readonly SessionTurn[] },\n now: number,\n): Pick<SessionEvent, 'durationMs' | 'tokens' | 'turns' | 'costUsd'> {\n /*\n * The latest TOP-LEVEL record, not a lookup by the signal's `runId`: the host\n * mints its own UUID for `run:end` bookkeeping while the session records the\n * agent's `run_N`, so they never match.\n *\n * `depth === 0` is load-bearing, not defensive. Subagent runs are pushed onto\n * the SAME `runs` array (`agent.ts:4440` → `session.startRun`), and a child\n * starts after its parent — so at the parent's run end `at(-1)` is the most\n * recently started CHILD. Taking it made a long delegating run report its\n * last subagent's duration, tokens and cost instead of its own. `depth` is\n * always numeric (the loop defaults it to 0), but `?? 0` keeps records\n * written before that default readable.\n */\n const run = data.runs.filter(r => (r.depth ?? 0) === 0).at(-1)\n if (!run)\n return {}\n const runTurns = data.turns.filter(t => t.runId === run.id)\n const usage = run.totalUsage\n ?? run.turnUsage?.reduce((acc, u) => ({ input: acc.input + u.input, output: acc.output + u.output }), { input: 0, output: 0 })\n const tokens = usage\n ? usage.input + usage.output\n : runTurns.reduce((n, t) => n + (t.usage ? t.usage.input + t.usage.output : 0), 0)\n const turns = run.turns ?? runTurns.length\n const durationMs = (run.endedAt ?? now) - run.startedAt\n const cost = run.cost ?? run.turnUsage?.reduce((n, u) => n + (u.cost ?? 0), 0) ?? 0\n return {\n ...(durationMs > 0 ? { durationMs } : {}),\n ...(tokens > 0 ? { tokens } : {}),\n ...(turns > 0 ? { turns } : {}),\n ...(cost > 0 ? { costUsd: cost } : {}),\n }\n}\n\n/**\n * What a blocked session is asking, in one line. This is often enough for the\n * main to answer without opening the transcript — which is the point of\n * shipping it on the event instead of making the main call `read`.\n */\nexport function attentionDetail(signal: Extract<HostSignal, { kind: 'approval:request' | 'interaction:request' }>): string | undefined {\n if (signal.kind === 'approval:request') {\n const r = signal.request\n const target = r.edit?.path ?? (typeof r.input?.command === 'string' ? r.input.command : undefined)\n return target ? `approve ${r.tool}: ${truncate(target, 160)}` : `approve ${r.tool}`\n }\n const req = signal.request\n if (req.kind === 'plan')\n return `review plan: ${truncate(req.payload.title, 160)}`\n if (req.kind === 'question') {\n const first = req.payload.questions[0]\n const lead = req.payload.intro ?? first?.prompt\n return lead ? `question: ${truncate(lead, 160)}` : 'question'\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// Small projections\n// ---------------------------------------------------------------------------\n\nexport function titleOf(metadata: Record<string, unknown> | undefined, fallback: string): string {\n const title = metadata?.title\n return typeof title === 'string' && title.trim() ? title : fallback\n}\n\nexport function cwdOf(metadata: Record<string, unknown> | undefined): string {\n const cwd = metadata?.cwd\n return typeof cwd === 'string' ? cwd : ''\n}\n\nexport function assistantText(turn: SessionTurn): string {\n return turn.content\n .filter((b): b is { type: 'text', text: string } => b.type === 'text')\n .map(b => b.text)\n .join('\\n')\n .trim()\n}\n\nexport function truncate(text: string, max: number): string {\n return text.length <= max ? text : `${text.slice(0, max - 1)}…`\n}\n","/**\n * The single observation seam: how orchestration learns that a session's run\n * ended, that it is blocked on a decision, or that sessions came and went.\n */\nimport type { HostSignal } from '../signals'\nimport type { Delivery } from './delivery'\nimport type { Directory } from './directory'\nimport type { OrchestrationState } from './state'\nimport type { OrchestrationDeps, WorkerSummary } from './types'\nimport { artifactsFromTurns } from '../../orchestration'\nimport { attentionDetail, runMetrics, truncate } from './projections'\n\nexport function createSignalObserver(\n deps: OrchestrationDeps,\n state: OrchestrationState,\n directory: Pick<Directory, 'enabled' | 'reportsTo'>,\n delivery: Delivery,\n read: (sessionId: string) => Promise<WorkerSummary | null>,\n): (signal: HostSignal) => void {\n const { enabled, reportsTo } = directory\n const { deliver, flush } = delivery\n\n return function onSignal(signal: HostSignal): void {\n // Every streamed delta passes here, and `enabled()` reads the settings\n // (from disk on the daemon): only the kinds below may pay for it.\n switch (signal.kind) {\n case 'run:end': {\n if (!enabled())\n return\n void (async () => {\n // Whatever this worker was blocked on is resolved or gone; let a\n // future block re-report.\n state.flagged.delete(signal.sessionId)\n // A main going idle is the flush edge for its buffered events.\n if (state.pending.has(signal.sessionId)) {\n await flush(signal.sessionId)\n return\n }\n const target = await reportsTo(signal.sessionId)\n if (!target)\n return\n // The assignment applied to the run that just ended; drop it so the\n // next run falls back to the default rule (see `wakePolicy`).\n state.wakePolicy.delete(signal.sessionId)\n const summary = await read(signal.sessionId)\n const now = Date.now()\n const data = deps.liveSession(signal.sessionId) ?? await deps.store.load(signal.sessionId)\n const metrics = data ? runMetrics(data, now) : {}\n /*\n * The run that just ended is the session's latest top-level record.\n * From it: the prompt that STARTED it (the goal — pairs with the\n * last message so the main can judge whether the run did what was\n * asked), the abnormal finish reason if any, and what the run\n * touched. All read off persisted data; nothing is inferred.\n */\n const record = data ? [...data.runs].reverse().find(r => r.parentRunId === undefined) : undefined\n const runTurns = record && data ? data.turns.filter(t => t.runId === record.id) : []\n const lastAssistant = [...runTurns].reverse().find(t => t.role === 'assistant')\n const finish = lastAssistant?.usage?.finishReason\n const artifacts = artifactsFromTurns(runTurns)\n deliver(target.main, {\n sessionId: signal.sessionId,\n title: summary?.title ?? signal.sessionId,\n status: signal.ok ? 'done' : 'error',\n summary: signal.ok\n ? (summary?.lastMessage ?? 'finished with no message')\n : `failed: ${signal.error ?? 'unknown error'}`,\n at: now,\n worker: target.worker,\n // Always present: '' means directory-less, which the main must be\n // able to tell apart from \"not reported\".\n cwd: summary?.cwd ?? '',\n ...(record?.prompt ? { goal: truncate(record.prompt, 300) } : {}),\n ...(finish === 'length' || finish === 'pause' || finish === 'content-filter' ? { finishReason: finish } : {}),\n ...(artifacts ? { artifacts } : {}),\n ...(!signal.ok && signal.error ? { error: signal.error } : {}),\n ...metrics,\n }, target.wake)\n })()\n return\n }\n case 'approval:request':\n case 'interaction:request': {\n if (!enabled())\n return\n const sessionId = signal.kind === 'approval:request' ? signal.request.sessionId : signal.sessionId\n const detail = attentionDetail(signal)\n // Shape key: identical requests collapse, a different question does not.\n const key = detail ?? signal.kind\n if (state.flagged.get(sessionId)?.has(key))\n return\n void (async () => {\n const target = await reportsTo(sessionId)\n if (!target)\n return\n // Record only once we know it reports somewhere, so the main's own\n // approvals never occupy the map. Re-checked after the await.\n const seen = state.flagged.get(sessionId) ?? new Set<string>()\n if (seen.has(key))\n return\n seen.add(key)\n state.flagged.set(sessionId, seen)\n const summary = await read(sessionId)\n // A blocked session always wakes the main: someone has to decide.\n deliver(target.main, {\n sessionId,\n title: summary?.title ?? sessionId,\n status: 'needs-attention',\n summary: signal.kind === 'approval:request'\n ? `waiting for approval: ${signal.request.tool}`\n : 'waiting for a decision',\n ...(detail ? { detail } : {}),\n at: Date.now(),\n worker: target.worker,\n ...(summary?.cwd ? { cwd: summary.cwd } : {}),\n }, true)\n })()\n return\n }\n // Not gated: forgetting a deleted session is cheap and must happen even\n // after the feature was switched off with entries still held.\n case 'sessions:changed': {\n if (signal.op === 'delete') {\n state.lineage.delete(signal.sessionId)\n state.wakePolicy.delete(signal.sessionId)\n state.pending.delete(signal.sessionId)\n state.flagged.delete(signal.sessionId)\n const timer = state.flushTimers.get(signal.sessionId)\n if (timer) {\n clearTimeout(timer)\n state.flushTimers.delete(signal.sessionId)\n }\n if (state.cachedMain === signal.sessionId)\n state.cachedMain = undefined\n }\n /*\n * \"No main exists\" must NOT be cached across a session appearing.\n * A `null` here is a snapshot of the store at one instant, and another\n * writer can mint the main behind our back — the TUI creates one\n * locally through `createMainSession` whenever it has no daemon\n * connection yet, with the setting already on. Keeping the `null` then\n * makes `reportsTo` deliver nothing and the next `ensureMain` mint a\n * SECOND `role: 'main'` session, which is exactly the pin/jump\n * divergence the single-flight lock exists to avoid. A positive id is\n * left alone: the main's id is stable for the store's lifetime.\n */\n else if (state.cachedMain === null) {\n state.cachedMain = undefined\n }\n break\n }\n default:\n break\n }\n }\n}\n","/**\n * Orchestration's mutable state: lineage and wake caches, buffered events and\n * their flush bookkeeping, attention flags, and the cached / in-flight main.\n * One object, so every part reads it live.\n */\nimport type { SessionEvent } from '../../orchestration'\n\nexport interface OrchestrationState {\n /**\n * Worker → main lineage, cached. Populated on `createWorker` and lazily on\n * first sight of an unknown session (a worker created before a daemon\n * restart). `null` = \"looked up, not a worker\" so ordinary sessions cost one\n * store read, ever.\n */\n lineage: Map<string, string | null>\n /** Events waiting for their main to go idle. */\n pending: Map<string, Array<{ event: SessionEvent, wake: boolean }>>\n /** Flush in flight per main — a second signal must not double-append. */\n flushing: Set<string>\n /** Per-main event sequence — dedup / gap detection for consumers. Restarts with the process; monotonic within it. */\n seqByMain: Map<string, number>\n /**\n * Per session, the `needs-attention` requests already reported during the\n * current run — keyed by the request's SHAPE (see `attentionDetail`), and\n * cleared on that session's `run:end`.\n *\n * Keyed rather than a bare session flag because both failure modes matter. A\n * worker in safe mode delivers one request per tool call, so a per-request\n * key would turn twenty approvals into twenty wake RUNS on the main for a\n * condition that has not changed; but a bare per-SESSION flag went too far\n * the other way, swallowing a genuinely different question asked later in\n * the same run. Same question twice stays quiet; a different one reports.\n */\n flagged: Map<string, Set<string>>\n /**\n * Debounce timers per main. Bursts (several workers finishing at once, or a\n * worker emitting several requests) coalesce into ONE wake run instead of\n * one per event. Only the idle path needs this — while the main is running,\n * buffering already batches.\n */\n flushTimers: Map<string, ReturnType<typeof setTimeout>>\n /**\n * Wake preference for the NEXT run of a session, written by the main's\n * `create` / `send` and CONSUMED when that run ends (see the `run:end`\n * branch). One assignment, one wake: left in place it would outlive the run\n * it described, so a session the human also drives would keep waking the\n * main for turns the main never asked for.\n *\n * In-memory on purpose: it describes the main's current assignment, which is\n * meaningless after a daemon restart (the run it referred to is gone), and\n * writing it into a live session's metadata would race the agent's saves.\n * Absent = the default rule: own workers wake, other sessions only report.\n */\n wakePolicy: Map<string, boolean>\n /**\n * Cached once found: the main's id is stable for the store's lifetime, and\n * `store.list()` returns ids only, so discovery is a load per session.\n * `undefined` = not looked up yet; `null` = looked up, none exists.\n */\n cachedMain: string | null | undefined\n /**\n * In-flight `ensureMain`, so overlapping callers share one creation.\n *\n * Reachable in practice: the GUI fires its on-enable effect and the user can\n * hit the jump chord right behind it, and under a daemon a GUI and a TUI\n * both call `orchestration.main`. Without this both see \"no main\", both\n * create one, and the store ends up with two sessions tagged `role: 'main'`\n * — after which `mainId()` resolves to whichever `scan()` returns first, so\n * the pin and the jump can disagree and events route to an arbitrary one.\n */\n creating: Promise<string | null> | undefined\n}\n\nexport function createOrchestrationState(): OrchestrationState {\n return {\n lineage: new Map(),\n pending: new Map(),\n flushing: new Set(),\n seqByMain: new Map(),\n flagged: new Map(),\n flushTimers: new Map(),\n wakePolicy: new Map(),\n cachedMain: undefined,\n creating: undefined,\n }\n}\n","/**\n * The main's verbs over other sessions: create a worker, list, projects,\n * read, send, steer, cancel, transcript — each behind the gate and the\n * caller / target checks.\n */\nimport type { ProjectBrief } from '../../orchestration'\nimport type { Delivery } from './delivery'\nimport type { Directory } from './directory'\nimport type { OrchestrationState } from './state'\nimport type { CreateWorkerParams, OrchestrationDeps, WorkerRow, WorkerSummary } from './types'\nimport { loadSession } from '../../../session/index'\nimport { unwrapCallTool } from '../../../tools/call-tool'\nimport { isMainSession, ORCHESTRATED_BY_KEY, orchestratedBy } from '../../orchestration'\nimport { assistantText, cwdOf, titleOf, truncate } from './projections'\n\n/**\n * Default cap on `list`. Every row goes straight into the main's context, and a\n * user with a few hundred sessions would otherwise spend most of a turn on a\n * directory listing. Newest-first, so the cap drops the least relevant rows.\n */\nexport const DEFAULT_LIST_LIMIT = 30\n\n/** Projects in the main's system-prompt briefing — the recent ones, not the archive. */\nexport const DEFAULT_PROJECTS_LIMIT = 12\n\n/** Hard ceiling, so an over-eager `limit` cannot undo the cap's purpose. */\nconst MAX_LIST_LIMIT = 100\n\n/** Cap the model-facing summary so a chatty worker cannot flood the main's context. */\nconst SUMMARY_MAX = 600\n\nexport function createVerbs(deps: OrchestrationDeps, shared: OrchestrationState, directory: Directory, delivery: Pick<Delivery, 'deliver'>) {\n const { enabled, requireEnabled, requireMainCaller, metadataOf, mainOf, scan } = directory\n const { deliver } = delivery\n\n async function createWorker(main: string, params: CreateWorkerParams): Promise<string> {\n /*\n * Depth cap 1, enforced at the only place a worker is born: a main may not\n * create another main, and a worker may not create workers. Without this\n * two mains could dispatch to each other indefinitely, each run costing\n * real money, with nothing in the UI that would show why.\n */\n requireEnabled()\n const meta = await metadataOf(main)\n if (!isMainSession(meta ?? undefined))\n throw new Error('only a main session may create workers')\n const id = await deps.createSession({\n cwd: params.cwd,\n ...(params.title ? { title: params.title } : {}),\n ...(params.agentId ? { agentId: params.agentId } : {}),\n ...(params.providerKey ? { providerKey: params.providerKey } : {}),\n ...(params.modelId ? { modelId: params.modelId } : {}),\n })\n const session = await loadSession(deps.store, id)\n if (!session)\n throw new Error(`worker session ${id} vanished after creation`)\n session.setMeta(ORCHESTRATED_BY_KEY, main)\n await session.save()\n shared.lineage.set(id, main)\n shared.wakePolicy.set(id, params.wake ?? true)\n deps.broadcast({ kind: 'sessions:changed', op: 'update', sessionId: id })\n /*\n * Fire-and-forget: the main learns the outcome through `run:end`, not by\n * awaiting here — awaiting would pin the main's tool call for the worker's\n * entire run.\n *\n * But a REJECTION must not be silent. The tool has already told the model\n * \"you will receive a <session-event> when it finishes\", so a swallowed\n * failure leaves it waiting forever on an event that will never arrive,\n * next to a session that never ran. Synthesize the error event instead.\n */\n void deps.sendPrompt({ sessionId: id, prompt: params.prompt }).catch((err: unknown) => {\n deliver(main, {\n sessionId: id,\n title: params.title ?? id,\n status: 'error',\n summary: `never started: ${err instanceof Error ? err.message : String(err)}`,\n at: Date.now(),\n cwd: params.cwd,\n }, true)\n })\n return id\n }\n\n async function list(main: string, limit = DEFAULT_LIST_LIMIT): Promise<WorkerRow[]> {\n await requireMainCaller(main)\n // Every non-main session — the main observes the whole store; `worker`\n // marks the ones it created itself.\n const rows = (await scan())\n .filter(row => row.id !== main && !isMainSession(row.metadata))\n .map((row) => {\n const running = deps.isRunning(row.id)\n return {\n sessionId: row.id,\n title: titleOf(row.metadata, row.id),\n cwd: cwdOf(row.metadata),\n running,\n worker: orchestratedBy(row.metadata) === main,\n state: (shared.flagged.get(row.id)?.size ?? 0) > 0 ? 'blocked' as const : running ? 'running' as const : 'idle' as const,\n updatedAt: row.updatedAt,\n turns: row.turns,\n }\n })\n // Sorted before slicing so the cap keeps the rows most likely to matter.\n rows.sort((a, b) => b.updatedAt - a.updatedAt)\n return rows.slice(0, Math.max(1, Math.min(limit, MAX_LIST_LIMIT)))\n }\n\n async function projects(limit = DEFAULT_PROJECTS_LIMIT): Promise<ProjectBrief[]> {\n if (!enabled())\n return []\n const byRoot = new Map<string, ProjectBrief>()\n for (const row of await scan()) {\n if (isMainSession(row.metadata))\n continue\n // projectRoot is the sidebar's grouping key; cwd is the fallback for\n // legacy untagged sessions. Directory-less rows have neither.\n const root = row.projectRoot ?? cwdOf(row.metadata)\n if (!root)\n continue\n const running = deps.isRunning(row.id)\n const state = (shared.flagged.get(row.id)?.size ?? 0) > 0 ? 'blocked' as const : running ? 'running' as const : 'idle' as const\n const active = state === 'idle' ? 0 : 1\n const latest = { sessionId: row.id, title: titleOf(row.metadata, row.id), state }\n const prev = byRoot.get(root)\n if (!prev) {\n byRoot.set(root, { root, sessions: 1, lastActiveAt: row.updatedAt, active, latest })\n continue\n }\n prev.sessions += 1\n prev.active += active\n if (row.updatedAt > prev.lastActiveAt) {\n prev.lastActiveAt = row.updatedAt\n prev.latest = latest\n }\n }\n return [...byRoot.values()]\n .sort((a, b) => b.lastActiveAt - a.lastActiveAt)\n .slice(0, Math.max(1, limit))\n }\n\n async function read(sessionId: string): Promise<WorkerSummary | null> {\n if (!enabled())\n return null\n const data = deps.liveSession(sessionId) ?? await deps.store.load(sessionId)\n if (!data)\n return null\n const lastAssistant = [...data.turns].reverse().find(t => t.role === 'assistant')\n const lastMessage = lastAssistant ? assistantText(lastAssistant) : null\n const running = deps.isRunning(sessionId)\n return {\n sessionId,\n title: titleOf(data.metadata, sessionId),\n cwd: cwdOf(data.metadata),\n running,\n worker: orchestratedBy(data.metadata) !== null,\n state: (shared.flagged.get(sessionId)?.size ?? 0) > 0 ? 'blocked' : running ? 'running' : 'idle',\n updatedAt: 'updatedAt' in data && typeof data.updatedAt === 'number' ? data.updatedAt : Date.now(),\n lastMessage: lastMessage ? truncate(lastMessage, SUMMARY_MAX) : null,\n turns: data.turns.length,\n }\n }\n\n async function isWorkerOf(main: string, sessionId: string): Promise<boolean> {\n return (await mainOf(sessionId)) === main\n }\n\n /*\n * Verbs reach ANY non-main session, not only the ones this main created —\n * the main orchestrates all the agents, including chats the human started\n * elsewhere. What it may never do is target itself or another main: that is\n * the recursion the depth cap exists to prevent, so it is refused here for\n * the tool, the RPC, and any extension caller alike.\n *\n * The CALLER is checked too (see `requireMainCaller`), and so is the\n * feature gate — the same reason `createWorker` insists on both before\n * spending money on a run.\n */\n async function requireOrchestratable(main: string, sessionId: string): Promise<void> {\n requireEnabled()\n if (sessionId === main)\n throw new Error('a main session cannot orchestrate itself')\n await requireMainCaller(main)\n const meta = await metadataOf(sessionId)\n if (!meta)\n throw new Error(`unknown session ${sessionId}`)\n if (isMainSession(meta))\n throw new Error(`${sessionId} is a main session and cannot be orchestrated`)\n }\n\n async function canOrchestrate(main: string, sessionId: string): Promise<boolean> {\n try {\n await requireOrchestratable(main, sessionId)\n return true\n }\n catch {\n return false\n }\n }\n\n async function send(main: string, sessionId: string, prompt: string, wake = true): Promise<void> {\n await requireOrchestratable(main, sessionId)\n // The main asked for this run, so by default it wants to hear back — even\n // from a session the human started, which would otherwise only report.\n shared.wakePolicy.set(sessionId, wake)\n await deps.sendPrompt({ sessionId, prompt })\n }\n\n async function steer(main: string, sessionId: string, message: string): Promise<void> {\n await requireOrchestratable(main, sessionId)\n deps.steer(sessionId, message)\n }\n\n async function cancel(main: string, sessionId: string): Promise<void> {\n await requireOrchestratable(main, sessionId)\n deps.interrupt(sessionId)\n }\n\n async function transcript(main: string, sessionId: string, limit = 10): Promise<string> {\n await requireOrchestratable(main, sessionId)\n const data = deps.liveSession(sessionId) ?? await deps.store.load(sessionId)\n if (!data)\n return ''\n const capped = Math.max(1, Math.min(limit, 50))\n return data.turns\n .filter(t => t.role === 'user' || t.role === 'assistant')\n .slice(-capped)\n .map((t) => {\n const text = t.content\n .filter((b): b is { type: 'text', text: string } => b.type === 'text')\n .map(b => b.text)\n .join('\\n')\n .trim()\n const tools = t.content\n .filter(b => b.type === 'tool_call')\n // `call_tool` envelopes name the inner tool, like every other surface.\n .map(b => unwrapCallTool(b.name, b.input)?.name ?? b.name)\n const body = text || (tools.length ? `[tool calls: ${tools.join(', ')}]` : '[no text]')\n return `${t.role}: ${truncate(body, 1200)}`\n })\n .join('\\n\\n')\n }\n\n return { createWorker, list, projects, read, isWorkerOf, canOrchestrate, send, steer, cancel, transcript }\n}\n","import type { ToolDef } from '../../../tools/types'\nimport type { Orchestration } from './types'\n\n// ---------------------------------------------------------------------------\n// The model-facing tool\n// ---------------------------------------------------------------------------\n\nexport const SESSIONS_TOOL = 'sessions'\n\nconst SESSIONS_DESCRIPTION = `Orchestrate other sessions (\"workers\") from this main session.\n\nVerbs:\n- create: start a worker in a directory with a first prompt. Returns its sessionId. Do NOT wait for it — you will receive a <session-event> in this conversation when it finishes, fails, or needs a decision.\n- send: give a running or idle worker a new prompt (queued if it is mid-run).\n- wake (create / send, default true): whether that run finishing wakes you. Pass false for work you do not need to react to — the report still lands in your history for your next run. A blocked session always wakes you.\n- steer: inject guidance into a worker's CURRENT run at its next turn boundary.\n- cancel: interrupt a worker's run.\n- read: a summary of a session — title, cwd, state (idle/running/blocked), last message, turn count.\n- transcript: the last N turns (default 10, max 50) as plain text — the drill-down behind read's lastMessage.\n- list: other sessions with live status, newest first, capped at 30 by default (raise with limit, max 100) — the list may be PARTIAL. worker=true marks the ones you created.\n\nYou observe ALL sessions and receive a <session-event> whenever any of them finishes or gets blocked; only runs you asked for (create / send with wake true) and blocked sessions wake you. Each event carries: seq (dedup), goal (the prompt that started the run), summary (its last message), finish-reason when abnormal, artifacts (files changed, command count), cwd ('' = no directory), worker, and the run's duration/tokens/turns. You may send/steer/cancel/read any of them — but never another main session. Prefer one worker per independent unit of work (one repo, one feature).`\n\n/**\n * Build the `sessions` tool for ONE main session. Injected only into the main's\n * agent — a worker never sees it, which is the depth cap made structural.\n */\nexport function createSessionsTool(orch: Orchestration, mainId: string): ToolDef {\n const str = (v: unknown, name: string): string => {\n if (typeof v !== 'string' || !v.trim())\n throw new Error(`sessions: \\`${name}\\` is required`)\n return v\n }\n return {\n spec: {\n name: SESSIONS_TOOL,\n description: SESSIONS_DESCRIPTION,\n inputSchema: {\n type: 'object',\n properties: {\n verb: { type: 'string', enum: ['create', 'send', 'steer', 'cancel', 'read', 'list', 'transcript'] },\n sessionId: { type: 'string', description: 'Worker id — required for every verb except create and list.' },\n cwd: { type: 'string', description: 'create: directory the worker runs in.' },\n prompt: { type: 'string', description: 'create / send: the prompt.' },\n message: { type: 'string', description: 'steer: guidance for the current run.' },\n title: { type: 'string', description: 'create: optional worker title.' },\n agentId: { type: 'string', description: 'create: optional agent profile id.' },\n limit: { type: 'number', description: 'list: how many sessions (default 30, max 100). transcript: how many trailing turns (default 10, max 50).' },\n wake: { type: 'boolean', description: 'create / send: wake you (start a run here) when that run finishes. Default true. false = fire-and-forget: the report still lands in your history for your next run.' },\n },\n required: ['verb'],\n },\n },\n async execute(input: Record<string, unknown>) {\n const verb = str(input.verb, 'verb')\n switch (verb) {\n case 'create': {\n const id = await orch.createWorker(mainId, {\n cwd: str(input.cwd, 'cwd'),\n prompt: str(input.prompt, 'prompt'),\n ...(typeof input.title === 'string' ? { title: input.title } : {}),\n ...(typeof input.agentId === 'string' ? { agentId: input.agentId } : {}),\n ...(typeof input.wake === 'boolean' ? { wake: input.wake } : {}),\n })\n return input.wake === false\n ? `created worker ${id}. Its report will be in your history next time you run; it will not wake you.`\n : `created worker ${id}. You will receive a <session-event> when it finishes.`\n }\n case 'send': {\n const id = str(input.sessionId, 'sessionId')\n await orch.send(mainId, id, str(input.prompt, 'prompt'), typeof input.wake === 'boolean' ? input.wake : true)\n return input.wake === false ? `sent to ${id} (will not wake you)` : `sent to ${id}`\n }\n case 'steer': {\n const id = str(input.sessionId, 'sessionId')\n await orch.steer(mainId, id, str(input.message, 'message'))\n return `steered ${id}`\n }\n case 'cancel': {\n const id = str(input.sessionId, 'sessionId')\n await orch.cancel(mainId, id)\n return `cancelled ${id}`\n }\n case 'read': {\n const id = str(input.sessionId, 'sessionId')\n if (!(await orch.canOrchestrate(mainId, id)))\n throw new Error(`sessions: ${id} cannot be orchestrated (unknown, or a main session)`)\n return JSON.stringify(await orch.read(id))\n }\n case 'list': {\n // Compact JSON: indentation is ~half the tokens of this payload and\n // buys the model nothing.\n const limit = typeof input.limit === 'number' ? input.limit : undefined\n return JSON.stringify(await orch.list(mainId, limit))\n }\n case 'transcript': {\n const id = str(input.sessionId, 'sessionId')\n const limit = typeof input.limit === 'number' ? input.limit : undefined\n return await orch.transcript(mainId, id, limit)\n }\n default:\n throw new Error(`sessions: unknown verb ${verb}`)\n }\n },\n }\n}\n","/**\n * Orchestration — host-side: the main session, its workers, and how a worker's\n * outcome reaches the main.\n *\n * Deliberately its own module rather than more code in `engine.ts`. It needs\n * only a small, explicit slice of the host (send / steer / interrupt, the\n * live-session lookup, the signal fan-out) and it observes the rest through\n * ONE seam: `onSignal`, which the engine calls from `broadcast`. That single\n * seam is how it learns both that a worker finished and that the main went\n * idle, so no hook is registered on either agent.\n *\n * Delivery model — the part that had to be right:\n *\n * - The human sees a worker event IMMEDIATELY, mid-stream if need be: it is\n * broadcast as a `session-event` transcript row, which is pure display and\n * never touches the model's in-flight generation.\n * - The MODEL sees it at the next turn boundary. Events are buffered per\n * main and flushed only when the main is idle: each becomes a `role:\n * 'user'` turn (the only role the model reads) carrying `<session-event>`\n * XML, appended to the main's session, followed by an empty `wake` run.\n * An empty-prompt run is legal exactly when the trailing turn is `user`\n * (`validateAndPrepareResume`), which is the case by construction.\n *\n * Buffering rather than appending mid-run is not caution, it is correctness:\n * a user turn appended between an assistant `tool_call` and its\n * `tool_result` would leave the conversation malformed for the provider.\n * The run-end drain is the same discipline the host already applies to\n * background tasks and the shared queue.\n *\n * Ownership: the main holds no lock on its workers. Its `steer` and a window's\n * `steer` are both just queued messages, and the main learns the outcome via\n * `run:end` regardless of who triggered the run — so \"human wins\" is not a\n * rule to enforce, it is what falls out of having nothing to fight over.\n */\nimport type { Orchestration, OrchestrationDeps } from './types'\nimport { createDelivery } from './delivery'\nimport { createDirectory } from './directory'\nimport { createSignalObserver } from './signals'\nimport { createOrchestrationState } from './state'\nimport { createVerbs } from './verbs'\n\nexport { createSessionsTool, SESSIONS_TOOL } from './tool'\nexport type { CreateWorkerParams, Orchestration, OrchestrationDeps, WorkerRow, WorkerSummary } from './types'\nexport { DEFAULT_LIST_LIMIT, DEFAULT_PROJECTS_LIMIT } from './verbs'\n\nexport function createOrchestration(deps: OrchestrationDeps): Orchestration {\n const state = createOrchestrationState()\n const directory = createDirectory(deps, state)\n const delivery = createDelivery(deps, state)\n const verbs = createVerbs(deps, state, directory, delivery)\n const onSignal = createSignalObserver(deps, state, directory, delivery, verbs.read)\n const { mainId, ensureMain } = directory\n const { createWorker, list, projects, read, isWorkerOf, canOrchestrate, send, steer, cancel, transcript } = verbs\n\n return { onSignal, mainId, ensureMain, createWorker, list, projects, read, isWorkerOf, canOrchestrate, send, steer, cancel, transcript }\n}\n","/**\n * The tools a session's agent is built with, besides the preset's own:\n * interaction tools, `read_chat_turns`, the Main's sessions tool, and the\n * dev browser / terminal surfaces (with their background-task routing) —\n * plus the merged tool map and behavior.\n */\nimport type { ExecutionContext } from '../../../contexts/types'\nimport type { ToolDef } from '../../../index'\nimport type { Preset } from '../../../presets'\nimport type { InteractionRequest } from '../../interactions'\nimport type { BrowserHub } from '../browser'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { InteractionHub } from '../interactions'\nimport type { Orchestration } from '../orchestration'\nimport type { HostSettings } from '../signals'\nimport type { TerminalManager } from '../terminal'\nimport { hasLocalPty } from '../../../contexts/local-terminal'\nimport { createChatTurnsReadTool } from '../../../tools/read-chat-turns'\nimport { createBrowserTools } from '../../browser/tools'\nimport { createInteractionTools } from '../../interactions'\nimport { createTerminalTools } from '../../terminal/tools'\nimport { createSessionsTool, SESSIONS_TOOL } from '../orchestration'\n\nexport function createSessionInteractionTools({ env, interactions, sessionId }: {\n env: ChatHostEnvironment\n interactions: InteractionHub\n sessionId: string\n}) {\n const store = env.store\n /*\n * Interaction tools (`present_plan`, `ask_user`) — bound to this session\n * so clients can correlate request → surface → response. The preset's\n * own tools may shadow ours on name collision (interaction tools are\n * infrastructure, not preset choices).\n *\n * `interactionMode` is read at invocation time (not agent build time) so\n * Ask ↔ Skip applies without an agent rebuild. `disabled` leaves the tools\n * out of the build entirely (crossing into or out of it rebuilds agents,\n * see `applyAgentSettings`), with the call-time guard kept for a run that\n * started before the switch; the build also drops the interaction doctrine.\n *\n * `shouldSkipInteractions` is the shared automatic policy — the tool itself\n * answers with `createAutomaticInteractionResponse` — so every surface\n * (TUI local, GUI embedded, daemon) skips identically. Host-synthesized\n * prompts (slash commands, extension `ctx.interaction.*`) never route\n * through these tools, so they keep their modal regardless of mode.\n */\n const requestInteraction = interactions.requestInteractionFor(sessionId)\n const interactionTools = createInteractionTools({\n requestInteraction: (request: InteractionRequest) => {\n if (env.readSettings().interactionMode === 'disabled')\n return Promise.reject(new Error('Interaction tools are disabled in Settings.'))\n return requestInteraction(request)\n },\n shouldSkipInteractions: () => env.readSettings().interactionMode === 'skip',\n })\n const chatReferenceTokens = { current: [] as readonly string[] }\n const chatTurnsReadTool = createChatTurnsReadTool({\n store,\n getAllowedTokens: () => chatReferenceTokens.current,\n })\n return { interactionTools, chatReferenceTokens, chatTurnsReadTool }\n}\n\nexport function createHostSurfaceTools({ env, settings, browser, terminals, sessionId, context, environmentKind, withTerminalTasks }: {\n env: ChatHostEnvironment\n settings: HostSettings\n browser: BrowserHub\n terminals: TerminalManager\n sessionId: string\n /** The session execution's context, before terminal task routing. */\n context: ExecutionContext\n environmentKind: string\n withTerminalTasks: (context: ExecutionContext, sessionId: string, environmentKind: string) => ExecutionContext\n}) {\n /*\n * Dev browser tools, only while a browser host (the GUI) is connected:\n * a TUI-only session never sees tools it cannot use. Host arrival and\n * departure rebuild agents (see `browser.onAvailabilityChange`).\n */\n const browserTools = browser.hasHost()\n ? createBrowserTools((op, input, signal) => browser.request(sessionId, op, input, signal))\n : null\n /*\n * Terminals, where this host can run them: the agent reads (and, gated,\n * types into) the session's terminals, and its background `shell` tasks\n * run in terminals of their own that the user can watch. Each part has\n * its own switch in Settings › Terminal; a change rebuilds agents.\n * The tools (and their prompt guidance) also need a client that can show\n * terminals (`terminals.hasViewer()`), like the browser tools need a\n * browser host; its arrival and departure rebuild agents too. Task\n * routing stays on the host switch alone, so a viewer attaching or\n * leaving never moves a running task to another execution.\n */\n const terminalsOn = env.terminals !== false && hasLocalPty() && settings.terminal !== false\n const terminalTools = terminalsOn && settings.terminalAgent !== false && terminals.hasViewer()\n ? createTerminalTools(terminals, sessionId)\n : null\n const agentExecution = terminalsOn && settings.terminalAgentTasks !== false\n ? withTerminalTasks(context, sessionId, environmentKind)\n : context\n return { browserTools, terminalTools, agentExecution }\n}\n\nexport function mergeAgentTools({ settings, interactionTools, isMain, orchestration, sessionId, chatTurnsReadTool, browserTools, terminalTools, presetTools, modelCatalogTools }: {\n settings: HostSettings\n interactionTools: Record<string, ToolDef>\n isMain: boolean\n orchestration: Orchestration\n sessionId: string\n chatTurnsReadTool: ToolDef\n browserTools: Record<string, ToolDef> | null\n terminalTools: Record<string, ToolDef> | null\n presetTools: Preset['tools']\n modelCatalogTools: Record<string, ToolDef>\n}): Record<string, ToolDef> {\n /*\n * Tool merge order — interaction tools FIRST, preset tools SECOND so\n * a preset's own `present_plan` / `ask_user` would shadow ours on\n * name collision.\n */\n return {\n ...(settings.interactionMode === 'disabled' ? {} : interactionTools),\n // Only a MAIN session gets the orchestration tool — a worker never sees\n // it, which is the depth cap made structural rather than checked. Gated\n // on the setting as well: the main is persisted, so resuming it with the\n // feature off must not hand the model session-spawning powers.\n ...(isMain ? { [SESSIONS_TOOL]: createSessionsTool(orchestration, sessionId) } : {}),\n chatTurnsRead: chatTurnsReadTool,\n ...(browserTools ?? {}),\n ...(terminalTools ?? {}),\n ...(presetTools ?? {}),\n ...modelCatalogTools,\n }\n}\n\nexport function composeAgentBehavior({ presetBehavior, persistBehavior, settings, tasksDir }: {\n presetBehavior: Preset['behavior']\n persistBehavior: { persistDir: string, persistThreshold?: number }\n settings: HostSettings\n tasksDir: string\n}) {\n return {\n ...presetBehavior,\n ...persistBehavior,\n // `Settings.stableToolList` → `toolSearch.mode: 'dispatch'`: surfaced\n // MCP tools go through `call_tool` and the wire tools array never\n // changes. Spread over the preset's own `toolSearch` so `limit` survives.\n ...(settings.stableToolList\n ? { toolSearch: { ...(presetBehavior?.toolSearch ?? {}), mode: 'dispatch' as const } }\n : {}),\n // `Settings.codemode` → `behavior.codemode`: the profile's own mode (Build\n // (codemode) asks for `'only'`), else `true` (`'on'`). Off strips it, so\n // the setting is the one switch: a preset can't turn codemode on without it.\n ...(settings.codemode\n ? { codemode: presetBehavior?.codemode || true }\n : { codemode: undefined }),\n tasksDir,\n }\n}\n","import type { DiscoveredPlugin } from '../../plugins-discovery'\nimport { discoverProjectPlugins } from '../../plugins-discovery'\nimport { hostDebug } from '../debug'\n\nexport interface PluginCatalog {\n pluginsForCwd: (cwd: string, prefix: string, scanPaths: readonly string[]) => Promise<readonly DiscoveredPlugin[]>\n /** Drop every cached walk (teardown, `rebuildAllAgents({ rediscover })`). */\n clear: () => void\n}\n\nexport function createPluginCatalog(): PluginCatalog {\n /*\n * Per-cwd Agent Plugin catalog. Discovery walks the four scan roots and\n * loads each manifest, so it is real disk IO on a path that runs at every\n * agent build (session activation, model change, extension swap). Keyed by\n * cwd only: `enabledPlugins` is applied AFTER discovery by\n * `buildPluginContributions`, so a toggle needs no re-walk.\n *\n * Promise-valued so concurrent builds for the same cwd share one walk.\n * Cleared by `shutdown()`, which is what a settings change that invalidates\n * the runtime config (extensions, plugins, MCPs) already calls — so toggling\n * a plugin re-walks rather than serving a catalog that predates the toggle.\n *\n * Remaining staleness window: a plugin INSTALLED while the host is live and\n * no such setting is touched is not picked up until the next teardown. That\n * is not TUI parity — the TUI's discovery slot is explicitly refreshable via\n * `refreshPlugins` — it is a gap, and the honest fix is a host-level\n * discovery refresh the windows can call.\n */\n const pluginCatalogCache = new Map<string, Promise<readonly DiscoveredPlugin[]>>()\n\n function pluginsForCwd(cwd: string, prefix: string, scanPaths: readonly string[]): Promise<readonly DiscoveredPlugin[]> {\n const existing = pluginCatalogCache.get(cwd)\n if (existing)\n return existing\n const walk = discoverProjectPlugins({\n cwd,\n prefix,\n // Dev / host-provided roots (`ZIDANE_PLUGIN_DIRS`), same as the TUI.\n ...(scanPaths.length > 0 ? { extraRoots: scanPaths } : {}),\n })\n .then(({ plugins, errors }) => {\n // Root-level IO failures (an unreadable plugin dir) are a permissions\n // problem on the directory itself; per-plugin failures already surface\n // as rejected rows in the windows' Extensions tab.\n for (const error of errors)\n hostDebug('discoverProjectPlugins', `${error.source}: ${error.path}: ${error.message}`)\n return plugins as readonly DiscoveredPlugin[]\n })\n .catch((err) => {\n // A failed walk must never block the agent build — degrade to \"no\n // plugins\" and let the run proceed.\n hostDebug('discoverProjectPlugins failed', err)\n pluginCatalogCache.delete(cwd)\n return [] as readonly DiscoveredPlugin[]\n })\n pluginCatalogCache.set(cwd, walk)\n return walk\n }\n\n return { pluginsForCwd, clear: () => pluginCatalogCache.clear() }\n}\n","/**\n * Agent construction for one session — `buildActiveRun` resolves the session's\n * runtime config and composes preset, skills, MCP servers, tools, model chain\n * and system prompt, creates the `Agent`, then installs the feature hooks that\n * turn its events into host signals and persisted turns.\n */\nimport type { ExecutionContext, ExecutionHandle } from '../../../contexts/types'\nimport type { SessionData } from '../../../session/index'\nimport type { AgentRegistry } from '../../agents'\nimport type { SessionEnvironment } from '../../environment'\nimport type { ApprovalHub } from '../approvals'\nimport type { BrowserHub } from '../browser'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { InteractionHub } from '../interactions'\nimport type { SessionLaunchOverrides } from '../launch-overrides'\nimport type { MachineBuilds, MachineProject } from '../machines'\nimport type { createProviderBuilder } from '../models'\nimport type { Orchestration } from '../orchestration'\nimport type { HostSettings, HostSignal, RunningWorkItem } from '../signals'\nimport type { TerminalManager } from '../terminal'\nimport type { ActiveRun } from '../types'\nimport type { PluginCatalog } from './plugins'\nimport { createAgent, resolvePersistDir, resolveTasksDir } from '../../../index'\nimport { loadSession } from '../../../session/index'\nimport { availableAgents, DEFAULT_AGENT_ID } from '../../agents'\nimport { assertEnvironmentReady, readSessionEnvironment } from '../../environment'\nimport { parseMachineKind } from '../../machine-protocol'\nimport { subscribeMcpToolsCache } from '../../mcp-tools-cache'\nimport { isMainSession, MAIN_PLAYBOOK_FRAGMENT, renderProjectsBriefing } from '../../orchestration'\nimport { buildPluginContributions } from '../../plugins-discovery'\nimport { resolveSessionCwd } from '../../session-cwd'\nimport { createSessionFileReader } from '../approval-gate'\nimport { EditOutcomeLedger } from '../edit-outcome-ledger'\nimport { discoveryCwdFor, readMachineProject } from '../machines'\nimport { discoverSessionMcpServers, sessionMcpConnector, sessionMcpServerList } from '../mcp'\nimport { buildProviderChain, resolveSessionModel, subagentModelCatalogTools } from '../models'\nimport { emitSessionNotice } from '../notices'\nimport { composeSystem, systemFor } from '../prompt'\nimport { installProviderDiagnosticHook } from '../provider-diagnostic'\nimport { installSteerDelivery } from '../runs'\nimport { composeSessionSkills, readSessionSkillMarkers } from '../skills'\nimport { assembleActiveRun } from './active-run'\nimport { createCommandSeam } from './command-seam'\nimport { installSessionHooks } from './hooks'\nimport { composeSessionPreset, withMarkdownSubagents } from './preset'\nimport { composeAgentBehavior, createHostSurfaceTools, createSessionInteractionTools, mergeAgentTools } from './tools'\n\nexport type { PluginCatalog } from './plugins'\nexport { createPluginCatalog } from './plugins'\n\nexport interface AgentBuilderDeps {\n env: ChatHostEnvironment\n broadcast: (signal: HostSignal) => void\n active: Map<string, ActiveRun>\n launchOverrides: Map<string, SessionLaunchOverrides>\n sessionCwd: (sessionId: string, data: SessionData) => string\n artifactsDir: () => string\n interactions: InteractionHub\n approvals: ApprovalHub\n browser: BrowserHub\n terminals: TerminalManager\n orchestration: Orchestration\n pluginCatalog: PluginCatalog\n sessionSafelistFor: (sessionId: string) => Set<string>\n sessionExecution: (sessionId: string, input: { cwd: string, environment: SessionEnvironment, settings: HostSettings }) => Promise<{\n execution: { context: ExecutionContext, handle: () => Promise<ExecutionHandle> }\n sandbox: { warning?: string }\n promptCwd?: string\n }>\n withTerminalTasks: (context: ExecutionContext, sessionId: string, environmentKind: string) => ExecutionContext\n buildProvider: ReturnType<typeof createProviderBuilder>\n maybeWake: (sessionId: string) => void\n /** What a machine session's build needs about its machine (`docs/MACHINES.md` § Project files). */\n machineBuilds?: MachineBuilds\n}\n\n/**\n * Resolve the canonical agent id stored on the session document against the\n * registry. Falls back to `DEFAULT_AGENT_ID` for pre-registry sessions or\n * ids that are no longer registered.\n */\nfunction agentIdOf(stored: string | undefined, agents: AgentRegistry): string {\n if (stored && stored in agents)\n return stored\n return DEFAULT_AGENT_ID\n}\n\n/** A machine session's project files, read there; a failure leaves the user scope alone, with a notice. */\nasync function readMachineProjectFor(deps: Pick<AgentBuilderDeps, 'machineBuilds' | 'broadcast'>, input: { sessionId: string, kind: string, cwd: string, prefix: string, execution: { context: ExecutionContext, handle: () => Promise<ExecutionHandle> } }): Promise<MachineProject | undefined> {\n const { sessionId, kind, cwd, prefix, execution } = input\n const machines = deps.machineBuilds\n const roots = machines?.roots(kind)\n if (!machines || !roots)\n return undefined\n const notice = (text: string): void => emitSessionNotice({ sessionId, agent: undefined, broadcast: deps.broadcast }, { severity: 'warn', label: 'machine' }, text)\n // Never hold a send for an offline machine: the run starts (its tools wait), the project files load when it is back.\n if (!machines.online(kind)) {\n const name = parseMachineKind(kind)?.name ?? kind\n machines.skipped(sessionId, name)\n notice(`${name} is offline: its project instructions, skills and MCP servers load when it is back.`)\n return undefined\n }\n try {\n const project = await readMachineProject({ context: execution.context, handle: await execution.handle(), cwd, roots, prefix })\n for (const text of project.notices)\n notice(text)\n return project\n }\n catch (err) {\n notice(`Could not read the project's instructions, skills and MCP servers on the machine: ${(err as Error).message}`)\n return undefined\n }\n}\n\nexport function createAgentBuilder(deps: AgentBuilderDeps): { buildActiveRun: (sessionId: string) => Promise<ActiveRun> } {\n const { env, broadcast, active, launchOverrides, sessionCwd, artifactsDir, interactions, approvals, browser, terminals, orchestration, sessionSafelistFor, sessionExecution, withTerminalTasks, buildProvider, maybeWake } = deps\n const { pluginsForCwd } = deps.pluginCatalog\n\n async function buildActiveRun(sessionId: string): Promise<ActiveRun> {\n const settings = env.readSettings()\n const store = env.store\n const data = await store.load(sessionId)\n\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found. Create the session before sending a prompt.`)\n\n /*\n * THE readiness gate: every path that runs a session (send, `/` command,\n * context views, wake, queue drain) builds its agent here, so a session\n * whose environment is still provisioning — or failed to — never runs.\n */\n const environment = readSessionEnvironment(data.metadata)\n assertEnvironmentReady(environment)\n\n const cwd = sessionCwd(sessionId, data)\n const sessionFolder = resolveSessionCwd({ metadata: data.metadata, projectRoot: data.projectRoot ?? undefined })\n\n const { isExtensionEdit, skillEditMarker } = readSessionSkillMarkers(data.metadata)\n\n /*\n * A machine's folder (`docs/MACHINES.md` § Project files): this host reads\n * its user scope from a folder of its own (`discoveryCwd`), never the\n * machine's path on this filesystem; the project scope comes from the\n * machine, through the session's own execution, below.\n */\n const discoveryCwd = discoveryCwdFor(environment.kind, cwd, env.userDataDir())\n const onMachine = discoveryCwd !== cwd\n\n const runtimeConfig = await env.runtimeConfig(discoveryCwd)\n // Profiles gated on a setting that is off (Codemode) build as the default.\n const agents = availableAgents(runtimeConfig.agents, settings)\n const providers = runtimeConfig.providers\n const agentId = agentIdOf(data.agentId, agents)\n const profile = agents[agentId] ?? agents[DEFAULT_AGENT_ID] ?? Object.values(agents)[0]\n if (!profile)\n throw new Error('No agent profiles are registered.')\n /*\n * Agent Plugins discovered on disk near the session's cwd. Resolved BEFORE\n * the preset is composed because it feeds both gates below.\n *\n * `?? []` because a host may hand the engine a hand-built ResolvedConfig\n * that predates this field; a missing scan-path list means \"defaults only\".\n */\n const pluginCatalog = await pluginsForCwd(discoveryCwd, runtimeConfig.prefix, runtimeConfig.pluginScanPaths ?? [])\n const { liveExtensions, artifactsEnabled, composedPreset: extensionPreset } = composeSessionPreset({ settings, runtimeConfig, profile, pluginCatalog })\n\n /*\n * `loadSession` is the canonical resume path — it rehydrates the\n * in-memory `Session` wrapper from persisted `SessionData` so the model\n * sees the full turn history on the next `run()`. A miss here means the\n * row was deleted since the load above: refuse rather than recreate it,\n * which would resurrect a session the user just deleted. Creation only\n * happens through the shared factory (`session-factory.ts`).\n */\n const session = await loadSession(store, sessionId)\n if (!session)\n throw new Error(`Session \"${sessionId}\" not found. Create the session before sending a prompt.`)\n\n /*\n * Disk-plugin contributions, gated by `enabledPlugins`. Previously only the\n * TUI's in-process path ran this, so with `useDaemon` on (and in the GUI,\n * always) an enabled plugin's skills and MCP servers were simply absent\n * from the agent — the settings list still showed the plugin as on, so it\n * looked like the plugin doing nothing rather than never being loaded.\n */\n // `enabled` passed straight through: `undefined` already means \"every\n // discovered plugin\" there, matching `filterRegistryPlugins` (called in\n // `composeSessionPreset`, `./preset`) and the polarity of every other\n // enabled-allowlist setting.\n const pluginContributions = buildPluginContributions({\n discovered: pluginCatalog,\n enabled: settings.enabledPlugins,\n })\n // `Settings.sandbox*` → OS sandbox for the model's shell commands. Read\n // at build time like the other agent-shaping settings; `undefined` when\n // off, which leaves `createProcessContext` on its historical path.\n // Also the OS sandbox policy (`Settings.sandbox*`) the agent reports.\n const { execution: sessionExecutionHandle, sandbox, promptCwd } = await sessionExecution(sessionId, { cwd, environment, settings })\n const machineProject = onMachine ? await readMachineProjectFor(deps, { sessionId, kind: environment.kind, cwd, prefix: runtimeConfig.prefix, execution: sessionExecutionHandle }) : undefined\n\n const finalSkills = composeSessionSkills({\n cwd: discoveryCwd,\n ...(machineProject ? { machineSkills: machineProject.skills } : {}),\n prefix: runtimeConfig.prefix,\n settings,\n liveExtensions,\n pluginContributions,\n presetSkills: extensionPreset.skills,\n isExtensionEdit,\n skillEditMarker,\n })\n\n const mcpServers = discoverSessionMcpServers(discoveryCwd, runtimeConfig.prefix, settings, machineProject?.mcps)\n\n /*\n * Persist large tool outputs to disk so the conversation context doesn't\n * balloon, in the session's artifact tree\n * (`<artifactsDir>/sessions/<sessionId>/tool-results/`).\n */\n const persistDir = resolvePersistDir({ userDir: artifactsDir(), sessionId })\n const tasksDir = resolveTasksDir({ userDir: artifactsDir(), sessionId })\n const persistBehavior = settings.persistToolResults ? { persistDir } : { persistThreshold: 0, persistDir }\n\n const readSessionFile = createSessionFileReader({ cwd, promptCwd, sessionExecutionHandle })\n\n const { providerKey, providerDescriptor, modelOverride, model, modelFallbacks } = resolveSessionModel(data.metadata, providers)\n\n // After model resolution: Claude model aliases in agent files need `providerKey`.\n const composedPreset = withMarkdownSubagents(extensionPreset, { cwd: discoveryCwd, prefix: runtimeConfig.prefix, settings, providerKey })\n\n const { interactionTools, chatReferenceTokens, chatTurnsReadTool } = createSessionInteractionTools({ env, interactions, sessionId })\n\n /*\n * Per-call annotation ledger, captured by the hook closures below.\n * Attached to the `ActiveRun` so dispose/shutdown can force-clear it;\n * `agent:done` clears it at every run boundary.\n */\n const ledger = new EditOutcomeLedger()\n\n const builtInSystem = agentId === 'build' || agentId === 'plan'\n ? systemFor(env, agentId, discoveryCwd, runtimeConfig.prefix, promptCwd ?? cwd, machineProject)\n : null\n const isMain = isMainSession(session.metadata) && settings.orchestration === true\n /*\n * The main gets its playbook plus a Projects briefing (directories with\n * ongoing work and the session to address in each), so it does not spend\n * a `list` call rediscovering them every run. Snapshot at agent build —\n * the fragment says so and points at `list` for live state.\n */\n const mainFragments = isMain\n ? [MAIN_PLAYBOOK_FRAGMENT, renderProjectsBriefing(await orchestration.projects(), Date.now())]\n : []\n const { browserTools, terminalTools, agentExecution } = createHostSurfaceTools({\n env,\n settings,\n browser,\n terminals,\n sessionId,\n context: sessionExecutionHandle.context,\n environmentKind: environment.kind,\n withTerminalTasks,\n })\n // A launch `--system` replaces the base prompt; fragments still append (as in the local TUI).\n const launch = launchOverrides.get(sessionId)\n const system = composeSystem({\n base: launch?.system ?? builtInSystem?.system ?? composedPreset.system,\n metadata: session.metadata,\n extensionSystemFragments: runtimeConfig.extensionSystemFragments,\n mainFragments,\n browserTools: browserTools !== null,\n terminalTools: terminalTools !== null,\n })\n const work = new Map<string, RunningWorkItem>()\n const sessionSafelist = sessionSafelistFor(sessionId)\n\n const mcpCredentialStore = env.mcpCredentialStore\n\n const { primaryProvider, providerNameByKey, extraProviders, seenProviderNames } = buildProviderChain({ providers, providerKey, modelFallbacks, buildProvider })\n\n const modelCatalogTools = subagentModelCatalogTools({ settings, presetSpawn: composedPreset.tools?.spawn, providerNameByKey, runtimeConfig })\n\n const agentTools = mergeAgentTools({\n settings,\n interactionTools,\n isMain,\n orchestration,\n sessionId,\n chatTurnsReadTool,\n browserTools,\n terminalTools,\n presetTools: composedPreset.tools,\n modelCatalogTools,\n })\n\n const agentBehavior = composeAgentBehavior({ presetBehavior: composedPreset.behavior, persistBehavior, settings, tasksDir })\n\n const agent = createAgent({\n ...composedPreset,\n provider: extraProviders.length > 0 ? [primaryProvider, ...extraProviders] : primaryProvider,\n name: profile.label,\n ...(system ? { system } : {}),\n session,\n artifacts: artifactsEnabled,\n // The session's cached execution (see `executionCache`): a rebuild on\n // the same cwd + isolation reuses the handle, so running background\n // tasks survive; a changed configuration replaces it.\n execution: agentExecution,\n handle: sessionExecutionHandle.handle,\n skills: finalSkills,\n mcpServers: sessionMcpServerList({\n discovered: mcpServers,\n plugin: pluginContributions.mcpServers,\n launch: launch?.mcp,\n preset: composedPreset.mcpServers,\n }),\n mcpConnector: sessionMcpConnector(cwd, mcpCredentialStore, () => agent),\n\n tools: agentTools,\n contextBreakdownSections: [\n ...liveExtensions.contextBreakdownSections,\n ...liveExtensions.contextPanelSections,\n ],\n behavior: agentBehavior,\n })\n subscribeMcpToolsCache(agent.hooks, { dataDir: env.userDataDir() })\n installProviderDiagnosticHook(agent.hooks, (diagnostic) => {\n broadcast({ kind: 'provider:diagnostic', sessionId, diagnostic })\n })\n env.instrumentAgent?.(agent, { sessionId })\n\n const { hookContext, movableCwd, commandSeam, warnLog } = installSessionHooks({\n sessionId,\n agent,\n broadcast,\n env,\n active,\n launchOverrides,\n approvals,\n terminals,\n artifactsDir,\n maybeWake,\n cwd,\n sessionFolder,\n promptCwd,\n executionContext: sessionExecutionHandle.context,\n builtInSystem,\n launch,\n sandbox,\n ledger,\n work,\n readSessionFile,\n sessionSafelist,\n createCommandSeam: () => createCommandSeam({\n spawnCandidate: (composedPreset.tools ?? {}).spawn,\n primaryProvider,\n extraProviders,\n providerNameByKey,\n seenProviderNames,\n providers,\n runtimeConfig,\n userDataDir: env.userDataDir(),\n system,\n tools: agentTools,\n skills: finalSkills,\n behavior: agentBehavior,\n name: profile.label,\n }),\n })\n\n const run = assembleActiveRun({\n sessionId,\n cwd,\n discoveryCwd,\n sessionFolder,\n movableCwd,\n agent,\n providerKey,\n providerDescriptor,\n model,\n modelOverride,\n ledger,\n work,\n chatReferenceTokens,\n warnLog,\n modelFallbacks,\n providerNameByKey,\n system,\n builtInSystem,\n isExtensionEdit,\n skillEditMarker,\n commandSeam,\n })\n\n installSteerDelivery(hookContext, run)\n\n return run\n }\n\n return { buildActiveRun }\n}\n","import type { SessionExecutionCache } from '../../execution-cache'\n/**\n * The live agents' lifecycle: `ensureAgent` (one build per session, discarded\n * when the host was reset meanwhile), the single run teardown every dispose\n * path goes through, LRU and idle eviction, and agent rebuilds — immediate\n * when idle, deferred to run end when busy (`disposeAgentForRebuild`).\n */\nimport type { PluginCatalog } from '../agent-build'\nimport type { ApprovalHub } from '../approvals'\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport type { InteractionHub } from '../interactions'\nimport type { TerminalManager } from '../terminal'\nimport type { ActiveRun } from '../types'\nimport { broadcastWorkSnapshot } from '../work'\n\nconst MAX_IDLE_ACTIVE_AGENTS = 8\n\nexport function createAgentLifecycle({ ctx, interactions, approvals, terminals, executionCache, suspendEnvironment, buildActiveRun, pluginCatalog }: {\n ctx: HostContext\n interactions: InteractionHub\n approvals: ApprovalHub\n terminals: TerminalManager\n executionCache: SessionExecutionCache\n suspendEnvironment: (sessionId: string, stillIdle?: () => boolean, options?: { respectIdleSetting?: boolean }) => Promise<void>\n buildActiveRun: (sessionId: string) => Promise<ActiveRun>\n pluginCatalog: PluginCatalog\n}) {\n const { broadcast, active, pendingBuilds, lifecycle, trackWork, assertDispatchOpen, isSessionBusy } = ctx\n\n /**\n * Sessions whose live agent must be rebuilt at the CURRENT run's end\n * (model/agent swap requested mid-run). See `disposeAgentForRebuild`.\n */\n const pendingDispose = new Set<string>()\n /** Callers of `disposeAgentForRebuild` waiting for a deferred rebuild to land. */\n const pendingDisposeWaiters = new Map<string, Array<() => void>>()\n\n /**\n * Single teardown sequence for a run — every dispose path routes through\n * here so run-scoped resources (in-flight `/` command abort, manual\n * compaction, live run controller, MCP warn log, edit ledger, work map,\n * the agent itself) can't be missed by one variant.\n * `broadcastWork: false` skips the empty work snapshot for runs no\n * client ever saw (built-but-never-activated).\n */\n function teardownRun(run: ActiveRun, opts?: { broadcastWork?: boolean }): void {\n run.commandAbort?.abort()\n run.compactionController?.abort()\n run.controller.abort()\n if (run.warnLog)\n trackWork(run.warnLog.close()).catch(() => undefined)\n run.ledger.clear()\n run.work.clear()\n if (opts?.broadcastWork !== false)\n broadcastWorkSnapshot(broadcast, run)\n trackWork(run.agent.destroy()).catch(() => undefined)\n }\n\n /** Tear down a built-but-never-activated (or stale) run. */\n function discardRun(run: ActiveRun): void {\n teardownRun(run, { broadcastWork: false })\n }\n\n function disposeActiveEntry(sessionId: string, entry: ActiveRun): void {\n teardownRun(entry)\n active.delete(sessionId)\n }\n\n function pruneIdleAgents(): void {\n const idle = [...active.entries()]\n // An active `/` command (commandAbort set) counts as work even\n // between its sub-runs — pruning would abort it mid-flight.\n .filter(([sessionId, entry]) => !isSessionBusy(sessionId) && !entry.compacting && entry.commandAbort === undefined && entry.work.size === 0)\n .sort((a, b) => a[1].lastUsedAt - b[1].lastUsedAt)\n const overflow = active.size - MAX_IDLE_ACTIVE_AGENTS\n if (overflow <= 0)\n return\n for (const [sessionId] of idle.slice(0, overflow))\n evictIdleSession(sessionId, { respectIdleSetting: true })\n }\n\n /**\n * Let go of an idle session: dispose its agent, free its execution —\n * unless something is still running on it (then the next build adopts it)\n * — and let its environment pause what costs money while idle.\n * `respectIdleSetting`: evicted for capacity, not by the idle sweep — only\n * pause when the kind's idle suspension is on (`idleMinutes: 0` keeps it running).\n */\n function evictIdleSession(sessionId: string, options: { respectIdleSetting?: boolean } = {}): void {\n const entry = active.get(sessionId)\n if (entry) {\n interactions.clearSession(sessionId)\n approvals.denyAll(sessionId)\n disposeActiveEntry(sessionId, entry)\n }\n // Someone works in one of its terminals, or one would die with the\n // execution (a docker exec PTY): keep the execution and environment up.\n if (terminals.busy(sessionId) || terminals.holdsExecution(sessionId))\n return\n const idleNow = (): boolean => !active.has(sessionId) && !pendingBuilds.has(sessionId)\n trackWork(executionCache.releaseIfIdle(sessionId, idleNow).then(released => released\n // A prompt landing meanwhile resumed the environment: don't pause it under the run.\n ? suspendEnvironment(sessionId, () => idleNow() && !executionCache.sessions().includes(sessionId), options)\n : undefined)).catch(() => undefined)\n }\n\n async function ensureAgent(sessionId: string): Promise<ActiveRun> {\n assertDispatchOpen()\n const existing = active.get(sessionId)\n if (existing) {\n existing.lastUsedAt = Date.now()\n return existing\n }\n\n const inFlight = pendingBuilds.get(sessionId)\n if (inFlight)\n return inFlight\n\n const generation = lifecycle.teardownGeneration\n\n const build = buildActiveRun(sessionId).then((run) => {\n /*\n * Discard when the host was torn down (generation bump) or this\n * session's pending entry was consumed (`disposeSession`) while we\n * were constructing — inserting the run would resurrect a stale\n * agent. Callers see a retryable error instead.\n */\n if (generation !== lifecycle.teardownGeneration || pendingBuilds.get(sessionId) !== build) {\n discardRun(run)\n // The build may have acquired the session's execution after a\n // `deleteSession`/teardown released it; free it unless another build\n // took the session over or tasks still run on it.\n trackWork(executionCache.releaseIfIdle(sessionId, () => !active.has(sessionId) && [undefined, build].includes(pendingBuilds.get(sessionId)))).catch(() => undefined)\n throw new Error(`Session \"${sessionId}\" was reset while its agent was starting. Retry the action.`)\n }\n active.set(sessionId, run)\n // The now-live agent takes over tasks still running on the session's\n // handle from its predecessor (exit/stall callbacks + work entries).\n trackWork(executionCache.adopt(sessionId, run.agent.hooks)).catch(() => undefined)\n pruneIdleAgents()\n return run\n })\n\n pendingBuilds.set(sessionId, build)\n trackWork(build)\n\n build\n .catch(() => undefined)\n .finally(() => {\n if (pendingBuilds.get(sessionId) === build)\n pendingBuilds.delete(sessionId)\n })\n\n return build\n }\n\n /**\n * Tear down ONLY the live agent (not HITL queues / pending builds), so\n * the next `ensureAgent` rebuilds it against freshly-patched session\n * metadata. Used by the model/agent swap path — HITL state and the\n * type-ahead queue survive the swap.\n */\n function rebuildAgentOnly(sessionId: string): void {\n // Consume any in-flight `ensureAgent` build FIRST (same contract as\n // `disposeSession`) — a build racing the swap would otherwise insert\n // an agent built against pre-patch session metadata.\n pendingBuilds.delete(sessionId)\n const entry = active.get(sessionId)\n if (!entry)\n return\n disposeActiveEntry(sessionId, entry)\n }\n\n /** Consume a deferred `disposeAgentForRebuild` and wake its waiters. Idempotent. */\n function applyPendingDispose(sessionId: string): void {\n if (!pendingDispose.delete(sessionId))\n return\n rebuildAgentOnly(sessionId)\n const waiters = pendingDisposeWaiters.get(sessionId) ?? []\n pendingDisposeWaiters.delete(sessionId)\n for (const resolve of waiters)\n resolve()\n }\n\n /**\n * Apply a model/agent swap: patch already landed on session metadata;\n * now retire the live agent so the next run rebuilds on it. Deferred to\n * run end when a run is in flight — disposing mid-run would abort it for\n * EVERY window, diverging from the local TUI (which rebuilds at run end\n * via `pendingAgentRebuildRef`).\n */\n function disposeAgentForRebuild(sessionId: string): Promise<void> {\n if (!isSessionBusy(sessionId)) {\n rebuildAgentOnly(sessionId)\n return Promise.resolve()\n }\n pendingDispose.add(sessionId)\n return new Promise((resolve) => {\n const waiters = pendingDisposeWaiters.get(sessionId) ?? []\n waiters.push(resolve)\n pendingDisposeWaiters.set(sessionId, waiters)\n })\n }\n\n const methods: Pick<ChatHost, 'rebuildAllAgents'> = {\n rebuildAllAgents(options = {}) {\n if (options.rediscover)\n pluginCatalog.clear()\n // In-flight builds may hold the pre-reload registry: wait for each to\n // land, then retire it like any live agent, so callers disposing the old\n // registry after this resolves never pull it out from under one.\n const building = [...pendingBuilds].filter(([sessionId]) => !active.has(sessionId))\n return Promise.all([\n ...[...active.keys()].map(sessionId => disposeAgentForRebuild(sessionId)),\n ...building.map(([sessionId, build]) =>\n build.then(run => active.get(sessionId) === run ? disposeAgentForRebuild(sessionId) : undefined, () => undefined)),\n ]).then(() => undefined)\n },\n }\n\n /** Every agent is gone (`shutdown`): settle deferred rebuilds without performing them. */\n function releaseDeferredRebuilds(): void {\n // Every agent is gone: release `rebuildAllAgents` callers waiting on\n // a deferred rebuild so they can dispose what they held.\n pendingDispose.clear()\n for (const waiters of pendingDisposeWaiters.values()) {\n for (const resolve of waiters)\n resolve()\n }\n pendingDisposeWaiters.clear()\n }\n\n return {\n ensureAgent,\n teardownRun,\n disposeActiveEntry,\n pruneIdleAgents,\n evictIdleSession,\n rebuildAgentOnly,\n applyPendingDispose,\n disposeAgentForRebuild,\n releaseDeferredRebuilds,\n methods,\n }\n}\n","/**\n * The host's single signal fan-out. Holds a dispatch's final `run:end` until\n * the dispatch settles (`dispatchSignals`, written by `sendPrompt`), mirrors\n * signals to the debug stream, forwards to the transport, and lets\n * orchestration observe every signal.\n */\nimport type { ChatHostEnvironment } from './environment'\nimport type { Orchestration } from './orchestration'\nimport type { HostSignal } from './signals'\n\nexport type DispatchSignals = Map<string, { runId: string, end?: Extract<HostSignal, { kind: 'run:end' }> }>\n\nexport function createHostBroadcast(env: ChatHostEnvironment): {\n broadcast: (signal: HostSignal) => void\n dispatchSignals: DispatchSignals\n /** Bind the orchestration observer (created after `broadcast`, which it needs). */\n observeSignals: (orchestration: Orchestration) => void\n} {\n const debugStream = env.debugStream ?? process.env.ZIDANE_IPC_DEBUG_STREAM === '1'\n\n // Late-bound: orchestration needs `active`, which `createChatHost`\n // (`./engine`) creates after `broadcast`; bound through `observeSignals`.\n let orchestrationRef: Orchestration | undefined\n const dispatchSignals: DispatchSignals = new Map()\n const broadcast = (signal: HostSignal): void => {\n if (signal.kind === 'run:start' || signal.kind === 'run:end') {\n const dispatch = dispatchSignals.get(signal.sessionId)\n if (dispatch) {\n if (signal.kind === 'run:end') {\n dispatch.end = signal\n return\n }\n // Preserve intermediate command pairs; hold the final end until idle.\n const previous = dispatch.end\n dispatch.end = undefined\n if (previous) {\n dispatchSignals.delete(signal.sessionId)\n try {\n broadcast(previous)\n }\n finally {\n dispatchSignals.set(signal.sessionId, dispatch)\n }\n }\n dispatch.runId = signal.runId\n }\n }\n if (debugStream) {\n const preview\n = signal.kind === 'event' && signal.event.kind === 'markdown'\n ? `markdown:\"${signal.event.text.slice(0, 30)}${signal.event.text.length > 30 ? '…' : ''}\"`\n : signal.kind === 'event'\n ? `event:${signal.event.kind}${signal.event.kind === 'tool' || signal.event.kind === 'tool-result' ? `(${signal.event.tool})` : ''}`\n : signal.kind\n console.log(`[ipc-host] → ${preview}`)\n }\n env.broadcast(signal)\n // Orchestration observes every signal through this one seam — how it\n // learns that a worker finished AND that a main went idle, with no hook\n // registered on either agent. Late-bound via `observeSignals`.\n orchestrationRef?.onSignal(signal)\n }\n\n return {\n broadcast,\n dispatchSignals,\n observeSignals: (orchestration) => {\n orchestrationRef = orchestration\n },\n }\n}\n","/**\n * Browser hub: the agent's `browser_*` tools run where the agent runs (the\n * daemon, or the GUI's in-process host), but the page lives in the GUI's\n * main process. The GUI registers as a browser host; a tool call becomes a\n * `browser:request` signal addressed to that host, and resolves when the\n * host answers through `respond`. Same shape as the interaction hub.\n *\n * Every request is bounded (the operation's own wait plus transport slack)\n * and cancellable: a timeout or the run's abort sends `browser:cancel`, so\n * the page is freed instead of finishing work nobody waits for. Requests\n * never throw; failures come back as `{ ok: false, error }`.\n */\nimport type { BrowserOp, BrowserOpInputs, BrowserRequest, BrowserResponse } from '../browser/protocol'\nimport type { HostSignal } from './signals'\nimport { randomUUID } from 'node:crypto'\nimport {\n BROWSER_ACTION_TIMEOUT_MS,\n BROWSER_MAX_WAIT_MS,\n BROWSER_OPEN_MOUNT_MS,\n BROWSER_REQUEST_SLACK_MS,\n BROWSER_WAIT_TIMEOUT_MS,\n} from '../browser/protocol'\n\nexport interface BrowserHub {\n registerHost: (hostId: string) => void\n unregisterHost: (hostId: string) => void\n hasHost: () => boolean\n /** Fires when the first host arrives or the last one leaves. */\n onAvailabilityChange: (listener: (available: boolean) => void) => () => void\n request: <O extends BrowserOp>(sessionId: string, op: O, input: BrowserOpInputs[O], signal: AbortSignal) => Promise<BrowserResponse<O>>\n /** `fromHosts`: when given, only a request addressed to one of these hosts is answered. */\n respond: (requestId: string, response: BrowserResponse, fromHosts?: ReadonlySet<string>) => { ok: boolean }\n}\n\ninterface Pending {\n hostId: string\n sessionId: string\n resolve: (response: BrowserResponse) => void\n}\n\n/** How long the host may take: the operation's own wait, plus slack for the trip. */\nexport function browserRequestBudget(op: BrowserOp, input: Record<string, unknown>): number {\n const own = typeof input.timeoutMs === 'number' ? Math.min(Math.max(0, input.timeoutMs), BROWSER_MAX_WAIT_MS) : null\n switch (op) {\n case 'open':\n // Mounting the page (up to the host's open timeout) comes before its load.\n return BROWSER_OPEN_MOUNT_MS + (own ?? 15_000) + BROWSER_REQUEST_SLACK_MS\n case 'navigate':\n return (own ?? 15_000) + BROWSER_REQUEST_SLACK_MS\n case 'wait_for':\n return (own ?? BROWSER_WAIT_TIMEOUT_MS) + BROWSER_REQUEST_SLACK_MS\n case 'click':\n case 'type':\n return (own ?? BROWSER_ACTION_TIMEOUT_MS) + 3_000 + BROWSER_REQUEST_SLACK_MS\n case 'evaluate':\n case 'screenshot':\n return 12_000 + BROWSER_REQUEST_SLACK_MS\n default:\n return 10_000 + BROWSER_REQUEST_SLACK_MS\n }\n}\n\nexport function createBrowserHub({ broadcast }: { broadcast: (signal: HostSignal) => void }): BrowserHub {\n const hosts: string[] = []\n const pending = new Map<string, Pending>()\n const listeners = new Set<(available: boolean) => void>()\n const notify = (available: boolean) => {\n for (const l of listeners) l(available)\n }\n\n const finish = (requestId: string, response: BrowserResponse) => {\n const entry = pending.get(requestId)\n if (!entry)\n return false\n pending.delete(requestId)\n entry.resolve(response)\n return true\n }\n\n return {\n registerHost(hostId) {\n const had = hosts.length > 0\n const i = hosts.indexOf(hostId)\n if (i >= 0)\n hosts.splice(i, 1)\n hosts.push(hostId)\n if (!had)\n notify(true)\n },\n unregisterHost(hostId) {\n const i = hosts.indexOf(hostId)\n if (i < 0)\n return\n hosts.splice(i, 1)\n for (const [requestId, entry] of pending) {\n if (entry.hostId === hostId)\n finish(requestId, { ok: false, error: { code: 'no_browser', message: 'The app hosting the browser closed.' } })\n }\n if (hosts.length === 0)\n notify(false)\n },\n hasHost: () => hosts.length > 0,\n onAvailabilityChange(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n request(sessionId, op, input, signal) {\n const hostId = hosts.at(-1)\n if (!hostId) {\n return Promise.resolve({\n ok: false,\n error: { code: 'no_browser', message: 'No browser is available: open the Zidane app to use it.' },\n })\n }\n if (signal.aborted)\n return Promise.resolve({ ok: false, error: { code: 'cancelled', message: 'Cancelled.' } })\n const timeoutMs = browserRequestBudget(op, (input ?? {}) as Record<string, unknown>)\n const request: BrowserRequest = { requestId: randomUUID(), sessionId, op, input, timeoutMs }\n return new Promise((resolve) => {\n const cancel = (code: 'cancelled' | 'timeout', message: string) => {\n if (finish(request.requestId, { ok: false, error: { code, message } }))\n broadcast({ kind: 'browser:cancel', sessionId, hostId, requestId: request.requestId })\n }\n const onAbort = () => cancel('cancelled', 'Cancelled.')\n const timer = setTimeout(cancel, timeoutMs, 'timeout', `The browser did not answer within ${Math.round(timeoutMs / 1000)}s.`)\n pending.set(request.requestId, {\n hostId,\n sessionId,\n resolve: (response) => {\n clearTimeout(timer)\n signal.removeEventListener('abort', onAbort)\n resolve(response as never)\n },\n })\n signal.addEventListener('abort', onAbort, { once: true })\n broadcast({ kind: 'browser:request', sessionId, hostId, request })\n })\n },\n respond(requestId, response, fromHosts) {\n const entry = pending.get(requestId)\n if (!entry || (fromHosts && !fromHosts.has(entry.hostId)))\n return { ok: false }\n return { ok: finish(requestId, response) }\n },\n }\n}\n","/**\n * Where a host lets sessions work. A server is CONFINED to its workspace\n * roots (`ChatHostEnvironment.workspaceRoots`): every folder a session runs\n * in, every folder a catalog or command scan reads, and every path the\n * workspace file / exec / terminal entry points touch must resolve (real\n * path, symlinks followed) inside one of them, and never into the host's\n * data dir (credentials, tokens, audit log) unless through a root that\n * itself lives there. A local host is not confined; its roots are the\n * user's home (what a folder picker lists).\n *\n * The chat host owns one instance (`ChatHost.workspace`) and checks it at\n * its own entry points, so every caller (the wire, orchestration, the\n * model's tools that create sessions) goes through the same rule.\n *\n * Real paths come from `realpathSync.native` everywhere: on a\n * case-insensitive filesystem it returns the canonical spelling (Node's JS\n * `realpathSync` keeps the input's case, so a root and a folder inside it\n * given in different cases would not compare equal).\n */\nimport { realpathSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, isAbsolute, resolve, sep } from 'node:path'\n\nexport interface WorkspaceConfinement {\n readonly confined: boolean\n /** Real paths: the workspace roots, or the user's home when unconfined. */\n readonly roots: readonly string[]\n /** The real path of `path` when it is a folder inside the roots; throws otherwise. */\n resolveFolder: (path: string) => string\n /** A folder a session runs in or a scan reads: checked when confined (real path returned); `''` (no folder) passes. */\n checkFolder: (cwd: string) => string\n /** A new session's folder from a client: `cwd` checked when confined, the first root when confined and empty. */\n sessionFolder: (cwd: string) => string\n /** Where a session without a folder works on a confined host (the first root); `undefined` when unconfined. */\n folderlessCwd: () => string | undefined\n /**\n * A file or folder a workspace entry point reads or writes, on this\n * machine's filesystem: when confined, its real path (the nearest existing\n * ancestor's, for a file not written yet) must be inside the roots and not\n * in the data dir, or inside `environmentRoot` (a folder the host made for\n * the session, such as a worktree under the data dir). Throws otherwise;\n * a no-op when unconfined.\n */\n checkPath: (path: string, environmentRoot?: string) => void\n}\n\nexport function isInside(root: string, path: string): boolean {\n return path === root || path.startsWith(root.endsWith(sep) ? root : root + sep)\n}\n\nfunction realFolder(path: string): string {\n let real: string\n try {\n real = realpathSync.native(path)\n }\n catch {\n throw new Error(`${path} does not exist.`)\n }\n if (!statSync(real).isDirectory())\n throw new Error(`${path} is not a folder.`)\n return real\n}\n\n/** Real paths of `roots`; throws naming a root that is missing or not a folder. */\nfunction realWorkspaceRoots(roots: readonly string[]): string[] {\n return roots.map((root) => {\n try {\n return realFolder(root)\n }\n catch (err) {\n throw new Error(`Workspace root ${(err as Error).message}`)\n }\n })\n}\n\n/** The real path of `path`, or of its nearest existing ancestor joined with the rest. */\nfunction realPathOrAncestor(path: string): string {\n let current = path\n const rest: string[] = []\n for (;;) {\n try {\n return resolve(realpathSync.native(current), ...rest.reverse())\n }\n catch {\n const parent = dirname(current)\n if (parent === current)\n return path\n rest.push(current.slice(parent.length).replace(/^[/\\\\]+/, ''))\n current = parent\n }\n }\n}\n\nfunction realOrSelf(path: string): string {\n try {\n return realpathSync.native(path)\n }\n catch {\n return resolve(path)\n }\n}\n\nexport function createWorkspaceConfinement(\n confinedTo: readonly string[] | undefined,\n options: {\n dataDir?: string\n /**\n * More folders (or files) never reachable, with the data dir's rule: even\n * through a root that contains them, only inside a root that itself lives\n * there. A machine's: zidane's own folders and the credential folders\n * the sandbox hides (`docs/MACHINES.md` § Security model).\n */\n privateDirs?: readonly string[]\n /** How refusals name the roots and the data dir (a machine says \"the machine's roots\"). */\n names?: { roots: string, dataDir: string }\n } = {},\n): WorkspaceConfinement {\n const confined = confinedTo !== undefined\n const names = options.names ?? { roots: 'the workspace roots', dataDir: 'the host\\'s data dir, which workspace files can\\'t reach' }\n const roots = confined ? realWorkspaceRoots(confinedTo) : [realpathSync.native(homedir())]\n const dataDir = options.dataDir ? realOrSelf(options.dataDir) : undefined\n const privateDirs = [...new Set((options.privateDirs ?? []).map(realPathOrAncestor))]\n\n /** Inside a private folder, only what a root living there holds (the default root is `<data dir>/workspaces`). */\n const allowedIn = (dir: string, real: string): boolean =>\n roots.some(root => isInside(dir, root) && isInside(root, real))\n\n /** A real path inside the roots, and out of the data dir and the private folders (see the module header). */\n const assertReachable = (path: string, real: string): void => {\n if (!roots.some(root => isInside(root, real)))\n throw new Error(`${path} is outside ${names.roots} (${roots.join(', ')}).`)\n if (!confined)\n return\n if (dataDir && isInside(dataDir, real) && !allowedIn(dataDir, real))\n throw new Error(`${path} is in ${names.dataDir}.`)\n const hidden = privateDirs.find(dir => isInside(dir, real) && !allowedIn(dir, real))\n if (hidden)\n throw new Error(`${path} is private (${hidden}: zidane's own data or credentials), which the host can't reach.`)\n }\n\n const resolveFolder = (path: string): string => {\n if (!isAbsolute(path))\n throw new Error(`\"${path}\" is not an absolute path.`)\n const real = realFolder(path)\n assertReachable(path, real)\n return real\n }\n\n return {\n confined,\n roots,\n resolveFolder,\n checkFolder: cwd => (confined && cwd !== '' ? resolveFolder(cwd) : cwd),\n sessionFolder: cwd => (confined ? resolveFolder(cwd === '' ? roots[0]! : cwd) : cwd),\n folderlessCwd: () => (confined ? roots[0] : undefined),\n checkPath(path, environmentRoot) {\n if (!confined)\n return\n if (!isAbsolute(path))\n throw new Error(`\"${path}\" is not an absolute path.`)\n const real = realPathOrAncestor(path)\n if (environmentRoot && isInside(realOrSelf(environmentRoot), real))\n return\n assertReachable(path, real)\n },\n }\n}\n","/**\n * The chat host's shared state — created once by `createChatHost` and handed\n * to the features that need it: live agents, in-flight builds and dispatches,\n * lifecycle work, launch overrides, wake suppression, the teardown generation\n * / closed flag, and the helpers every feature checks them through.\n */\nimport type { SessionData } from '../../session/index'\nimport type { WorkspaceConfinement } from '../workspace-confinement'\nimport type { ChatHostEnvironment } from './environment'\nimport type { SessionLaunchOverrides } from './launch-overrides'\nimport type { HostSignal } from './signals'\nimport type { ActiveRun } from './types'\nimport { createWorkspaceConfinement } from '../workspace-confinement'\nimport { createSessionCwd } from './cwd'\n\nexport interface HostLifecycle {\n /** Set by `drain()`: the host refuses dispatch for good. */\n closed: boolean\n /**\n * Bumped by `shutdown`. A build that started before the bump is discarded\n * on completion instead of re-inserting a stale agent built from\n * pre-invalidation config.\n */\n teardownGeneration: number\n}\n\nexport interface HostContext {\n env: ChatHostEnvironment\n broadcast: (signal: HostSignal) => void\n active: Map<string, ActiveRun>\n pendingBuilds: Map<string, Promise<ActiveRun>>\n dispatches: Map<string, Promise<void>>\n lifecycleWork: Set<Promise<unknown>>\n launchOverrides: Map<string, SessionLaunchOverrides>\n suppressedWake: Set<string>\n lifecycle: HostLifecycle\n artifactsDir: () => string\n /** Where sessions may work (`ChatHostEnvironment.workspaceRoots`); unconfined on a local host. */\n workspace: WorkspaceConfinement\n sessionCwd: (sessionId: string, data: SessionData) => string\n trackWork: <T>(work: Promise<T>) => Promise<T>\n assertDispatchOpen: (generation?: number) => number\n isSessionBusy: (sessionId: string) => boolean\n}\n\nexport function createHostContext(env: ChatHostEnvironment, broadcast: (signal: HostSignal) => void): HostContext {\n const active = new Map<string, ActiveRun>()\n /** Per-session launch overrides (`setLaunchOverrides`), kept off the agent for the same reason as the approval safelists (agents are rebuilt for ordinary reasons). */\n const launchOverrides = new Map<string, SessionLaunchOverrides>()\n /** Root of the per-session artifact tree (`ChatHostEnvironment.cacheDir`). */\n const artifactsDir = (): string => env.cacheDir?.() ?? env.userDataDir()\n const workspace = createWorkspaceConfinement(env.workspaceRoots, { dataDir: env.userDataDir() })\n const sessionCwd = createSessionCwd(launchOverrides, workspace.folderlessCwd)\n /**\n * Sessions where the user explicitly interrupted — don't auto-start a\n * background-task wake run on their behalf until they send again\n * (mirrors the local TUI's esc-latch semantics).\n */\n const suppressedWake = new Set<string>()\n\n /**\n * In-flight agent builds keyed by sessionId. `ensureAgent` awaits\n * extensively before inserting into `active` — without this map, two\n * concurrent calls (e.g. `sessions.contextBreakdown` racing `chat.send`)\n * would each build an agent and the loser would leak (hooks keep\n * broadcasting, MCP connections stay open).\n */\n const pendingBuilds = new Map<string, Promise<ActiveRun>>()\n\n const lifecycle: HostLifecycle = { closed: false, teardownGeneration: 0 }\n const dispatches = new Map<string, Promise<void>>()\n const lifecycleWork = new Set<Promise<unknown>>()\n\n function trackWork<T>(work: Promise<T>): Promise<T> {\n lifecycleWork.add(work)\n void work.finally(() => lifecycleWork.delete(work)).catch(() => undefined)\n return work\n }\n\n function assertDispatchOpen(generation = lifecycle.teardownGeneration): number {\n if (lifecycle.closed || generation !== lifecycle.teardownGeneration)\n throw new Error('Chat host was shut down. Retry with an active host.')\n return generation\n }\n\n function isSessionBusy(sessionId: string): boolean {\n return dispatches.has(sessionId) || active.get(sessionId)?.agent.isRunning === true\n }\n\n return {\n env,\n broadcast,\n active,\n pendingBuilds,\n dispatches,\n lifecycleWork,\n launchOverrides,\n suppressedWake,\n lifecycle,\n artifactsDir,\n workspace,\n sessionCwd,\n trackWork,\n assertDispatchOpen,\n isSessionBusy,\n }\n}\n","/**\n * Per-session execution cache — the session, not the agent, owns where its\n * tools run.\n *\n * Hosts rebuild a session's agent for many reasons that have nothing to do\n * with execution: a model or profile swap, a settings change, an MCP login,\n * an extension reload. An agent that spawned its own handle destroys it on\n * teardown, and for the process context that SIGTERMs every background task\n * the session started (`npm run dev` dies because the user switched models);\n * for a container or remote sandbox it would delete the machine. So hosts\n * build agents on a HOST-OWNED handle from this cache instead\n * (`AgentOptions.handle` — the agent never spawns or destroys it) and the\n * handle outlives every rebuild:\n *\n * 1. `acquire(sessionId, key, create)` → the session's context + a lazy\n * handle resolver. Reused while `key` (the context's configuration:\n * cwd, isolation policy, …) is unchanged; a changed key replaces the\n * context — the old one is destroyed, taking its tasks with it, because\n * they run under the old configuration (e.g. without a sandbox the user\n * just enabled).\n * 2. `adopt(sessionId, agent.hooks)` once the new agent's listeners are\n * wired: running tasks' exit/stall callbacks move to the new agent's\n * hook bus, and each is announced via `background:adopt` so the host's\n * running-work view re-registers it. Tasks that exited while no agent\n * owned them still reach the model through the agent's run-boundary\n * `listBackground` reconcile.\n * 3. `release*` when the SESSION is done with its execution: deleted,\n * fully disposed, idle-evicted without running tasks, host shutdown.\n *\n * Subagents are unaffected: the spawn tool hands children the real context,\n * so a non-shared child still spawns (and destroys) its own handle.\n */\nimport type { Agent } from '../agent'\nimport type { ExecutionContext, ExecutionHandle } from '../contexts/types'\nimport { createDebugLog } from '../debug-log'\n\nconst debugLog = createDebugLog('execution-cache')\n\nexport interface SessionExecution {\n /** The session's execution context — pass as `AgentOptions.execution`. */\n context: ExecutionContext\n /** Host-owned handle, spawned on first use — pass as `AgentOptions.handle`. */\n handle: () => Promise<ExecutionHandle>\n}\n\nexport interface SessionExecutionCache {\n /**\n * The session's execution, created with `create()` on first use and\n * reused while `key` matches. A different `key` replaces it (the previous\n * context is released in the background).\n */\n acquire: (sessionId: string, key: string, create: () => ExecutionContext) => SessionExecution\n /**\n * The session's current execution, whatever its key — for side work\n * (environment actions) that must run where the agent runs without\n * re-deriving the key (a mismatch would replace the live context).\n */\n peek: (sessionId: string) => SessionExecution | undefined\n /**\n * Hand the session's still-running background tasks to a newly built\n * agent: rebind their exit/stall callbacks to `hooks` and fire\n * `background:adopt` per task. Returns how many were adopted.\n */\n adopt: (sessionId: string, hooks: Agent['hooks']) => Promise<number>\n /** True while any background task on the session's handle is running. */\n hasRunningTasks: (sessionId: string) => Promise<boolean>\n /**\n * Destroy the session's handle (killing its tasks) and forget it. Resolves\n * once the destroy has finished — including one already started by an\n * earlier release or a key replacement — so a caller can rely on the\n * session's processes being gone (e.g. before removing its worktree).\n */\n release: (sessionId: string) => Promise<void>\n /**\n * {@link release} unless tasks are still running; resolves whether it\n * released. `stillIdle` is re-checked after the (async) task listing,\n * right before destroying — hosts pass \"no agent was rebuilt for this\n * session meanwhile\", so an eviction can't pull the handle out from\n * under a build that just acquired it.\n */\n releaseIfIdle: (sessionId: string, stillIdle?: () => boolean) => Promise<boolean>\n /** Release every session — host shutdown. */\n releaseAll: () => Promise<void>\n /** Sessions currently holding an execution. */\n sessions: () => string[]\n}\n\ninterface Entry {\n key: string\n context: ExecutionContext\n handle: ExecutionHandle | null\n spawning: Promise<ExecutionHandle> | null\n released: boolean\n}\n\nexport function createSessionExecutionCache(): SessionExecutionCache {\n const entries = new Map<string, Entry>()\n /** Destroys in flight per session, so a later `release` can await them. */\n const destroying = new Map<string, Promise<void>>()\n\n /** Forget the session's entry and destroy it, tracking the in-flight destroy. */\n function detach(sessionId: string, entry: Entry): Promise<void> {\n if (entries.get(sessionId) === entry)\n entries.delete(sessionId)\n // Chain onto destroys already in flight (e.g. from a key replacement) so\n // awaiting this one also waits for every earlier destroy of the session.\n const pending = Promise.all([destroying.get(sessionId), destroyEntry(entry)]).then(() => {})\n destroying.set(sessionId, pending)\n void pending.finally(() => {\n if (destroying.get(sessionId) === pending)\n destroying.delete(sessionId)\n })\n return pending\n }\n\n function resolveHandle(entry: Entry): Promise<ExecutionHandle> {\n // A stale agent built on a replaced/released entry must not mint a\n // handle nobody will ever destroy.\n if (entry.released)\n return Promise.reject(new Error('session execution was released'))\n if (entry.handle)\n return Promise.resolve(entry.handle)\n // A release racing this spawn is handled by `destroyEntry`, which\n // awaits the in-flight spawn and destroys what it yields.\n entry.spawning ??= entry.context.spawn().then(\n (handle) => {\n entry.handle = handle\n entry.spawning = null\n return handle\n },\n (err: unknown) => {\n entry.spawning = null\n throw err\n },\n )\n return entry.spawning\n }\n\n async function destroyEntry(entry: Entry): Promise<void> {\n if (entry.released)\n return\n entry.released = true\n const handle = entry.handle ?? await entry.spawning?.catch(() => null) ?? null\n if (!handle)\n return\n entry.handle = null\n try {\n await entry.context.destroy(handle)\n }\n catch (err) {\n debugLog('destroy failed', err)\n }\n }\n\n async function runningTasks(entry: Entry | undefined) {\n if (!entry?.handle || !entry.context.listBackground)\n return []\n try {\n return (await entry.context.listBackground(entry.handle)).filter(task => task.status === 'running')\n }\n catch (err) {\n debugLog('listBackground failed', err)\n return []\n }\n }\n\n const cache: SessionExecutionCache = {\n acquire(sessionId, key, create) {\n let entry = entries.get(sessionId)\n if (entry && entry.key !== key) {\n void detach(sessionId, entry)\n entry = undefined\n }\n if (!entry) {\n entry = { key, context: create(), handle: null, spawning: null, released: false }\n entries.set(sessionId, entry)\n }\n const bound = entry\n return { context: bound.context, handle: () => resolveHandle(bound) }\n },\n\n peek(sessionId) {\n const entry = entries.get(sessionId)\n return entry ? { context: entry.context, handle: () => resolveHandle(entry) } : undefined\n },\n\n async adopt(sessionId, hooks) {\n const entry = entries.get(sessionId)\n const handle = entry?.handle\n if (!entry || !handle || !entry.context.reassignBackgroundTasks)\n return 0\n let adopted\n try {\n adopted = await entry.context.reassignBackgroundTasks(\n handle,\n handle,\n (info) => {\n Promise.resolve(hooks.callHook('background:exit', info)).catch(err => debugLog('background:exit hook rejected', err))\n },\n (info) => {\n Promise.resolve(hooks.callHook('background:stall', info)).catch(err => debugLog('background:stall hook rejected', err))\n },\n )\n }\n catch (err) {\n debugLog('adopt failed', err)\n return 0\n }\n for (const task of adopted) {\n await Promise.resolve(hooks.callHook('background:adopt', {\n taskId: task.taskId,\n pid: task.pid,\n command: task.command,\n cwd: task.cwd,\n outputPath: task.outputPath,\n startedAt: task.startedAt,\n })).catch(err => debugLog('background:adopt hook rejected', err))\n }\n return adopted.length\n },\n\n async hasRunningTasks(sessionId) {\n return (await runningTasks(entries.get(sessionId))).length > 0\n },\n\n async release(sessionId) {\n const entry = entries.get(sessionId)\n if (!entry)\n return destroying.get(sessionId)\n await detach(sessionId, entry)\n },\n\n async releaseIfIdle(sessionId, stillIdle) {\n const entry = entries.get(sessionId)\n if (!entry)\n return true\n if ((await runningTasks(entry)).length > 0)\n return false\n // Re-check after the await: the entry may have been replaced, or the\n // host may have started using it again.\n if (entries.get(sessionId) !== entry || (stillIdle && !stillIdle()))\n return false\n await cache.release(sessionId)\n return true\n },\n\n sessions: () => [...entries.keys()],\n\n async releaseAll() {\n const all = [...entries]\n await Promise.all([...all.map(([sessionId, entry]) => detach(sessionId, entry)), ...destroying.values()])\n },\n }\n return cache\n}\n","/**\n * File-backed secret storage for environment providers (sandbox API keys,\n * the Git token remote kinds clone and push with).\n *\n * Lives at `<dataDir>/environment-credentials.json` (mode 0o600), apart from\n * `credentials.json` (AI-provider auth, whose entries are provider-shaped and\n * enumerated by the auth screens) — same reasoning as `mcp-credentials.ts`.\n * Schema: `Record<kind, Record<fieldKey, string>>`.\n *\n * Atomic write-then-rename; a missing or corrupt file reads as empty so a bad\n * hand-edit never locks the user out, and the next write moves a corrupt file\n * to `environment-credentials.json.corrupt-<ms>` instead of overwriting it. Read-modify-write is unlocked: writes\n * come from explicit settings edits, where a concurrent edit of the SAME file\n * from two windows is the only race, and it loses one edit, not the file.\n */\nimport type { EnvironmentSecrets } from './environment-settings'\nimport { existsSync, readFileSync, renameSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { writeFileAtomic } from '../atomic-write'\n\nconst FILE_MODE = 0o600\n\nexport function environmentCredentialsPath(dataDir: string): string {\n return resolve(dataDir, 'environment-credentials.json')\n}\n\ntype SecretsFile = Record<string, Record<string, string>>\n\n/** Parse the file; throws when it exists but isn't a JSON object. */\nfunction parseAll(path: string): SecretsFile {\n if (!existsSync(path))\n return {}\n const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))\n throw new Error('not a JSON object')\n const out: SecretsFile = {}\n for (const [kind, values] of Object.entries(parsed as Record<string, unknown>)) {\n if (!values || typeof values !== 'object' || Array.isArray(values))\n continue\n out[kind] = Object.fromEntries(Object.entries(values as Record<string, unknown>).filter((entry): entry is [string, string] => typeof entry[1] === 'string'))\n }\n return out\n}\n\nfunction readAll(dataDir: string): SecretsFile {\n try {\n return parseAll(environmentCredentialsPath(dataDir))\n }\n catch {\n return {}\n }\n}\n\n/** For a write: a corrupt file is moved aside (not overwritten) so its other secrets stay recoverable. */\nfunction readAllForWrite(dataDir: string): SecretsFile {\n const path = environmentCredentialsPath(dataDir)\n try {\n return parseAll(path)\n }\n catch {\n renameSync(path, `${path}.corrupt-${Date.now()}`)\n return {}\n }\n}\n\nexport function createFileEnvironmentSecrets(dataDir: string): EnvironmentSecrets {\n return {\n get: (kind, key) => readAll(dataDir)[kind]?.[key],\n set: (kind, key, value) => {\n const all = readAllForWrite(dataDir)\n const values = { ...all[kind] }\n if (value === null)\n delete values[key]\n else\n values[key] = value\n if (Object.keys(values).length === 0)\n delete all[kind]\n else\n all[kind] = values\n writeFileAtomic(environmentCredentialsPath(dataDir), `${JSON.stringify(all, null, 2)}\\n`, { ensureDir: true, mode: FILE_MODE })\n },\n }\n}\n\n/** In-memory secrets — tests and hosts without a data dir. */\nexport function createMemoryEnvironmentSecrets(initial: Record<string, Record<string, string>> = {}): EnvironmentSecrets {\n const all: SecretsFile = JSON.parse(JSON.stringify(initial)) as SecretsFile\n return {\n get: (kind, key) => all[kind]?.[key],\n set: (kind, key, value) => {\n const values = { ...all[kind] }\n if (value === null)\n delete values[key]\n else\n values[key] = value\n all[kind] = values\n },\n }\n}\n","/**\n * Environments in Settings — which kinds are offered, the default, and each\n * kind's options — plus the wire-safe descriptors every picker and settings\n * section renders. Shared by the chat host (daemon / GUI) and the TUI's local\n * runtime so both surfaces show and store exactly the same thing.\n *\n * Storage:\n * - `Settings.environments` (`state.json`, synced like every setting):\n * `{ defaultKind?, disabled?, config?: { [kind]: { [key]: value } } }`.\n * - Fields bound to a pre-existing setting (`field.setting`, e.g. Local's\n * OS sandbox → `Settings.sandbox`) read and write THAT key.\n * - `secret` fields live in the 0600 environment credential store\n * (`environment-credentials.ts`) and never reach a client — descriptors\n * only say whether one is configured (stored, or via its env var).\n *\n * Readers are tolerant (anything malformed reads as the default); writes go\n * through {@link applyEnvironmentSettingsChange}, which validates against the\n * provider's schema — the boundary check for every client.\n */\nimport type {\n EnvironmentConfig,\n EnvironmentConfigField,\n EnvironmentConfigValue,\n EnvironmentProvider,\n EnvironmentRegistry,\n} from './environment'\nimport { environmentTakesBranch, LOCAL_ENVIRONMENT, probeEnvironment } from './environment'\n\n/** `Settings.environments`. Every part optional: absent = defaults. */\nexport interface EnvironmentSettings {\n /** Kind new sessions start in. Default / invalid / disabled → `local`. */\n defaultKind?: string\n /** Kinds hidden from pickers and refused at creation. `local` can't be disabled. */\n disabled?: string[]\n /** Kinds turned on that are off by default (`provider.offByDefault`). */\n enabled?: string[]\n /** Per-kind options (non-secret, non-bound fields only). */\n config?: Record<string, Record<string, EnvironmentConfigValue>>\n}\n\n/** Where `secret` fields live — see `environment-credentials.ts`. */\nexport interface EnvironmentSecrets {\n get: (kind: string, key: string) => string | undefined\n /** `null` clears. */\n set: (kind: string, key: string, value: string | null) => void\n}\n\n/**\n * The settings object this module reads: `environments` plus any keys fields\n * are bound to (`field.setting`). Any `Settings`-shaped object fits.\n */\nexport type EnvironmentSettingsSource = object\n\nfunction boundSetting(settings: EnvironmentSettingsSource | undefined, key: string): unknown {\n return (settings as Record<string, unknown> | undefined)?.[key]\n}\n\n/** Tolerant read of `Settings.environments`. */\nexport function readEnvironmentSettings(settings: EnvironmentSettingsSource | undefined): Required<EnvironmentSettings> {\n const raw = (settings as { environments?: unknown } | undefined)?.environments\n const record = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw as Record<string, unknown> : {}\n const kinds = (value: unknown): string[] => Array.isArray(value)\n ? [...new Set(value.filter((kind): kind is string => typeof kind === 'string' && kind !== LOCAL_ENVIRONMENT.kind))]\n : []\n const disabled = kinds(record.disabled)\n const enabled = kinds(record.enabled)\n const config: Record<string, Record<string, EnvironmentConfigValue>> = {}\n if (record.config && typeof record.config === 'object' && !Array.isArray(record.config)) {\n for (const [kind, values] of Object.entries(record.config as Record<string, unknown>)) {\n if (!values || typeof values !== 'object' || Array.isArray(values))\n continue\n const entries = Object.entries(values as Record<string, unknown>)\n .filter((entry): entry is [string, EnvironmentConfigValue] => ['string', 'number', 'boolean'].includes(typeof entry[1]))\n config[kind] = Object.fromEntries(entries)\n }\n }\n return {\n defaultKind: typeof record.defaultKind === 'string' && record.defaultKind ? record.defaultKind : LOCAL_ENVIRONMENT.kind,\n disabled,\n enabled,\n config,\n }\n}\n\n/**\n * Whether `kind` may be picked. `local` always can: it is the fallback. An\n * `offByDefault` provider needs turning on first — pass it to honour that.\n */\nexport function isEnvironmentEnabled(settings: EnvironmentSettingsSource | undefined, kind: string, provider?: Pick<EnvironmentProvider, 'offByDefault'>): boolean {\n if (kind === LOCAL_ENVIRONMENT.kind)\n return true\n const { disabled, enabled } = readEnvironmentSettings(settings)\n if (disabled.includes(kind))\n return false\n return provider?.offByDefault ? enabled.includes(kind) : true\n}\n\n/** The default kind for new sessions: the configured one when registered and enabled, else `local`. */\nexport function defaultEnvironmentKind(registry: EnvironmentRegistry, settings: EnvironmentSettingsSource | undefined): string {\n const { defaultKind } = readEnvironmentSettings(settings)\n const provider = registry.get(defaultKind)\n return provider && isEnvironmentEnabled(settings, defaultKind, provider) ? defaultKind : LOCAL_ENVIRONMENT.kind\n}\n\n/** Coerce a stored / submitted value to the field's type; `undefined` when it doesn't fit. */\nfunction coerce(field: EnvironmentConfigField, value: unknown): EnvironmentConfigValue | undefined {\n switch (field.type) {\n case 'boolean':\n return typeof value === 'boolean' ? value : value === 'true' ? true : value === 'false' ? false : undefined\n case 'number': {\n const n = typeof value === 'number' ? value : typeof value === 'string' && value.trim() ? Number(value) : Number.NaN\n return Number.isFinite(n) ? n : undefined\n }\n case 'choice':\n return typeof value === 'string' && field.choices?.some(choice => choice.value === value) ? value : undefined\n default:\n return typeof value === 'string' ? value : undefined\n }\n}\n\nexport interface ResolveConfigContext {\n settings: EnvironmentSettingsSource | undefined\n secrets: EnvironmentSecrets\n /** Env-var fallbacks. Default: `process.env`. */\n env?: Record<string, string | undefined>\n}\n\n/**\n * A kind's effective options: bound settings, stored values, secrets, env-var\n * fallbacks, then schema defaults — in that order.\n */\nexport function resolveProviderConfig(provider: EnvironmentProvider, context: ResolveConfigContext): EnvironmentConfig {\n const env = context.env ?? process.env\n const stored = readEnvironmentSettings(context.settings).config[provider.kind] ?? {}\n const out: Record<string, EnvironmentConfigValue | undefined> = {}\n for (const field of provider.configSchema ?? []) {\n let value: EnvironmentConfigValue | undefined\n if (field.setting)\n value = coerce(field, boundSetting(context.settings, field.setting))\n else if (field.type === 'secret')\n value = context.secrets.get(provider.kind, field.key) || undefined\n else\n value = coerce(field, stored[field.key])\n if (value === undefined && field.env && env[field.env])\n value = coerce(field, env[field.env])\n out[field.key] = value ?? field.default\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Wire-safe descriptors (pickers + settings sections)\n// ---------------------------------------------------------------------------\n\nexport interface EnvironmentFieldDescriptor {\n key: string\n label: string\n description?: string\n type: EnvironmentConfigField['type']\n choices?: EnvironmentConfigField['choices']\n placeholder?: string\n /** Current value — omitted for secrets. */\n value?: EnvironmentConfigValue\n default?: EnvironmentConfigValue\n /** Secrets: a value is stored, or its env var is set. */\n configured?: boolean\n /** Secrets / fallbacks: the env var currently supplying the value. */\n fromEnv?: string\n /** False while its `when` condition doesn't hold — renderers hide it. */\n visible: boolean\n}\n\nexport interface EnvironmentDescriptor {\n kind: string\n label: string\n description?: string\n enabled: boolean\n isDefault: boolean\n /** Can be offered for the requested folder right now. */\n available: boolean\n reason?: string\n takesBranch: boolean\n suggestedBranch?: string\n /** The kind has a \"Test connection\" (`provider.verify`). */\n canVerify: boolean\n /** What creating one here will do (`provider.note`), when available. */\n note?: string\n /** A machine's kind (`local@<name>`): which machine, and whether it is online now. */\n machine?: { id: string, name: string, status: 'online' | 'offline' }\n fields: EnvironmentFieldDescriptor[]\n}\n\n/** Every registered kind, described for `cwd` — what `environments.list` returns. */\nexport async function describeEnvironments(\n registry: EnvironmentRegistry,\n context: ResolveConfigContext & { cwd: string },\n): Promise<EnvironmentDescriptor[]> {\n const env = context.env ?? process.env\n const defaultKind = defaultEnvironmentKind(registry, context.settings)\n // A forgotten machine's kinds stay registered (a registry never drops one) but are not offered.\n const listed = registry.list().filter(provider => !provider.machine || provider.machine() !== undefined)\n return Promise.all(listed.map(async (provider) => {\n const config = resolveProviderConfig(provider, context)\n const machine = provider.machine?.()\n const availability = await probeEnvironment(provider, { cwd: context.cwd, config })\n const takesBranch = environmentTakesBranch(provider, config)\n const note = availability.ok ? await provider.note?.({ cwd: context.cwd, config }).catch(() => undefined) : undefined\n return {\n kind: provider.kind,\n label: provider.label,\n ...(provider.description ? { description: provider.description } : {}),\n enabled: isEnvironmentEnabled(context.settings, provider.kind, provider),\n isDefault: provider.kind === defaultKind,\n available: availability.ok,\n ...(availability.ok ? {} : { reason: availability.reason }),\n takesBranch,\n ...(takesBranch && provider.suggestBranch ? { suggestedBranch: provider.suggestBranch(config) } : {}),\n canVerify: provider.verify !== undefined,\n ...(note ? { note } : {}),\n ...(machine ? { machine } : {}),\n fields: (provider.configSchema ?? []).map((field): EnvironmentFieldDescriptor => {\n const secret = field.type === 'secret'\n const stored = secret ? context.secrets.get(provider.kind, field.key) : undefined\n const envSupplied = field.env && env[field.env] && (secret ? !stored : config[field.key] === coerce(field, env[field.env])) ? field.env : undefined\n return {\n key: field.key,\n label: field.label,\n ...(field.description ? { description: field.description } : {}),\n type: field.type,\n ...(field.choices ? { choices: field.choices } : {}),\n ...(field.placeholder ? { placeholder: field.placeholder } : {}),\n ...(secret ? { configured: Boolean(stored) || Boolean(envSupplied) } : { value: config[field.key] }),\n ...(field.default !== undefined && !secret ? { default: field.default } : {}),\n ...(envSupplied ? { fromEnv: envSupplied } : {}),\n visible: !field.when || config[field.when.key] === field.when.equals,\n }\n }),\n }\n }))\n}\n\n// ---------------------------------------------------------------------------\n// Writes\n// ---------------------------------------------------------------------------\n\n/** One edit from a settings UI. */\nexport interface EnvironmentSettingsChange {\n kind: string\n enabled?: boolean\n /** Make this kind the default for new sessions (enables it). */\n makeDefault?: boolean\n /** Field values; `null` resets to the default (or clears a secret). */\n values?: Record<string, EnvironmentConfigValue | null>\n}\n\nexport interface EnvironmentSettingsWrite {\n /** Patch for `settings.set` — `environments` plus any bound keys. */\n settingsPatch: Record<string, unknown>\n /** Secret writes for the environment credential store. */\n secrets: Array<{ key: string, value: string | null }>\n}\n\n/**\n * Validate `change` against the kind's schema and turn it into a settings\n * patch + secret writes. Throws with a user-facing message on an unknown\n * kind or field, a value that doesn't fit its type, or disabling `local`.\n */\nexport function applyEnvironmentSettingsChange(\n registry: EnvironmentRegistry,\n settings: EnvironmentSettingsSource | undefined,\n change: EnvironmentSettingsChange,\n): EnvironmentSettingsWrite {\n const provider = registry.get(change.kind)\n if (!provider)\n throw new Error(`Unknown environment \"${change.kind}\".`)\n const current = readEnvironmentSettings(settings)\n const next: Required<EnvironmentSettings> = {\n defaultKind: current.defaultKind,\n disabled: [...current.disabled],\n enabled: [...current.enabled],\n config: { ...current.config, [change.kind]: { ...current.config[change.kind] } },\n }\n const settingsPatch: Record<string, unknown> = {}\n const secrets: Array<{ key: string, value: string | null }> = []\n\n if (change.enabled === false) {\n if (change.kind === LOCAL_ENVIRONMENT.kind)\n throw new Error('Local can\\'t be disabled: it is the fallback environment.')\n if (!next.disabled.includes(change.kind))\n next.disabled.push(change.kind)\n next.enabled = next.enabled.filter(kind => kind !== change.kind)\n if (next.defaultKind === change.kind)\n next.defaultKind = LOCAL_ENVIRONMENT.kind\n }\n if (change.enabled === true || change.makeDefault) {\n next.disabled = next.disabled.filter(kind => kind !== change.kind)\n if (provider.offByDefault && !next.enabled.includes(change.kind))\n next.enabled.push(change.kind)\n }\n if (change.makeDefault)\n next.defaultKind = change.kind\n\n for (const [key, raw] of Object.entries(change.values ?? {})) {\n const field = provider.configSchema?.find(candidate => candidate.key === key)\n if (!field)\n throw new Error(`${provider.label} has no option \"${key}\".`)\n if (field.type === 'secret') {\n if (raw !== null && typeof raw !== 'string')\n throw new Error(`${field.label} must be text.`)\n secrets.push({ key, value: raw === null || raw === '' ? null : raw })\n continue\n }\n const value = raw === null ? null : coerce(field, raw)\n if (value === undefined)\n throw new Error(`${field.label}: ${field.type === 'choice' ? `pick one of ${field.choices?.map(choice => choice.value).join(', ')}` : `expected a ${field.type}`}.`)\n if (field.setting) {\n settingsPatch[field.setting] = value ?? field.default\n continue\n }\n if (value === null)\n delete next.config[change.kind]![key]\n else\n next.config[change.kind]![key] = value\n }\n if (Object.keys(next.config[change.kind]!).length === 0)\n delete next.config[change.kind]\n settingsPatch.environments = next\n return { settingsPatch, secrets }\n}\n","/**\n * Environment kinds this host can create and run, where their secrets live,\n * and a kind's effective options right now.\n */\nimport type { EnvironmentConfig, EnvironmentRegistry, SessionEnvironment } from '../../environment'\nimport type { EnvironmentSecrets } from '../../environment-settings'\nimport type { ChatHostEnvironment } from '../environment'\nimport { createEnvironmentRegistry } from '../../environment'\nimport { createFileEnvironmentSecrets } from '../../environment-credentials'\nimport { resolveProviderConfig } from '../../environment-settings'\nimport { builtinEnvironmentProviders } from '../../environments'\n\n/** Same provisioned environment (an owner and its forks): same kind and ref. */\nexport function sameEnvironment(a: SessionEnvironment, b: SessionEnvironment): boolean {\n return a.ref !== undefined && a.kind === b.kind && JSON.stringify(a.ref) === JSON.stringify(b.ref)\n}\n\nexport interface EnvironmentKinds {\n environments: EnvironmentRegistry\n environmentSecrets: EnvironmentSecrets\n environmentConfig: (kind: string) => EnvironmentConfig\n}\n\nexport function createEnvironmentKinds(env: ChatHostEnvironment): EnvironmentKinds {\n /** Environment kinds this host can create and run (`chat/environment.ts`). */\n const environments = env.environments ?? createEnvironmentRegistry(builtinEnvironmentProviders({ dataDir: env.userDataDir() }))\n /** Where environment secrets live (sandbox API keys, the Git token). */\n const environmentSecrets = env.environmentSecrets?.() ?? createFileEnvironmentSecrets(env.userDataDir())\n /** A kind's effective options right now: settings + secrets + env fallbacks + defaults. */\n const environmentConfig = (kind: string): EnvironmentConfig => {\n const provider = environments.get(kind)\n return provider ? resolveProviderConfig(provider, { settings: env.readSettings(), secrets: environmentSecrets }) : {}\n }\n return { environments, environmentSecrets, environmentConfig }\n}\n","/**\n * The host methods over where a session's work runs: session creation, the\n * environment catalog and actions, the session workspace, environment retry,\n * and session delete (which ends here so the execution and environment\n * teardown cannot be skipped).\n */\nimport type { SessionData } from '../../../session/index'\nimport type { SessionEnvironment } from '../../environment'\nimport type { SessionExecutionCache } from '../../execution-cache'\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport type { TerminalManager } from '../terminal'\nimport type { EnvironmentKinds } from './environments'\nimport type { Provisioning } from './provisioning'\nimport type { createSessionExecution } from './session-execution'\nimport { assertEnvironmentReady, environmentActionSummaries, environmentMetadata, readSessionEnvironment, runSessionEnvironmentAction, teardownSessionEnvironment, verifyEnvironment, workspacePath } from '../../environment'\nimport { describeEnvironments } from '../../environment-settings'\nimport { resolveSessionCwd } from '../../session-cwd'\nimport { deleteSessionData } from '../../session-factory'\nimport { createFolderResolver } from '../machines'\nimport { sameEnvironment } from './environments'\n\nexport type ExecutionMethods = Pick<\n ChatHost,\n | 'createSession'\n | 'environments'\n | 'environmentSecrets'\n | 'listEnvironments'\n | 'verifyEnvironment'\n | 'listEnvironmentActions'\n | 'workspaceExec'\n | 'workspaceExecStream'\n | 'workspaceReadFile'\n | 'workspaceWriteFile'\n | 'workspaceListFiles'\n | 'workspaceFileSize'\n | 'runEnvironmentAction'\n | 'retryEnvironment'\n | 'deleteSession'\n>\n\nexport function createExecutionMethods({ ctx, host, kinds, provisioning: provisioningFeature, sessionExecution: sessionExecutionFeature, executionCache, terminals, sessionSafelists }: {\n ctx: Pick<HostContext, 'env' | 'broadcast' | 'launchOverrides' | 'sessionCwd' | 'artifactsDir' | 'workspace'>\n host: () => ChatHost\n kinds: EnvironmentKinds\n provisioning: Provisioning\n sessionExecution: ReturnType<typeof createSessionExecution>\n executionCache: SessionExecutionCache\n terminals: TerminalManager\n /** Forgotten on session delete. */\n sessionSafelists: Map<string, Set<string>>\n}): ExecutionMethods {\n const { env, broadcast, launchOverrides, sessionCwd, artifactsDir, workspace: confinement } = ctx\n const { environments, environmentSecrets, environmentConfig } = kinds\n const resolveFolder = createFolderResolver({ environments, workspace: confinement })\n const { provisioning, createSessionInStore, startProvisioning } = provisioningFeature\n const { sessionExecution, sessionWorkspace } = sessionExecutionFeature\n\n /**\n * Other sessions (forks) running in the environment `sessionId` owns — its\n * teardown would pull their cwd out from under them. Forks keep the\n * parent's `projectRoot`, so the scan stays within that project.\n */\n async function findEnvironmentSharers(sessionId: string, data: SessionData): Promise<{ id: string, environment: SessionEnvironment }[]> {\n const own = readSessionEnvironment(data.metadata)\n if (own.owned === false || own.ref === undefined)\n return []\n const filter = { projectRoot: data.projectRoot ?? null }\n const metas = env.store.listMeta\n ? (await env.store.listMeta(filter)).map(row => ({ id: row.id, metadata: row.metadata }))\n : (await Promise.all((await env.store.list(filter)).map(async id => ({ id, metadata: (await env.store.load(id))?.metadata }))))\n return metas.flatMap(({ id, metadata }) => {\n if (id === sessionId || !metadata)\n return []\n const other = readSessionEnvironment(metadata)\n return other.owned === false && sameEnvironment(other, own) ? [{ id, environment: other }] : []\n })\n }\n\n /**\n * The session's workspace and `path` resolved in it. On a confined host,\n * a path on this machine (a process context; a sandbox confines its own)\n * must stay in the workspace roots and out of the data dir.\n */\n async function workspaceTarget(sessionId: string, path: string | undefined) {\n const workspace = await sessionWorkspace(sessionId)\n const target = path === undefined ? workspace.root : workspacePath(workspace.root, path)\n if (workspace.execution.context.type === 'process')\n confinement.checkPath(target, workspace.environmentRoot)\n return { workspace, target, handle: await workspace.execution.handle() }\n }\n\n const methods: ExecutionMethods = {\n createSession: createSessionInStore,\n\n environments,\n environmentSecrets,\n async listEnvironments(cwd, kind) {\n const folder = resolveFolder(cwd, kind)\n const described = await describeEnvironments(environments, { cwd: folder.cwd, settings: env.readSettings(), secrets: environmentSecrets })\n // A machine's folder: this host's own kinds can't run there (their folders are this host's).\n const machine = folder.machine\n return machine\n ? described.map(entry => (entry.machine ? entry : { ...entry, available: false, reason: `The folder is on ${machine.name}.` }))\n : described\n },\n verifyEnvironment: kind => verifyEnvironment(environments, kind, environmentConfig(kind)),\n\n async listEnvironmentActions(sessionId) {\n const data = await env.store.load(sessionId)\n if (!data)\n return []\n const environment = readSessionEnvironment(data.metadata)\n return environmentActionSummaries(environments, environment, environmentConfig(environment.kind))\n },\n\n async workspaceExec(sessionId, command, options = {}) {\n const { workspace, target, handle } = await workspaceTarget(sessionId, options.cwd)\n return workspace.execution.context.exec(handle, command, {\n cwd: target,\n ...(options.env ? { env: options.env } : {}),\n timeout: options.timeoutSeconds ?? 30,\n })\n },\n\n async workspaceExecStream(sessionId, command, options = {}) {\n const { workspace, target, handle } = await workspaceTarget(sessionId, options.cwd)\n const { context } = workspace.execution\n if (!context.execStream)\n return null\n return context.execStream(handle, command, { cwd: target, ...(options.env ? { env: options.env } : {}) })\n },\n\n async workspaceReadFile(sessionId, path) {\n const { workspace, target, handle } = await workspaceTarget(sessionId, path)\n return workspace.execution.context.readFile(handle, target)\n },\n\n async workspaceWriteFile(sessionId, path, content) {\n const { workspace, target, handle } = await workspaceTarget(sessionId, path)\n await workspace.execution.context.writeFile(handle, target, content)\n },\n\n async workspaceListFiles(sessionId, path, options) {\n const { workspace, target, handle } = await workspaceTarget(sessionId, path)\n return workspace.execution.context.listFiles(handle, target, options)\n },\n\n async workspaceFileSize(sessionId, path) {\n const { workspace, target, handle } = await workspaceTarget(sessionId, path)\n return await workspace.execution.context.fileSize?.(handle, target) ?? null\n },\n\n async runEnvironmentAction(sessionId, actionId) {\n const data = await env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n const environment = readSessionEnvironment(data.metadata)\n assertEnvironmentReady(environment)\n const cwd = sessionCwd(sessionId, data)\n const { execution } = await sessionExecution(sessionId, { cwd, environment, settings: env.readSettings() })\n return runSessionEnvironmentAction({ registry: environments, sessionId, actionId, environment, config: environmentConfig(environment.kind), cwd, execution })\n },\n\n async retryEnvironment(sessionId, opts) {\n if (provisioning.has(sessionId))\n return\n const data = await env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n const current = readSessionEnvironment(data.metadata)\n if (current.state === 'ready')\n return\n // Flip the row before starting (the same patch the attempt itself would\n // write): `background` callers return now and must not see `failed`.\n if (current.state === 'failed' && !provisioning.has(sessionId)) {\n const { error: _previousError, owned: _owned, ...rest } = current\n await host().patchSessionMeta(sessionId, environmentMetadata({ ...rest, state: 'provisioning' }))\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId })\n }\n const done = startProvisioning(sessionId)\n if (!opts?.background)\n await done\n },\n\n async deleteSession(sessionId) {\n // Stop provisioning first: an aborted attempt tears down what it made.\n const inFlight = provisioning.get(sessionId)\n inFlight?.controller.abort()\n // Retire the live agent + HITL state: a still-running agent's next\n // save would resurrect the row this is about to delete.\n host().disposeSession(sessionId)\n sessionSafelists.delete(sessionId)\n launchOverrides.delete(sessionId)\n // The session's processes must be gone before its environment is\n // removed (a worktree deleted under a running dev server).\n await terminals.closeSession(sessionId)\n await executionCache.release(sessionId)\n const provisioned = await inFlight?.done\n const data = await env.store.load(sessionId)\n const sharers = provisioned?.tornDown || !data ? [] : await findEnvironmentSharers(sessionId, data)\n // Hand ownership to a fork, or the last one's delete would never tear it down.\n if (sharers.length > 0) {\n const { owned: _owned, ...heir } = sharers[0]!.environment\n await host().patchSessionMeta(sharers[0]!.id, environmentMetadata(heir))\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId: sharers[0]!.id })\n }\n const environment = provisioned?.tornDown || !data\n ? { removed: true }\n : sharers.length > 0\n ? { removed: false, reason: `still used by ${sharers.length} forked session${sharers.length === 1 ? '' : 's'}` }\n : await teardownSessionEnvironment(environments, data.metadata, {\n config: environmentConfig,\n cwd: resolveSessionCwd({ metadata: data.metadata, projectRoot: data.projectRoot ?? undefined }),\n })\n await deleteSessionData(env.store, sessionId, { userDir: artifactsDir() })\n return { environment }\n },\n }\n\n return methods\n}\n","/**\n * One provisioning attempt for a session's environment — shared by the chat\n * host (runs it in the background after `createSession`) and the TUI's local\n * runtime (runs it inline, with progress, before activating the session).\n *\n * `provisioning` → provider `prepare` → `ready` (merging its result, moving\n * `metadata.cwd` when it returns one) | `failed` (with the error).\n *\n * Every persisted transition goes through `persist`, which the caller wires\n * to its safe metadata write + change announcement. Aborted (the session is\n * being deleted) or not persistable (another surface deleted it meanwhile):\n * whatever `prepare` produced is torn down here — nobody else ever will.\n */\nimport type { SessionData } from '../session/index'\nimport type { EnvironmentConfig, EnvironmentPrepareResult, EnvironmentRegistry, SessionEnvironment } from './environment'\nimport { environmentMetadata, readSessionEnvironment, teardownSessionEnvironment } from './environment'\nimport { resolveSessionCwd } from './session-cwd'\n\nexport interface ProvisionSessionEnvironmentInput {\n sessionId: string\n /** The session as persisted now. */\n load: () => Promise<SessionData | null>\n registry: EnvironmentRegistry\n config: (kind: string) => EnvironmentConfig\n /** Persist a metadata patch and announce it; `false` when the session no longer exists, throws on other write errors. */\n persist: (patch: Record<string, unknown>) => Promise<boolean>\n signal?: AbortSignal\n}\n\nexport interface ProvisionSessionEnvironmentResult {\n /** The attempt tore down what it prepared (aborted, or the session vanished). */\n tornDown: boolean\n /** The environment as it ended — absent when there was nothing to provision. */\n environment?: SessionEnvironment\n}\n\nexport async function provisionSessionEnvironment(input: ProvisionSessionEnvironmentInput): Promise<ProvisionSessionEnvironmentResult> {\n const { sessionId, registry, config, persist, signal } = input\n const data = await input.load()\n if (!data)\n return { tornDown: false }\n const current = readSessionEnvironment(data.metadata)\n if (current.state === 'ready')\n return { tornDown: false, environment: current }\n const cwd = resolveSessionCwd({ metadata: data.metadata, projectRoot: data.projectRoot ?? undefined })\n // Whatever `prepare` makes is this session's own, even if it was stamped\n // as shared: a not-owned environment here would never be torn down.\n const { error: _previousError, owned: _owned, ...rest } = current\n const pending: SessionEnvironment = { ...rest, state: 'provisioning' }\n // A retry of a failed attempt shows as provisioning again right away.\n if (current.state === 'failed' && !await persist(environmentMetadata(pending)))\n return { tornDown: false }\n\n const provider = registry.get(current.kind)\n let prepared: EnvironmentPrepareResult | undefined\n let failure: string | undefined\n try {\n if (!provider)\n throw new Error(`Unknown session environment \"${current.kind}\". Is the extension that provides it enabled?`)\n prepared = provider.prepare\n ? await provider.prepare({ sessionId, cwd, environment: pending, config: config(current.kind), ...(signal ? { signal } : {}) })\n : {}\n }\n catch (err) {\n failure = err instanceof Error ? err.message : String(err)\n }\n\n const outcome: SessionEnvironment = failure !== undefined\n ? { ...pending, state: 'failed', error: failure }\n : { ...pending, ...prepared?.environment, state: 'ready' }\n const outcomeCwd = prepared?.cwd ?? cwd\n const cleanUp = async (): Promise<ProvisionSessionEnvironmentResult> => {\n await teardownSessionEnvironment(registry, environmentMetadata(outcome), { cwd: outcomeCwd, config })\n return { tornDown: true }\n }\n if (signal?.aborted)\n return cleanUp()\n let persisted: boolean\n try {\n persisted = await persist({\n ...environmentMetadata(outcome),\n ...(prepared?.cwd ? { cwd: prepared.cwd } : {}),\n })\n }\n catch (err) {\n // The session lives but the outcome never reached disk: nothing will\n // ever find what `prepare` made, so remove it and leave a retryable failure.\n const result = await cleanUp()\n const failed: SessionEnvironment = { ...pending, state: 'failed', error: `Couldn't save the environment: ${err instanceof Error ? err.message : String(err)}` }\n await persist(environmentMetadata(failed)).catch(() => false)\n return { ...result, environment: failed }\n }\n // Deleted by another surface while we prepared: nobody will own it.\n return persisted ? { tornDown: false, environment: outcome } : cleanUp()\n}\n","/**\n * Session creation with its environment, and background provisioning of the\n * environments that need it.\n */\nimport type { HostContext } from '../context'\nimport type { ChatHost, CreateSessionRequest } from '../host-api'\nimport type { EnvironmentKinds } from './environments'\nimport { initialEnvironment } from '../../environment'\nimport { provisionSessionEnvironment } from '../../environment-provisioning'\nimport { isEnvironmentEnabled } from '../../environment-settings'\nimport { createSessionInStore as createSessionInSharedStore } from '../../session-factory'\nimport { hostDebug } from '../debug'\n\nexport interface Provisioning {\n /**\n * In-flight provisioning per session. `done` resolves with whether the run\n * already tore down what it prepared (the session was deleted under it), so\n * a delete neither leaks nor double-tears-down the environment.\n */\n provisioning: Map<string, { controller: AbortController, done: Promise<{ tornDown: boolean }> }>\n createSessionInStore: (request: CreateSessionRequest) => Promise<string>\n startProvisioning: (sessionId: string) => Promise<{ tornDown: boolean }>\n}\n\nexport function createProvisioning({ ctx, host, kinds, drainQueue }: {\n ctx: Pick<HostContext, 'env' | 'broadcast' | 'trackWork' | 'workspace'>\n host: () => ChatHost\n kinds: EnvironmentKinds\n drainQueue: (sessionId: string) => void\n}): Provisioning {\n const { env, broadcast, trackWork, workspace } = ctx\n const { environments, environmentConfig } = kinds\n const provisioning: Provisioning['provisioning'] = new Map()\n\n /**\n * The shared factory (`chat/session-factory.ts`) bound to this host's store,\n * plus the environment: resolved here (unknown / unavailable kinds throw\n * before anything is written) and provisioned in the background when the\n * kind needs it. Orchestration workers are created through this too, so a\n * confined host's workspace roots hold for every caller here.\n */\n async function createSessionInStore(request: CreateSessionRequest): Promise<string> {\n const { environment: environmentRequest, ...requested } = request\n // A machine's folder is not on this host: its provider checks it (against the machine's roots) instead.\n const ownFolders = environmentRequest ? environments.get(environmentRequest.kind)?.checkFolder : undefined\n const params = { ...requested, cwd: ownFolders ? ownFolders(requested.cwd) : workspace.checkFolder(requested.cwd) }\n if (environmentRequest && !isEnvironmentEnabled(env.readSettings(), environmentRequest.kind, environments.get(environmentRequest.kind)))\n throw new Error(`The \"${environmentRequest.kind}\" environment is disabled in Settings → Environments.`)\n const environment = environmentRequest\n ? await initialEnvironment(environments, environmentRequest, { cwd: params.cwd, config: environmentConfig(environmentRequest.kind) })\n : undefined\n const id = await createSessionInSharedStore(env.store, { ...params, ...(environment ? { environment } : {}) })\n if (environment?.state === 'provisioning')\n startProvisioning(id)\n return id\n }\n\n function startProvisioning(sessionId: string): Promise<{ tornDown: boolean }> {\n const existing = provisioning.get(sessionId)\n if (existing)\n return existing.done\n const controller = new AbortController()\n const done = provisionEnvironment(sessionId, controller.signal)\n .catch((err: unknown) => {\n hostDebug('provisioning failed unexpectedly', err)\n return { tornDown: false }\n })\n .finally(() => {\n if (provisioning.get(sessionId)?.done === done)\n provisioning.delete(sessionId)\n // Deliver what was parked behind it; a failed environment leaves the\n // items queued (with an error event) until a retry succeeds.\n drainQueue(sessionId)\n })\n provisioning.set(sessionId, { controller, done })\n trackWork(done).catch(() => undefined)\n return done\n }\n\n /**\n * One provisioning attempt — the shared `provisionSessionEnvironment`,\n * persisting through the live-session-safe metadata patch and announcing\n * each transition as `sessions:changed`.\n */\n async function provisionEnvironment(sessionId: string, signal: AbortSignal): Promise<{ tornDown: boolean }> {\n const { tornDown } = await provisionSessionEnvironment({\n sessionId,\n load: () => env.store.load(sessionId),\n registry: environments,\n config: environmentConfig,\n signal,\n persist: async (patch) => {\n try {\n await host().patchSessionMeta(sessionId, patch)\n }\n catch (err) {\n if (!await env.store.load(sessionId).catch(() => null))\n return false // the session is gone\n throw err\n }\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId })\n return true\n },\n })\n return { tornDown }\n }\n\n return { provisioning, createSessionInStore, startProvisioning }\n}\n","/**\n * File-backed credential storage for MCP OAuth.\n *\n * Lives at `<dataDir>/mcp-credentials.json` (mode 0o600). Separate from\n * `credentials.json` (which holds AI-provider auth) so MCP server tokens\n * can't collide with provider keys, and so a future \"clear MCP auth\"\n * action can wipe just this file.\n *\n * Schema is `Record<serverName, McpCredentialEntry>`:\n * - `tokens` — current OAuth tokens (access + refresh + expiry).\n * - `clientInformation` — RFC 7591 dynamic client registration response.\n * Saved so subsequent runs don't re-register (most auth servers\n * rate-limit DCR and assign a new client per registration).\n * - `discoveryState` — RFC 9728 + RFC 8414 discovery cache. Avoids two\n * well-known requests on every cold start.\n *\n * All file operations are atomic write-then-rename and tolerate missing /\n * corrupt files (return `undefined` for a missing entry, `{}` for a\n * corrupt root file). The store implements `McpCredentialStore` so the\n * SDK-facing `McpOAuthProvider` stays pure (no FS dependency) — tests use\n * the in-memory store from `src/mcp/oauth-provider`.\n */\n\nimport type { OAuthDiscoveryState } from '@modelcontextprotocol/sdk/client/auth.js'\nimport type {\n OAuthClientInformationMixed,\n OAuthTokens,\n} from '@modelcontextprotocol/sdk/shared/auth.js'\nimport type { McpCredentialEntry, McpCredentialStore } from '../mcp/oauth-provider'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { writeFileAtomic } from '../atomic-write'\n\nconst FILE_MODE = 0o600\n\nexport function mcpCredentialsPath(dataDir: string): string {\n return resolve(dataDir, 'mcp-credentials.json')\n}\n\ntype CredentialsFile = Record<string, McpCredentialEntry>\n\nfunction readAll(dataDir: string): CredentialsFile {\n const path = mcpCredentialsPath(dataDir)\n if (!existsSync(path))\n return {}\n try {\n const raw = readFileSync(path, 'utf-8')\n const parsed = JSON.parse(raw)\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))\n return {}\n return parsed as CredentialsFile\n }\n catch {\n // Corrupt file — return empty so the user can re-auth without\n // a hand-edit lockout. (Same defensive pattern as `credentials.ts`.)\n return {}\n }\n}\n\nfunction writeAll(dataDir: string, all: CredentialsFile): void {\n writeFileAtomic(\n mcpCredentialsPath(dataDir),\n `${JSON.stringify(all, null, 2)}\\n`,\n { ensureDir: true, mode: FILE_MODE },\n )\n}\n\n/**\n * Build a file-backed `McpCredentialStore`. All per-server reads / writes\n * funnel through the single `mcp-credentials.json` file — this keeps\n * concurrent flows for different servers from clobbering each other since\n * each save reads-modifies-writes the full file atomically.\n *\n * Two flows for the same server name CAN race (last write wins). MCP OAuth\n * flows are user-driven and serial in practice (one login modal at a time),\n * so this is acceptable; a per-server file split + cross-process lock would\n * be required to handle a multi-process scenario.\n */\nexport function createFileMcpCredentialStore(dataDir: string): McpCredentialStore {\n return {\n load(name: string): McpCredentialEntry | undefined {\n return readAll(dataDir)[name]\n },\n save(name: string, entry: McpCredentialEntry): void {\n const all = readAll(dataDir)\n all[name] = entry\n writeAll(dataDir, all)\n },\n delete(name: string): void {\n const all = readAll(dataDir)\n if (!(name in all))\n return\n delete all[name]\n writeAll(dataDir, all)\n },\n }\n}\n\n/**\n * Convenience patches for individual sub-fields. The provider class uses\n * these so a `saveTokens` call doesn't have to round-trip `clientInformation`\n * + `discoveryState` it never touched.\n */\nexport function patchMcpCredential(\n store: McpCredentialStore,\n name: string,\n patch: Partial<McpCredentialEntry>,\n): void {\n const existing = store.load(name) ?? {}\n store.save(name, { ...existing, ...patch })\n}\n\nexport type { McpCredentialEntry, McpCredentialStore }\nexport type { OAuthClientInformationMixed, OAuthDiscoveryState, OAuthTokens }\n","/**\n * `Settings.sandbox*` → `SpawnConfig.isolation` for the process execution\n * context. One resolver shared by every chat host (daemon engine, in-process\n * TUI) so they agree on the policy — the writable roots, the credential\n * masks, the fail-closed availability check — from the same three settings.\n *\n * Two entry points with one policy: the TUI builds its agent synchronously\n * and takes the sync form (blocking that one window on a short git probe is\n * acceptable); the daemon must never block its shared event loop and takes\n * the async form.\n */\n\nimport type { IsolationPolicy } from '../contexts/isolation'\nimport type { Settings } from './types'\nimport {\n DEFAULT_UNREADABLE_DIRS,\n isolationAvailability,\n parseAllowWriteSetting,\n resolveUnreadableDirs,\n resolveWritableRoots,\n resolveWritableRootsAsync,\n} from '../contexts/isolation'\nimport { credentialsPath } from './credentials'\nimport { mcpCredentialsPath } from './mcp-credentials'\n\nexport interface ResolvedSandbox {\n /** `undefined` = sandbox off; spread into `createProcessContext({ cwd, isolation })`. */\n isolation: IsolationPolicy | undefined\n /**\n * Set when the sandbox is ON but cannot be enforced on this host. The\n * process context already fails closed for every command; this is the\n * text hosts surface to the user on activation so the first refusal is\n * explained before it happens.\n */\n warning: string | undefined\n}\n\nexport interface SandboxSettingsOptions {\n /**\n * The host's resolved data directory (`config.paths.userDir` /\n * `env.userDataDir()`). zidane's own credential stores live there and the\n * whole root moves with `ZIDANE_STORAGE_DIR`, so the mask must be built\n * from the REAL location — the `~/.zidane/...` entries in\n * {@link DEFAULT_UNREADABLE_DIRS} only cover a default install.\n */\n dataDir?: string\n}\n\ntype SandboxSettings = Pick<Settings, 'sandbox' | 'sandboxNetwork' | 'sandboxAllowWrite'>\n\nconst OFF: ResolvedSandbox = { isolation: undefined, warning: undefined }\n\n/**\n * Credential paths hidden from sandboxed commands: the home-relative\n * defaults plus zidane's provider and MCP credential files at the host's\n * actual data dir. Exported for tests; hosts go through the resolvers.\n */\nexport function sandboxUnreadableDirs(dataDir: string | undefined): string[] {\n const dirs = resolveUnreadableDirs(DEFAULT_UNREADABLE_DIRS)\n if (dataDir)\n dirs.push(credentialsPath(dataDir), mcpCredentialsPath(dataDir))\n return [...new Set(dirs)]\n}\n\nfunction finish(settings: SandboxSettings, writableRoots: string[], options: SandboxSettingsOptions): ResolvedSandbox {\n const isolation: IsolationPolicy = {\n writableRoots,\n network: settings.sandboxNetwork ?? 'allow',\n unreadableDirs: sandboxUnreadableDirs(options.dataDir),\n }\n const availability = isolationAvailability()\n const warning = availability.ok\n ? undefined\n : `\"Sandbox shell commands\" is on but cannot be enforced: ${availability.reason}. Shell commands will be refused until you fix this or turn the setting off.`\n return { isolation, warning }\n}\n\n/** Sync form — in-process TUI (`buildAgent` is synchronous). */\nexport function resolveSandboxFromSettings(settings: SandboxSettings, cwd: string, options: SandboxSettingsOptions = {}): ResolvedSandbox {\n if (!settings.sandbox)\n return OFF\n const extra = parseAllowWriteSetting(settings.sandboxAllowWrite ?? '', cwd)\n return finish(settings, resolveWritableRoots(cwd, { extra }), options)\n}\n\n/** Async form — daemon host; the git worktree probe must not block the shared loop. */\nexport async function resolveSandboxFromSettingsAsync(settings: SandboxSettings, cwd: string, options: SandboxSettingsOptions = {}): Promise<ResolvedSandbox> {\n if (!settings.sandbox)\n return OFF\n const extra = parseAllowWriteSetting(settings.sandboxAllowWrite ?? '', cwd)\n return finish(settings, await resolveWritableRootsAsync(cwd, { extra }), options)\n}\n\n/**\n * A machine's own policy (`docs/MACHINES.md` § Sandbox): the machine user's\n * `sandbox*` settings over every folder it shares, plus `extraWritable`\n * (its worktrees and task logs). The machine applies it to every command it\n * runs for any host; a host cannot turn it off.\n */\nexport type LooseSandboxSettings = Partial<SandboxSettings>\n\nexport function resolveSandboxForRoots(settings: LooseSandboxSettings, roots: readonly string[], options: SandboxSettingsOptions & { extraWritable?: readonly string[] } = {}): ResolvedSandbox {\n if (!settings.sandbox || roots.length === 0)\n return OFF\n const writable = roots.flatMap(root => resolveWritableRoots(root, { extra: parseAllowWriteSetting(settings.sandboxAllowWrite ?? '', root) }))\n return finish({ sandbox: true, sandboxNetwork: settings.sandboxNetwork ?? 'allow', sandboxAllowWrite: settings.sandboxAllowWrite ?? '' }, [...new Set([...writable, ...(options.extraWritable ?? [])])], options)\n}\n","/**\n * The execution a `zidane run --context …` launch runs in, in place of the\n * session environment's own: the same context the TUI's local agent builds\n * for a launch (`createCliExecution`), cached under a key that covers its\n * whole configuration, so a rebuild with the same launch reuses the live\n * container or sandbox.\n */\nimport type { ExecutionContext } from '../../contexts/types'\nimport type { LaunchExecution } from './launch-overrides'\nimport { stableStringify } from '../../behaviors/repeat-guard'\nimport { createCliExecution } from '../../cli-shared'\n\nexport function launchExecution(execution: LaunchExecution, cwd: string): { key: string, create: () => ExecutionContext } {\n return {\n key: `launch:${stableStringify({ execution, cwd })}`,\n create: () => createCliExecution(execution.context, {\n ...(execution.image !== undefined ? { image: execution.image } : {}),\n // Docker bind-mounts the host cwd at the same path; a remote sandbox\n // has no such path, so it keeps its own working directory.\n ...(execution.context === 'docker' ? { cwd } : {}),\n ...(execution.env !== undefined ? { env: execution.env } : {}),\n ...(execution.pregame !== undefined ? { pregame: execution.pregame } : {}),\n ...(execution.sandboxId !== undefined ? { sandboxId: execution.sandboxId } : {}),\n ...(execution.sandboxOnDestroy !== undefined ? { sandboxOnDestroy: execution.sandboxOnDestroy } : {}),\n }),\n }\n}\n","/**\n * THE session execution (cached across agent rebuilds) and the session\n * workspace over it.\n */\nimport type { SessionEnvironment } from '../../environment'\nimport type { SessionExecutionCache } from '../../execution-cache'\nimport type { HostContext } from '../context'\nimport type { HostSettings } from '../signals'\nimport type { EnvironmentKinds } from './environments'\nimport type { IdleSuspension } from './suspension'\nimport { assertEnvironmentReady, readSessionEnvironment, resolveExecution } from '../../environment'\nimport { resolveSandboxFromSettingsAsync } from '../../sandbox-settings'\nimport { launchExecution } from '../launch-execution'\n\nexport function createSessionExecution({ ctx, kinds, executionCache, suspension }: {\n ctx: Pick<HostContext, 'env' | 'launchOverrides' | 'sessionCwd'>\n kinds: EnvironmentKinds\n executionCache: SessionExecutionCache\n suspension: Pick<IdleSuspension, 'touchActivity' | 'markSuspended'>\n}) {\n const { env, launchOverrides, sessionCwd } = ctx\n const { environments, environmentConfig } = kinds\n const { touchActivity, markSuspended } = suspension\n\n /**\n * THE session execution: the environment's provider decides the context\n * (`resolveExecution`); its key covers everything the context is configured\n * with, so a rebuild on the same key reuses the live handle (tasks survive)\n * and a new cwd or sandbox policy replaces it. Agent builds and environment\n * actions both go through here. Clears a `suspended` flag — using the\n * execution resumes the environment.\n */\n async function sessionExecution(sessionId: string, input: { cwd: string, environment: SessionEnvironment, settings: HostSettings }) {\n const { cwd, environment, settings } = input\n /*\n * A `zidane run --context …` launch runs in its own execution, overriding\n * the session environment's, and without the OS sandbox (it is the\n * isolation the user asked for), as in the TUI's local agent.\n */\n const launched = launchOverrides.get(sessionId)?.execution\n if (launched) {\n const resolved = launchExecution(launched, cwd)\n const execution = executionCache.acquire(sessionId, resolved.key, resolved.create)\n touchActivity(sessionId)\n return { execution, sandbox: { isolation: undefined, warning: undefined } }\n }\n // A machine's commands run under the machine's own sandbox settings, never this host's (`docs/MACHINES.md` § Sandbox).\n const onMachine = environments.get(environment.kind)?.machine !== undefined\n const sandbox = onMachine ? { isolation: undefined, warning: undefined } : await resolveSandboxFromSettingsAsync(settings, cwd, { dataDir: env.userDataDir() })\n const resolved = resolveExecution(environments, {\n sessionId,\n cwd,\n environment,\n config: environmentConfig(environment.kind),\n ...(sandbox.isolation ? { isolation: sandbox.isolation } : {}),\n })\n const execution = executionCache.acquire(sessionId, resolved.key, resolved.create)\n touchActivity(sessionId)\n if (environment.suspended)\n await markSuspended(sessionId, environment, false)\n return { execution, sandbox, ...(resolved.promptCwd ? { promptCwd: resolved.promptCwd } : {}) }\n }\n\n /**\n * The session's execution (the cached one its agent uses) and the\n * workspace root: inside the environment when its files live there, else\n * the session's cwd on this machine.\n */\n async function sessionWorkspace(sessionId: string) {\n const data = await env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n const environment = readSessionEnvironment(data.metadata)\n assertEnvironmentReady(environment)\n const cwd = sessionCwd(sessionId, data)\n const { execution } = await sessionExecution(sessionId, { cwd, environment, settings: env.readSettings() })\n // `environmentRoot`: a folder the environment made (a worktree), trusted like a workspace root.\n return { root: environment.execCwd ?? cwd, ...(environment.execCwd ? { environmentRoot: environment.execCwd } : {}), execution }\n }\n\n return { sessionExecution, sessionWorkspace }\n}\n","/**\n * Idle suspension: the once-a-minute sweep that evicts sessions idle past\n * their kind's limit, and the environment `suspend` once an execution is let\n * go while its session lives on.\n */\nimport type { SessionEnvironment } from '../../environment'\nimport type { SessionExecutionCache } from '../../execution-cache'\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport type { TerminalManager } from '../terminal'\nimport type { EnvironmentKinds } from './environments'\nimport type { Provisioning } from './provisioning'\nimport { environmentMetadata, readSessionEnvironment } from '../../environment'\nimport { hostDebug } from '../debug'\nimport { sameEnvironment } from './environments'\n\n/** How often idle environments are checked against their kind's suspend limit. */\nconst IDLE_SWEEP_MS = 60_000\n\nexport interface IdleSuspension {\n touchActivity: (sessionId: string) => void\n stopIdleSweep: () => void\n markSuspended: (sessionId: string, environment: SessionEnvironment, suspended: boolean) => Promise<void>\n environmentInUseElsewhere: (sessionId: string, environment: SessionEnvironment) => Promise<boolean>\n}\n\nexport function createIdleSuspension({ ctx, host, kinds, executionCache, provisioning, evictIdleSession }: {\n ctx: Pick<HostContext, 'env' | 'broadcast' | 'active' | 'pendingBuilds' | 'lifecycle' | 'isSessionBusy'>\n host: () => ChatHost\n kinds: EnvironmentKinds\n executionCache: SessionExecutionCache\n provisioning: Provisioning['provisioning']\n evictIdleSession: (sessionId: string) => void\n}): IdleSuspension {\n const { env, broadcast, active, pendingBuilds, lifecycle, isSessionBusy } = ctx\n const { environments, environmentConfig } = kinds\n\n /**\n * Idle suspension (`provider.idleSuspendMinutes`): a once-a-minute sweep over\n * sessions holding an execution. One idle past its kind's limit is evicted\n * like an LRU overflow — agent disposed, execution released, environment\n * suspended (a paused container / sandbox stops costing money). The next\n * prompt resumes it. `lastActivity` covers sessions whose agent is already\n * gone but whose execution is still held.\n */\n const lastActivity = new Map<string, number>()\n const touchActivity = (sessionId: string): void => {\n lastActivity.set(sessionId, Date.now())\n }\n const idleSweep = setInterval(() => {\n void sweepIdleEnvironments().catch(err => hostDebug('idle environment sweep failed', err))\n }, env.environmentIdleSweepMs ?? IDLE_SWEEP_MS)\n idleSweep.unref?.()\n\n async function sweepIdleEnvironments(): Promise<void> {\n const now = Date.now()\n for (const sessionId of executionCache.sessions()) {\n if (lifecycle.closed)\n return\n if (isSessionBusy(sessionId) || pendingBuilds.has(sessionId) || provisioning.has(sessionId))\n continue\n const entry = active.get(sessionId)\n if (entry && (entry.compacting || entry.commandAbort !== undefined || entry.work.size > 0))\n continue\n const data = await env.store.load(sessionId)\n if (!data)\n continue\n const environment = readSessionEnvironment(data.metadata)\n const provider = environments.get(environment.kind)\n const minutes = provider?.idleSuspendMinutes?.(environmentConfig(environment.kind))\n if (!minutes || minutes <= 0)\n continue\n const last = Math.max(entry?.lastUsedAt ?? 0, lastActivity.get(sessionId) ?? 0)\n if (now - last >= minutes * 60_000)\n evictIdleSession(sessionId)\n }\n }\n\n /**\n * Another session holding a live execution (or about to build one) in the\n * same environment — an owner and its forks share one sandbox, so pausing\n * it for one would pull it out from under the other.\n */\n async function environmentInUseElsewhere(sessionId: string, environment: SessionEnvironment): Promise<boolean> {\n if (environment.ref === undefined)\n return false\n const others = new Set([...executionCache.sessions(), ...pendingBuilds.keys()])\n others.delete(sessionId)\n for (const id of others) {\n const data = await env.store.load(id)\n if (data && sameEnvironment(readSessionEnvironment(data.metadata), environment))\n return true\n }\n return false\n }\n\n /** Persist (and announce) the environment's `suspended` flag. */\n async function markSuspended(sessionId: string, environment: SessionEnvironment, suspended: boolean): Promise<void> {\n const { suspended: _previous, ...rest } = environment\n try {\n await host().patchSessionMeta(sessionId, environmentMetadata(suspended ? { ...rest, suspended: true } : rest), { bumpUpdatedAt: false })\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId })\n }\n catch (err) {\n hostDebug('marking the environment suspended failed', err)\n }\n }\n\n return { touchActivity, stopIdleSweep: () => clearInterval(idleSweep), markSuspended, environmentInUseElsewhere }\n}\n\nexport function createEnvironmentSuspend({ env, kinds, terminals, suspension }: {\n env: HostContext['env']\n kinds: EnvironmentKinds\n terminals: TerminalManager\n suspension: Pick<IdleSuspension, 'markSuspended' | 'environmentInUseElsewhere'>\n}): (sessionId: string, stillIdle?: () => boolean, options?: { respectIdleSetting?: boolean }) => Promise<void> {\n const { environments, environmentConfig } = kinds\n const { markSuspended, environmentInUseElsewhere } = suspension\n\n /**\n * The session's execution was let go while the session lives on: hand the\n * environment its `suspend` (pause a remote sandbox). Best-effort — a\n * failed pause leaves the environment running, never broken.\n */\n return async function suspendEnvironment(sessionId: string, stillIdle: () => boolean = () => true, options: { respectIdleSetting?: boolean } = {}): Promise<void> {\n const data = await env.store.load(sessionId)\n if (!data)\n return\n const environment = readSessionEnvironment(data.metadata)\n const provider = environments.get(environment.kind)\n if (environment.state !== 'ready' || !provider?.suspend || !stillIdle())\n return\n if (options.respectIdleSetting && !((provider.idleSuspendMinutes?.(environmentConfig(environment.kind)) ?? 0) > 0))\n return\n if (await environmentInUseElsewhere(sessionId, environment))\n return\n // Someone is working in one of its terminals (or an agent task runs in one): stay up.\n if (terminals.busy(sessionId))\n return\n // Remote terminals let go now and reconnect on next use.\n await terminals.suspendSession(sessionId)\n try {\n await provider.suspend(environment, { config: environmentConfig(environment.kind) })\n }\n catch (err) {\n hostDebug('environment suspend failed', err)\n return\n }\n // Rows show it paused; the next execution clears the flag (it resumes).\n if (stillIdle())\n await markSuspended(sessionId, environment, true)\n }\n}\n","/**\n * The agent's side: listing and reading a session's terminals as plain text,\n * waiting for output to settle, and terminals for agent background tasks.\n */\nimport type { TerminalProcess } from '../../../contexts/types'\nimport type { TerminalLifecycle } from './lifecycle'\nimport type { TerminalOutput } from './output'\nimport type { TerminalRegistry } from './registry'\nimport type { TerminalManager } from './types'\nimport { randomUUID } from 'node:crypto'\nimport { TERMINAL_READ_MAX_CHARS, TERMINAL_TEXT_MAX_LINES, TerminalError } from '../../terminal/protocol'\n\nexport type AgentMethods = Pick<TerminalManager, 'ownerOf' | 'list' | 'read' | 'settle' | 'agentTask'>\n\nexport function createAgentMethods(\n registry: Pick<TerminalRegistry, 'entries' | 'infos' | 'changed' | 'newEntry' | 'restore'>,\n output: Pick<TerminalOutput, 'onOutput' | 'flush'>,\n lifecycle: Pick<TerminalLifecycle, 'adopt'>,\n): AgentMethods {\n const { entries, infos, changed, newEntry, restore } = registry\n const { onOutput, flush } = output\n const { adopt } = lifecycle\n\n return {\n ownerOf: terminalId => entries.get(terminalId)?.info.owner,\n\n async list(sessionId, opts = {}) {\n await restore(sessionId)\n return infos(sessionId).filter(t => opts.includeHidden || !t.hiddenFromAgent)\n },\n\n async read(sessionId, terminalId, opts = {}) {\n const entry = entries.get(terminalId)\n if (!entry || entry.info.sessionId !== sessionId || entry.info.hiddenFromAgent)\n throw new TerminalError('not_found', `No terminal ${terminalId} in this session. Call terminal_list.`)\n flush(entry)\n const end = entry.lineBase + entry.lines.length\n const want = Math.max(1, Math.min(opts.lines ?? 200, TERMINAL_TEXT_MAX_LINES))\n let from = opts.since !== undefined ? Math.max(opts.since, entry.lineBase) : Math.max(entry.lineBase, end - want)\n from = Math.min(from, end)\n const selected = entry.lines.slice(from - entry.lineBase)\n const partial = entry.stripper.partial()\n if (partial)\n selected.push(partial)\n const shown = entry.shownPartial\n if (opts.since !== undefined && shown?.line === from && selected[0]?.startsWith(shown.text)) {\n const rest = selected[0].slice(shown.text.length)\n if (rest)\n selected[0] = rest\n else\n selected.shift()\n }\n entry.shownPartial = partial ? { line: end, text: partial } : undefined\n let truncated = 0\n let size = selected.reduce((n, l) => n + l.length + 1, 0)\n while (size > TERMINAL_READ_MAX_CHARS && selected.length > 1) {\n size -= selected.shift()!.length + 1\n truncated++\n }\n let text = selected.join('\\n')\n if (text.length > TERMINAL_READ_MAX_CHARS)\n text = text.slice(-TERMINAL_READ_MAX_CHARS)\n return { terminal: { ...entry.info }, text, next: end, truncated }\n },\n\n settle(terminalId, opts = {}) {\n const entry = entries.get(terminalId)\n if (!entry)\n return Promise.resolve()\n const quietMs = opts.quietMs ?? 400\n const maxMs = opts.maxMs ?? 3000\n return new Promise<void>((resolve) => {\n let quiet: ReturnType<typeof setTimeout> | undefined\n let cap: ReturnType<typeof setTimeout> | undefined\n function done(): void {\n clearTimeout(quiet)\n clearTimeout(cap)\n entry!.quietWaiters.delete(wake)\n opts.signal?.removeEventListener('abort', done)\n resolve()\n }\n function wake(): void {\n clearTimeout(quiet)\n quiet = setTimeout(done, entry!.process ? quietMs : 0)\n }\n cap = setTimeout(done, maxMs)\n entry.quietWaiters.add(wake)\n opts.signal?.addEventListener('abort', done, { once: true })\n wake()\n })\n },\n\n agentTask(sessionId, { command, cwd, environment }) {\n const now = Date.now()\n const oneLine = command.replace(/\\s+/g, ' ').trim()\n const entry = newEntry({\n id: `term-${randomUUID().slice(0, 8)}`,\n sessionId,\n label: oneLine.length > 48 ? `${oneLine.slice(0, 47)}…` : oneLine,\n owner: 'agent',\n target: 'session',\n environment,\n cwd,\n status: 'starting',\n cols: 120,\n rows: 30,\n hiddenFromAgent: false,\n sizeSeq: 0,\n createdAt: now,\n lastActivityAt: now,\n })\n let io: { write: (data: string | Uint8Array) => void, resize: (cols: number, rows: number) => void } | null = null\n let exitCode: (code: number) => void = () => {}\n const exited = new Promise<number>((resolve) => {\n exitCode = resolve\n })\n return {\n options: {\n cols: entry.info.cols,\n rows: entry.info.rows,\n onData: data => onOutput(entry, data),\n onReady: (ready) => {\n io = ready\n },\n },\n started: ({ taskId, terminal, kill }) => {\n if (!terminal) {\n // The context ran it with pipes: nothing to show as a terminal.\n entries.delete(entry.info.id)\n return\n }\n entry.info.taskId = taskId\n entry.killTask = kill\n const proc: TerminalProcess = {\n id: taskId,\n reconnectable: false,\n write: data => io?.write(data),\n resize: (c, r) => io?.resize(c, r),\n kill,\n detach: async () => {},\n exited,\n }\n adopt(entry, proc)\n changed(sessionId)\n },\n exited: (code) => {\n if (!entries.has(entry.info.id))\n return\n if (entry.process)\n exitCode(code ?? 1)\n else\n entries.delete(entry.info.id)\n changed(sessionId)\n },\n }\n },\n }\n}\n","/**\n * Whether a program in a terminal wants mouse reports, followed from its\n * output, and the reports themselves in input. Lets a host drop reports that\n * reach the PTY after the program turned tracking off (a view decides from\n * its own, slightly late, copy of the screen), which a shell would otherwise\n * read as typed text: `80;41;31M`.\n */\n\n/** DEC private modes that turn mouse reporting on: X10, normal, button-event, any-event. */\nconst TRACKING_MODES = new Set(['9', '1000', '1002', '1003'])\n\n/** Longest escape sequence a chunk boundary can split that matters here. */\nconst TAIL = 32\n\n// eslint-disable-next-line no-control-regex\nconst MODE_OR_RESET = /\\x1B\\[\\?([\\d;]+)([hl])|\\x1Bc/g\n// SGR (`ESC [ < b ; x ; y M|m`) and X10 (`ESC [ M` + three bytes) reports.\n// eslint-disable-next-line no-control-regex\nconst REPORT = /\\x1B\\[<\\d+;\\d+;\\d+[Mm]|\\x1B\\[M[\\s\\S]{3}/g\nconst PASTE_START = '\\x1B[200~'\n\nexport interface MouseModeTracker {\n /** Feed output; returns whether mouse tracking is on afterwards. */\n push: (output: string) => boolean\n readonly tracking: boolean\n}\n\nexport function createMouseModeTracker(): MouseModeTracker {\n const on = new Set<string>()\n let tail = ''\n return {\n push(output) {\n const text = tail + output\n MODE_OR_RESET.lastIndex = 0\n for (let m = MODE_OR_RESET.exec(text); m !== null; m = MODE_OR_RESET.exec(text)) {\n if (m[0] === '\\x1Bc') {\n on.clear()\n continue\n }\n for (const mode of m[1]!.split(';')) {\n if (!TRACKING_MODES.has(mode))\n continue\n if (m[2] === 'h')\n on.add(mode)\n else\n on.delete(mode)\n }\n }\n // A sequence split across chunks is whole in the next `text`. Re-reading\n // the end of this one is harmless: sequences apply again, in order.\n tail = text.slice(-TAIL)\n return on.size > 0\n },\n get tracking() {\n return on.size > 0\n },\n }\n}\n\n/** Input without mouse reports (a paste is left alone). */\nexport function stripMouseReports(input: string): string {\n if (input.startsWith(PASTE_START))\n return input\n return input.replace(REPORT, '')\n}\n","/**\n * A terminal's process: connecting (open or reconnect) through the session's\n * execution, adopting it, foreground-program labels, exit, and ending it.\n */\nimport type { TerminalProcess } from '../../../contexts/types'\nimport type { TerminalOutput } from './output'\nimport type { TerminalRegistry } from './registry'\nimport type { Entry, TerminalManagerDeps } from './types'\nimport { execFile } from 'node:child_process'\nimport { basename } from 'node:path'\nimport { TerminalError } from '../../terminal/protocol'\n\nconst LABEL_POLL_MS = 2_000\n/** Ended agent task terminals kept per session (with their history) for reading back. */\nconst MAX_EXITED_AGENT_TERMINALS = 8\n\nexport function createTerminalLifecycle(deps: TerminalManagerDeps, registry: TerminalRegistry, output: Pick<TerminalOutput, 'onOutput' | 'flush'>) {\n const { entries, bySession, changed, persist, closed, requireAvailable } = registry\n const { onOutput, flush } = output\n\n function onExit(entry: Entry, proc: TerminalProcess, code: number): void {\n if (entry.process !== proc)\n return\n flush(entry)\n entry.process = null\n stopLabels(entry)\n const tail = entry.stripper.takePartial()\n if (tail)\n entry.lines.push(tail)\n if (code === -1 && entry.remoteId) {\n entry.info.status = 'paused'\n }\n else {\n entry.info.status = 'exited'\n entry.info.exitCode = code\n delete entry.info.program\n }\n for (const wake of entry.quietWaiters) wake()\n // A shell the user ended cleanly (`exit`, ctrl+d) is done: close its tab,\n // as the close button would. A failure stays so its output can be read;\n // agent task terminals stay for the agent to read (and are pruned below).\n if (entry.info.owner === 'user' && entry.info.status === 'exited' && code === 0 && deps.closeOnCleanExit?.() === true) {\n if (entry.flushTimer)\n clearTimeout(entry.flushTimer)\n entries.delete(entry.info.id)\n }\n else if (entry.info.owner === 'agent') {\n pruneExitedAgentTerminals(entry.info.sessionId)\n }\n persist(entry.info.sessionId)\n changed(entry.info.sessionId)\n }\n\n /** Drop the oldest ended agent task terminals nobody is viewing, past the cap. */\n function pruneExitedAgentTerminals(sessionId: string): void {\n const done = bySession(sessionId).filter(e => e.info.owner === 'agent' && e.info.status === 'exited' && e.clients.size === 0)\n for (const e of done.slice(0, Math.max(0, done.length - MAX_EXITED_AGENT_TERMINALS)))\n entries.delete(e.info.id)\n }\n\n function adopt(entry: Entry, proc: TerminalProcess): void {\n entry.process = proc\n entry.remoteId = proc.reconnectable ? proc.id : undefined\n entry.info.status = 'running'\n delete entry.info.exitCode\n delete entry.info.error\n void proc.exited.then(code => onExit(entry, proc, code))\n startLabels(entry)\n }\n\n /** Foreground program of a local shell: its terminal's foreground process group leader. */\n function startLabels(entry: Entry): void {\n const pid = entry.process?.localPid\n if (!pid || entry.labelTimer)\n return\n const poll = () => {\n if (entry.clients.size === 0)\n return\n foregroundProgram(pid).then((program) => {\n if (program !== entry.info.program) {\n if (program)\n entry.info.program = program\n else\n delete entry.info.program\n changed(entry.info.sessionId)\n }\n }, () => {})\n }\n entry.labelTimer = setInterval(poll, LABEL_POLL_MS)\n entry.labelTimer.unref?.()\n }\n\n function stopLabels(entry: Entry): void {\n if (entry.labelTimer)\n clearInterval(entry.labelTimer)\n entry.labelTimer = null\n }\n\n /** Adopt a fresh process, or end it when the terminal was closed while it started. */\n async function adoptUnlessClosed(entry: Entry, proc: TerminalProcess): Promise<void> {\n if (closed(entry)) {\n await proc.kill().catch(() => {})\n return\n }\n adopt(entry, proc)\n }\n\n async function connect(entry: Entry, mode: 'open' | 'reconnect'): Promise<void> {\n const sessionId = entry.info.sessionId\n const execution = await deps.resolve(sessionId, entry.info.target)\n if (closed(entry))\n return\n entry.execution = execution\n const options = {\n cwd: entry.info.cwd || undefined,\n cols: entry.info.cols,\n rows: entry.info.rows,\n ...(deps.unsetEnv ? { unsetEnv: deps.unsetEnv } : {}),\n onData: (data: Uint8Array) => onOutput(entry, data),\n }\n if (mode === 'reconnect') {\n const proc = entry.remoteId && execution.context.reconnectTerminal\n ? await execution.context.reconnectTerminal(execution.handle, entry.remoteId, options)\n : null\n if (!proc) {\n entry.info.status = 'exited'\n entry.info.error = 'This terminal ended while it was disconnected.'\n entry.remoteId = undefined\n return\n }\n await adoptUnlessClosed(entry, proc)\n return\n }\n if (!execution.context.openTerminal)\n throw new TerminalError('unavailable', `Terminals are not supported in ${execution.environment} environments.`)\n if (!entry.info.cwd)\n entry.info.cwd = execution.handle.cwd\n entry.info.environment = execution.environment\n await adoptUnlessClosed(entry, await execution.context.openTerminal(execution.handle, { ...options, cwd: entry.info.cwd }))\n }\n\n /** Bring a paused terminal back (reconnect), once, however many views ask. */\n async function ensureConnected(entry: Entry): Promise<void> {\n if (entry.info.status !== 'paused')\n return\n // Terminals turned off: a stored shell stays paused, whichever client asks.\n requireAvailable()\n entry.connecting ??= connect(entry, 'reconnect')\n .catch((err) => {\n entry.info.status = 'error'\n entry.info.error = errorText(err)\n })\n .finally(() => {\n entry.connecting = null\n persist(entry.info.sessionId)\n changed(entry.info.sessionId)\n })\n await entry.connecting\n }\n\n async function end(entry: Entry): Promise<void> {\n stopLabels(entry)\n if (entry.flushTimer)\n clearTimeout(entry.flushTimer)\n const proc = entry.process\n entry.process = null\n if (entry.killTask)\n await entry.killTask().catch(() => {})\n else\n await proc?.kill().catch(() => {})\n for (const wake of entry.quietWaiters) wake()\n }\n\n return { onExit, adopt, stopLabels, connect, ensureConnected, end }\n}\n\nexport type TerminalLifecycle = ReturnType<typeof createTerminalLifecycle>\n\nexport function errorText(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nfunction run(file: string, args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(file, args, { timeout: 1500 }, (err, stdout) => err ? reject(err) : resolve(String(stdout)))\n })\n}\n\n/** Name of what runs in the foreground of the shell's terminal, or undefined for the shell itself. */\nasync function foregroundProgram(shellPid: number): Promise<string | undefined> {\n const tpgid = Number.parseInt((await run('ps', ['-o', 'tpgid=', '-p', String(shellPid)])).trim(), 10)\n if (!Number.isFinite(tpgid) || tpgid <= 0 || tpgid === shellPid)\n return undefined\n const comm = (await run('ps', ['-o', 'comm=', '-p', String(tpgid)])).trim()\n return comm ? basename(comm).replace(/^-/, '') : undefined\n}\n","/**\n * The methods a client window drives: state, open, attach / detach, typing,\n * resize, acks, restart, close, and hiding a terminal from the agent.\n */\nimport type { TerminalLifecycle } from './lifecycle'\nimport type { TerminalOutput } from './output'\nimport type { TerminalRegistry } from './registry'\nimport type { TerminalManager, TerminalManagerDeps } from './types'\nimport type { TerminalViews } from './views'\nimport { randomUUID } from 'node:crypto'\nimport { stripMouseReports } from '../../../contexts/terminal-mouse'\nimport { TERMINAL_MAX_PER_SESSION, TERMINAL_OUTPUT_WINDOW, TerminalError } from '../../terminal/protocol'\nimport { errorText } from './lifecycle'\n\nexport type ClientMethods = Pick<TerminalManager, 'state' | 'open' | 'attach' | 'detach' | 'detachClient' | 'write' | 'resize' | 'ack' | 'restart' | 'close' | 'setHidden'>\n\nexport function createClientMethods(\n deps: TerminalManagerDeps,\n registry: TerminalRegistry,\n output: TerminalOutput,\n lifecycle: TerminalLifecycle,\n views: Pick<TerminalViews, 'applySize' | 'detach'>,\n): ClientMethods {\n const { entries, bySession, infos, changed, nextLabel, persist, newEntry, restore, get, requireAvailable } = registry\n const { activity, record, lag, flush, snapshot, reset } = output\n const { connect, ensureConnected, end } = lifecycle\n const { applySize, detach } = views\n\n return {\n async state(sessionId) {\n const ok = deps.available()\n await restore(sessionId)\n const environment = await deps.environmentOf(sessionId).catch(() => ({ kind: 'local', remote: false }))\n return {\n available: ok.ok,\n ...(ok.ok ? {} : { reason: ok.reason }),\n environment,\n terminals: infos(sessionId),\n }\n },\n\n async open({ sessionId, target = 'session', cols, rows }) {\n requireAvailable()\n await restore(sessionId)\n // Agent task terminals do not count: they would lock the user out.\n const live = bySession(sessionId).filter(e => e.info.owner === 'user'\n && (e.info.status === 'running' || e.info.status === 'starting' || e.info.status === 'paused'))\n if (live.length >= TERMINAL_MAX_PER_SESSION)\n throw new TerminalError('limit', `A session can have ${TERMINAL_MAX_PER_SESSION} terminals open; close one first.`)\n // A shell on this machine next to a sandboxed session starts hidden from\n // the agent: showing it would hand the agent the host the user isolated\n // it from. The user can reveal it.\n const hostShellInSandbox = target === 'local'\n && (await deps.environmentOf(sessionId).catch(() => ({ remote: true }))).remote\n const now = Date.now()\n const entry = newEntry({\n id: `term-${randomUUID().slice(0, 8)}`,\n sessionId,\n label: nextLabel(sessionId),\n owner: 'user',\n target,\n environment: target === 'local' ? 'local' : '',\n cwd: '',\n status: 'starting',\n cols,\n rows,\n hiddenFromAgent: hostShellInSandbox,\n sizeSeq: 0,\n createdAt: now,\n lastActivityAt: now,\n })\n changed(sessionId)\n try {\n await connect(entry, 'open')\n }\n catch (err) {\n entry.info.status = 'error'\n entry.info.error = errorText(err)\n }\n persist(sessionId)\n changed(sessionId)\n return { ...entry.info }\n },\n\n async attach(terminalId, clientId) {\n const entry = get(terminalId)\n await ensureConnected(entry)\n flush(entry)\n entry.clients.set(clientId, entry.total)\n if (entry.clients.size === 1) {\n entry.sent = entry.total\n entry.stalled = false\n }\n return { terminal: { ...entry.info }, data: snapshot(entry), offset: entry.total }\n },\n\n detach,\n\n detachClient(clientId) {\n for (const entry of entries.values()) {\n if (entry.clients.has(clientId))\n detach(entry.info.id, clientId)\n }\n },\n\n async write(terminalId, data, from) {\n const entry = get(terminalId)\n /*\n * A reply the terminal emulator generated (cursor position, device\n * attributes) comes from every view that parsed the query: only the\n * view that owns the size answers, or the shell reads the extra ones\n * as typed text (`;1R;1R…`).\n */\n if (from?.response) {\n if (!entry.process || (entry.sizeOwner !== undefined && entry.sizeOwner !== from.clientId))\n return\n entry.process.write(data)\n return\n }\n await ensureConnected(entry)\n if (!entry.process)\n throw new TerminalError('not_running', `${entry.info.label} is not running.`)\n activity(entry)\n /*\n * Mouse reports a view sent after the program turned tracking off (it\n * quit, the view hadn't drawn that yet): the shell would print them.\n */\n const input = entry.mouse.tracking ? data : stripMouseReports(data)\n if (input)\n entry.process.write(input)\n },\n\n resize(terminalId, clientId, cols, rows, claim = false) {\n const entry = entries.get(terminalId)\n if (!entry || !Number.isFinite(cols) || !Number.isFinite(rows) || cols < 2 || rows < 2)\n return\n if (entry.clients.has(clientId)) {\n entry.sizeRequests.delete(clientId)\n entry.sizeRequests.set(clientId, { cols, rows })\n }\n if (!claim && entry.sizeOwner !== undefined && entry.sizeOwner !== clientId)\n return\n applySize(entry, clientId, cols, rows)\n },\n\n ack(terminalId, clientId, offset) {\n const entry = entries.get(terminalId)\n if (!entry || !entry.clients.has(clientId) || !Number.isFinite(offset))\n return\n entry.clients.set(clientId, Math.max(entry.clients.get(clientId)!, Math.min(offset, entry.sent)))\n if (entry.stalled && lag(entry) <= TERMINAL_OUTPUT_WINDOW / 2)\n reset(entry)\n },\n\n async restart(terminalId) {\n requireAvailable()\n const entry = get(terminalId)\n if (entry.info.owner === 'agent')\n throw new TerminalError('failed', 'Agent terminals end with their task; ask the agent to run it again.')\n await end(entry)\n entry.remoteId = undefined\n const banner = '\\r\\n[restarted]\\r\\n'\n record(entry, banner)\n entry.pending += banner\n flush(entry)\n entry.info.status = 'starting'\n changed(entry.info.sessionId)\n try {\n await connect(entry, 'open')\n }\n catch (err) {\n entry.info.status = 'error'\n entry.info.error = errorText(err)\n }\n persist(entry.info.sessionId)\n changed(entry.info.sessionId)\n return { ...entry.info }\n },\n\n async close(terminalId) {\n const entry = entries.get(terminalId)\n if (!entry)\n return\n entries.delete(terminalId)\n await end(entry)\n persist(entry.info.sessionId)\n changed(entry.info.sessionId)\n },\n\n setHidden(terminalId, hidden) {\n const entry = get(terminalId)\n if (entry.info.hiddenFromAgent === hidden)\n return\n entry.info.hiddenFromAgent = hidden\n persist(entry.info.sessionId)\n changed(entry.info.sessionId)\n },\n }\n}\n","/**\n * Output pacing: chunks are recorded (history, plain lines for the agent),\n * batched and sent with their start offset, and held back once the slowest\n * attached client is a window behind — then everyone is reset from history.\n */\nimport type { Entry, TerminalManagerDeps } from './types'\nimport { TERMINAL_HISTORY_MAX_CHARS, TERMINAL_OUTPUT_WINDOW, TERMINAL_TEXT_MAX_LINES } from '../../terminal/protocol'\n\nconst FLUSH_MS = 16\nconst TOUCH_EVERY_MS = 10_000\n\nexport function createTerminalOutput(deps: TerminalManagerDeps) {\n function activity(entry: Entry): void {\n const now = Date.now()\n entry.info.lastActivityAt = now\n if (now - entry.lastTouch > TOUCH_EVERY_MS) {\n entry.lastTouch = now\n deps.touch(entry.info.sessionId)\n }\n }\n\n function record(entry: Entry, text: string): void {\n entry.history.push(text)\n entry.historyChars += text.length\n while (entry.historyChars > TERMINAL_HISTORY_MAX_CHARS && entry.history.length > 1)\n entry.historyChars -= entry.history.shift()!.length\n entry.total += text.length\n const completed = entry.stripper.push(text)\n if (completed) {\n const parts = completed.split('\\n')\n parts.pop()\n entry.lines.push(...parts)\n const over = entry.lines.length - TERMINAL_TEXT_MAX_LINES\n if (over > 0) {\n entry.lines.splice(0, over)\n entry.lineBase += over\n }\n }\n }\n\n function onOutput(entry: Entry, data: Uint8Array): void {\n const text = entry.decoder.decode(data, { stream: true })\n if (!text)\n return\n entry.mouse.push(text)\n record(entry, text)\n activity(entry)\n entry.pending += text\n entry.flushTimer ??= setTimeout(flush, FLUSH_MS, entry)\n for (const wake of entry.quietWaiters) wake()\n }\n\n function lag(entry: Entry): number {\n let slowest = entry.sent\n for (const acked of entry.clients.values()) slowest = Math.min(slowest, acked)\n return entry.sent - slowest\n }\n\n function flush(entry: Entry): void {\n if (entry.flushTimer)\n clearTimeout(entry.flushTimer)\n entry.flushTimer = null\n const data = entry.pending\n entry.pending = ''\n if (!data)\n return\n if (entry.clients.size === 0) {\n entry.sent = entry.total\n return\n }\n if (entry.stalled || lag(entry) > TERMINAL_OUTPUT_WINDOW) {\n entry.stalled = true\n return\n }\n const offset = entry.sent\n entry.sent += data.length\n deps.broadcast({ kind: 'terminal:output', sessionId: entry.info.sessionId, terminalId: entry.info.id, offset, data })\n }\n\n /** Recorded output, or only its last `maxChars` characters. */\n function snapshot(entry: Entry, maxChars = Infinity): string {\n if (entry.historyChars <= maxChars)\n return entry.history.join('')\n const tail: string[] = []\n let size = 0\n for (let i = entry.history.length - 1; i >= 0 && size < maxChars; i--) {\n tail.unshift(entry.history[i]!)\n size += entry.history[i]!.length\n }\n return tail.join('').slice(-maxChars)\n }\n\n function reset(entry: Entry): void {\n flush(entry)\n entry.stalled = false\n entry.pending = ''\n entry.sent = entry.total\n for (const id of entry.clients.keys()) entry.clients.set(id, entry.total)\n // Capped: this goes to every attached view unpaced, and the full history\n // could overflow a peer's socket buffer.\n deps.broadcast({ kind: 'terminal:reset', sessionId: entry.info.sessionId, terminalId: entry.info.id, offset: entry.total, data: snapshot(entry, TERMINAL_OUTPUT_WINDOW) })\n }\n\n return { activity, record, onOutput, lag, flush, snapshot, reset }\n}\n\nexport type TerminalOutput = ReturnType<typeof createTerminalOutput>\n","/**\n * The manager's terminals and their bookkeeping: entries by id, labels, the\n * persisted records (loaded once per session, rewritten only on change), and\n * the lookups every other part goes through.\n */\nimport type { TerminalInfo } from '../../terminal/protocol'\nimport type { Entry, PersistedTerminal, TerminalManagerDeps } from './types'\nimport { createAnsiStripper } from '../../../contexts/ansi-strip'\nimport { createMouseModeTracker } from '../../../contexts/terminal-mouse'\nimport { TerminalError } from '../../terminal/protocol'\n\nexport function createTerminalRegistry(deps: TerminalManagerDeps) {\n const entries = new Map<string, Entry>()\n /** Sessions whose persisted terminals were loaded. */\n const restored = new Map<string, Promise<void>>()\n const counters = new Map<string, number>()\n /** Last records written per session, to skip writes that change nothing. */\n const persisted = new Map<string, string>()\n\n const bySession = (sessionId: string) => [...entries.values()].filter(e => e.info.sessionId === sessionId)\n const infos = (sessionId: string) => bySession(sessionId).map(e => ({ ...e.info }))\n\n const changed = (sessionId: string) => deps.broadcast({ kind: 'terminal:changed', sessionId, terminals: infos(sessionId) })\n\n function nextLabel(sessionId: string): string {\n const n = (counters.get(sessionId) ?? 0) + 1\n counters.set(sessionId, n)\n return `Terminal ${n}`\n }\n\n function persist(sessionId: string): void {\n const records: PersistedTerminal[] = bySession(sessionId).flatMap(e =>\n e.remoteId && e.info.owner === 'user' && (e.info.status === 'running' || e.info.status === 'paused')\n ? [{\n id: e.info.id,\n label: e.info.label,\n target: e.info.target,\n environment: e.info.environment,\n cwd: e.info.cwd,\n remoteId: e.remoteId,\n createdAt: e.info.createdAt,\n ...(e.info.hiddenFromAgent ? { hiddenFromAgent: true } : {}),\n }]\n : [])\n // Records never loaded (or failed to): writing now could overwrite them.\n if (!persisted.has(sessionId))\n return\n const key = JSON.stringify(records)\n if (persisted.get(sessionId) === key)\n return\n persisted.set(sessionId, key)\n void deps.saveRecords(sessionId, records).catch(() => {})\n }\n\n function newEntry(info: TerminalInfo): Entry {\n const entry: Entry = {\n info,\n process: null,\n history: [],\n historyChars: 0,\n total: 0,\n decoder: new TextDecoder(),\n mouse: createMouseModeTracker(),\n stripper: createAnsiStripper({\n onTitle: (title) => {\n if (entry.info.title !== title) {\n entry.info.title = title\n changed(entry.info.sessionId)\n }\n },\n }),\n lines: [],\n lineBase: 0,\n clients: new Map(),\n sizeRequests: new Map(),\n sent: 0,\n pending: '',\n flushTimer: null,\n stalled: false,\n lastTouch: 0,\n quietWaiters: new Set(),\n labelTimer: null,\n connecting: null,\n }\n entries.set(info.id, entry)\n return entry\n }\n\n /** Closed (removed from the map) while an await was pending. */\n const closed = (entry: Entry): boolean => entries.get(entry.info.id) !== entry\n\n function restore(sessionId: string): Promise<void> {\n let pending = restored.get(sessionId)\n if (!pending) {\n pending = deps.loadRecords(sessionId).then((records) => {\n persisted.set(sessionId, JSON.stringify(records))\n for (const r of records) {\n if (entries.has(r.id))\n continue\n const n = Number.parseInt(r.label.replace(/^Terminal /, ''), 10)\n if (Number.isFinite(n))\n counters.set(sessionId, Math.max(counters.get(sessionId) ?? 0, n))\n const entry = newEntry({\n id: r.id,\n sessionId,\n label: r.label,\n owner: 'user',\n target: r.target,\n environment: r.environment,\n cwd: r.cwd,\n status: 'paused',\n cols: 80,\n rows: 24,\n hiddenFromAgent: r.hiddenFromAgent === true,\n sizeSeq: 0,\n createdAt: r.createdAt,\n lastActivityAt: r.createdAt,\n })\n entry.remoteId = r.remoteId\n }\n // Terminals opened while the records were unavailable.\n persist(sessionId)\n }, () => {\n // Retry on the next call instead of hiding the stored terminals until restart.\n restored.delete(sessionId)\n })\n restored.set(sessionId, pending)\n }\n return pending\n }\n\n function get(terminalId: string): Entry {\n const entry = entries.get(terminalId)\n if (!entry)\n throw new TerminalError('not_found', `No terminal ${terminalId}.`)\n return entry\n }\n\n function requireAvailable(): void {\n const ok = deps.available()\n if (!ok.ok)\n throw new TerminalError('unavailable', ok.reason)\n }\n\n return { entries, restored, counters, persisted, bySession, infos, changed, nextLabel, persist, newEntry, closed, restore, get, requireAvailable }\n}\n\nexport type TerminalRegistry = ReturnType<typeof createTerminalRegistry>\n","/**\n * Session- and host-wide terminal lifecycle: activity and execution holds,\n * suspending a session's remote terminals, closing a session's or every\n * user's terminals, and host shutdown.\n */\nimport type { TerminalLifecycle } from './lifecycle'\nimport type { TerminalRegistry } from './registry'\nimport type { TerminalManager, TerminalManagerDeps } from './types'\n\nconst DEFAULT_BUSY_MS = 2 * 60_000\n\nexport type SessionMethods = Pick<TerminalManager, 'busy' | 'holdsExecution' | 'hasRunningLocal' | 'suspendSession' | 'closeUserTerminals' | 'closeSession' | 'shutdown'>\n\nexport function createSessionMethods(\n deps: TerminalManagerDeps,\n registry: Pick<TerminalRegistry, 'entries' | 'restored' | 'counters' | 'persisted' | 'bySession' | 'changed' | 'persist'>,\n lifecycle: Pick<TerminalLifecycle, 'stopLabels' | 'end'>,\n): SessionMethods {\n const { entries, restored, counters, persisted, bySession, changed, persist } = registry\n const { stopLabels, end } = lifecycle\n\n return {\n busy(sessionId, withinMs = DEFAULT_BUSY_MS) {\n const now = Date.now()\n return bySession(sessionId).some(e => e.process !== null\n && (e.info.owner === 'agent' || now - e.info.lastActivityAt < withinMs))\n },\n\n holdsExecution(sessionId) {\n return bySession(sessionId).some(e => e.info.owner === 'user' && e.info.target === 'session'\n && e.process !== null && !e.process.reconnectable)\n },\n\n hasRunningLocal() {\n return [...entries.values()].some(e => e.info.owner === 'user' && e.process !== null && !e.process.reconnectable)\n },\n\n async suspendSession(sessionId) {\n await Promise.all(bySession(sessionId).map(async (entry) => {\n const proc = entry.process\n if (!proc || !proc.reconnectable)\n return\n entry.process = null\n stopLabels(entry)\n entry.info.status = 'paused'\n await proc.detach().catch(() => {})\n }))\n persist(sessionId)\n changed(sessionId)\n },\n\n async closeUserTerminals() {\n const list = [...entries.values()].filter(e => e.info.owner === 'user')\n for (const entry of list) entries.delete(entry.info.id)\n await Promise.all(list.map(async (entry) => {\n await end(entry)\n // A paused remote shell still runs in the sandbox: reattach to kill it,\n // or it outlives the record that could find it again.\n const remoteId = entry.remoteId\n entry.remoteId = undefined\n if (!remoteId || entry.info.status !== 'paused')\n return\n try {\n const execution = await deps.resolve(entry.info.sessionId, entry.info.target)\n const proc = await execution.context.reconnectTerminal?.(execution.handle, remoteId, {\n cols: entry.info.cols,\n rows: entry.info.rows,\n onData: () => {},\n })\n await proc?.kill()\n }\n catch {}\n }))\n for (const sessionId of new Set(list.map(e => e.info.sessionId))) {\n persist(sessionId)\n changed(sessionId)\n }\n },\n\n async closeSession(sessionId) {\n const list = bySession(sessionId)\n for (const entry of list) entries.delete(entry.info.id)\n restored.delete(sessionId)\n counters.delete(sessionId)\n persisted.delete(sessionId)\n await Promise.all(list.map(end))\n },\n\n async shutdown() {\n await Promise.all([...entries.values()].map(async (entry) => {\n const proc = entry.process\n stopLabels(entry)\n if (!proc)\n return\n entry.process = null\n // Remote PTYs outlive the host (a restart reconnects them); local ones end with it.\n if (proc.reconnectable)\n await proc.detach().catch(() => {})\n else if (entry.killTask)\n await entry.killTask().catch(() => {})\n else\n await proc.kill().catch(() => {})\n }))\n },\n }\n}\n","/**\n * Who shows a terminal and who sizes it: viewer clients (which gate the\n * agent's terminal tools), the size owner among attached views, and detach.\n */\nimport type { TerminalOutput } from './output'\nimport type { TerminalRegistry } from './registry'\nimport type { Entry, TerminalManager } from './types'\nimport { TERMINAL_OUTPUT_WINDOW } from '../../terminal/protocol'\n\nexport function createTerminalViews(registry: Pick<TerminalRegistry, 'entries' | 'changed'>, output: Pick<TerminalOutput, 'lag' | 'reset'>) {\n const { entries, changed } = registry\n const { lag, reset } = output\n\n function applySize(entry: Entry, clientId: string, cols: number, rows: number): void {\n entry.sizeOwner = clientId\n const c = Math.min(Math.floor(cols), 1000)\n const r = Math.min(Math.floor(rows), 1000)\n if (c === entry.info.cols && r === entry.info.rows)\n return\n entry.info.cols = c\n entry.info.rows = r\n entry.info.sizeSeq++\n entry.process?.resize(c, r)\n changed(entry.info.sessionId)\n }\n\n function detach(terminalId: string, clientId: string): void {\n const entry = entries.get(terminalId)\n if (!entry)\n return\n entry.clients.delete(clientId)\n entry.sizeRequests.delete(clientId)\n if (entry.sizeOwner === clientId) {\n delete entry.sizeOwner\n // The view still showing it takes the size it last asked for.\n const next = [...entry.sizeRequests].at(-1)\n if (next)\n applySize(entry, next[0], next[1].cols, next[1].rows)\n }\n if (entry.stalled && lag(entry) <= TERMINAL_OUTPUT_WINDOW / 2)\n reset(entry)\n }\n\n const viewers = new Set<string>()\n const viewerListeners = new Set<(available: boolean) => void>()\n const notifyViewers = (available: boolean): void => {\n for (const listener of viewerListeners)\n listener(available)\n }\n\n const methods: Pick<TerminalManager, 'registerViewer' | 'unregisterViewer' | 'hasViewer' | 'onViewerChange'> = {\n registerViewer(viewerId) {\n const had = viewers.size > 0\n viewers.add(viewerId)\n if (!had)\n notifyViewers(true)\n },\n unregisterViewer(viewerId) {\n if (viewers.delete(viewerId) && viewers.size === 0)\n notifyViewers(false)\n },\n hasViewer: () => viewers.size > 0,\n onViewerChange(listener) {\n viewerListeners.add(listener)\n return () => viewerListeners.delete(listener)\n },\n }\n\n return { applySize, detach, methods }\n}\n\nexport type TerminalViews = ReturnType<typeof createTerminalViews>\n","/**\n * Terminal manager: the session's terminals live here, in the host, so they\n * keep running while no window shows them and every view (the GUI's drawer,\n * its panel tab, another window) sees the same one.\n *\n * Where a terminal runs is the execution context's business\n * (`ExecutionContext.openTerminal`): this machine, the session's container,\n * its remote sandbox. The manager only keeps history, paces output to\n * clients, tracks who sets the size, and gives the agent a plain-text view.\n *\n * Output pacing: chunks are batched (16 ms) and carry their start offset.\n * Each attached client acknowledges what it wrote; once the slowest is a\n * window behind, sending stops, history keeps recording, and when it\n * catches up every client is reset from history.\n */\nimport type { TerminalManager, TerminalManagerDeps } from './types'\nimport { createAgentMethods } from './agent-methods'\nimport { createClientMethods } from './client-methods'\nimport { createTerminalLifecycle } from './lifecycle'\nimport { createTerminalOutput } from './output'\nimport { createTerminalRegistry } from './registry'\nimport { createSessionMethods } from './session-methods'\nimport { createTerminalViews } from './views'\n\nexport type { AgentTaskTerminal, PersistedTerminal, TerminalExecution, TerminalManager, TerminalManagerDeps } from './types'\n\nexport function createTerminalManager(deps: TerminalManagerDeps): TerminalManager {\n const registry = createTerminalRegistry(deps)\n const output = createTerminalOutput(deps)\n const lifecycle = createTerminalLifecycle(deps, registry, output)\n const views = createTerminalViews(registry, output)\n\n return {\n ...views.methods,\n ...createClientMethods(deps, registry, output, lifecycle, views),\n ...createAgentMethods(registry, output, lifecycle),\n ...createSessionMethods(deps, registry, lifecycle),\n }\n}\n","/**\n * The sessions' terminals as this host wires them: where a terminal opens\n * (the session's execution, or this machine), persisted records, and the\n * agent's background tasks routed into terminals the user can watch.\n */\nimport type { ExecutionContext, TaskHandle } from '../../../contexts/types'\nimport type { SessionData } from '../../../session/index'\nimport type { SessionEnvironment } from '../../environment'\nimport type { SessionExecution, SessionExecutionCache } from '../../execution-cache'\nimport type { ChatHostEnvironment } from '../environment'\nimport type { HostSettings, HostSignal } from '../signals'\nimport type { PersistedTerminal, TerminalManager } from '../terminal'\nimport { hasLocalPty } from '../../../contexts/local-terminal'\nimport { createProcessContext } from '../../../contexts/process'\nimport { assertEnvironmentReady, readSessionEnvironment } from '../../environment'\nimport { createTerminalManager } from '../terminal'\n\n/** Host plumbing a user's terminal must not inherit (a dev server would grab `PORT`, a child would think it is Electron). */\nconst TERMINAL_UNSET_ENV = [\n 'PORT',\n 'ELECTRON_RUN_AS_NODE',\n 'ELECTRON_RENDERER_PORT',\n 'ZIDANE_DAEMON_SOCKET',\n 'ZIDANE_GUI_TEST_HOOKS',\n 'ZIDANE_GUI_HEADLESS',\n 'ZIDANE_GUI_DATA_DIR',\n 'ZIDANE_GUI_ELECTRON_USERDATA',\n] as const\n\n/** Kinds whose sessions run off this machine's project checkout: their terminals can also open locally. */\nfunction isRemoteEnvironment(kind: string): boolean {\n return kind !== 'local' && kind !== 'worktree'\n}\n\nexport function createHostTerminals({ env, broadcast, sessionCwd, executionCache, sessionExecution, touchActivity, saveRecords }: {\n env: ChatHostEnvironment\n broadcast: (signal: HostSignal) => void\n sessionCwd: (sessionId: string, data: SessionData) => string\n executionCache: SessionExecutionCache\n sessionExecution: (sessionId: string, input: { cwd: string, environment: SessionEnvironment, settings: HostSettings }) => Promise<{ execution: SessionExecution }>\n touchActivity: (sessionId: string) => void\n saveRecords: (sessionId: string, records: PersistedTerminal[]) => Promise<void>\n}): TerminalManager {\n /**\n * Terminals open where the session runs: through the session's execution\n * (its container, its sandbox), or on this machine in the session's\n * directory (`target: 'local'`). Only a Bun host has a PTY, so under the\n * GUI's in-process host (Node) terminals are unavailable: they need the\n * daemon, which also keeps them alive across windows.\n */\n const localTerminalContext = createProcessContext()\n return createTerminalManager({\n broadcast,\n closeOnCleanExit: () => env.readSettings().closeTerminalOnCleanExit !== false,\n available: () => env.readSettings().terminal === false\n ? { ok: false, reason: 'Terminals are turned off in Settings.' }\n : hasLocalPty()\n ? { ok: true }\n : { ok: false, reason: 'Terminals run in the Zidane daemon, which is not connected.' },\n async resolve(sessionId, target) {\n const data = await env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n const environment = readSessionEnvironment(data.metadata)\n const cwd = sessionCwd(sessionId, data)\n if (target === 'local') {\n const localCwd = isRemoteEnvironment(environment.kind) ? (data.projectRoot ?? cwd) : cwd\n return { context: localTerminalContext, handle: await localTerminalContext.spawn({ cwd: localCwd }), environment: 'local' }\n }\n assertEnvironmentReady(environment)\n const execution = executionCache.peek(sessionId)\n ?? (await sessionExecution(sessionId, { cwd, environment, settings: env.readSettings() })).execution\n return { context: execution.context, handle: await execution.handle(), environment: environment.kind }\n },\n async environmentOf(sessionId) {\n const data = await env.store.load(sessionId)\n const kind = data ? readSessionEnvironment(data.metadata).kind : 'local'\n return { kind, remote: isRemoteEnvironment(kind) }\n },\n async loadRecords(sessionId) {\n const data = await env.store.load(sessionId)\n const stored = data?.metadata?.terminals\n return Array.isArray(stored) ? stored as PersistedTerminal[] : []\n },\n saveRecords,\n touch: touchActivity,\n unsetEnv: TERMINAL_UNSET_ENV,\n })\n}\n\nexport function createTerminalTaskRouting(terminals: TerminalManager): (context: ExecutionContext, sessionId: string, environmentKind: string) => ExecutionContext {\n /**\n * The agent's execution, with background tasks run in terminals the user\n * can watch and type into (when the context supports it; otherwise pipes,\n * as before). Exit is followed through `waitBackground`, whose watchers\n * survive the owner-callback rebinding an agent rebuild does.\n */\n function withTerminalTasks(context: ExecutionContext, sessionId: string, environmentKind: string): ExecutionContext {\n const execBackground = context.execBackground\n if (!execBackground)\n return context\n return {\n ...context,\n async execBackground(handle, command, options) {\n if (options.terminal)\n return execBackground(handle, command, options)\n const tab = terminals.agentTask(sessionId, { command, cwd: options.cwd ?? handle.cwd, environment: environmentKind })\n let task: TaskHandle\n try {\n task = await execBackground(handle, command, { ...options, terminal: tab.options })\n }\n catch (err) {\n tab.exited(null)\n throw err\n }\n tab.started({\n taskId: task.taskId,\n terminal: task.terminal === true,\n kill: async () => {\n await context.killBackground?.(handle, task.taskId)\n },\n })\n void (context.waitBackground?.(handle, task.taskId) ?? Promise.resolve(null))\n .then(info => tab.exited(info?.exitCode ?? null), () => tab.exited(null))\n return task\n },\n }\n }\n return withTerminalTasks\n}\n","/**\n * Where a session's work runs: the session execution (cached across agent\n * rebuilds), environment kinds with their settings and secrets, background\n * provisioning, idle suspension (sweep + suspend), forks sharing an\n * environment, the session workspace, the sessions' terminals — and the host\n * methods over them, session delete included (it ends here so the execution\n * and environment teardown cannot be skipped).\n */\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport { createSessionExecutionCache } from '../../execution-cache'\nimport { createEnvironmentKinds } from './environments'\nimport { createExecutionMethods } from './methods'\nimport { createProvisioning } from './provisioning'\nimport { createSessionExecution } from './session-execution'\nimport { createEnvironmentSuspend, createIdleSuspension } from './suspension'\nimport { createHostTerminals, createTerminalTaskRouting } from './terminals'\n\nexport type { ExecutionMethods } from './methods'\n\nexport function createExecution({ ctx, host, drainQueue, evictIdleSession, sessionSafelists }: {\n ctx: HostContext\n /** The finished host — features are built before it, and only call this at runtime. */\n host: () => ChatHost\n drainQueue: (sessionId: string) => void\n evictIdleSession: (sessionId: string) => void\n /** Forgotten on session delete. */\n sessionSafelists: Map<string, Set<string>>\n}) {\n const { env, broadcast, sessionCwd } = ctx\n /*\n * Each session's execution context + host-owned handle, kept across agent\n * rebuilds (model/profile swap, settings teardown via `shutdown()`, MCP\n * login, idle eviction with running tasks) so its background tasks survive\n * them. Released only when the SESSION ends: `disposeSession` (delete),\n * idle eviction with nothing running, `drain()` (process exit).\n */\n const executionCache = createSessionExecutionCache()\n\n const kinds = createEnvironmentKinds(env)\n const provisioning = createProvisioning({ ctx, host, kinds, drainQueue })\n const suspension = createIdleSuspension({ ctx, host, kinds, executionCache, provisioning: provisioning.provisioning, evictIdleSession })\n const execution = createSessionExecution({ ctx, kinds, executionCache, suspension })\n const { sessionExecution } = execution\n\n let patchSessionMetaLate: ChatHost['patchSessionMeta'] = async () => {}\n const terminals = createHostTerminals({\n env,\n broadcast,\n sessionCwd,\n executionCache,\n sessionExecution,\n touchActivity: suspension.touchActivity,\n // Bound once `host` exists (`bindHostMetaPatch`): its metadata patch knows about live agents.\n saveRecords: (sessionId, records) => patchSessionMetaLate(sessionId, { terminals: records }, { bumpUpdatedAt: false }),\n })\n const withTerminalTasks = createTerminalTaskRouting(terminals)\n const suspendEnvironment = createEnvironmentSuspend({ env, kinds, terminals, suspension })\n\n const methods = createExecutionMethods({ ctx, host, kinds, provisioning, sessionExecution: execution, executionCache, terminals, sessionSafelists })\n\n return {\n executionCache,\n provisioning: provisioning.provisioning,\n terminals,\n withTerminalTasks,\n sessionExecution,\n suspendEnvironment,\n createSessionInStore: provisioning.createSessionInStore,\n stopIdleSweep: suspension.stopIdleSweep,\n bindHostMetaPatch: (patch: ChatHost['patchSessionMeta']) => {\n patchSessionMetaLate = patch\n },\n methods,\n }\n}\n","import type { SessionStore } from '../../session/index'\n/**\n * Interaction hub — `present_plan` + `ask_user` HITL flow.\n *\n * Bridge between the canonical `createInteractionTools` factory and the\n * host's clients. The agent loop's tool body calls back into\n * `requestInteractionFor(sessionId)(req)`; the returned Promise resolves\n * once ANY client submits an answer through `respond`.\n *\n * Symmetry with the approval hub:\n * - Both queue per-session requests in memory.\n * - Both broadcast a `*:request` signal so clients can pop a UI surface.\n * - Both rehydrate requests left dangling by a prior process exit —\n * canonical `pendingInteractionsFromTurns` for interactions.\n *\n * Resume semantics — when a session reloads with unanswered\n * `present_plan` / `ask_user` `tool_use` blocks, `rehydrate` re-queues every\n * orphan (ordered by turn appearance). Resumed answers accumulate in memory\n * and flush only when every sibling orphan has an explicit response, so the\n * next `agent.run()` sees a protocol-clean history.\n */\nimport type { InteractionRequest, InteractionResponse } from '../interactions'\nimport type { Settings } from '../types'\nimport type { HostSignal, PendingInteraction } from './signals'\nimport { randomUUID } from 'node:crypto'\nimport { buildResumedToolResultsTurn, createAutomaticInteractionResponse, isModelInteraction, pendingInteractionsFromTurns } from '../interactions'\n\ninterface Slot {\n sessionId: string\n request: InteractionRequest\n resolve: (response: InteractionResponse) => void\n reject: (err: Error) => void\n\n /**\n * `true` when raised by a live agent loop; `false` for rehydrated\n * orphans (resolve/reject are no-ops until the resumed flow lands a\n * `buildResumedToolResultsTurn`). Clients use this flag to decide\n * whether to auto-pop a modal.\n */\n live: boolean\n}\n\nexport interface InteractionHub {\n /** Build the `requestInteraction` callback bound to one session. */\n requestInteractionFor: (sessionId: string) => (request: InteractionRequest) => Promise<InteractionResponse>\n respond: (requestId: string, response: InteractionResponse) => { ok: boolean }\n cancel: (requestId: string, reason?: string) => { ok: boolean }\n list: (sessionId?: string) => PendingInteraction[]\n rehydrate: (sessionId: string) => Promise<PendingInteraction[]>\n /**\n * Answer every pending MODEL interaction with the canonical automatic\n * response — the runtime half of `interactionMode: 'skip'`. Flipping the\n * setting mid-run must not leave modals that were raised under `ask` hanging\n * for an answer the new mode says nobody will give. Host-synthesized prompts\n * are left alone (local code is awaiting a real decision on those). Returns\n * the number resolved.\n */\n resolveAutomatically: (sessionId?: string) => number\n /** Drop every pending interaction for a session (session delete / dispose). */\n clearSession: (sessionId: string) => void\n}\n\nexport function createInteractionHub(options: {\n broadcast: (signal: HostSignal) => void\n store: SessionStore\n /**\n * Live settings read. The hub consults `interactionMode` itself at rehydrate\n * time rather than taking an `automatic` flag from each caller: the daemon\n * dispatch, the GUI adapter, and the host's own activation path all\n * rehydrate, and a flag any one of them could omit is exactly how a policy\n * silently stops applying on one surface.\n */\n readSettings: () => Settings\n /**\n * Called after a LIVE plan is answered `reject`. The TUI's in-process\n * flow aborts the run at that point (the model records the rejection as\n * its tool_result, then the loop unwinds) — the hub does the same for\n * every host surface so a rejected plan means \"stop\", not \"carry on\n * without approval\", in the GUI and over the daemon alike.\n */\n onPlanRejected?: (sessionId: string) => void\n}): InteractionHub {\n const { broadcast, store, readSettings, onPlanRejected } = options\n\n /** Slots keyed by `request.id` (canonical tool_call id — stable across the wire). */\n const pending = new Map<string, Slot>()\n\n /**\n * Per-session `requestId → response` map for resumed (non-live)\n * interactions. Flushed as ONE `buildResumedToolResultsTurn` user turn\n * once every sibling orphan has an explicit response.\n */\n const resumedResponses = new Map<string, Map<string, InteractionResponse>>()\n\n /**\n * Per-session flush serialization — two rapid answers would otherwise\n * race the persisted-turn read and double-append the resume turn.\n */\n const flushChains = new Map<string, Promise<void>>()\n\n function scheduleFlush(sessionId: string): void {\n const prior = flushChains.get(sessionId) ?? Promise.resolve()\n const next = prior.catch(() => undefined).then(() => flushResumedBatch(sessionId))\n flushChains.set(sessionId, next)\n next.finally(() => {\n if (flushChains.get(sessionId) === next)\n flushChains.delete(sessionId)\n })\n }\n\n async function flushResumedBatch(sessionId: string): Promise<void> {\n const responses = resumedResponses.get(sessionId)\n if (!responses || responses.size === 0)\n return\n\n const data = await store.load(sessionId)\n if (!data)\n return\n\n /*\n * Recompute orphans against the latest persisted turns — another\n * action may have resolved some calls between rehydrate and respond.\n */\n const orphans = pendingInteractionsFromTurns(data.turns)\n if (orphans.length === 0) {\n resumedResponses.delete(sessionId)\n return\n }\n\n /*\n * Only flush once every sibling has an explicit response — a partial\n * flush would leave unanswered sibling `tool_call`s without an\n * immediately-following `tool_result`.\n */\n if (!orphans.every((r: InteractionRequest) => responses.has(r.id)))\n return\n\n const turn = buildResumedToolResultsTurn(orphans, responses, { turnId: randomUUID() })\n await store.appendTurns(sessionId, [turn])\n\n for (const r of orphans)\n pending.delete(r.id)\n resumedResponses.delete(sessionId)\n }\n\n const hub: InteractionHub = {\n requestInteractionFor(sessionId) {\n return request => new Promise<InteractionResponse>((resolve, reject) => {\n pending.set(request.id, { sessionId, request, resolve, reject, live: true })\n broadcast({ kind: 'interaction:request', sessionId, request, live: true })\n })\n },\n\n respond(requestId, response) {\n const slot = pending.get(requestId)\n if (!slot)\n return { ok: false }\n\n pending.delete(requestId)\n\n if (slot.live) {\n slot.resolve(response)\n broadcast({ kind: 'interaction:resolved', sessionId: slot.sessionId, requestId })\n if (response.kind === 'plan' && response.decision === 'reject')\n onPlanRejected?.(slot.sessionId)\n return { ok: true }\n }\n\n /*\n * Resumed path — the agent loop is long gone. Collect into the\n * per-session response map and schedule a serialized flush.\n */\n const bucket = resumedResponses.get(slot.sessionId) ?? new Map<string, InteractionResponse>()\n bucket.set(requestId, response)\n resumedResponses.set(slot.sessionId, bucket)\n scheduleFlush(slot.sessionId)\n\n broadcast({ kind: 'interaction:resolved', sessionId: slot.sessionId, requestId })\n return { ok: true }\n },\n\n cancel(requestId, reason = 'Interaction cancelled by user.') {\n const slot = pending.get(requestId)\n if (!slot)\n return { ok: false }\n\n pending.delete(requestId)\n\n if (slot.live)\n slot.reject(new Error(reason))\n\n broadcast({ kind: 'interaction:resolved', sessionId: slot.sessionId, requestId })\n return { ok: true }\n },\n\n list(sessionId) {\n const out: PendingInteraction[] = []\n for (const slot of pending.values()) {\n if (sessionId && slot.sessionId !== sessionId)\n continue\n out.push({ sessionId: slot.sessionId, request: slot.request, live: slot.live })\n }\n return out\n },\n\n async rehydrate(sessionId) {\n const data = await store.load(sessionId)\n if (!data)\n return []\n\n const orphans = pendingInteractionsFromTurns(data.turns)\n const queued: PendingInteraction[] = []\n /*\n * Skip mode resolves orphaned MODEL interactions with the canonical\n * automatic policy instead of surfacing a modal for them — the same\n * answer the live tool would have given under this mode, so a resume\n * behaves like the run never paused. Host-synthesized prompts (slash\n * commands, extension `ctx.interaction.*`) are excluded by\n * `isModelInteraction`: local code is awaiting a real decision on those\n * and an automatic answer would be a wrong one, not a skipped one.\n */\n const automatic = readSettings().interactionMode === 'skip'\n const autoResolved: InteractionRequest[] = []\n\n for (const request of orphans) {\n if (pending.has(request.id))\n continue\n\n pending.set(request.id, {\n sessionId,\n request,\n live: false,\n // No live caller on the resume path — `respond` routes to the\n // batched flush instead of these.\n resolve: () => undefined,\n reject: () => undefined,\n })\n if (automatic && isModelInteraction(request)) {\n autoResolved.push(request)\n continue\n }\n queued.push({ sessionId, request, live: false })\n broadcast({ kind: 'interaction:request', sessionId, request, live: false })\n }\n // Resolve after the loop so the batched flush sees every sibling orphan\n // registered before the first answer lands.\n for (const request of autoResolved)\n hub.respond(request.id, createAutomaticInteractionResponse(request))\n return queued\n },\n\n resolveAutomatically(sessionId) {\n const slots = [...pending.values()].filter(slot =>\n (!sessionId || slot.sessionId === sessionId) && isModelInteraction(slot.request))\n for (const slot of slots)\n hub.respond(slot.request.id, createAutomaticInteractionResponse(slot.request))\n return slots.length\n },\n\n clearSession(sessionId) {\n for (const [id, slot] of pending) {\n if (slot.sessionId !== sessionId)\n continue\n if (slot.live)\n slot.reject(new Error('Session disposed before interaction resolved.'))\n pending.delete(id)\n }\n resumedResponses.delete(sessionId)\n },\n }\n return hub\n}\n","/**\n * The host's queue methods: push / add / remove / list / update / push-now.\n */\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport type { PromptAttachment, SendOptions } from '../signals'\nimport type { QueueStore } from './store'\nimport { randomUUID } from 'node:crypto'\n\nexport type QueueMethods = Pick<ChatHost, 'pushQueued' | 'queueAdd' | 'queueRemove' | 'queueList' | 'queueUpdate' | 'queueAttachments' | 'queuePushNow'>\n\nexport function createQueueMethods({ ctx, store, sendPrompt, isProvisioning }: {\n ctx: Pick<HostContext, 'active' | 'assertDispatchOpen' | 'isSessionBusy' | 'env'>\n store: Pick<QueueStore, 'queues' | 'toQueuedItem' | 'broadcastQueue'>\n sendPrompt: (opts: SendOptions, internal?: { ownMarkerExempt?: boolean, onCommand?: () => void, onForeignRun?: () => void }) => Promise<{ runId: string }>\n isProvisioning: (sessionId: string) => boolean\n}): QueueMethods {\n const { active, assertDispatchOpen, isSessionBusy, env } = ctx\n const { queues, toQueuedItem, broadcastQueue } = store\n\n const methods: QueueMethods = {\n async pushQueued(sessionId, message, activatedSkills) {\n assertDispatchOpen()\n const parkQueued = (): { delivered: 'queued' } => {\n const queue = queues.get(sessionId) ?? []\n queue.push({\n id: randomUUID(),\n text: message,\n ...(activatedSkills?.length ? { activatedSkills } : {}),\n })\n queues.set(sessionId, queue)\n broadcastQueue(sessionId)\n return { delivered: 'queued' as const }\n }\n\n const entry = active.get(sessionId)\n if (entry?.agent.isRunning === true) {\n // Delivery-time broadcast via `steer:inject` — see steer().\n // Command routing doesn't apply mid-run (the TUI steers literal\n // text too).\n if (entry.agent.steer(message)) {\n entry.pendingInjections.push(message)\n return { delivered: 'steer' as const }\n }\n // Refused (the run is aborted and unwinding): the run-end drain sends it.\n return parkQueued()\n }\n\n if (isSessionBusy(sessionId) || isProvisioning(sessionId))\n return parkQueued()\n\n let command = false\n let foreign = false\n try {\n await sendPrompt({\n sessionId,\n prompt: message,\n ...(activatedSkills ? { activatedSkills } : {}),\n }, { onCommand: () => { command = true }, onForeignRun: () => { foreign = true } })\n return { delivered: command ? 'command' as const : 'send' as const }\n }\n catch (err) {\n /*\n * Race: another window started a run between the `isRunning` check\n * above and `sendPrompt`'s own in-flight guard. `pushQueued` is the\n * race-free spelling, so park behind its preparation/settlement\n * reservation rather than surfacing the hard error.\n */\n assertDispatchOpen()\n if (foreign || isSessionBusy(sessionId))\n return parkQueued()\n throw err\n }\n },\n\n async queueAdd(sessionId, text, activatedSkills, attachments, asCommand) {\n assertDispatchOpen()\n // \"Queue messages\" off: steer into the live run. Attachments can't ride a\n // steer and commands need the idle `/` router, so those still queue.\n const live = active.get(sessionId)\n if (env.readSettings().queueMessages === false && !asCommand && !attachments?.length && live?.agent.isRunning === true) {\n // Same activation `prepare` does before a run: pinned skills' tool gates must hold.\n for (const name of activatedSkills ?? []) {\n try {\n await live.agent.activateSkill(name)\n }\n catch {\n // Not resolvable (disabled / unknown): same as an idle send.\n }\n }\n // Delivery-time broadcast via `steer:inject`, as in pushQueued.\n if (live.agent.steer(text)) {\n live.pendingInjections.push(text)\n return { delivered: 'steer' as const }\n }\n // Refused (the run is aborted and unwinding): queue it for the drain.\n }\n\n const enqueue = (): { delivered: 'queued' } => {\n const queue = queues.get(sessionId) ?? []\n queue.push({\n id: randomUUID(),\n text,\n ...(activatedSkills?.length ? { activatedSkills } : {}),\n ...(attachments?.length ? { attachments } : {}),\n ...(asCommand ? { asCommand } : {}),\n })\n queues.set(sessionId, queue)\n broadcastQueue(sessionId)\n return { delivered: 'queued' as const }\n }\n\n // Also parks behind this host's provisioning — delivered once it's ready.\n if (isSessionBusy(sessionId) || isProvisioning(sessionId))\n return enqueue()\n\n try {\n await sendPrompt({\n sessionId,\n prompt: text,\n ...(activatedSkills?.length ? { activatedSkills } : {}),\n ...(attachments?.length ? { attachments } : {}),\n ...(asCommand ? { asCommand } : {}),\n })\n return { delivered: 'sent' as const }\n }\n catch (err) {\n // Race: another window started a run between the check and the\n // send — park it in the queue instead of surfacing the error.\n assertDispatchOpen()\n if (isSessionBusy(sessionId))\n return enqueue()\n throw err\n }\n },\n\n queueRemove(sessionId, id) {\n const queue = queues.get(sessionId)\n if (!queue)\n return false\n const index = queue.findIndex(item => item.id === id)\n if (index < 0)\n return false\n queue.splice(index, 1)\n if (queue.length === 0)\n queues.delete(sessionId)\n broadcastQueue(sessionId)\n return true\n },\n\n queueList(sessionId) {\n return (queues.get(sessionId) ?? []).map(toQueuedItem)\n },\n\n queueUpdate(sessionId, id, text, attachments) {\n const entry = queues.get(sessionId)?.find(item => item.id === id)\n if (!entry)\n return false\n let changed = false\n if (entry.text !== text) {\n entry.text = text\n changed = true\n }\n if (attachments && !sameAttachments(entry.attachments ?? [], attachments)) {\n if (attachments.length > 0)\n entry.attachments = attachments\n else\n delete entry.attachments\n changed = true\n }\n if (changed)\n broadcastQueue(sessionId)\n return true\n },\n\n queueAttachments(sessionId, id) {\n const entry = queues.get(sessionId)?.find(item => item.id === id)\n return entry ? [...(entry.attachments ?? [])] : null\n },\n\n async queuePushNow(sessionId, id) {\n assertDispatchOpen()\n const queue = queues.get(sessionId)\n const entry = queue?.find(item => item.id === id)\n if (!queue || !entry)\n return { delivered: 'missing' as const }\n\n /*\n * PEEK, dispatch, and only remove after the dispatch was ACCEPTED —\n * same contract as drainQueue. Splicing first would lose the\n * message from every window's queue box when the idle-path\n * `sendPrompt` throws (cross-process guard, provider failure).\n */\n const removeAndBroadcast = (): void => {\n const live = queues.get(sessionId)\n const index = live?.findIndex(item => item.id === id) ?? -1\n if (live && index >= 0) {\n live.splice(index, 1)\n if (live.length === 0)\n queues.delete(sessionId)\n }\n broadcastQueue(sessionId)\n }\n\n // A command entry is never steered as prose: it goes through\n // `sendPrompt` like the drain. While the session is busy it stays\n // queued — the drain dispatches it at run end — and push-now says so.\n if (entry.asCommand && isSessionBusy(sessionId))\n return { delivered: 'queued' as const }\n const live = active.get(sessionId)\n if (!entry.asCommand && live?.agent.isRunning === true && live.agent.steer(entry.text)) {\n live.pendingInjections.push(entry.text)\n removeAndBroadcast()\n return { delivered: 'steer' as const }\n }\n await sendPrompt({\n sessionId,\n prompt: entry.text,\n ...(entry.activatedSkills?.length ? { activatedSkills: entry.activatedSkills } : {}),\n ...(entry.attachments?.length ? { attachments: entry.attachments } : {}),\n ...(entry.asCommand ? { asCommand: entry.asCommand } : {}),\n })\n removeAndBroadcast()\n return { delivered: 'send' as const }\n },\n\n }\n\n return methods\n}\n\nfunction sameAttachments(a: readonly PromptAttachment[], b: readonly PromptAttachment[]): boolean {\n return a.length === b.length\n && a.every((x, i) => x.mediaType === b[i]!.mediaType && x.data === b[i]!.data && x.name === b[i]!.name)\n}\n","/**\n * The per-session queue entries and their wire projection.\n */\nimport type { HostSignal, PromptAttachment, QueuedItem } from '../signals'\n\nexport interface QueuedEntry extends QueuedItem {\n activatedSkills?: string[]\n attachments?: PromptAttachment[]\n /** See `SendOptions.asCommand` — survives the queue so the drain refuses too. */\n asCommand?: string\n}\n\nexport interface QueueStore {\n queues: Map<string, QueuedEntry[]>\n toQueuedItem: (entry: QueuedEntry) => QueuedItem\n broadcastQueue: (sessionId: string) => void\n dropQueue: (sessionId: string) => void\n dropAllQueues: () => void\n}\n\nexport function createQueueStore(broadcast: (signal: HostSignal) => void): QueueStore {\n const queues = new Map<string, QueuedEntry[]>()\n\n /** Wire shape of a queued entry: text plus an attachment SUMMARY, never the bytes. */\n function toQueuedItem({ id, text, attachments }: QueuedEntry): QueuedItem {\n return {\n id,\n text,\n ...(attachments?.length\n ? { attachments: attachments.map(a => ({ mediaType: a.mediaType, ...(a.name ? { name: a.name } : {}) })) }\n : {}),\n }\n }\n\n function broadcastQueue(sessionId: string): void {\n broadcast({ kind: 'queue:changed', sessionId, items: (queues.get(sessionId) ?? []).map(toQueuedItem) })\n }\n\n /** Forget a session's queue (session disposed), announcing the empty list. */\n function dropQueue(sessionId: string): void {\n if (queues.delete(sessionId))\n broadcastQueue(sessionId)\n }\n\n /** Forget every queue (host teardown), announcing each empty list. */\n function dropAllQueues(): void {\n for (const sessionId of [...queues.keys()]) {\n queues.delete(sessionId)\n broadcastQueue(sessionId)\n }\n }\n\n return { queues, toQueuedItem, broadcastQueue, dropQueue, dropAllQueues }\n}\n","/**\n * The shared type-ahead queue — host-owned so every window renders and\n * manipulates the same list — with its FIFO drain at run end (and when\n * provisioning settles), and the host-initiated wake runs that share its\n * guards (background-task notifications, orchestration events).\n */\nimport type { HostContext } from '../context'\nimport type { SendOptions } from '../signals'\nimport { createQueueMethods } from './methods'\nimport { createQueueStore } from './store'\n\nexport type { QueueMethods } from './methods'\n\nexport function createQueue({ ctx, sendPrompt, isProvisioning }: {\n ctx: HostContext\n sendPrompt: (opts: SendOptions, internal?: { ownMarkerExempt?: boolean, onCommand?: () => void, onForeignRun?: () => void }) => Promise<{ runId: string }>\n /** This host is still provisioning the session's environment (items park until it settles). */\n isProvisioning: (sessionId: string) => boolean\n}) {\n const { broadcast, active, lifecycle, isSessionBusy, suppressedWake } = ctx\n\n const store = createQueueStore(broadcast)\n const { queues, broadcastQueue, dropQueue, dropAllQueues } = store\n\n /** Per-session drain lock — two overlapping drains would double-send the head. */\n const draining = new Set<string>()\n\n /**\n * Background-task notification delivery: when a session is idle with\n * pending `<task-notification>`s (a task finished mid-run, or while\n * idle), run a wake pass so the model sees the result now instead of on\n * the user's next prompt. Host-owned, so it happens even with zero\n * windows attached. Wake runs carry an empty prompt and skip the\n * `user-prompt` broadcast — there is no user message.\n */\n function maybeWake(sessionId: string): void {\n const entry = active.get(sessionId)\n if (lifecycle.closed || !entry || isSessionBusy(sessionId) || !entry.agent.hasPendingTaskNotifications)\n return\n void wakeRun(sessionId).catch(() => undefined)\n }\n\n /**\n * The tail every host-initiated wake shares — background-task notifications\n * and orchestration's buffered `<session-event>` turns alike. The three\n * guards are the point:\n * - `suppressedWake`: the user pressed esc; do not start a run on their\n * behalf until they send again.\n * - a non-empty type-ahead queue: let the drain dispatch instead, or the\n * wake and the drain both send.\n * - `ownMarkerExempt: false`: wakes fire AT run end, exactly when a stale\n * 'running' marker of our own is most likely to still be on disk —\n * exempting it there would open a double-run window.\n * Resolves either way; the caller cannot tell a declined wake from a run,\n * because in both cases the turns it appended are already durable.\n */\n async function wakeRun(sessionId: string): Promise<void> {\n if (lifecycle.closed || suppressedWake.has(sessionId))\n return\n if ((queues.get(sessionId)?.length ?? 0) > 0)\n return\n await sendPrompt({ sessionId, prompt: '', wake: true }, { ownMarkerExempt: false })\n }\n\n /**\n * FIFO auto-drain at run end — the host owns delivery so a queued\n * message runs even after the window that queued it closed. The head is\n * PEEKED (not shifted) and only removed after `sendPrompt` accepted it,\n * so a failed dispatch leaves the entry queued for retry/drop. The\n * short retry loop covers the gap between the run-end broadcast and the\n * agent's `isRunning` flag flipping; chained multi-entry queues drain\n * one-per-run via `sendPrompt`'s own run-end hook calling back in here.\n */\n function drainQueue(sessionId: string, attempt = 0): void {\n // Provisioning drains the queue itself once it settles.\n if (lifecycle.closed || draining.has(sessionId) || isProvisioning(sessionId))\n return\n const queue = queues.get(sessionId)\n if (!queue || queue.length === 0) {\n maybeWake(sessionId)\n return\n }\n if (isSessionBusy(sessionId)) {\n if (attempt < 100)\n setTimeout(drainQueue, 25, sessionId, attempt + 1)\n return\n }\n\n const next = queue[0]!\n draining.add(sessionId)\n\n void sendPrompt({\n sessionId,\n prompt: next.text,\n ...(next.activatedSkills?.length ? { activatedSkills: next.activatedSkills } : {}),\n ...(next.attachments?.length ? { attachments: next.attachments } : {}),\n ...(next.asCommand ? { asCommand: next.asCommand } : {}),\n }, { ownMarkerExempt: false })\n .then(() => {\n const live = queues.get(sessionId)\n const index = live?.findIndex(item => item.id === next.id) ?? -1\n if (live && index >= 0) {\n live.splice(index, 1)\n if (live.length === 0)\n queues.delete(sessionId)\n }\n broadcastQueue(sessionId)\n })\n .catch((err) => {\n broadcast({\n kind: 'event',\n sessionId,\n event: { kind: 'error', text: `Queued message failed to send: ${(err as Error).message}` },\n })\n })\n .finally(() => {\n draining.delete(sessionId)\n })\n }\n\n const methods = createQueueMethods({ ctx, store, sendPrompt, isProvisioning })\n\n return { maybeWake, wakeRun, drainQueue, dropQueue, dropAllQueues, methods }\n}\n","/**\n * Session operations outside a run: history edits under the session's\n * dispatch reservation, folder binding, appended turns and notes, metadata\n * patches that are safe against a live session's saves, the model pick, and\n * forks.\n */\nimport type { SessionData } from '../../../session/index'\nimport type { SessionTurn } from '../../../types'\nimport type { CommandOutputBlock } from '../../commands'\nimport type { HostContext } from '../context'\nimport type { ChatHost } from '../host-api'\nimport type { ActiveRun } from '../types'\nimport { randomUUID } from 'node:crypto'\nimport { statSync } from 'node:fs'\nimport { isAbsolute } from 'node:path'\nimport { commandBlocksToContent, commandBlockToEvent } from '../../commands'\nimport { readSessionEnvironment } from '../../environment'\nimport { parseMachineKind } from '../../machine-protocol'\nimport { modelChainMetadata } from '../../model-chain-metadata'\nimport { isMainSession } from '../../orchestration'\nimport { projectRootOf } from '../../project-root'\nimport { enabledModelOptions } from '../../providers'\nimport { forkSession as forkSharedSession } from '../../session-factory'\nimport { getSessionMeta } from '../../store'\nimport { deleteTurnSafely, replaceTurnTextBlocks } from '../../turn-operations'\nimport { hostDebug } from '../debug'\nimport { STALE_RUN_MARKER_MS } from '../runs'\n\nexport type SessionOpsMethods = Pick<\n ChatHost,\n | 'forkSession'\n | 'deleteTurn'\n | 'editTurnText'\n | 'setSessionFolder'\n | 'appendTurns'\n | 'appendNote'\n | 'patchLiveSessionMeta'\n | 'patchSessionMeta'\n | 'setSessionModel'\n | 'setLiveSessionAgentId'\n>\n\nexport function createSessionOps({ ctx, host, rebuildAgentOnly, applyPendingDispose, disposeAgentForRebuild, drainQueue }: {\n ctx: HostContext\n /** The finished host — features are built before it, and only call this at runtime. */\n host: () => ChatHost\n rebuildAgentOnly: (sessionId: string) => void\n applyPendingDispose: (sessionId: string) => void\n disposeAgentForRebuild: (sessionId: string) => Promise<void>\n drainQueue: (sessionId: string) => void\n}) {\n const { env, broadcast, active, pendingBuilds, dispatches, lifecycle, artifactsDir, isSessionBusy } = ctx\n\n /**\n * `ctx.appendNote` from an extension tool/hook DURING a run: a durable,\n * display-only `command` turn — same block vocabulary, live events and\n * persisted form as command output, so it renders now and survives reload.\n * Live events and the turn share one pre-minted id (anchors depend on it).\n */\n function appendNoteTurn(run: ActiveRun, blocks: readonly CommandOutputBlock[]): Promise<void> {\n const session = run.agent.session\n if (!session)\n return Promise.resolve()\n const turnId = randomUUID()\n for (const block of blocks)\n broadcast({ kind: 'event', sessionId: run.sessionId, event: { ...commandBlockToEvent(block), turnId } })\n return session\n .appendTurns([{ id: turnId, role: 'command', createdAt: Date.now(), content: commandBlocksToContent(blocks) }])\n .catch(err => hostDebug('append-note', `persist failed: ${String(err)}`))\n }\n\n /* ----------------------------------------------------------------------\n * History edits\n * -------------------------------------------------------------------- */\n\n /**\n * Run a session edit while holding its dispatch slot. Refuses while the\n * session runs: in this host, or in another process by its fresh run\n * marker (a crashed process's stale marker doesn't block). Holding the\n * slot from the check through the write makes a concurrent send refuse\n * (or park, via `pushQueued`) instead of building an agent from the\n * pre-edit state whose run-end save would overwrite the edit.\n */\n async function withEditReservation<T>(sessionId: string, what: string, edit: () => Promise<T>): Promise<T> {\n const refusal = `Cannot ${what}: a run is in progress. Stop it first.`\n if (isSessionBusy(sessionId))\n throw new Error(refusal)\n const reservation = Promise.withResolvers<void>()\n dispatches.set(sessionId, reservation.promise)\n try {\n const meta = await (env.store.getMeta ? env.store.getMeta(sessionId) : env.store.load(sessionId))\n if (meta?.status === 'running' && Date.now() - meta.updatedAt < STALE_RUN_MARKER_MS)\n throw new Error(refusal)\n // Idle (the slot is ours), so retire the cached agent now: its\n // in-memory state predates the edit and must not be saved back over it.\n rebuildAgentOnly(sessionId)\n return await edit()\n }\n finally {\n if (dispatches.get(sessionId) === reservation.promise)\n dispatches.delete(sessionId)\n reservation.resolve()\n if (!isSessionBusy(sessionId))\n applyPendingDispose(sessionId)\n // A message parked by `pushQueued` during the edit dispatches now.\n if (!lifecycle.closed)\n setTimeout(drainQueue, 0, sessionId)\n }\n }\n\n async function editHistory(sessionId: string, what: string, mutate: (turns: SessionTurn[]) => SessionTurn[] | null): Promise<void> {\n await withEditReservation(sessionId, what, () => writeHistoryEdit(sessionId, mutate))\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId })\n }\n\n async function writeHistoryEdit(sessionId: string, mutate: (turns: SessionTurn[]) => SessionTurn[] | null): Promise<void> {\n const store = env.store\n let result: 'ok' | 'no-session' | 'unchanged'\n if (store.mutateTurns) {\n result = await store.mutateTurns(sessionId, mutate)\n }\n else {\n const data = await store.load(sessionId)\n const next = data ? mutate(data.turns) : null\n result = !data ? 'no-session' : next === null ? 'unchanged' : 'ok'\n if (data && next !== null)\n await store.save({ ...data, turns: next, updatedAt: Date.now() })\n }\n if (result === 'no-session')\n throw new Error(`Session \"${sessionId}\" not found.`)\n }\n\n const methods: SessionOpsMethods = {\n forkSession: params => forkSharedSession(env.store, { ...params, userDir: artifactsDir() }),\n\n async deleteTurn(sessionId, turnId) {\n await editHistory(sessionId, 'delete the turn', (turns) => {\n // Strips the tool-call / tool-result pair the removal would orphan.\n const next = deleteTurnSafely(turns, turnId)\n if (next === null)\n throw new Error(`Turn \"${turnId}\" not found in session \"${sessionId}\".`)\n return next\n })\n },\n\n async editTurnText(sessionId, turnId, text) {\n await editHistory(sessionId, 'edit the turn', (turns) => {\n const next = replaceTurnTextBlocks(turns, turnId, text)\n if (next === null)\n throw new Error(`Turn \"${turnId}\" has no editable text blocks.`)\n return next\n })\n },\n\n async setSessionFolder(sessionId, requested) {\n const loaded = await env.store.load(sessionId)\n if (!loaded)\n throw new Error(`Session \"${sessionId}\" not found.`)\n // A machine's session: its machine checks the folder (its roots, on its filesystem), never this host.\n const kind = readSessionEnvironment(loaded.metadata).kind\n const onMachine = requested !== '' && parseMachineKind(kind) !== null\n // A confined host (a server): inside its workspace roots (real path); `''` detaches.\n const cwd = onMachine ? (await host().verifyFolder(requested, kind)).cwd : ctx.workspace.checkFolder(requested)\n if (cwd && !onMachine && (!isAbsolute(cwd) || !statSync(cwd, { throwIfNoEntry: false })?.isDirectory()))\n throw new Error(`Folder \"${cwd}\" is not an absolute path to an existing directory.`)\n if (cwd && isMainSession(loaded.metadata))\n throw new Error('The Main session cannot be bound to a folder.')\n // The reservation retires the cached agent (it runs in the old folder);\n // the next send rebuilds in the new one.\n await withEditReservation(sessionId, cwd ? 'attach a folder' : 'detach the folder', async () => {\n // Reload: a turn appended while the checks awaited must survive a\n // store without `saveMeta`, whose `save` rewrites the turns.\n const data = await env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n // `''` (not a deleted key) clears the folder: every reader coerces it to \"unset\".\n const { projectRoot: _previous, ...rest } = data\n const next: SessionData = {\n ...rest,\n metadata: { ...data.metadata, cwd },\n ...(cwd ? { projectRoot: onMachine ? cwd : projectRootOf(cwd) } : {}),\n updatedAt: Date.now(),\n }\n await (env.store.saveMeta ? env.store.saveMeta(next) : env.store.save(next))\n })\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId })\n },\n\n async appendTurns(sessionId, turns) {\n const live = active.get(sessionId)?.agent.session\n if (live) {\n await live.appendTurns(turns)\n }\n else {\n // The store starts a header-less session for an id it never saw: a client's write\n // aimed at the wrong host would leave a ghost row here. Refuse it instead.\n if (!(await getSessionMeta(env.store, sessionId)))\n throw new Error(`No session \"${sessionId}\" on this host.`)\n await env.store.appendTurns(sessionId, turns)\n }\n broadcast({ kind: 'sessions:changed', op: 'update', sessionId })\n },\n\n async appendNote(sessionId, blocks) {\n if (blocks.length === 0)\n return false\n // An agent being built is loading the session: append after it, into\n // its copy. A built one (running or not) takes the note at once.\n if (!active.has(sessionId))\n await pendingBuilds.get(sessionId)?.catch(() => undefined)\n const run = active.get(sessionId)\n if (run?.agent.session) {\n await appendNoteTurn(run, blocks)\n return true\n }\n const turn: SessionTurn = { id: randomUUID(), role: 'command', createdAt: Date.now(), content: commandBlocksToContent(blocks) }\n try {\n await writeHistoryEdit(sessionId, turns => [...turns, turn])\n }\n catch {\n return false\n }\n for (const block of blocks)\n broadcast({ kind: 'event', sessionId, event: { ...commandBlockToEvent(block), turnId: turn.id } })\n return true\n },\n\n /**\n * Metadata-only patch that is safe to run mid-run. When a live agent is\n * hosting the session, route the write through its in-memory `Session`\n * (whose turn history is the source of truth) so the full-document\n * `save()` re-persists the CURRENT turns instead of a stale snapshot —\n * a store-level `store.save(load())` would wipe turns appended between\n * load and save. When idle, no run is appending, so the caller's\n * store-level fallback is race-free.\n *\n * Returns `true` when handled here (live session), `false` when the\n * caller should apply its own store-level patch.\n */\n async patchLiveSessionMeta(sessionId, patch) {\n const entry = active.get(sessionId)\n const session = entry?.agent.session\n if (!session)\n return false\n entry!.lastUsedAt = Date.now()\n for (const [key, value] of Object.entries(patch))\n session.setMeta(key, value)\n await session.save()\n return true\n },\n\n async patchSessionMeta(sessionId, patch, opts = {}) {\n if (await host().patchLiveSessionMeta(sessionId, patch))\n return\n /*\n * No live agent in THIS host. \"Idle\" is not guaranteed though — a\n * command dispatch whose agent was pruned/rebuilt, or another process\n * (GUI, second daemon) may be appending — so write the header only\n * (`saveMeta`) rather than a bulk `save` that would replace the turn\n * list with this snapshot.\n */\n const data = await env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined)\n delete data.metadata[key]\n else\n data.metadata[key] = value\n }\n if (opts.bumpUpdatedAt !== false)\n data.updatedAt = Date.now()\n if (env.store.saveMeta)\n await env.store.saveMeta(data)\n else\n await env.store.save(data)\n },\n\n async setSessionModel(sessionId, pick) {\n /*\n * Patch FIRST (race-safe), then retire the agent: the rebuild reads\n * the persisted document, so the order guarantees the next agent sees\n * the new pick. `undefined` clears — effort and options are per-model\n * knobs and `modelChain` is replaced wholesale, never merged.\n */\n await host().patchSessionMeta(sessionId, {\n providerKey: pick.providerKey,\n modelId: pick.modelId,\n modelChain: modelChainMetadata(pick.providerKey, pick.modelId, pick.fallbacks),\n effort: pick.effort,\n modelOptions: pick.modelOptions && Object.keys(pick.modelOptions).length > 0\n ? enabledModelOptions(pick.modelOptions)\n : undefined,\n })\n disposeAgentForRebuild(sessionId)\n },\n\n async setLiveSessionAgentId(sessionId, agentId) {\n const entry = active.get(sessionId)\n const session = entry?.agent.session\n if (!session)\n return false\n entry!.lastUsedAt = Date.now()\n session.setAgentId(agentId)\n await session.save()\n return true\n },\n\n }\n\n return { appendNoteTurn, methods }\n}\n","/**\n * `ChatHost.generateSessionTitle`: the host titles a session with ITS\n * providers and credentials, so a session's transcript only ever goes to the\n * provider of the machine it lives on (a server's, for a server session).\n *\n * - The providers are the session's project config on this host\n * (`runtimeConfig(cwd)`, the session's `metadata.cwd`), as its runs use.\n * - The window may hint a provider/model; it counts only when this host has\n * that provider as its own key (a wire client's `constructor` is none).\n * - Titling is a rename: the title is written without a recency bump\n * (`updatedAt` stays), as `sessions.setTitle` does, so the row keeps its\n * place in recency-ordered lists. The host's write tells every window\n * (`sessions:changed`); callers announce nothing more.\n */\nimport type { Provider } from '../../providers'\nimport type { ProviderKey } from '../auth'\nimport type { ProviderDescriptor } from '../providers'\nimport type { ChatHostEnvironment } from './environment'\nimport { readSessionEnvironment } from '../environment'\nimport { generateSessionTitle } from '../generate-title'\nimport { isMainSession } from '../orchestration'\nimport { discoveryCwdFor } from './machines'\nimport { resolveModel, resolveSessionModel } from './models/index'\n\n/** The window's pick, honored when this host has that provider. */\nexport interface SessionTitleHint {\n providerKey?: string\n model?: string\n}\n\nexport async function generateHostSessionTitle(\n deps: {\n env: Pick<ChatHostEnvironment, 'store' | 'runtimeConfig' | 'userDataDir'>\n buildProvider: (providers: Readonly<Record<string, ProviderDescriptor>>, providerKey: ProviderKey) => Provider\n patchSessionMeta: (sessionId: string, patch: Record<string, unknown>, opts?: { bumpUpdatedAt?: boolean }) => Promise<void>\n },\n sessionId: string,\n hint: SessionTitleHint = {},\n): Promise<string> {\n const data = await deps.env.store.load(sessionId)\n if (!data)\n throw new Error(`Session \"${sessionId}\" not found.`)\n // The main is always \"Main\": the pinned row, the jump chord and worker events all name it that.\n if (isMainSession(data.metadata))\n throw new Error('The Main session keeps its name.')\n const cwd = typeof data.metadata?.cwd === 'string' ? data.metadata.cwd : ''\n const { providers } = await deps.env.runtimeConfig(discoveryCwdFor(readSessionEnvironment(data.metadata).kind, cwd, deps.env.userDataDir()))\n // The window's pick when this host has it (what it would use window-side), else the session's own.\n const { providerKey, modelId } = hint.providerKey !== undefined && Object.hasOwn(providers, hint.providerKey)\n ? resolveModel(providers, hint.providerKey as ProviderKey, hint.model)\n : (({ providerKey, model }) => ({ providerKey, modelId: model }))(resolveSessionModel(data.metadata, providers))\n const title = await generateSessionTitle({ provider: deps.buildProvider(providers, providerKey), model: modelId, turns: data.turns })\n // As a rename: no recency bump.\n await deps.patchSessionMeta(sessionId, { title }, { bumpUpdatedAt: false })\n return title\n}\n","/**\n * Host teardown: one session (`disposeSession`), every agent (`shutdown`, also\n * the settings-change rebuild path), and the whole host at process exit\n * (`drain`).\n */\nimport type { PluginCatalog } from '../agent-build'\nimport type { createAgentLifecycle } from '../agents'\nimport type { ApprovalHub } from '../approvals'\nimport type { HostContext } from '../context'\nimport type { createExecution } from '../execution'\nimport type { ChatHost } from '../host-api'\nimport type { InteractionHub } from '../interactions'\nimport type { createQueue } from '../queue'\n\nexport type TeardownMethods = Pick<ChatHost, 'disposeSession' | 'drain' | 'shutdown'>\n\nexport function createTeardown({ ctx, host, interactions, approvals, queue, agents, execution, pluginCatalog }: {\n ctx: HostContext\n /** The finished host — features are built before it, and only call this at runtime. */\n host: () => ChatHost\n interactions: InteractionHub\n approvals: ApprovalHub\n queue: Pick<ReturnType<typeof createQueue>, 'dropQueue' | 'dropAllQueues'>\n agents: Pick<ReturnType<typeof createAgentLifecycle>, 'applyPendingDispose' | 'disposeActiveEntry' | 'teardownRun' | 'releaseDeferredRebuilds'>\n execution: Pick<ReturnType<typeof createExecution>, 'executionCache' | 'terminals' | 'stopIdleSweep' | 'suspendEnvironment'>\n pluginCatalog: PluginCatalog\n}): TeardownMethods {\n const { active, pendingBuilds, dispatches, lifecycleWork, lifecycle, suppressedWake, trackWork } = ctx\n const { executionCache, terminals } = execution\n let drainPromise: Promise<void> | undefined\n\n return {\n /**\n * Tear down a single in-flight session — used when the user deletes the\n * session or changes its model. Sweeps pending interactions + safe-mode\n * requests even without a live agent so no ghost HITL state lingers.\n */\n disposeSession(sessionId) {\n interactions.clearSession(sessionId)\n approvals.denyAll(sessionId)\n suppressedWake.delete(sessionId)\n queue.dropQueue(sessionId)\n\n /*\n * Consume any in-flight build — when it completes it sees its pending\n * entry gone and self-discards instead of inserting an agent for a\n * session the user just tore down.\n */\n pendingBuilds.delete(sessionId)\n // The agent is going away either way — a deferred rebuild is moot.\n agents.applyPendingDispose(sessionId)\n\n // The session is done with its execution: its handle (and any\n // background task still running on it) goes too.\n trackWork(executionCache.release(sessionId)).catch(() => undefined)\n\n const entry = active.get(sessionId)\n if (!entry)\n return\n\n agents.disposeActiveEntry(sessionId, entry)\n },\n\n /**\n * Drain every session. Call before process exit (or a settings change\n * that invalidates the runtime config) so active runs, in-flight\n * compactions, and pending HITL promises all unwind cleanly.\n */\n drain() {\n if (!drainPromise) {\n lifecycle.closed = true\n execution.stopIdleSweep()\n // A call waiting for an offline machine (a run, a provisioning) must not hold the drain.\n host().machines.close()\n const compactions = [...active.values()].flatMap(entry => entry.compacting ? [entry.compacting] : [])\n host().shutdown()\n drainPromise = (async () => {\n await Promise.allSettled(compactions)\n while (dispatches.size > 0 || lifecycleWork.size > 0)\n await Promise.allSettled([...dispatches.values(), ...lifecycleWork])\n // Process exit: every session's execution ends with the host.\n // (`shutdown()` alone keeps them — it is also the settings-change\n // \"rebuild every agent\" path, and tasks must survive that.) The\n // sessions live on, so their environments get to suspend.\n const held = executionCache.sessions()\n // Local terminals end with the host; remote ones are let go, to reconnect after a restart.\n await terminals.shutdown()\n await executionCache.releaseAll()\n await Promise.allSettled(held.map(id => execution.suspendEnvironment(id)))\n })()\n }\n return drainPromise\n },\n\n shutdown() {\n suppressedWake.clear()\n /*\n * Discovery caches die with the agents that were built from them, so a\n * settings change that tears the host down (extensions, plugins, MCPs)\n * re-walks the disk on the next build instead of serving a catalog that\n * predates the toggle.\n */\n pluginCatalog.clear()\n queue.dropAllQueues()\n /*\n * Invalidate every in-flight build: a build that started before this\n * teardown discards itself on completion.\n */\n lifecycle.teardownGeneration += 1\n pendingBuilds.clear()\n\n approvals.denyAll()\n\n for (const [sessionId, entry] of active) {\n agents.teardownRun(entry)\n interactions.clearSession(sessionId)\n }\n active.clear()\n agents.releaseDeferredRebuilds()\n },\n }\n}\n","/**\n * Transport-agnostic chat host — owns live `Agent` instances and forwards\n * agent-loop hooks as `HostSignal`s to whatever transport the embedding\n * process wires in (Electron `webContents.send`, daemon socket peers, an\n * in-process callback for tests).\n *\n * Extracted from the GUI main-process engine; behavior is intentionally\n * identical. All module-level state became per-host instance state so one\n * process can host independent instances (tests, future multi-profile).\n *\n * Dependency invariant: `src/chat` (this module included) has NO dependency\n * on `src/ipc`; the direction is strictly `src/ipc` → `src/chat`. The host\n * is the chat engine — deleting `src/ipc` (plus the daemon CLI and the\n * clients' daemon branches) removes the socket transport but leaves the\n * engine intact. Wire shapes the host emits (`HostSignal` & co.) live in\n * `./signals`, re-exported by `src/ipc/protocol.ts` for `zidane/ipc`\n * consumers.\n */\nimport type { ChatHostEnvironment } from './environment'\nimport type { ChatHost } from './host-api'\nimport type { SendOptions } from './signals'\nimport type { ActiveRun } from './types'\nimport { createAgentBuilder, createPluginCatalog } from './agent-build'\nimport { createAgentLifecycle } from './agents'\nimport { createSessionSafelists } from './approval-gate'\nimport { createApprovalHub } from './approvals'\nimport { createHostBroadcast } from './broadcast'\nimport { createBrowserHub } from './browser'\nimport { createCommandModule } from './commands'\nimport { createCompactSessionNow } from './compaction'\nimport { createHostContext } from './context'\nimport { createLaunchOverridesSetter } from './cwd'\nimport { createExecution } from './execution'\nimport { createInteractionHub } from './interactions'\nimport { createMachineFolders, createMachines } from './machines'\nimport { createProviderBuilder } from './models'\nimport { createOrchestration } from './orchestration'\nimport { createPromptMethods } from './prompt'\nimport { createQueue } from './queue'\nimport { createRunControls, createRuns } from './runs'\nimport { createSessionOps } from './session-ops'\nimport { generateHostSessionTitle } from './session-title'\nimport { createTeardown } from './teardown'\nimport { createTodoMethods } from './todos'\nimport { createWorkMethods } from './work'\n\nexport type { ChatHost, ContextSegmentsReport, CreateSessionRequest, SessionModelPick, WorkspaceExecOptions, WorkspaceListFilesOptions } from './host-api'\nexport { STALE_RUN_MARKER_MS } from './runs'\nexport type { ActiveRun, CommandSpawnSeam } from './types'\n\n/**\n * The composition root: creates the shared host state (`context.ts`) and the\n * feature modules, wires them to each other, and assembles the `ChatHost`.\n * Features never import this module. Where a feature needs one built after\n * it, it gets one of the hoisted forwarders at the bottom of this function\n * (only ever called at runtime, after construction).\n */\nexport function createChatHost(env: ChatHostEnvironment): ChatHost {\n const { broadcast, dispatchSignals, observeSignals } = createHostBroadcast(env)\n const ctx = createHostContext(env, broadcast)\n const { active, dispatches, lifecycleWork, launchOverrides, assertDispatchOpen, isSessionBusy } = ctx\n const interactions = createInteractionHub({\n broadcast,\n store: env.store,\n readSettings: () => env.readSettings(),\n // Rejecting a plan aborts the run once the rejection has been handed\n // to the model — mirrors the TUI's `onInteractionResolve`.\n onPlanRejected: sessionId => hostApi().interrupt(sessionId),\n })\n const approvals = createApprovalHub({\n broadcast,\n userDataDir: env.userDataDir,\n ...(env.approvalsPersistence ? { persistence: env.approvalsPersistence } : {}),\n })\n const runControls = createRunControls(ctx, { approvals, interactions })\n const browser = createBrowserHub({ broadcast })\n\n const { sessionSafelists, sessionSafelistFor } = createSessionSafelists()\n const execution = createExecution({ ctx, host: hostApi, drainQueue, evictIdleSession, sessionSafelists })\n const { executionCache, terminals } = execution\n // A machine back online rebuilds the sessions built without its project files (late-bound: agents come later).\n const agentsRef: { current?: ReturnType<typeof createAgentLifecycle> } = {}\n const { registry: machines, builds: machineBuilds } = createMachines({ ctx, environments: execution.methods.environments, interrupt: sessionId => runControls.interrupt(sessionId), rebuild: sessionId => void agentsRef.current?.disposeAgentForRebuild(sessionId) })\n const folders = createMachineFolders({ machines, environments: execution.methods.environments, workspace: ctx.workspace, dataDir: () => env.userDataDir() })\n\n const orchestration = createOrchestration({\n store: env.store,\n broadcast,\n readSettings: () => env.readSettings(),\n sendPrompt: opts => sendPrompt(opts),\n wake: wakeRun,\n steer: runControls.steer,\n interrupt: runControls.interrupt,\n liveSession: sessionId => active.get(sessionId)?.agent.session ?? undefined,\n isRunning: isSessionBusy,\n createSession: execution.createSessionInStore,\n })\n observeSignals(orchestration)\n\n const buildProvider = createProviderBuilder(env)\n const pluginCatalog = createPluginCatalog()\n\n /*\n * `/` command execution — `ensureAgent` is a hoisted function\n * declaration, so handing it to the factory here (before the agent\n * lifecycle exists) is safe: the module only calls it at command time.\n */\n const commands = createCommandModule({\n env: {\n ...env,\n runtimeConfig: async (cwd) => {\n const generation = assertDispatchOpen()\n const config = await env.runtimeConfig(cwd)\n assertDispatchOpen(generation)\n return config\n },\n },\n broadcast,\n ensureAgent,\n buildProvider,\n interactions,\n })\n\n const agentBuilder = createAgentBuilder({\n env,\n broadcast,\n active,\n launchOverrides,\n sessionCwd: ctx.sessionCwd,\n artifactsDir: ctx.artifactsDir,\n interactions,\n approvals,\n browser,\n terminals,\n orchestration,\n pluginCatalog,\n sessionSafelistFor,\n sessionExecution: execution.sessionExecution,\n withTerminalTasks: execution.withTerminalTasks,\n buildProvider,\n maybeWake,\n machineBuilds,\n })\n const agents = agentsRef.current = createAgentLifecycle({\n ctx,\n interactions,\n approvals,\n terminals,\n executionCache,\n suspendEnvironment: execution.suspendEnvironment,\n buildActiveRun: agentBuilder.buildActiveRun,\n pluginCatalog,\n })\n const sessionOps = createSessionOps({\n ctx,\n host: hostApi,\n rebuildAgentOnly: agents.rebuildAgentOnly,\n applyPendingDispose: agents.applyPendingDispose,\n disposeAgentForRebuild: agents.disposeAgentForRebuild,\n drainQueue,\n })\n const runs = createRuns({\n ctx,\n dispatchSignals,\n ensureAgent: agents.ensureAgent,\n commands,\n buildProvider,\n applyPendingDispose: agents.applyPendingDispose,\n pruneIdleAgents: agents.pruneIdleAgents,\n drainQueue,\n appendNoteTurn: sessionOps.appendNoteTurn,\n })\n const queue = createQueue({ ctx, sendPrompt: runs.sendPrompt, isProvisioning: sessionId => execution.provisioning.has(sessionId) })\n const teardown = createTeardown({ ctx, host: hostApi, interactions, approvals, queue, agents, execution, pluginCatalog })\n\n const host: ChatHost = {\n interactions,\n approvals,\n browser,\n terminals,\n sendPrompt: runs.sendPrompt,\n workspace: ctx.workspace,\n machines,\n ...folders.hostMethods,\n listCommands: async (cwd, kind) => commands.listCommands(folders.discoveryCwd(cwd, kind)),\n completeCommandArgs: async (cwd, name, argsPrefix, kind) => commands.completeCommandArgs(folders.discoveryCwd(cwd, kind), name, argsPrefix),\n ...runControls,\n ...queue.methods,\n\n isSessionRunning(sessionId) {\n const entry = active.get(sessionId)\n if (entry)\n entry.lastUsedAt = Date.now()\n return isSessionBusy(sessionId)\n },\n\n listLiveSessions() {\n return [...new Set([...active.keys(), ...dispatches.keys()])].map(sessionId => ({\n sessionId,\n running: isSessionBusy(sessionId),\n }))\n },\n\n getLiveTurns(sessionId) {\n return active.get(sessionId)?.agent.session?.turns ?? null\n },\n\n getLiveSession(sessionId) {\n return active.get(sessionId)?.agent.session ?? null\n },\n\n hasActiveWork() {\n if (dispatches.size > 0 || lifecycleWork.size > 0)\n return true\n // Local terminals end with the host: a running one keeps it alive.\n if (terminals.hasRunningLocal())\n return true\n for (const entry of active.values()) {\n // `commandAbort` set = a `/` command is mid-flight — between its\n // sub-runs nothing else reads as active, and an idle-exit would\n // kill the command host mid-workflow.\n if (entry.agent.isRunning || entry.compacting || entry.commandAbort !== undefined || entry.work.size > 0)\n return true\n }\n return false\n },\n\n ...createWorkMethods(active),\n ...createTodoMethods({ active, broadcast }),\n ...execution.methods,\n ...sessionOps.methods,\n orchestration,\n ...createPromptMethods({ env, active, ensureAgent: agents.ensureAgent }),\n ...agents.methods,\n\n disposeAgentForRebuild(sessionId) {\n agents.disposeAgentForRebuild(sessionId)\n },\n // A machine session's cwd override is checked against its machine's roots, not this host's.\n setLaunchOverrides: createLaunchOverridesSetter({ launchOverrides, active, disposeAgentForRebuild: agents.disposeAgentForRebuild, workspace: { checkFolder: cwd => folders.resolve(cwd).cwd } }),\n applyAgentSettings(before, next) {\n const terminalKeys = ['terminal', 'terminalAgent', 'terminalAgentTasks'] as const\n const terminalsChanged = terminalKeys.some(key => (before[key] !== false) !== (next[key] !== false))\n const shapeChanged = terminalsChanged\n || Boolean(before.subagentModels) !== Boolean(next.subagentModels)\n // Adds/removes `codemode`, and gates the Codemode profile.\n || Boolean(before.codemode) !== Boolean(next.codemode)\n // Ask <-> Skip is read per call; only `disabled` changes the tool list.\n || (before.interactionMode === 'disabled') !== (next.interactionMode === 'disabled')\n if (!shapeChanged)\n return\n if (terminalsChanged && next.terminal === false)\n void terminals.closeUserTerminals()\n void host.rebuildAllAgents()\n },\n\n compactSessionNow: createCompactSessionNow({ active, broadcast, store: env.store, ensureAgent: agents.ensureAgent }),\n generateSessionTitle: (sessionId, hint) => generateHostSessionTitle({ env, buildProvider, patchSessionMeta: (...args) => host.patchSessionMeta(...args) }, sessionId, hint),\n ...teardown,\n }\n\n // A browser host arriving or leaving changes which tools agents have: rebuild\n // them (a busy agent is rebuilt once its run ends).\n browser.onAvailabilityChange(() => void host.rebuildAllAgents())\n terminals.onViewerChange(() => void host.rebuildAllAgents())\n execution.bindHostMetaPatch(host.patchSessionMeta)\n\n return host\n\n /*\n * Hoisted forwarders into features built after the one that needs them.\n */\n function hostApi(): ChatHost {\n return host\n }\n function ensureAgent(sessionId: string): Promise<ActiveRun> {\n return agents.ensureAgent(sessionId)\n }\n function evictIdleSession(sessionId: string): void {\n agents.evictIdleSession(sessionId)\n }\n function sendPrompt(opts: SendOptions): Promise<{ runId: string }> {\n return runs.sendPrompt(opts)\n }\n function drainQueue(sessionId: string): void {\n queue.drainQueue(sessionId)\n }\n function maybeWake(sessionId: string): void {\n queue.maybeWake(sessionId)\n }\n function wakeRun(sessionId: string): Promise<void> {\n return queue.wakeRun(sessionId)\n }\n}\n","/**\n * Renderer-agnostic shaping of session artifacts for display — grouping\n * and row presentation. Shared by the TUI rail + modal, the GUI rail and\n * the sessions-list badge, so every surface agrees on what an artifact\n * looks like.\n */\n\nimport type { ExtensionArtifactRow, ExtensionRegistry } from '../extensions'\nimport type { SessionArtifact } from '../session'\nimport { artifactKindLabel, renderArtifactRow } from '../extensions/builtin-artifact-kinds'\n\nexport type ArtifactScope = 'session' | 'project'\n\nexport interface ArtifactViewRow {\n artifact: SessionArtifact\n row: ExtensionArtifactRow\n}\n\nexport interface ArtifactViewGroup {\n kind: string\n /** Human kind label (`Pull request`), raw kind when unregistered. */\n label: string\n rows: ArtifactViewRow[]\n}\n\ntype KindRegistry = Pick<ExtensionRegistry, 'artifactKinds'> | undefined\n\n/** Display order for the built-in kinds; anything else follows alphabetically. */\nconst KIND_ORDER = ['pull_request', 'branch', 'commit', 'file']\n\n/**\n * Group by kind (built-ins first in a fixed order, then extension kinds\n * alphabetically); rows inside a group keep the store's newest-first order.\n */\nexport function groupArtifacts(artifacts: readonly SessionArtifact[], registry?: KindRegistry): ArtifactViewGroup[] {\n const byKind = new Map<string, ArtifactViewRow[]>()\n for (const artifact of artifacts) {\n const list = byKind.get(artifact.kind) ?? []\n list.push({ artifact, row: renderArtifactRow(artifact, registry) })\n byKind.set(artifact.kind, list)\n }\n const kinds = [...byKind.keys()].sort((a, b) => {\n const ai = KIND_ORDER.indexOf(a)\n const bi = KIND_ORDER.indexOf(b)\n if (ai !== -1 || bi !== -1)\n return (ai === -1 ? KIND_ORDER.length : ai) - (bi === -1 ? KIND_ORDER.length : bi)\n return a.localeCompare(b)\n })\n return kinds.map(kind => ({ kind, label: artifactKindLabel(kind, registry), rows: byKind.get(kind)! }))\n}\n\n/** `3 PRs · 2 files` style summary; empty string for none. */\nexport function summarizeArtifactCounts(artifacts: readonly SessionArtifact[], registry?: KindRegistry): string {\n return groupArtifacts(artifacts, registry)\n .map(g => `${g.rows.length} ${pluralizeKind(g.label, g.rows.length)}`)\n .join(' · ')\n}\n\nfunction pluralizeKind(label: string, count: number): string {\n const lower = label.toLowerCase()\n if (count === 1)\n return lower\n return /(?:s|x|ch|sh)$/.test(lower) ? `${lower}es` : `${lower}s`\n}\n","/** Whether any of `vars` is set to a truthy value (anything but unset, `''`, `0`, `false`). */\nexport function envOptedOut(vars: readonly string[], env: NodeJS.ProcessEnv = process.env): boolean {\n for (const key of vars) {\n const v = env[key]\n if (v !== undefined && v !== '' && v !== '0' && v.toLowerCase() !== 'false')\n return true\n }\n return false\n}\n","// ---------------------------------------------------------------------------\n// Auto-update — renderer-agnostic core.\n//\n// Three layers, all reusable by any consumer that wraps `zidane/tui`:\n// 1. `checkForUpdate` — fetches the latest version from an npm-compatible\n// registry, persisted on disk with a TTL so the hot path costs zero\n// network on a warm cache.\n// 2. `performSelfUpdate` — spawns the host package manager (npm, pnpm,\n// yarn, bun, volta) and tells it to re-install the package globally.\n// 3. `performInPlaceSelfUpdate` — downloads the platform-binary tarball\n// from the registry, extracts the binary, atomically swaps it over\n// the live one. Used when no package manager is reachable (offline\n// install path, restricted shells) or when the user wants speed.\n//\n// Pure data + Node-builtin I/O. No React, no OpenTUI, no external deps —\n// hosts replacing the runtime can re-implement just the layer they need.\n// ---------------------------------------------------------------------------\n\nimport type { Buffer } from 'node:buffer'\nimport { spawn } from 'node:child_process'\nimport { createHash } from 'node:crypto'\nimport {\n chmodSync,\n createReadStream,\n createWriteStream,\n mkdirSync,\n mkdtempSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { homedir, tmpdir } from 'node:os'\nimport { dirname, join, resolve, sep } from 'node:path'\nimport { createGunzip } from 'node:zlib'\nimport { envOptedOut } from './env-opt-out'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface CheckForUpdateOptions {\n /** Full npm package name to query. e.g. `'zidane-tui'`. */\n packageName: string\n /** Current installed version. Inlined at build time from the consumer's `package.json`. */\n currentVersion: string\n /**\n * Registry base URL. Defaults to `https://registry.npmjs.org`. Strip the\n * trailing slash; the helper appends `/${packageName}/${channel}`.\n */\n registry?: string\n /**\n * dist-tag to read. Defaults to `'latest'`. Set to `'next'` (or any\n * custom tag) for prerelease channels — the comparison still goes through\n * `compareSemver`, so `5.6.0-beta.2 > 5.5.0` evaluates correctly.\n */\n channel?: string\n /** Directory used for the on-disk TTL cache. Skipped when omitted. */\n cacheDir?: string\n /** Cache lifetime. Defaults to 24 h. Negative / 0 disables caching. */\n cacheTtlMs?: number\n /** Network timeout. Defaults to 3 000 ms. */\n timeoutMs?: number\n /** Abort signal — wins over the internal timeout. */\n signal?: AbortSignal\n /**\n * When `true`, ignore env-var opt-outs (`CI`, `NO_UPDATE_NOTIFIER`,\n * `ZIDANE_NO_UPDATE`) AND bypass the on-disk TTL cache (always hit\n * the registry). Used by the explicit `zidane upgrade` path where the\n * user typed the command — they expect fresh data, not a 24-hour-old\n * cached value. The cache is still WRITTEN with the fresh result so\n * subsequent background checks benefit; cache reads only feed the\n * etag into the next request so the registry can short-circuit with\n * 304 when nothing changed.\n */\n force?: boolean\n /** Inject for tests. Defaults to `globalThis.fetch`. */\n fetcher?: typeof fetch\n /** Inject for tests. Defaults to `Date.now`. */\n now?: () => number\n}\n\nexport interface UpdateStatus {\n /** Always present — echoes `currentVersion`. */\n current: string\n /** `null` when the lookup failed / was skipped / cache was empty. */\n latest: string | null\n /** `true` when `latest` is strictly greater than `current` by semver. */\n hasUpdate: boolean\n /**\n * - `'fresh'` — fetched from the registry this call.\n * - `'cached'` — served from the on-disk cache.\n * - `'skipped'` — opt-out env var, missing fetch, network refused, etc.\n * - `'error'` — registry returned non-2xx or threw; details on `error`.\n */\n source: 'fresh' | 'cached' | 'skipped' | 'error'\n /** Error message when `source === 'error'`. */\n error?: string\n /** When the registry was last queried (ms since epoch). `null` when never. */\n checkedAt: number | null\n /** dist-tag used for the lookup — handy when surfacing \"v5.6.0 (next)\". */\n channel: string\n}\n\nexport interface PackageManagerCommand {\n /** Stable identifier. `npm` is the fallback when no other signal fires. */\n id: PackageManagerId\n /** Argv that, when execve'd, installs `packageName@channel` globally. */\n argv: string[]\n /**\n * Free-form note for the user — explains *why* this command was chosen\n * (e.g. \"Volta-managed install detected via ~/.volta/bin\").\n */\n note?: string\n}\n\nexport type PackageManagerId = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'volta'\n\nexport interface DetectPackageManagerOptions {\n /** Override the resolved binary path (defaults to `process.execPath`). */\n binaryPath?: string\n /** Override the user-agent string (defaults to `process.env.npm_config_user_agent`). */\n userAgent?: string | undefined\n /** Override env. Used in tests. */\n env?: Readonly<Record<string, string | undefined>>\n /** Override `homedir()`. Used in tests. */\n home?: string\n /** Override `process.platform`. Used in tests. */\n platform?: NodeJS.Platform\n /** When set, the host already knows the package name (avoids the test seam). */\n packageName?: string\n /** dist-tag. Defaults to `'latest'`. */\n channel?: string\n}\n\n// ---------------------------------------------------------------------------\n// Env-var opt-outs\n//\n// `NO_UPDATE_NOTIFIER` is the de-facto npm-ecosystem convention (yeoman,\n// update-notifier). `ZIDANE_NO_UPDATE` is the project-specific knob so\n// hosts wrapping the TUI can wire their own without colliding.\n// `CI=true` is set by every major CI runner; skipping there avoids\n// surprise registry chatter from build pipelines.\n// ---------------------------------------------------------------------------\n\nconst OPT_OUT_VARS = ['ZIDANE_NO_UPDATE', 'NO_UPDATE_NOTIFIER', 'CI'] as const\n\nfunction isOptedOut(env: NodeJS.ProcessEnv = process.env): boolean {\n return envOptedOut(OPT_OUT_VARS, env)\n}\n\n// ---------------------------------------------------------------------------\n// Semver compare — tiny self-contained implementation.\n//\n// We support the subset of semver the npm registry actually returns:\n// `MAJOR.MINOR.PATCH` plus optional `-prerelease[.N…]` and `+build`. Build\n// metadata is ignored per spec; prereleases compare via the standard rule\n// (numeric vs string, longer chain wins after equal prefix).\n//\n// Inlining this beats pulling in `semver` (~70 KB) just to compare two\n// strings; we already accept the maintenance trade-off for `tail-truncated`\n// shells and other tiny utilities. Tested in `test/chat/auto-update.test.ts`.\n// ---------------------------------------------------------------------------\n\nexport function parseSemver(input: string): { major: number, minor: number, patch: number, prerelease: string[] } | null {\n const m = /^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([\\w.-]+))?(?:\\+[\\w.-]+)?$/.exec(input.trim())\n if (!m)\n return null\n return {\n major: Number(m[1]),\n minor: Number(m[2]),\n patch: Number(m[3]),\n prerelease: m[4] ? m[4].split('.') : [],\n }\n}\n\n/** Returns `-1 / 0 / 1`. Unparseable inputs sort as `0` (assume equal). */\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const A = parseSemver(a)\n const B = parseSemver(b)\n if (!A || !B)\n return 0\n for (const k of ['major', 'minor', 'patch'] as const) {\n if (A[k] !== B[k])\n return A[k] < B[k] ? -1 : 1\n }\n // A release version is greater than its prereleases (1.0.0 > 1.0.0-rc.1).\n if (A.prerelease.length === 0 && B.prerelease.length > 0)\n return 1\n if (A.prerelease.length > 0 && B.prerelease.length === 0)\n return -1\n const len = Math.max(A.prerelease.length, B.prerelease.length)\n for (let i = 0; i < len; i++) {\n const ai = A.prerelease[i]\n const bi = B.prerelease[i]\n if (ai === undefined)\n return -1\n if (bi === undefined)\n return 1\n const an = /^\\d+$/.test(ai) ? Number(ai) : null\n const bn = /^\\d+$/.test(bi) ? Number(bi) : null\n if (an !== null && bn !== null) {\n if (an !== bn)\n return an < bn ? -1 : 1\n }\n else if (an !== null) {\n return -1 // numeric < alphanumeric per spec\n }\n else if (bn !== null) {\n return 1\n }\n else if (ai !== bi) {\n return ai < bi ? -1 : 1\n }\n }\n return 0\n}\n\n// ---------------------------------------------------------------------------\n// Cache\n// ---------------------------------------------------------------------------\n\ninterface UpdateCheckFile {\n packageName: string\n channel: string\n latest: string\n checkedAt: number\n /** Last-seen registry ETag — flows through If-None-Match on the next check. */\n etag?: string\n}\n\nfunction cacheFilePath(cacheDir: string, packageName: string, channel: string): string {\n // Embed package + channel in the filename so a host running multiple\n // checks (e.g. against `latest` and `next`) doesn't trample state.\n const slug = `${packageName.replaceAll('/', '__')}@${channel}`\n return resolve(cacheDir, `update-check-${slug}.json`)\n}\n\nfunction readCache(path: string): UpdateCheckFile | null {\n try {\n const raw = readFileSync(path, 'utf8')\n const parsed = JSON.parse(raw) as UpdateCheckFile\n if (typeof parsed.latest !== 'string' || typeof parsed.checkedAt !== 'number')\n return null\n return parsed\n }\n catch {\n return null\n }\n}\n\nfunction writeCache(path: string, entry: UpdateCheckFile): void {\n try {\n mkdirSync(dirname(path), { recursive: true })\n // Format with a trailing newline so hand-inspection in a terminal\n // doesn't render the prompt glued to the closing brace.\n writeFileSync(path, `${JSON.stringify(entry, null, 2)}\\n`)\n }\n catch {\n // Cache failures are non-fatal — the next call just re-fetches.\n }\n}\n\n// ---------------------------------------------------------------------------\n// Registry fetch\n// ---------------------------------------------------------------------------\n\n/** Strip a trailing slash so URL assembly is uniform. */\nfunction trimSlash(s: string): string {\n return s.endsWith('/') ? s.slice(0, -1) : s\n}\n\ninterface FetchedRelease {\n latest: string\n etag: string | null\n}\n\nasync function fetchLatestRelease(opts: {\n registry: string\n packageName: string\n channel: string\n etag: string | undefined\n fetcher: typeof fetch\n signal: AbortSignal\n}): Promise<FetchedRelease> {\n // Use the `<pkg>/<dist-tag>` endpoint which returns a single packument\n // (the smallest payload). Falls back to the abbreviated metadata mime\n // type so npm proxies (Verdaccio, JFrog) that don't honor it still\n // return JSON.\n const url = `${trimSlash(opts.registry)}/${encodeURIComponent(opts.packageName)}/${encodeURIComponent(opts.channel)}`\n const headers: Record<string, string> = {\n 'accept': 'application/vnd.npm.install-v1+json, application/json',\n 'user-agent': 'zidane-update-check/1',\n }\n if (opts.etag)\n headers['if-none-match'] = opts.etag\n const res = await opts.fetcher(url, { headers, signal: opts.signal, redirect: 'follow' })\n if (res.status === 304) {\n // Caller falls back to the cached entry when this throws — keep the\n // signal explicit instead of overloading the return shape.\n throw new NotModifiedError()\n }\n if (!res.ok)\n throw new Error(`registry returned ${res.status}`)\n const body = await res.json() as { version?: string, name?: string }\n if (!body.version)\n throw new Error('registry payload missing `version`')\n return { latest: body.version, etag: res.headers.get('etag') }\n}\n\nclass NotModifiedError extends Error {\n constructor() { super('not-modified') }\n}\n\n// ---------------------------------------------------------------------------\n// Public API: checkForUpdate\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the latest available version of `packageName`, honoring an\n * on-disk TTL cache so the warm path costs zero network. Never throws —\n * registry failures degrade to `{ source: 'error', latest: null }`.\n *\n * Designed for boot-path usage: short timeout, swallows errors, opt-outs\n * for CI / restricted shells. Consumers driving the explicit `upgrade`\n * subcommand should set `force: true` to ignore env opt-outs.\n */\nexport async function checkForUpdate(options: CheckForUpdateOptions): Promise<UpdateStatus> {\n const channel = options.channel ?? 'latest'\n const now = options.now ?? Date.now\n const fetcher = options.fetcher ?? globalThis.fetch\n const ttl = options.cacheTtlMs ?? 24 * 60 * 60 * 1000\n const timeoutMs = options.timeoutMs ?? 3000\n\n if (!options.force && isOptedOut())\n return skipped(options.currentVersion, channel)\n\n const cachePath = options.cacheDir\n ? cacheFilePath(options.cacheDir, options.packageName, channel)\n : null\n\n // Fast-path the warm cache — but only when the cached payload still\n // matches `packageName + channel`. The slug guards against an\n // older zidane writing a different package's cache file at the same\n // path (host rename scenarios). `force` skips the freshness short-\n // circuit entirely: the user-typed `upgrade` path always wants the\n // truth from the registry, never a 24-hour-old cached \"no update\".\n const cached = cachePath ? readCache(cachePath) : null\n if (!options.force && cached && cached.packageName === options.packageName && cached.channel === channel) {\n const fresh = ttl > 0 && (now() - cached.checkedAt) < ttl\n if (fresh) {\n const hasUpdate = compareSemver(cached.latest, options.currentVersion) > 0\n return {\n current: options.currentVersion,\n latest: cached.latest,\n hasUpdate,\n source: 'cached',\n checkedAt: cached.checkedAt,\n channel,\n }\n }\n }\n\n // Fetch is required for the cold path. Falling back to a stale cache is\n // checked further below, but the contract for `skipped` is \"we didn't\n // even try\" — without a fetcher we can't try.\n if (typeof fetcher !== 'function') {\n if (cached) {\n return {\n current: options.currentVersion,\n latest: cached.latest,\n hasUpdate: compareSemver(cached.latest, options.currentVersion) > 0,\n source: 'cached',\n checkedAt: cached.checkedAt,\n channel,\n }\n }\n return skipped(options.currentVersion, channel)\n }\n\n // Tie the user's signal to our timeout so abort propagates. The\n // controller is local to this call — we never leak it to callers.\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(new Error('timeout')), timeoutMs)\n if (options.signal) {\n if (options.signal.aborted)\n controller.abort(options.signal.reason as Error)\n else\n options.signal.addEventListener('abort', () => controller.abort(options.signal!.reason as Error), { once: true })\n }\n\n try {\n const release = await fetchLatestRelease({\n registry: options.registry ?? 'https://registry.npmjs.org',\n packageName: options.packageName,\n channel,\n etag: cached?.etag,\n fetcher,\n signal: controller.signal,\n })\n const checkedAt = now()\n if (cachePath) {\n writeCache(cachePath, {\n packageName: options.packageName,\n channel,\n latest: release.latest,\n checkedAt,\n ...(release.etag ? { etag: release.etag } : {}),\n })\n }\n return {\n current: options.currentVersion,\n latest: release.latest,\n hasUpdate: compareSemver(release.latest, options.currentVersion) > 0,\n source: 'fresh',\n checkedAt,\n channel,\n }\n }\n catch (err) {\n if (err instanceof NotModifiedError && cached) {\n // 304 — extend the cache freshness window so we don't re-poll\n // every boot when the registry agrees we're current.\n const checkedAt = now()\n if (cachePath) {\n writeCache(cachePath, {\n ...cached,\n checkedAt,\n })\n }\n return {\n current: options.currentVersion,\n latest: cached.latest,\n hasUpdate: compareSemver(cached.latest, options.currentVersion) > 0,\n source: 'cached',\n checkedAt,\n channel,\n }\n }\n if (cached) {\n // Fall back to a stale cache rather than reporting `null` when we\n // have data — the user still sees something useful.\n return {\n current: options.currentVersion,\n latest: cached.latest,\n hasUpdate: compareSemver(cached.latest, options.currentVersion) > 0,\n source: 'cached',\n checkedAt: cached.checkedAt,\n channel,\n }\n }\n return {\n current: options.currentVersion,\n latest: null,\n hasUpdate: false,\n source: 'error',\n error: err instanceof Error ? err.message : String(err),\n checkedAt: null,\n channel,\n }\n }\n finally {\n clearTimeout(timer)\n }\n}\n\nfunction skipped(current: string, channel: string): UpdateStatus {\n return { current, latest: null, hasUpdate: false, source: 'skipped', checkedAt: null, channel }\n}\n\n// ---------------------------------------------------------------------------\n// Package-manager detection\n//\n// Layered heuristics — strongest signal wins:\n// 1. Resolved binary path. Volta lives under `~/.volta/bin`, bun under\n// `~/.bun/install/global/node_modules/.bin` (or `$BUN_INSTALL/bin`),\n// pnpm under `~/.local/share/pnpm` or `~/Library/pnpm`, classic yarn\n// under `~/.yarn/bin`, npm anywhere else under a `<prefix>/bin`.\n// 2. `npm_config_user_agent` env var — set during `npm/pnpm/yarn/bun\n// install` runs, so this still helps when the user is mid-install.\n// 3. Default to npm. Universally available; users on more exotic PMs\n// have to pass `--package-manager` (or set up their env so the path\n// heuristic fires).\n//\n// Volta is treated as a first-class PM here even though it wraps another\n// (typically npm) — `volta install` is the only correct way to update a\n// Volta-pinned tool. Writing through the inner PM would leave Volta's\n// catalog stale and re-pin the old version on the next shell.\n// ---------------------------------------------------------------------------\n\nfunction normalizePath(path: string): string {\n // Resolve symlinks so a `/usr/local/bin/zidane` → `/opt/homebrew/...`\n // chain still matches the inner location. `realpathSync` throws on\n // broken links; fall back to the literal path then.\n try {\n return realpathSync(path)\n }\n catch {\n return path\n }\n}\n\n/**\n * The command to show for a manual reinstall. Volta treats `install` of an\n * already-recorded version as a no-op, so the only way to replace a broken\n * install is to remove it first.\n */\nexport function reinstallHint(command: PackageManagerCommand, packageName: string, channel: string): string {\n const cmd = command.argv.join(' ')\n return command.id === 'volta' ? `volta uninstall ${packageName} && volta install ${packageName}@${channel}` : cmd\n}\n\nexport function detectPackageManager(opts: DetectPackageManagerOptions = {}): PackageManagerCommand {\n const env = opts.env ?? process.env\n const home = opts.home ?? homedir()\n const platform = opts.platform ?? process.platform\n const channel = opts.channel ?? 'latest'\n const packageName = opts.packageName ?? 'zidane-tui'\n const binaryPath = opts.binaryPath ?? process.execPath\n const resolvedBinary = normalizePath(binaryPath)\n const userAgent = opts.userAgent ?? env.npm_config_user_agent\n\n // The argv contract:\n // - `argv[0]` is the binary we exec — needs to be on PATH or absolute.\n // - Remaining tokens are the install command.\n // We rely on PATH resolution so users with shimmed wrappers (volta,\n // mise, asdf) still hit their managed binary.\n const target = `${packageName}@${channel}`\n\n // 1. Path-based heuristics ------------------------------------------------\n //\n // Match path SEGMENTS, not substrings — `/Users/me/.volta-old/bin/x` must\n // NOT match `/Users/me/.volta`. We anchor the comparison to a separator\n // on both sides so the directory name has to be exact.\n\n const containsSegment = (path: string, segment: string) => {\n // `segment` is `<home>/.<name>` (no trailing separator). To match, the\n // path must contain `<segment><sep>` OR end with `<segment>`.\n const tail = `${segment}${sep}`\n return path.includes(tail) || path.endsWith(segment)\n }\n const inPath = (segment: string) =>\n containsSegment(resolvedBinary, segment) || containsSegment(binaryPath, segment)\n const homeSeg = (rest: string) => `${home}${sep}${rest}`\n\n // Binary-path check — strongest signal. A binary living under `~/.volta/`\n // was DEFINITELY installed by Volta; same logic for the others.\n if (inPath(homeSeg('.volta'))) {\n return {\n id: 'volta',\n argv: ['volta', 'install', target],\n note: 'Volta-managed install detected, refreshing via `volta install`.',\n }\n }\n if (inPath(homeSeg('.bun'))) {\n return {\n id: 'bun',\n argv: ['bun', 'add', '--global', target],\n note: 'Bun global install detected.',\n }\n }\n if (\n inPath(homeSeg('.local/share/pnpm'))\n || inPath(homeSeg('Library/pnpm'))\n || resolvedBinary.includes(`${sep}pnpm${sep}`)\n ) {\n return {\n id: 'pnpm',\n argv: ['pnpm', 'add', '--global', target],\n note: 'pnpm global install detected.',\n }\n }\n if (inPath(homeSeg('.yarn'))) {\n return {\n id: 'yarn',\n argv: ['yarn', 'global', 'add', target],\n note: 'Yarn classic global install detected.',\n }\n }\n\n // 2. User-agent heuristic (mid-install or recently-installed shells) ------\n // `npm_config_user_agent` looks like `npm/10.2.3 node/v22.0.0 darwin arm64`\n // or `pnpm/8.15.0 npm/? node/v22.0.0 darwin arm64`. This fires when the\n // binary lives in an unrecognized prefix (corporate npm proxy, custom\n // global root, …) but the calling shell still identifies a PM.\n if (userAgent) {\n const ua = userAgent.toLowerCase()\n if (ua.startsWith('pnpm/'))\n return { id: 'pnpm', argv: ['pnpm', 'add', '--global', target] }\n if (ua.startsWith('yarn/'))\n return { id: 'yarn', argv: ['yarn', 'global', 'add', target] }\n if (ua.startsWith('bun/'))\n return { id: 'bun', argv: ['bun', 'add', '--global', target] }\n if (ua.startsWith('npm/'))\n return { id: 'npm', argv: ['npm', 'install', '--global', target] }\n }\n\n // 3. Env-var fallback — only fires when both the path and the user-agent\n // failed to identify a PM. We trust these LESS than the binary path\n // because a user can install zidane outside their main PM (e.g. via\n // npm) while still having $VOLTA_HOME / $BUN_INSTALL set for unrelated\n // tooling.\n if (env.VOLTA_HOME)\n return { id: 'volta', argv: ['volta', 'install', target], note: '$VOLTA_HOME set, using `volta install`. If the install is not Volta-managed, pass `--package-manager npm`.' }\n if (env.BUN_INSTALL)\n return { id: 'bun', argv: ['bun', 'add', '--global', target] }\n if (env.PNPM_HOME)\n return { id: 'pnpm', argv: ['pnpm', 'add', '--global', target] }\n\n // 4. Default to npm — universally available.\n\n void platform // Reserved for Windows-specific tweaks (none yet).\n return {\n id: 'npm',\n argv: ['npm', 'install', '--global', target],\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API: tarball readiness\n// ---------------------------------------------------------------------------\n\nexport interface TarballAvailabilityOptions {\n packageName: string\n version: string\n registry?: string\n timeoutMs?: number\n /** Inject for tests. */\n fetcher?: typeof fetch\n}\n\n/**\n * Whether `<packageName>@<version>` can actually be DOWNLOADED right now, not\n * merely resolved. Right after a publish the registry serves the new\n * manifest minutes before the tarball reaches the CDN; a package manager\n * that hits that window on an `optionalDependencies` platform binary\n * silently skips it and leaves a bin with nothing behind it. `upgrade` asks\n * this before spawning the PM so it can wait instead of breaking the install.\n *\n * - `'ok'` tarball responds 2xx\n * - `'missing'` manifest or tarball 404 (published, not propagated)\n * - `'unknown'` network / registry error; the caller decides\n */\nexport async function checkTarballAvailable(opts: TarballAvailabilityOptions): Promise<'ok' | 'missing' | 'unknown'> {\n const fetcher = opts.fetcher ?? globalThis.fetch\n const registry = trimSlash(opts.registry ?? 'https://registry.npmjs.org')\n const ac = new AbortController()\n const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? 8000)\n try {\n const manifest = await fetcher(\n `${registry}/${encodeURIComponent(opts.packageName)}/${encodeURIComponent(opts.version)}`,\n { headers: { 'accept': 'application/json', 'user-agent': 'zidane-update-check/1' }, signal: ac.signal, redirect: 'follow' },\n )\n if (manifest.status === 404)\n return 'missing'\n if (!manifest.ok)\n return 'unknown'\n const body = await manifest.json() as { dist?: { tarball?: string } }\n const tarball = body.dist?.tarball\n if (!tarball)\n return 'unknown'\n const head = await fetcher(tarball, { method: 'HEAD', signal: ac.signal, redirect: 'follow' })\n if (head.status === 404)\n return 'missing'\n return head.ok ? 'ok' : 'unknown'\n }\n catch {\n return 'unknown'\n }\n finally {\n clearTimeout(timer)\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API: performSelfUpdate (PM-spawned)\n// ---------------------------------------------------------------------------\n\nexport interface PerformSelfUpdateOptions {\n packageName: string\n channel?: string\n /** Force a specific PM instead of auto-detect. */\n packageManager?: PackageManagerId | 'auto'\n /** Don't actually spawn — return the command we WOULD run. */\n dryRun?: boolean\n /** When set, write `pm stdout/stderr` to these streams instead of stdio inherit. */\n stdout?: NodeJS.WritableStream\n stderr?: NodeJS.WritableStream\n /** Abort the install. */\n signal?: AbortSignal\n /** Override env (e.g. set `npm_config_loglevel=error`). */\n env?: Readonly<Record<string, string>>\n /** Inject for tests. */\n spawn?: typeof spawn\n /** Inject for tests. */\n detect?: typeof detectPackageManager\n}\n\nexport interface SelfUpdateResult {\n command: PackageManagerCommand\n /** PM exit code. `null` when `dryRun` or the process was killed. */\n exitCode: number | null\n /** Set when the spawn itself failed (`ENOENT`, EACCES). */\n spawnError?: string\n}\n\n/**\n * Re-install the package globally via the host's package manager. Resolves\n * with the spawned command's exit code, or rejects only when the caller's\n * `signal` aborts. PM failures surface as a non-zero `exitCode` — the\n * caller decides whether to retry or fall back to in-place.\n */\nexport async function performSelfUpdate(options: PerformSelfUpdateOptions): Promise<SelfUpdateResult> {\n const detect = options.detect ?? detectPackageManager\n const command = options.packageManager && options.packageManager !== 'auto'\n ? overrideManager(options.packageManager, options.packageName, options.channel ?? 'latest')\n : detect({ packageName: options.packageName, channel: options.channel ?? 'latest' })\n\n if (options.dryRun)\n return { command, exitCode: null }\n\n const useSpawn = options.spawn ?? spawn\n return await new Promise<SelfUpdateResult>((resolveP) => {\n const [bin, ...args] = command.argv\n const child = useSpawn(bin!, args, {\n stdio: options.stdout || options.stderr\n ? ['ignore', 'pipe', 'pipe']\n : 'inherit',\n env: { ...process.env, ...options.env },\n })\n if (options.stdout && child.stdout)\n child.stdout.pipe(options.stdout)\n if (options.stderr && child.stderr)\n child.stderr.pipe(options.stderr)\n child.on('error', (err) => {\n // ENOENT here means the PM binary isn't on PATH — surface a\n // clear message rather than the bare error.\n resolveP({ command, exitCode: null, spawnError: err.message })\n })\n child.on('exit', (code) => {\n resolveP({ command, exitCode: code })\n })\n if (options.signal) {\n const onAbort = () => child.kill()\n if (options.signal.aborted)\n onAbort()\n else\n options.signal.addEventListener('abort', onAbort, { once: true })\n }\n })\n}\n\n/** The global-install command that pins `<packageName>@<channel>` for package manager `id`. */\nexport function overrideManager(id: PackageManagerId, packageName: string, channel: string): PackageManagerCommand {\n const target = `${packageName}@${channel}`\n switch (id) {\n case 'pnpm': return { id, argv: ['pnpm', 'add', '--global', target] }\n case 'yarn': return { id, argv: ['yarn', 'global', 'add', target] }\n case 'bun': return { id, argv: ['bun', 'add', '--global', target] }\n case 'volta': return { id, argv: ['volta', 'install', target] }\n case 'npm':\n default: return { id: 'npm', argv: ['npm', 'install', '--global', target] }\n }\n}\n\n// ---------------------------------------------------------------------------\n// In-place self-update\n//\n// Downloads `<packageName>@<channel>` from the npm registry, untars the\n// `bin/<filename>` entry, codesigns ad-hoc on darwin if needed, and atomic-\n// renames over the live binary. The host needs to know:\n// - the platform-specific package name to fetch (e.g. `zidane-tui-darwin-arm64`)\n// - the path inside that tarball where the binary lives (defaults to\n// `package/bin/<binaryName>`, which matches the project layout under\n// `tui/npm/<key>/bin/`)\n// - the path of the running binary, so we know where to write\n//\n// Volta-managed installs are explicitly refused — Volta's catalog needs\n// the PM path. The caller should detect via `detectPackageManager` and\n// fall through to `performSelfUpdate` instead.\n// ---------------------------------------------------------------------------\n\nexport interface PerformInPlaceUpdateOptions {\n /** Platform-specific tarball package, e.g. `'zidane-tui-darwin-arm64'`. */\n packageName: string\n channel?: string\n /** Resolved path of the running binary. Defaults to `process.execPath`. */\n binaryPath?: string\n /** Inside the tarball — usually `bin/<name>`. Defaults to `bin/<basename(binaryPath)>`. */\n tarballBinaryPath?: string\n registry?: string\n /** Network timeout (per request). Defaults to 30 000 ms — tarballs are MB-scale. */\n timeoutMs?: number\n signal?: AbortSignal\n /** Don't replace — just download + verify. */\n dryRun?: boolean\n fetcher?: typeof fetch\n /** When set, refuse the swap if the resolved binary lives under one of these prefixes. */\n refuseUnderPrefixes?: readonly string[]\n}\n\nexport interface InPlaceUpdateResult {\n /** `'success' | 'refused' | 'failed'`. */\n status: 'success' | 'refused' | 'failed'\n /** Version that was installed (from the tarball's package.json). */\n installedVersion?: string\n /** Why we bailed. Always present on `refused` / `failed`. */\n reason?: string\n /** Resolved binary path after the swap. */\n binaryPath?: string\n}\n\n/**\n * Replace the running binary with the latest tarball-shipped one. Works on\n * macOS + Linux (POSIX unlink-while-running); refuses on Windows. Returns\n * a result object instead of throwing — callers usually want to print\n * `result.reason` and fall back to a PM-driven update.\n */\nexport async function performInPlaceSelfUpdate(options: PerformInPlaceUpdateOptions): Promise<InPlaceUpdateResult> {\n if (process.platform === 'win32')\n return { status: 'refused', reason: 'in-place update not supported on Windows; use `zidane upgrade` instead.' }\n\n const binaryPath = options.binaryPath ?? process.execPath\n const resolved = normalizePath(binaryPath)\n const refused = options.refuseUnderPrefixes\n if (refused?.some(p => resolved.startsWith(p))) {\n return { status: 'refused', reason: `binary at ${resolved} sits under a managed prefix; use \\`zidane upgrade\\` to update via your package manager.` }\n }\n // Volta is the canonical \"managed prefix\" — refuse by default so users\n // don't end up with a stale catalog after the swap.\n if (resolved.includes(`${homedir()}${sep}.volta${sep}`)) {\n return { status: 'refused', reason: 'Volta-managed install detected. Use `zidane upgrade` (runs `volta install`) instead.' }\n }\n\n const fetcher = options.fetcher ?? globalThis.fetch\n if (typeof fetcher !== 'function')\n return { status: 'failed', reason: 'global fetch unavailable; rebuild with Node ≥ 18 or Bun.' }\n\n const channel = options.channel ?? 'latest'\n const registry = options.registry ?? 'https://registry.npmjs.org'\n const timeoutMs = options.timeoutMs ?? 30_000\n\n // 1. Resolve dist-tag → packument entry for the exact version + tarball URL.\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(new Error('timeout')), timeoutMs)\n if (options.signal) {\n if (options.signal.aborted)\n controller.abort(options.signal.reason as Error)\n else\n options.signal.addEventListener('abort', () => controller.abort(options.signal!.reason as Error), { once: true })\n }\n\n try {\n const metaUrl = `${trimSlash(registry)}/${encodeURIComponent(options.packageName)}/${encodeURIComponent(channel)}`\n const metaRes = await fetcher(metaUrl, {\n headers: { 'accept': 'application/json', 'user-agent': 'zidane-update-check/1' },\n signal: controller.signal,\n })\n if (!metaRes.ok)\n return { status: 'failed', reason: `registry returned ${metaRes.status} for ${options.packageName}@${channel}` }\n const meta = await metaRes.json() as {\n version?: string\n dist?: { tarball?: string, integrity?: string, shasum?: string }\n }\n if (!meta.version || !meta.dist?.tarball)\n return { status: 'failed', reason: `registry payload missing version or tarball for ${options.packageName}@${channel}` }\n // Defense-in-depth: the npm registry serves over HTTPS, but a user\n // running with `--registry <custom>` might point at a less-trusted\n // mirror. Refuse to overwrite the live binary if the registry didn't\n // ship at least one integrity field for us to verify.\n if (!meta.dist.integrity && !meta.dist.shasum)\n return { status: 'failed', reason: `registry payload missing integrity / shasum for ${options.packageName}@${channel}; refusing to overwrite the binary.` }\n\n // 2. Stage adjacent to the target binary's directory so the final\n // `rename` stays on a single filesystem (avoids EXDEV on Linux where\n // /tmp is often tmpfs). Falls back to the OS tmpdir if the target's\n // parent is non-writable.\n const targetDir = dirname(binaryPath)\n let stagingDir: string\n try {\n stagingDir = mkdtempSync(join(targetDir, '.zidane-update-'))\n }\n catch {\n stagingDir = mkdtempSync(join(tmpdir(), 'zidane-update-'))\n }\n const tarballPath = join(stagingDir, 'package.tgz')\n\n try {\n const tgzRes = await fetcher(meta.dist.tarball, {\n headers: { 'user-agent': 'zidane-update-check/1' },\n signal: controller.signal,\n })\n if (!tgzRes.ok || !tgzRes.body)\n return { status: 'failed', reason: `tarball download failed: ${tgzRes.status}` }\n const digests = await streamToFile(tgzRes.body, tarballPath)\n\n // 3. Verify integrity. Prefer SRI (sha512) when present; fall back\n // to the legacy `shasum` (SHA-1) which every package on the registry\n // still carries. A mismatch is a hard refusal — never overwrite the\n // live binary with content we can't authenticate.\n const integrityCheck = verifyIntegrity(meta.dist, digests)\n if (!integrityCheck.ok)\n return { status: 'failed', reason: `integrity check failed: ${integrityCheck.reason}` }\n\n // 4. Extract just the binary entry.\n const tarballBinaryPath = options.tarballBinaryPath\n ?? `bin/${binaryNameFrom(binaryPath)}`\n const extractedPath = await extractEntryFromTarball(tarballPath, tarballBinaryPath, stagingDir)\n if (!extractedPath)\n return { status: 'failed', reason: `tarball did not contain ${tarballBinaryPath}` }\n\n if (options.dryRun) {\n return { status: 'success', installedVersion: meta.version, binaryPath: extractedPath }\n }\n\n // 5. Mark executable + atomic rename. POSIX permits unlink-while-running.\n chmodSync(extractedPath, 0o755)\n const targetForSwap = binaryPath\n try {\n renameSync(extractedPath, targetForSwap)\n }\n catch (err) {\n return { status: 'failed', reason: `failed to write ${targetForSwap}: ${err instanceof Error ? err.message : String(err)}` }\n }\n return { status: 'success', installedVersion: meta.version, binaryPath: targetForSwap }\n }\n finally {\n try { rmSync(stagingDir, { recursive: true, force: true }) }\n catch { /* best-effort */ }\n }\n }\n catch (err) {\n return { status: 'failed', reason: err instanceof Error ? err.message : String(err) }\n }\n finally {\n clearTimeout(timer)\n }\n}\n\nfunction binaryNameFrom(path: string): string {\n const last = path.split(/[\\\\/]/).at(-1) ?? ''\n return last.endsWith('.exe') ? last.slice(0, -4) : last\n}\n\ninterface StreamDigests {\n sha1: string\n sha512Base64: string\n size: number\n}\n\n/**\n * Stream `body` to `path` while computing integrity digests on the fly —\n * we never load the whole tarball into a Buffer just to hash it. Returns\n * SHA-1 (hex, for the legacy `dist.shasum`) and SHA-512 (base64, for SRI's\n * `sha512-<base64>`).\n */\nasync function streamToFile(body: ReadableStream<Uint8Array>, path: string): Promise<StreamDigests> {\n const file = createWriteStream(path)\n const sha1 = createHash('sha1')\n const sha512 = createHash('sha512')\n let size = 0\n const reader = body.getReader()\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done)\n break\n if (value && value.byteLength > 0) {\n sha1.update(value)\n sha512.update(value)\n size += value.byteLength\n await new Promise<void>((res, rej) => file.write(value, err => err ? rej(err) : res()))\n }\n }\n }\n finally {\n await new Promise<void>(res => file.end(() => res()))\n }\n return {\n sha1: sha1.digest('hex'),\n sha512Base64: sha512.digest('base64'),\n size,\n }\n}\n\n/**\n * Validate the downloaded tarball's digest against the registry's\n * `dist.integrity` (SRI: `sha512-<base64>` / `sha384-…` / `sha256-…`) or\n * the legacy `dist.shasum` (hex SHA-1). Either must match — we don't\n * accept \"neither provided\" because that's what `performInPlaceSelfUpdate`\n * already short-circuited above.\n */\nfunction verifyIntegrity(\n dist: { integrity?: string, shasum?: string },\n digests: StreamDigests,\n): { ok: true } | { ok: false, reason: string } {\n if (dist.integrity) {\n // SRI may carry multiple space-separated hashes — any match wins.\n const entries = dist.integrity.split(/\\s+/).filter(Boolean)\n for (const entry of entries) {\n const m = /^(sha(?:256|384|512))-(.+)$/.exec(entry)\n if (!m)\n continue\n const algo = m[1]!\n const expected = m[2]!\n if (algo === 'sha512' && digests.sha512Base64 === expected)\n return { ok: true }\n // Recompute on demand for the rarer algorithms. We only re-hash if\n // the registry shipped a non-512 SRI, which is unusual but legal.\n // For now, fail closed — refuse rather than skip the check.\n if (algo !== 'sha512')\n return { ok: false, reason: `unsupported SRI algorithm \\`${algo}\\`. Re-run via your package manager.` }\n }\n return { ok: false, reason: 'SRI mismatch: tarball does not match the registry\\'s `dist.integrity`.' }\n }\n if (dist.shasum) {\n if (digests.sha1 === dist.shasum.toLowerCase())\n return { ok: true }\n return { ok: false, reason: 'SHA-1 mismatch: tarball does not match the registry\\'s `dist.shasum`.' }\n }\n return { ok: false, reason: 'no integrity field shipped by the registry.' }\n}\n\n// ---------------------------------------------------------------------------\n// Minimal tar extractor — POSIX ustar format. Only handles the entries\n// produced by `npm pack`: filenames < 100 bytes, no PAX extended headers\n// (npm only emits them for paths > 100 chars; we already root the binary\n// at `bin/<name>` which stays well under that), no GNU long-name records.\n// ---------------------------------------------------------------------------\n\nasync function extractEntryFromTarball(\n tarballPath: string,\n entryRelPath: string,\n outDir: string,\n): Promise<string | null> {\n const matchSuffix = `/${entryRelPath}`\n const out = join(outDir, 'binary.bin')\n\n // Read whole tarball into memory — platform packages clock in around\n // 20-30 MB, well within the budget for a temp buffer.\n const chunks: Uint8Array[] = []\n const gunzip = createGunzip()\n const input = createReadStream(tarballPath)\n await new Promise<void>((res, rej) => {\n gunzip.on('data', (c: Buffer) => chunks.push(c))\n gunzip.on('end', () => res())\n gunzip.on('error', rej)\n input.on('error', rej)\n input.pipe(gunzip)\n })\n const tar = concatChunks(chunks)\n let offset = 0\n while (offset + 512 <= tar.length) {\n const header = tar.subarray(offset, offset + 512)\n if (header.every(b => b === 0))\n break\n const name = readNulString(header, 0, 100)\n const sizeOct = readNulString(header, 124, 12).trim()\n const size = sizeOct === '' ? 0 : Number.parseInt(sizeOct, 8)\n const dataStart = offset + 512\n const dataEnd = dataStart + size\n if (name && (name === entryRelPath || name.endsWith(matchSuffix))) {\n writeFileSync(out, tar.subarray(dataStart, dataEnd))\n return out\n }\n // 512-byte aligned padding.\n offset = dataEnd + ((512 - (size % 512)) % 512)\n }\n return null\n}\n\nfunction readNulString(buf: Uint8Array, start: number, len: number): string {\n const end = start + len\n let stop = end\n for (let i = start; i < end; i++) {\n if (buf[i] === 0) { stop = i; break }\n }\n return new TextDecoder('utf8').decode(buf.subarray(start, stop))\n}\n\nfunction concatChunks(chunks: Uint8Array[]): Uint8Array {\n let total = 0\n for (const c of chunks) total += c.byteLength\n const out = new Uint8Array(total)\n let offset = 0\n for (const c of chunks) {\n out.set(c, offset)\n offset += c.byteLength\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Resolve the platform-specific tarball package\n//\n// Mirrors the resolution table in `tui/bin/zidane.mjs` — `darwin/arm64`,\n// `darwin/x64`, `linux/x64` (glibc), `linux/arm64` (glibc). Returns\n// `null` for unsupported targets so the caller can print a clear message.\n// ---------------------------------------------------------------------------\n\nexport interface PlatformTarballOptions {\n /** Override `process.platform`. */\n platform?: NodeJS.Platform\n /** Override `process.arch`. */\n arch?: NodeJS.Architecture | string\n /** Override the libc check (returned from `detectLibc`). */\n libc?: 'glibc' | 'musl'\n /** Prefix joined to the platform key. Defaults to `'zidane-tui-'`. */\n prefix?: string\n}\n\nexport function resolvePlatformPackage(opts: PlatformTarballOptions = {}): string | null {\n const platform = opts.platform ?? process.platform\n const arch = opts.arch ?? process.arch\n const libc = opts.libc ?? detectLibc()\n const prefix = opts.prefix ?? 'zidane-tui-'\n if (platform === 'darwin') {\n if (arch === 'arm64')\n return `${prefix}darwin-arm64`\n if (arch === 'x64')\n return `${prefix}darwin-x64`\n return null\n }\n if (platform === 'linux') {\n if (libc !== 'glibc')\n return null\n if (arch === 'arm64')\n return `${prefix}linux-arm64`\n if (arch === 'x64')\n return `${prefix}linux-x64`\n return null\n }\n return null\n}\n\n/** Mirrors `tui/bin/zidane.mjs#detectLibc`. */\nexport function detectLibc(): 'glibc' | 'musl' {\n if (process.platform !== 'linux')\n return 'glibc'\n try {\n // eslint-disable-next-line ts/no-require-imports\n const { execSync } = require('node:child_process') as typeof import('node:child_process')\n const out = execSync('ldd --version 2>&1', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }) as string\n return out.toLowerCase().includes('musl') ? 'musl' : 'glibc'\n }\n catch {\n return 'musl'\n }\n}\n\n// ---------------------------------------------------------------------------\n// `_` re-exports for tests that don't want to mock through the module\n// boundary. Not part of the public surface; keep names underscored.\n// ---------------------------------------------------------------------------\n\nexport const _internal = {\n cacheFilePath,\n readCache,\n writeCache,\n binaryNameFrom,\n extractEntryFromTarball,\n}\n","// ---------------------------------------------------------------------------\n// Companion packages — sibling globals that `zidane upgrade` keeps in step\n// with the TUI. Today that is `zidane-gui`: same version line, same npm\n// release, but installed separately (and possibly with a different package\n// manager). This module answers one question — \"is <package> installed on\n// this machine, at what version, and where?\" — so the CLI can check the\n// registry for it and re-run the install through the PM that owns it.\n//\n// Discovery is by the package's bin on PATH, not by asking a PM: `npm ls -g`\n// is slow, differs per manager, and lies under Volta. The bin is what the\n// user actually invokes, so it is also the most honest signal of \"installed\".\n// ---------------------------------------------------------------------------\n\nimport { existsSync, readFileSync, realpathSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { delimiter, dirname, join, sep } from 'node:path'\n\nexport interface CompanionSpec {\n /** npm package name, e.g. `'zidane-gui'`. */\n packageName: string\n /** Executable name on PATH. Defaults to `packageName`. */\n binName?: string\n}\n\nexport interface InstalledCompanion {\n packageName: string\n /** Version from the installed `package.json`. */\n version: string\n /** Root of the installed package. */\n packageDir: string\n /**\n * The bin as found on PATH (NOT resolved). `detectPackageManager` wants\n * this: `~/.volta/bin/<name>` identifies Volta even though its realpath is\n * the generic `volta-shim`.\n */\n binaryPath: string\n}\n\nexport interface FindCompanionOptions {\n env?: Readonly<Record<string, string | undefined>>\n home?: string\n platform?: NodeJS.Platform\n}\n\n/**\n * Locate a globally installed companion. `null` when its bin is not on PATH\n * or no `package.json` with that name can be found behind it.\n */\nexport function findInstalledCompanion(spec: CompanionSpec, opts: FindCompanionOptions = {}): InstalledCompanion | null {\n const env = opts.env ?? process.env\n const home = opts.home ?? homedir()\n const platform = opts.platform ?? process.platform\n const binName = spec.binName ?? spec.packageName\n\n const binaryPath = findOnPath(binName, env.PATH ?? '', platform)\n if (!binaryPath)\n return null\n\n const packageDir = resolvePackageDir(spec.packageName, binaryPath, home)\n if (!packageDir)\n return null\n\n const version = readPackageVersion(packageDir, spec.packageName)\n if (!version)\n return null\n\n return { packageName: spec.packageName, version, packageDir, binaryPath }\n}\n\nfunction findOnPath(binName: string, pathVar: string, platform: NodeJS.Platform): string | null {\n const candidates = platform === 'win32' ? [binName, `${binName}.cmd`, `${binName}.exe`] : [binName]\n for (const dir of pathVar.split(delimiter)) {\n if (!dir)\n continue\n for (const name of candidates) {\n const full = join(dir, name)\n try {\n if (statSync(full).isFile())\n return full\n }\n catch {\n // not here\n }\n }\n }\n return null\n}\n\n/**\n * From the bin to the package root. Two strategies:\n * 1. Follow the symlink (`<prefix>/bin/zidane-gui` → `…/node_modules/\n * zidane-gui/bin/zidane-gui.mjs`) and climb until a `package.json`\n * carries the expected name. Covers npm, pnpm, yarn and bun.\n * 2. Volta: the bin is a shim whose realpath is `volta-shim`, so nothing to\n * climb. Its global packages live at a fixed layout under `$VOLTA_HOME`\n * (the same one the GUI installer maps staging paths to).\n */\nfunction resolvePackageDir(packageName: string, binaryPath: string, home: string): string | null {\n let resolved = binaryPath\n try {\n resolved = realpathSync(binaryPath)\n }\n catch {\n // dangling link — fall through to the Volta layout check\n }\n\n const climbed = climbToPackage(dirname(resolved), packageName)\n if (climbed)\n return climbed\n\n const voltaHome = voltaHomeFor(binaryPath, resolved, home)\n if (voltaHome) {\n const dir = join(voltaHome, 'tools', 'image', 'packages', packageName, 'lib', 'node_modules', packageName)\n if (existsSync(join(dir, 'package.json')))\n return dir\n }\n return null\n}\n\nfunction climbToPackage(start: string, packageName: string): string | null {\n let dir = start\n for (let depth = 0; depth < 6; depth++) {\n if (readPackageVersion(dir, packageName))\n return dir\n const parent = dirname(dir)\n if (parent === dir)\n break\n dir = parent\n }\n return null\n}\n\nfunction voltaHomeFor(binaryPath: string, resolved: string, home: string): string | null {\n const marker = `${sep}.volta${sep}`\n for (const p of [binaryPath, resolved]) {\n const idx = p.indexOf(marker)\n if (idx !== -1)\n return p.slice(0, idx + marker.length - 1)\n }\n const fallback = join(home, '.volta')\n return existsSync(fallback) ? fallback : null\n}\n\nfunction readPackageVersion(dir: string, packageName: string): string | null {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as { name?: unknown, version?: unknown }\n if (pkg.name !== packageName || typeof pkg.version !== 'string')\n return null\n return pkg.version\n }\n catch {\n return null\n }\n}\n","// ---------------------------------------------------------------------------\n// \"A newer version is on disk — restart to use it.\"\n//\n// Two things live here:\n//\n// 1. The APPLIED MARKER — `<cacheDir>/update-applied.json`, written by every\n// path that installs a release (`zidane upgrade`, the GUI's in-app\n// update). It is a wake-up call, not the truth: running surfaces watch\n// the file and re-probe the disk when it changes.\n//\n// 2. The INSTALLED-VERSION WATCHER — compares the version the running\n// process was built with against the version its package has on disk\n// (resolved from the bin on PATH, the same way `zidane upgrade` finds\n// companions). `restartRequired` when disk > running. Re-probes on the\n// marker, on a slow poll (an upgrade run from another machine's shell\n// over the same home dir writes no local marker), and on demand\n// (`check()` — the GUI calls it on window focus).\n//\n// Renderer-agnostic: Node `fs` only, no React except the hook at the bottom.\n// ---------------------------------------------------------------------------\n\nimport type { FSWatcher } from 'node:fs'\nimport type { CompanionSpec, FindCompanionOptions, InstalledCompanion } from './auto-update-companion'\nimport { existsSync, mkdirSync, readFileSync, watch, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { useEffect, useState } from 'react'\nimport { compareSemver } from './auto-update'\nimport { findInstalledCompanion } from './auto-update-companion'\n\nexport const UPDATE_APPLIED_MARKER = 'update-applied.json'\n\nexport interface UpdateAppliedMarker {\n /** ms since epoch. */\n at: number\n /** Every package the run installed, with the version now on disk. */\n packages: Array<{ packageName: string, version: string }>\n}\n\nexport function updateAppliedMarkerPath(cacheDir: string): string {\n return join(cacheDir, UPDATE_APPLIED_MARKER)\n}\n\n/**\n * Record that an install just landed. Best-effort: a failure to write the\n * marker must never fail the upgrade that succeeded — the poll catches up.\n */\nexport function writeUpdateAppliedMarker(cacheDir: string, marker: UpdateAppliedMarker): boolean {\n try {\n mkdirSync(cacheDir, { recursive: true })\n writeFileSync(updateAppliedMarkerPath(cacheDir), `${JSON.stringify(marker, null, 2)}\\n`)\n return true\n }\n catch {\n return false\n }\n}\n\nexport function readUpdateAppliedMarker(cacheDir: string): UpdateAppliedMarker | null {\n try {\n const raw = JSON.parse(readFileSync(updateAppliedMarkerPath(cacheDir), 'utf8')) as unknown\n if (!raw || typeof raw !== 'object')\n return null\n const { at, packages } = raw as Partial<UpdateAppliedMarker>\n if (typeof at !== 'number' || !Array.isArray(packages))\n return null\n return {\n at,\n packages: packages.filter(p => p && typeof p.packageName === 'string' && typeof p.version === 'string'),\n }\n }\n catch {\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// Installed-version watcher\n// ---------------------------------------------------------------------------\n\nexport interface InstalledVersionState {\n /** Version the running process was built with. */\n running: string\n /** Version found on disk for the package; `null` when the probe found nothing (dev checkout, PATH without the bin). */\n installed: string | null\n /** `installed` is strictly newer than `running` — the process is stale. */\n restartRequired: boolean\n /** When the disk was last probed (ms since epoch). */\n checkedAt: number\n}\n\nexport interface WatchInstalledVersionOptions {\n /** The running package, e.g. `{ packageName: 'zidane-tui', binName: 'zidane' }`. */\n spec: CompanionSpec\n /** Inlined at build time. An empty string disables the watcher (dev runs). */\n currentVersion: string\n /** Where the applied marker lives. Omit to rely on the poll alone. */\n cacheDir?: string\n /** Poll interval. Defaults to 5 min; `0` disables the poll. */\n pollMs?: number\n /** Debounce for marker events (installs touch the file more than once). Defaults to 500 ms. */\n debounceMs?: number\n onChange: (state: InstalledVersionState) => void\n /** Injected for tests. */\n probe?: (spec: CompanionSpec, opts?: FindCompanionOptions) => InstalledCompanion | null\n /** Injected for tests. */\n now?: () => number\n}\n\nexport interface InstalledVersionWatcher {\n /** Re-probe now. Returns the fresh state (also delivered to `onChange` when it differs). */\n check: () => InstalledVersionState\n /** Last delivered state. */\n current: () => InstalledVersionState\n close: () => void\n}\n\n/**\n * Compute the state once — the pure heart of the watcher, exported so a host\n * without a lifecycle (a one-shot IPC handler) can answer \"is a restart\n * pending?\" without holding a watcher.\n */\nexport function probeInstalledVersion(\n spec: CompanionSpec,\n currentVersion: string,\n probe: WatchInstalledVersionOptions['probe'] = findInstalledCompanion,\n now: () => number = Date.now,\n): InstalledVersionState {\n const installed = currentVersion ? probe(spec)?.version ?? null : null\n return {\n running: currentVersion,\n installed,\n restartRequired: installed !== null && compareSemver(installed, currentVersion) > 0,\n checkedAt: now(),\n }\n}\n\nexport function watchInstalledVersion(options: WatchInstalledVersionOptions): InstalledVersionWatcher {\n const probe = options.probe ?? findInstalledCompanion\n const now = options.now ?? Date.now\n const enabled = options.currentVersion.length > 0\n let state = probeInstalledVersion(options.spec, options.currentVersion, probe, now)\n let closed = false\n\n const deliver = (next: InstalledVersionState) => {\n const changed = next.installed !== state.installed || next.restartRequired !== state.restartRequired\n state = next\n if (changed && !closed)\n options.onChange(next)\n }\n const check = (): InstalledVersionState => {\n if (!enabled || closed)\n return state\n deliver(probeInstalledVersion(options.spec, options.currentVersion, probe, now))\n return state\n }\n\n let watcher: FSWatcher | null = null\n let debounce: ReturnType<typeof setTimeout> | null = null\n let poll: ReturnType<typeof setInterval> | null = null\n\n if (enabled) {\n if (options.cacheDir) {\n // Watch the DIRECTORY: the marker may not exist yet, and installers\n // replace files (rename) rather than rewrite them in place.\n try {\n mkdirSync(options.cacheDir, { recursive: true })\n watcher = watch(options.cacheDir, (_event, filename) => {\n if (filename && filename.toString() !== UPDATE_APPLIED_MARKER)\n return\n if (debounce)\n clearTimeout(debounce)\n debounce = setTimeout(() => {\n debounce = null\n check()\n }, options.debounceMs ?? 500)\n })\n watcher.on('error', () => {\n // A vanished cache dir or an exhausted inotify budget must not\n // take the host down; the poll still covers us.\n watcher?.close()\n watcher = null\n })\n }\n catch {\n watcher = null\n }\n }\n const pollMs = options.pollMs ?? 5 * 60_000\n if (pollMs > 0) {\n poll = setInterval(check, pollMs)\n // Never keep a process alive for this.\n if (typeof poll === 'object' && 'unref' in poll)\n poll.unref()\n }\n }\n\n return {\n check,\n current: () => state,\n close: () => {\n closed = true\n watcher?.close()\n if (debounce)\n clearTimeout(debounce)\n if (poll)\n clearInterval(poll)\n },\n }\n}\n\n/** Quick existence check so hosts can decide whether to read the marker at all. */\nexport function hasUpdateAppliedMarker(cacheDir: string): boolean {\n return existsSync(updateAppliedMarkerPath(cacheDir))\n}\n\n// ---------------------------------------------------------------------------\n// React hook — the TUI's consumer. The GUI runs the watcher in its main\n// process and forwards the state over IPC instead.\n// ---------------------------------------------------------------------------\n\nexport interface UseRestartRequiredOptions {\n spec: CompanionSpec | null\n currentVersion: string\n cacheDir?: string\n /** Master switch — mirrors `Settings.checkForUpdates`. */\n enabled: boolean\n pollMs?: number\n}\n\n/**\n * `null` until the first probe (or when disabled / no spec), then the live\n * state. Flipping `enabled` off tears the watcher down and clears the state\n * so no stale \"restart\" chip lingers.\n */\nexport function useRestartRequired(options: UseRestartRequiredOptions): InstalledVersionState | null {\n const [state, setState] = useState<InstalledVersionState | null>(null)\n const { spec, currentVersion, cacheDir, enabled, pollMs } = options\n const packageName = spec?.packageName\n const binName = spec?.binName\n\n useEffect(() => {\n if (!enabled || !packageName || !currentVersion) {\n setState(null)\n return\n }\n const watcher = watchInstalledVersion({\n spec: binName ? { packageName, binName } : { packageName },\n currentVersion,\n cacheDir,\n pollMs,\n onChange: setState,\n })\n setState(watcher.current())\n return () => watcher.close()\n }, [enabled, packageName, binName, currentVersion, cacheDir, pollMs])\n\n return state\n}\n","// ---------------------------------------------------------------------------\n// `zidane upgrade` subcommand — drop-in handler for consumer CLIs.\n//\n// Wraps `checkForUpdate` + `performSelfUpdate` + `performInPlaceSelfUpdate`\n// into a single function the host's `cli.ts` can call. The behavior layers:\n//\n// - no flags → check + run the package manager\n// - `--check` → check only, print the latest version + bail\n// - `--in-place` → skip the PM, download + atomic-rename the binary\n// - `--dry-run` → resolve everything but don't actually swap\n// - `--channel <tag>` → override dist-tag (defaults to `'latest'`)\n// - `--registry <url>`→ override the npm registry URL\n// - `--tui-only` → skip companion packages (see `companions`)\n//\n// Companions: sibling globals released on the same version line (today\n// `zidane-gui`). When one is installed, `upgrade` checks and re-installs it\n// too — through the package manager that owns THAT install, which may differ\n// from the TUI's. Companion failures are reported and fail the exit code but\n// never block the TUI's own upgrade.\n//\n// Pure I/O — writes to stdout/stderr, returns the exit code the caller\n// should pass to `process.exit`. No React, no OpenTUI; safe to call\n// before / instead of `runTui`.\n// ---------------------------------------------------------------------------\n\nimport type { PackageManagerCommand, UpdateStatus } from './auto-update'\nimport type { CompanionSpec, InstalledCompanion } from './auto-update-companion'\nimport type { UpdateAppliedMarker } from './auto-update-restart'\nimport {\n checkForUpdate,\n checkTarballAvailable,\n compareSemver,\n detectPackageManager,\n overrideManager,\n performInPlaceSelfUpdate,\n performSelfUpdate,\n reinstallHint,\n resolvePlatformPackage,\n} from './auto-update'\nimport { findInstalledCompanion } from './auto-update-companion'\nimport { writeUpdateAppliedMarker } from './auto-update-restart'\n\nexport interface RunUpdateCommandOptions {\n /** Top-level package the user installs (e.g. `'zidane-tui'`). */\n packageName: string\n /** Inlined at build time. */\n currentVersion: string\n /** Args passed after `upgrade` (typically `process.argv.slice(3)`). */\n argv: readonly string[]\n /** Where to persist the TTL cache. Usually `paths.userDir`. */\n cacheDir?: string\n /** Default channel when `--channel` isn't passed. Defaults to `'latest'`. */\n defaultChannel?: string\n /**\n * Override the platform-package-name prefix used by `--in-place`.\n * Defaults to `'<packageName>-'`, matching the `zidane-tui-<key>` layout.\n */\n platformPackagePrefix?: string\n /** Override registry. Defaults to npmjs. */\n registry?: string\n /** stdout. Defaults to `process.stdout`. */\n stdout?: NodeJS.WritableStream\n /** stderr. Defaults to `process.stderr`. */\n stderr?: NodeJS.WritableStream\n /**\n * Sibling packages to keep in step when installed (e.g. `zidane-gui`).\n * Absent companions are silently skipped; `--tui-only` skips them all.\n */\n companions?: readonly CompanionSpec[]\n /**\n * Reports the version now installed for `packageName` (e.g. by running the\n * bin with `--version`), `null` when nothing usable is there, `undefined`\n * to skip verification. The host wires this; the library cannot know how\n * its own bin is invoked.\n */\n verifyInstalled?: (packageName: string) => string | null | undefined\n /** Inject for tests. */\n findCompanion?: typeof findInstalledCompanion\n /** Inject for tests. */\n performSelfUpdate?: typeof performSelfUpdate\n /** Inject for tests. */\n checkTarballAvailable?: typeof checkTarballAvailable\n /** Inject for tests. */\n writeMarker?: typeof writeUpdateAppliedMarker\n}\n\nexport interface RunUpdateCommandResult {\n exitCode: number\n}\n\nconst UPGRADE_HELP = `Usage: zidane upgrade [options]\n\nUpdate the zidane CLI to the latest release. A globally installed\nzidane-gui is upgraded alongside it, through its own package manager.\n\nOptions:\n --check Print the latest version and exit (no install).\n --tui-only Leave companion packages (zidane-gui) alone.\n --in-place Download the platform binary directly from npm\n and atomic-rename over the running binary.\n Skips the package manager. Refused on Volta.\n --dry-run Resolve everything but don't actually install.\n --channel <tag> dist-tag to query (default: latest).\n --registry <url> Override the npm registry.\n --package-manager <pm> Force npm | pnpm | yarn | bun | volta.\n --force Run the install even if we're already on latest,\n or the registry check failed.\n -h, --help Print this help.\n\nEnvironment:\n NO_UPDATE_NOTIFIER Silence the background check (set to \"1\").\n ZIDANE_NO_UPDATE Same, project-specific.\n`\n\n/**\n * Run the `upgrade` subcommand. Exit code contract:\n * - `0` — update succeeded, `--check` reported no update, or `--check`\n * reported an update (informational only).\n * - `1` — update failed (PM exit non-zero, in-place download failed,\n * registry returned non-2xx, release not downloadable yet).\n * - `2` — argv parse error (unknown flag).\n *\n * Output is a short ledger, one line per package, ASCII-only apart from the\n * arrow:\n * zidane-tui 7.0.7 → 7.0.8\n * $ volta install zidane-tui@latest\n * …\n * zidane-tui 7.0.8 ok\n * Diagnostics go to stderr and say what to do next.\n */\nexport async function runUpdateCommand(options: RunUpdateCommandOptions): Promise<RunUpdateCommandResult> {\n const out = options.stdout ?? process.stdout\n const err = options.stderr ?? process.stderr\n const parsed = parseArgs(options.argv)\n if (parsed.kind === 'error') {\n err.write(`zidane upgrade: ${parsed.message}\\n`)\n err.write(UPGRADE_HELP)\n return { exitCode: 2 }\n }\n if (parsed.help) {\n out.write(UPGRADE_HELP)\n return { exitCode: 0 }\n }\n const flags: ParsedFlags = parsed\n\n const channel = flags.channel ?? options.defaultChannel ?? 'latest'\n const registry = flags.registry ?? options.registry\n const tarballAvailable = options.checkTarballAvailable ?? checkTarballAvailable\n const install = options.performSelfUpdate ?? performSelfUpdate\n\n // Always force the check — user typed `upgrade`, env opt-outs shouldn't\n // get in the way.\n const status = await checkForUpdate({\n packageName: options.packageName,\n currentVersion: options.currentVersion,\n channel,\n registry,\n cacheDir: options.cacheDir,\n force: true,\n timeoutMs: 8000,\n })\n const self: Entry = {\n name: options.packageName,\n current: options.currentVersion,\n status,\n outdated: status.latest !== null && compareSemver(status.latest, options.currentVersion) > 0,\n }\n\n // Companions: discovered locally, then checked on the registry with the\n // same channel. Only installed ones take part; nothing is printed for the\n // rest, so users without the GUI see the exact output they always did.\n const companions = flags.tuiOnly ? [] : await resolveCompanions(options, channel, registry)\n const entries: Entry[] = [self, ...companions]\n const label = (name: string) => name.padEnd(Math.max(...entries.map(e => e.name.length)))\n\n // `--check` is informational — degrade gracefully on registry errors\n // (offline laptop, restricted proxy) and exit 0 so the user can script\n // around it without quoting tricks.\n if (flags.check) {\n for (const e of entries)\n out.write(`${label(e.name)} ${statusText(e)}\\n`)\n return { exitCode: 0 }\n }\n\n // Install path — a registry error means we don't KNOW if we need an\n // update. Refuse to spawn the PM blindly unless the user explicitly\n // asks via `--force`.\n if (status.source === 'error') {\n err.write(`${self.name}: registry check failed: ${status.error ?? 'unknown error'}\\n`)\n if (!flags.force) {\n err.write('Use --force to install anyway.\\n')\n return { exitCode: 1 }\n }\n }\n for (const c of companions.filter(c => c.status.source === 'error' && !flags.force))\n err.write(`${c.name}: registry check failed: ${c.status.error ?? 'unknown error'}\\n`)\n\n const selfPending = flags.force || self.outdated\n const pendingCompanions = companions.filter(c => flags.force || c.outdated)\n for (const e of entries.filter(e => !e.outdated && e.status.source !== 'error'))\n out.write(`${label(e.name)} ${statusText(e)}\\n`)\n if (!selfPending && pendingCompanions.length === 0)\n return { exitCode: 0 }\n\n // The TUI's own install runs first (in-place or PM); companions follow.\n // A companion failure sets the exit code but never undoes or blocks the\n // TUI upgrade that already happened.\n let exitCode = 0\n const applied: UpdateAppliedMarker['packages'] = []\n if (selfPending) {\n exitCode = await upgradeSelf()\n if (exitCode === 0 && !flags.dryRun && status.latest)\n applied.push({ packageName: self.name, version: status.latest })\n }\n for (const c of pendingCompanions) {\n const code = await upgradeCompanion(c)\n if (code === 0 && !flags.dryRun && c.status.latest)\n applied.push({ packageName: c.name, version: c.status.latest })\n if (exitCode === 0)\n exitCode = code\n }\n // Wake running TUIs / GUIs: they watch this marker and offer a restart.\n if (applied.length > 0 && options.cacheDir)\n (options.writeMarker ?? writeUpdateAppliedMarker)(options.cacheDir, { at: Date.now(), packages: applied })\n return { exitCode }\n\n /**\n * Refuse to spawn the PM while the release is not fetchable yet: npm treats\n * a 404 on an `optionalDependencies` platform binary as \"skip\" and leaves\n * an empty install behind the bin. `--force` overrides (mirrors, offline\n * registries).\n */\n async function ready(packageName: string, version: string): Promise<boolean> {\n if (flags.force || flags.dryRun)\n return true\n const availability = await tarballAvailable({ packageName, version, registry })\n if (availability !== 'missing')\n return true\n err.write(`${packageName} ${version} is published but not downloadable yet. Try again in a few minutes.\\n`)\n return false\n }\n\n async function upgradeSelf(): Promise<number> {\n const target = status.latest ?? channel\n out.write(`${label(self.name)} ${self.current} → ${target}\\n`)\n\n if (flags.inPlace) {\n const platformPkg = resolvePlatformPackage({\n prefix: options.platformPackagePrefix ?? `${options.packageName}-`,\n })\n if (!platformPkg) {\n err.write(`${self.name}: no prebuilt binary for ${process.platform}/${process.arch}. Use your package manager instead.\\n`)\n return 1\n }\n if (status.latest && !await ready(platformPkg, status.latest))\n return 1\n const result = await performInPlaceSelfUpdate({ packageName: platformPkg, channel, registry, dryRun: flags.dryRun })\n if (result.status === 'success') {\n out.write(`${label(self.name)} ${result.installedVersion} ${flags.dryRun ? 'would install' : 'ok'}\\n`)\n return 0\n }\n err.write(`${self.name}: in-place update failed: ${result.reason ?? 'unknown error'}\\n`)\n if (result.status === 'refused')\n err.write('Drop --in-place to go through the package manager.\\n')\n return 1\n }\n\n // The platform binary is the part that can be missing from the CDN; the\n // meta package is tiny and published right after it.\n const platformPkg = resolvePlatformPackage({ prefix: options.platformPackagePrefix ?? `${options.packageName}-` })\n if (status.latest && !await ready(platformPkg ?? options.packageName, status.latest))\n return 1\n\n const command = flags.packageManager\n ? overrideManager(flags.packageManager, options.packageName, channel)\n : detectPackageManager({ packageName: options.packageName, channel })\n out.write(`$ ${command.argv.join(' ')}\\n`)\n if (flags.dryRun)\n return 0\n const result = await install({ packageName: options.packageName, channel, packageManager: flags.packageManager ?? 'auto' })\n if (result.spawnError) {\n err.write(`${self.name}: could not run ${result.command.argv[0]}: ${result.spawnError}\\n`)\n return 1\n }\n if (result.exitCode !== 0) {\n err.write(`${self.name}: ${result.command.argv[0]} exited with ${result.exitCode ?? 'unknown'}\\n`)\n return result.exitCode ?? 1\n }\n return verify(self.name, status.latest, options.verifyInstalled?.(options.packageName), result.command)\n }\n\n async function upgradeCompanion(c: CompanionEntry): Promise<number> {\n const target = c.status.latest ?? channel\n out.write(`${label(c.name)} ${c.current} → ${target}\\n`)\n if (c.status.latest && !await ready(c.name, c.status.latest))\n return 1\n // `--package-manager` is an override for the TUI's install; the\n // companion follows the PM that owns its own bin unless forced too.\n const command = flags.packageManager ? overrideManager(flags.packageManager, c.name, channel) : c.command\n out.write(`$ ${command.argv.join(' ')}\\n`)\n if (flags.dryRun)\n return 0\n const result = await install({ packageName: c.name, channel, packageManager: flags.packageManager ?? c.command.id })\n if (result.spawnError) {\n err.write(`${c.name}: could not run ${result.command.argv[0]}: ${result.spawnError}\\n`)\n return 1\n }\n if (result.exitCode !== 0) {\n err.write(`${c.name}: ${result.command.argv[0]} exited with ${result.exitCode ?? 'unknown'}\\n`)\n return 1\n }\n const find = options.findCompanion ?? findInstalledCompanion\n return verify(c.name, c.status.latest, find(c.spec)?.version, result.command)\n }\n\n /**\n * The PM exiting 0 is not proof: a skipped optional platform binary or a\n * Volta no-op (\"already installed\") both exit 0 and leave the old version\n * behind. Compare what is actually on disk with what we asked for.\n */\n function verify(name: string, expected: string | null, actual: string | undefined | null, command: PackageManagerCommand): number {\n if (!expected || actual === undefined) {\n out.write(`${label(name)} ${expected ?? channel} ok\\n`)\n return 0\n }\n if (actual !== null && compareSemver(actual, expected) >= 0) {\n out.write(`${label(name)} ${actual} ok\\n`)\n return 0\n }\n err.write(`${name}: install finished but ${actual ?? 'nothing'} is on disk, expected ${expected}.\\n`)\n err.write(`Reinstall: ${reinstallHint(command, name, channel)}\\n`)\n return 1\n }\n}\n\nfunction statusText(e: Entry): string {\n if (e.status.source === 'error')\n return `${e.current} (check failed: ${e.status.error ?? 'unknown error'})`\n if (!e.status.latest)\n return `${e.current} (latest unknown)`\n return e.outdated ? `${e.current} → ${e.status.latest} available` : `${e.current} up to date`\n}\n\n// ---------------------------------------------------------------------------\n// Ledger entries\n// ---------------------------------------------------------------------------\n\ninterface Entry {\n name: string\n /** Installed version. */\n current: string\n status: UpdateStatus\n /** Registry knows a newer version than the installed one. */\n outdated: boolean\n}\n\ninterface CompanionEntry extends Entry {\n spec: CompanionSpec\n installed: InstalledCompanion\n /** The PM that owns this install — from ITS bin path, not the TUI's. */\n command: PackageManagerCommand\n}\n\nasync function resolveCompanions(\n options: RunUpdateCommandOptions,\n channel: string,\n registry: string | undefined,\n): Promise<CompanionEntry[]> {\n const find = options.findCompanion ?? findInstalledCompanion\n const found = (options.companions ?? [])\n .map(spec => ({ spec, installed: find(spec) }))\n .filter((c): c is { spec: CompanionSpec, installed: InstalledCompanion } => c.installed !== null)\n return await Promise.all(found.map(async ({ spec, installed }) => {\n const status = await checkForUpdate({\n packageName: installed.packageName,\n currentVersion: installed.version,\n channel,\n registry,\n cacheDir: options.cacheDir,\n force: true,\n timeoutMs: 8000,\n })\n return {\n spec,\n installed,\n name: installed.packageName,\n current: installed.version,\n status,\n outdated: status.latest !== null && compareSemver(status.latest, installed.version) > 0,\n command: detectPackageManager({ packageName: installed.packageName, channel, binaryPath: installed.binaryPath }),\n }\n }))\n}\n\n// ---------------------------------------------------------------------------\n// Argv parser — minimal, just enough to drop into the consumer's `cli.ts`.\n// We deliberately don't pull in commander/yargs for a 5-flag surface.\n// ---------------------------------------------------------------------------\n\ntype ParsedFlags = Extract<ParseResult, { kind: 'ok' }>\n\ntype ParseResult\n = | {\n kind: 'ok'\n check: boolean\n inPlace: boolean\n dryRun: boolean\n force: boolean\n help: boolean\n tuiOnly: boolean\n channel?: string\n registry?: string\n packageManager?: 'npm' | 'pnpm' | 'yarn' | 'bun' | 'volta'\n }\n | { kind: 'error', message: string }\n\nfunction parseArgs(argv: readonly string[]): ParseResult {\n let check = false\n let inPlace = false\n let dryRun = false\n let force = false\n let help = false\n let tuiOnly = false\n let channel: string | undefined\n let registry: string | undefined\n let packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun' | 'volta' | undefined\n\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!\n switch (a) {\n case '--check': check = true; break\n case '--in-place':\n case '--inplace': inPlace = true; break\n case '--dry-run':\n case '--dryrun': dryRun = true; break\n case '--force': force = true; break\n case '--tui-only': tuiOnly = true; break\n case '-h':\n case '--help': help = true; break\n case '--channel':\n channel = argv[++i]\n if (!channel)\n return { kind: 'error', message: '--channel requires a value' }\n break\n case '--registry':\n registry = argv[++i]\n if (!registry)\n return { kind: 'error', message: '--registry requires a value' }\n break\n case '--package-manager':\n case '--pm': {\n const v = argv[++i]\n if (!v)\n return { kind: 'error', message: '--package-manager requires a value' }\n if (v !== 'npm' && v !== 'pnpm' && v !== 'yarn' && v !== 'bun' && v !== 'volta')\n return { kind: 'error', message: `unknown package manager: ${v}` }\n packageManager = v\n break\n }\n default:\n return { kind: 'error', message: `unknown argument: ${a}` }\n }\n }\n\n return { kind: 'ok', check, inPlace, dryRun, force, help, tuiOnly, channel, registry, packageManager }\n}\n","// ---------------------------------------------------------------------------\n// `useUpdateCheck` — renderer-agnostic React hook driving the auto-update\n// footer chip + any banner a host wants to wire.\n//\n// Lives in `zidane/chat` (not `zidane/tui`) so a future GUI shell can\n// consume the same status. Pure React + the renderer-agnostic core in\n// `./auto-update`; no OpenTUI imports.\n// ---------------------------------------------------------------------------\n\nimport type { UpdateStatus } from './auto-update'\nimport type { Hint } from './hints'\nimport { useEffect, useRef, useState } from 'react'\nimport { checkForUpdate } from './auto-update'\n\nexport interface UseUpdateCheckOptions {\n /** npm package name. e.g. `'zidane-tui'`. */\n packageName: string\n /** Inlined at build time. Skips the check if empty/falsy. */\n currentVersion: string\n /**\n * Master enable flag — usually `Settings.checkForUpdates`. When `false`\n * the hook short-circuits without scheduling any work AND clears the\n * last-known status so a stale chip doesn't linger after the user\n * disabled the feature.\n */\n enabled: boolean\n /** Directory under which the on-disk cache lives. Usually `paths.userDir`. */\n cacheDir?: string\n registry?: string\n channel?: string\n /**\n * Cache lifetime for the read-through. **Defaults to `0`** (always\n * fetch fresh) — the TUI chip is the user's source of truth for \"what\n * version of zidane is on npm right now\"; we'd rather pay one HTTPS\n * call per session than tell them yesterday's news for up to 24 hours.\n *\n * The on-disk cache is still WRITTEN with each fresh result (so\n * `zidane upgrade` and other tooling reads benefit) and still READ to\n * feed the registry's ETag (so the cold path can short-circuit on 304\n * — meaningful bandwidth win when nothing changed). Pass a positive\n * value (e.g. `3_600_000` for 1 h) to enable read-through caching for\n * a GUI shell that mounts the hook in many places.\n */\n cacheTtlMs?: number\n /**\n * Wall-clock delay before the first check fires. Defaults to 1 500 ms so\n * we never compete with the boot path's first paint. The check itself\n * is async, so this only affects WHEN the chip first appears — never\n * blocks anything else.\n */\n delayMs?: number\n /** Injected for tests. */\n now?: () => number\n /** Injected for tests. */\n fetcher?: typeof fetch\n}\n\n/**\n * Returns the current update status. The check fires:\n * - Once per mount (every TUI launch).\n * - Every time `enabled` flips from `false` → `true` (user re-enabling\n * the setting expects an immediate refresh).\n *\n * The check is async and deferred by `delayMs` so it never competes with\n * first paint. Result is `null` until the first check resolves; flipping\n * `enabled` to `false` resets to `null` so any chip rendered against\n * `hasUpdate` disappears immediately.\n *\n * The hook owns its own AbortController so an unmount cancels any in-flight\n * registry request cleanly.\n */\nexport function useUpdateCheck(options: UseUpdateCheckOptions): UpdateStatus | null {\n const [status, setStatus] = useState<UpdateStatus | null>(null)\n // Ref-mirror so the effect doesn't re-run on every keystroke when the\n // host wraps the result into derived hint state.\n const optsRef = useRef(options)\n optsRef.current = options\n\n useEffect(() => {\n if (!options.enabled || !options.currentVersion) {\n // Disabling the setting must hide a chip that was already painted\n // — otherwise the user sees a stale `↑ vX.Y.Z` linger until the\n // next launch. React bails on identical-state updates so the\n // initial-mount case (status already null) costs nothing.\n setStatus(null)\n return\n }\n const controller = new AbortController()\n const timer = setTimeout(() => {\n void checkForUpdate({\n packageName: optsRef.current.packageName,\n currentVersion: optsRef.current.currentVersion,\n cacheDir: optsRef.current.cacheDir,\n registry: optsRef.current.registry,\n channel: optsRef.current.channel,\n // Default to TTL=0 (always fetch fresh). See `cacheTtlMs` docs.\n cacheTtlMs: optsRef.current.cacheTtlMs ?? 0,\n signal: controller.signal,\n now: optsRef.current.now,\n fetcher: optsRef.current.fetcher,\n }).then((s) => {\n if (!controller.signal.aborted)\n setStatus(s)\n })\n }, options.delayMs ?? 1500)\n return () => {\n clearTimeout(timer)\n controller.abort()\n }\n // Re-run when the master enable / package / version flip. Other\n // option changes stay inside `optsRef.current`; re-running on every\n // option mutation would cause render storms when the host wraps\n // the result into derived hint state.\n }, [options.enabled, options.packageName, options.currentVersion])\n\n return status\n}\n\n// ---------------------------------------------------------------------------\n// Footer chip helper — pure function so any renderer (TUI Footer, future\n// GUI status bar) can compose against the same `Hint`. The chip is\n// suppressed when there's no update; callers spread the result into their\n// hint array unconditionally.\n//\n// Color contract: the chip rides whatever accent the host passes (typically\n// `theme.colors.accent`). Renderers that want a \"fresh check\" badge can\n// inspect `status.source === 'fresh'` themselves — this helper sticks to\n// the one-line discoverability surface.\n// ---------------------------------------------------------------------------\n\nexport interface BuildUpdateHintOptions {\n /** Foreground color for the `↑` glyph + version label. */\n color: string\n /**\n * When true (default), the chip renders the literal version (`↑ v5.6.0`).\n * When false, just the glyph + `update` label — useful when the row is\n * tight and the version would push higher-priority chips off the right.\n */\n showVersion?: boolean\n /** Override the leading glyph. Defaults to `'↑'`. */\n glyph?: string\n}\n\nexport function buildUpdateHint(status: UpdateStatus | null, options: BuildUpdateHintOptions): Hint | null {\n if (!status?.hasUpdate || !status.latest)\n return null\n const label = options.showVersion === false\n ? 'update'\n : `v${stripVPrefix(status.latest)}`\n return {\n key: options.glyph ?? '↑',\n keyColor: options.color,\n label,\n labelColor: options.color,\n }\n}\n\n/**\n * `↻ v7.0.31` — a newer build is on disk than the one running (this\n * process is stale; see `auto-update-restart.ts`). Takes precedence over\n * the `↑` chip: once the release is installed, \"available\" is old news and\n * \"restart\" is the one action left. Same color contract as `buildUpdateHint`.\n */\nexport function buildRestartHint(\n state: { restartRequired: boolean, installed: string | null } | null,\n options: BuildUpdateHintOptions,\n): Hint | null {\n if (!state?.restartRequired || !state.installed)\n return null\n return {\n key: options.glyph ?? '↻',\n keyColor: options.color,\n label: options.showVersion === false ? 'restart' : `v${stripVPrefix(state.installed)}`,\n labelColor: options.color,\n }\n}\n\nfunction stripVPrefix(v: string): string {\n return v.startsWith('v') ? v.slice(1) : v\n}\n","// ---------------------------------------------------------------------------\n// Structured, host-agnostic upgrade of every INSTALLED zidane package.\n//\n// `runUpdateCommand` is the terminal-facing ledger for `zidane upgrade`; it\n// knows the TUI is the primary and detects that install's package manager\n// from `process.execPath`. A GUI cannot reuse it — its `execPath` is\n// Electron's — and wants results, not text. This module is the shared\n// engine both can build on: every target is located by its bin on PATH\n// (`findInstalledCompanion`), checked against the registry, installed through\n// the package manager that owns THAT bin, and verified on disk afterwards\n// (a PM exiting 0 is not proof; an optional platform binary that 404s is\n// silently skipped).\n//\n// On success the applied marker is written so running surfaces can offer a\n// restart — see `auto-update-restart.ts`.\n// ---------------------------------------------------------------------------\n\nimport type { PackageManagerCommand, UpdateStatus } from './auto-update'\nimport type { CompanionSpec, InstalledCompanion } from './auto-update-companion'\nimport { Writable } from 'node:stream'\nimport {\n checkForUpdate,\n checkTarballAvailable,\n compareSemver,\n detectPackageManager,\n performSelfUpdate,\n reinstallHint,\n} from './auto-update'\nimport { findInstalledCompanion } from './auto-update-companion'\nimport { writeUpdateAppliedMarker } from './auto-update-restart'\n\nexport interface UpgradePackageResult {\n packageName: string\n /** Version on disk before the run; `null` when not installed. */\n from: string | null\n /** Version the registry advertises; `null` when the check failed. */\n to: string | null\n /**\n * - `'updated'` — installed and verified on disk.\n * - `'up-to-date'` — nothing to do.\n * - `'not-installed'` — bin not on PATH; skipped silently.\n * - `'unavailable'` — published but the tarball is not downloadable yet.\n * - `'failed'` — registry error, PM failure, or the install did not land; see `error`.\n */\n status: 'updated' | 'up-to-date' | 'not-installed' | 'unavailable' | 'failed'\n /** The PM command that ran (or would run). */\n command?: string[]\n error?: string\n}\n\nexport interface UpgradeReport {\n results: UpgradePackageResult[]\n /** No `failed` / `unavailable` entries. */\n ok: boolean\n /** At least one package was actually installed — a restart is now pending. */\n installedAny: boolean\n}\n\nexport type UpgradeProgressEvent\n = | { kind: 'check', packageName: string }\n | { kind: 'install', packageName: string, from: string, to: string, command: string[] }\n | { kind: 'log', packageName: string, stream: 'stdout' | 'stderr', line: string }\n | { kind: 'done', result: UpgradePackageResult }\n\nexport interface UpgradeInstalledPackagesOptions {\n /** Packages to keep in step, e.g. `[{ packageName: 'zidane-gui' }, { packageName: 'zidane-tui', binName: 'zidane' }]`. */\n targets: readonly CompanionSpec[]\n channel?: string\n registry?: string\n /** Where the registry cache and the applied marker live. */\n cacheDir?: string\n /** Install even when the registry check failed or reports up-to-date. */\n force?: boolean\n signal?: AbortSignal\n onProgress?: (event: UpgradeProgressEvent) => void\n /** Injected for tests. */\n findInstalled?: typeof findInstalledCompanion\n performSelfUpdate?: typeof performSelfUpdate\n checkTarballAvailable?: typeof checkTarballAvailable\n checkForUpdate?: typeof checkForUpdate\n detectPackageManager?: typeof detectPackageManager\n writeMarker?: typeof writeUpdateAppliedMarker\n now?: () => number\n}\n\nexport async function upgradeInstalledPackages(options: UpgradeInstalledPackagesOptions): Promise<UpgradeReport> {\n const channel = options.channel ?? 'latest'\n const find = options.findInstalled ?? findInstalledCompanion\n const check = options.checkForUpdate ?? checkForUpdate\n const available = options.checkTarballAvailable ?? checkTarballAvailable\n const install = options.performSelfUpdate ?? performSelfUpdate\n const detect = options.detectPackageManager ?? detectPackageManager\n const progress = options.onProgress ?? (() => {})\n\n const results: UpgradePackageResult[] = []\n for (const spec of options.targets) {\n if (options.signal?.aborted)\n break\n const installed = find(spec)\n if (!installed) {\n results.push({ packageName: spec.packageName, from: null, to: null, status: 'not-installed' })\n continue\n }\n progress({ kind: 'check', packageName: spec.packageName })\n const status = await check({\n packageName: installed.packageName,\n currentVersion: installed.version,\n channel,\n registry: options.registry,\n cacheDir: options.cacheDir,\n force: true,\n timeoutMs: 8000,\n signal: options.signal,\n })\n const result = await upgradeOne(installed, status)\n progress({ kind: 'done', result })\n results.push(result)\n }\n\n const installedAny = results.some(r => r.status === 'updated')\n if (installedAny && options.cacheDir) {\n const writeMarker = options.writeMarker ?? writeUpdateAppliedMarker\n writeMarker(options.cacheDir, {\n at: (options.now ?? Date.now)(),\n packages: results\n .filter(r => r.status === 'updated' && r.to)\n .map(r => ({ packageName: r.packageName, version: r.to! })),\n })\n }\n return {\n results,\n ok: results.every(r => r.status !== 'failed' && r.status !== 'unavailable'),\n installedAny,\n }\n\n async function upgradeOne(installed: InstalledCompanion, status: UpdateStatus): Promise<UpgradePackageResult> {\n const base = { packageName: installed.packageName, from: installed.version, to: status.latest }\n if (status.source === 'error' && !options.force)\n return { ...base, status: 'failed', error: `registry check failed: ${status.error ?? 'unknown error'}` }\n const outdated = status.latest !== null && compareSemver(status.latest, installed.version) > 0\n if (!outdated && !options.force)\n return { ...base, status: 'up-to-date' }\n if (status.latest && !options.force) {\n const availability = await available({ packageName: installed.packageName, version: status.latest, registry: options.registry })\n if (availability === 'missing')\n return { ...base, status: 'unavailable', error: `${installed.packageName} ${status.latest} is published but not downloadable yet. Try again in a few minutes.` }\n }\n // The PM that owns THIS bin — npm/pnpm/yarn/bun/Volta differ per install.\n const command: PackageManagerCommand = detect({ packageName: installed.packageName, channel, binaryPath: installed.binaryPath })\n progress({ kind: 'install', packageName: installed.packageName, from: installed.version, to: status.latest ?? channel, command: command.argv })\n\n const outcome = await install({\n packageName: installed.packageName,\n channel,\n packageManager: command.id,\n signal: options.signal,\n stdout: lineSink(installed.packageName, 'stdout'),\n stderr: lineSink(installed.packageName, 'stderr'),\n // Quiet PM output: the UI shows one live line, not a progress bar dump.\n env: { npm_config_loglevel: 'error', npm_config_progress: 'false' },\n })\n if (outcome.spawnError)\n return { ...base, status: 'failed', command: command.argv, error: `could not run ${command.argv[0]}: ${outcome.spawnError}` }\n if (outcome.exitCode !== 0)\n return { ...base, status: 'failed', command: command.argv, error: `${command.argv[0]} exited with ${outcome.exitCode ?? 'unknown'}` }\n\n // Verify: what is on disk now vs. what we asked for.\n const after = find(installed)\n if (status.latest && after && compareSemver(after.version, status.latest) < 0) {\n return {\n ...base,\n status: 'failed',\n command: command.argv,\n error: `install finished but ${after.version} is on disk, expected ${status.latest}. Reinstall: ${reinstallHint(command, installed.packageName, channel)}`,\n }\n }\n return { ...base, to: after?.version ?? status.latest, status: 'updated', command: command.argv }\n }\n\n /** Split a PM's byte stream into trimmed lines for the progress sink. */\n function lineSink(packageName: string, stream: 'stdout' | 'stderr'): NodeJS.WritableStream {\n let buffer = ''\n const flush = (final: boolean) => {\n const parts = buffer.split(/\\r?\\n/)\n buffer = final ? '' : parts.pop() ?? ''\n for (const part of parts) {\n const line = part.trim()\n if (line)\n progress({ kind: 'log', packageName, stream, line })\n }\n }\n return new Writable({\n write(chunk: Uint8Array | string, _enc, cb) {\n buffer += chunk.toString()\n flush(false)\n cb()\n },\n final(cb) {\n flush(true)\n cb()\n },\n })\n }\n}\n","// ---------------------------------------------------------------------------\n// Boot-time wall-clock profiler.\n//\n// Sprinkle `bootTick('<label>')` at strategic points along the startup\n// chain (cli.ts → runTui → setupTreeSitter → resolveConfig →\n// createCliRenderer → React mount → discovery effects → session\n// resume). When `ZIDANE_BOOT_PROFILE=1` is set, each call emits one\n// line on stderr with the delta since the previous tick and the total\n// since module load:\n//\n// $ ZIDANE_BOOT_PROFILE=1 zidane\n// [boot] +0.0ms / total 0.0ms / cli:enter\n// [boot] +12.3ms / total 12.3ms / cli:after-bundled-treesitter-setup\n// [boot] +47.8ms / total 60.1ms / runTui:after-setupTreeSitter\n// ...\n//\n// Renderer-agnostic on purpose — lives in `zidane/chat` so a future GUI\n// shell can wire it into its own boot path with the same env var and\n// the same output format. Writes to stderr, which OpenTUI's renderer\n// leaves alone (stdout is the frame buffer surface).\n// ---------------------------------------------------------------------------\n\nconst enabled = !!process.env.ZIDANE_BOOT_PROFILE\n/**\n * High-resolution origin for the running profile. Captured at module\n * load time so the first {@link bootTick} call inside the same process\n * reflects \"time since the boot profiler was first reached\", which for\n * the standard `cli.ts → runTui` path is effectively \"time since the\n * TUI binary started executing user code\".\n */\nconst start = performance.now()\nlet last = start\n\n/**\n * Record a checkpoint. No-op unless `ZIDANE_BOOT_PROFILE` is truthy in\n * the environment.\n *\n * The leading delta is the time since the PREVIOUS tick (so a long\n * delta highlights the immediately-preceding work); the trailing total\n * is the time since the profiler started. Both round to one decimal of\n * a millisecond.\n */\nexport function bootTick(label: string): void {\n if (!enabled)\n return\n const now = performance.now()\n const delta = now - last\n const total = now - start\n last = now\n // 10-char label pad keeps the alignment readable in a terminal even\n // when delta or total widens; longer labels just push the line out\n // slightly without breaking the format.\n process.stderr.write(\n `[boot] +${delta.toFixed(1).padStart(7)}ms / total ${total.toFixed(1).padStart(7)}ms / ${label}\\n`,\n )\n}\n\n/**\n * Returns `true` when `ZIDANE_BOOT_PROFILE` is set. Useful for guarding\n * heavier instrumentation (e.g. wrapping a costly call in a span) that\n * you don't want paying its own cost in the default path.\n */\nexport function bootProfileEnabled(): boolean {\n return enabled\n}\n","/**\n * Best-effort cross-platform browser open.\n *\n * macOS uses `open`, Linux uses `xdg-open`, Windows uses `start`. Failures\n * are swallowed — both callers (AI-provider OAuth + MCP-server OAuth) show\n * the URL on-screen for manual click anyway, and the underlying flows have\n * their own progress/cancel paths.\n *\n * Uses `spawn` (not `exec`) so the URL is passed as an argv element rather\n * than interpolated into a shell command — URLs containing `&`, `?`, `\"`,\n * or other shell metacharacters don't need quoting.\n *\n * Detached + unref so the spawned helper outlives the parent: the user\n * can finish authorizing in the browser even if the TUI is later\n * suspended (Ctrl-Z) or killed.\n */\n\nimport { spawn } from 'node:child_process'\nimport { dirname } from 'node:path'\n\nexport function tryOpenBrowser(url: string): void {\n const [cmd, ...args] = (() => {\n if (process.platform === 'darwin')\n return ['open', url]\n if (process.platform === 'win32')\n return ['cmd', '/c', 'start', '', url]\n return ['xdg-open', url]\n })()\n try {\n const child = spawn(cmd, args, { stdio: 'ignore', detached: true })\n child.on('error', () => {}) // ENOENT etc. — silently fall through\n child.unref()\n }\n catch {\n // spawn() itself failed (e.g. invalid binary path). Swallow.\n }\n}\n\n/**\n * Reveal a local path in the OS file manager: a file is selected inside its\n * folder (`open -R` on macOS, `explorer /select,` on Windows), a directory is\n * opened. Linux has no portable \"select\" — the containing directory opens.\n * Same fire-and-forget posture as {@link tryOpenBrowser}.\n */\nexport function tryRevealPath(path: string, isDirectory = false): void {\n const target = path.replace(/^file:\\/\\//, '')\n const [cmd, ...args] = (() => {\n if (process.platform === 'darwin')\n return isDirectory ? ['open', target] : ['open', '-R', target]\n if (process.platform === 'win32')\n return isDirectory ? ['explorer', target] : ['explorer', `/select,${target}`]\n return ['xdg-open', isDirectory ? target : dirname(target)]\n })()\n try {\n const child = spawn(cmd, args, { stdio: 'ignore', detached: true })\n child.on('error', () => {})\n child.unref()\n }\n catch {\n // swallow — a missing opener is not an error the rail should surface\n }\n}\n","/**\n * Write-side companion to `mcps-discovery.ts` — upsert one MCP server\n * entry into an `mcps.json` config file WITHOUT disturbing anything else\n * in it.\n *\n * Discovery tolerates three shapes (flat `McpServerConfig[]`, name-keyed\n * map, and the Claude/Cursor `{ \"mcpServers\": { … } }` wrapper). Users\n * hand-author these files and copy-paste from other tools, so the writer\n * must be shape-preserving: it parses the RAW json (not the normalized\n * view), locates the collection in whatever shape it's in, upserts by\n * name, and re-serializes — unknown sibling fields, unknown per-entry\n * fields on OTHER entries, and the wrapper shape all survive untouched.\n * A fresh file is created in the canonical flat-array shape.\n *\n * Scope roots mirror discovery: `<gitRoot>/.zidane/mcps.json` (project)\n * or `~/.zidane/mcps.json` (user) — the `.agents/` siblings stay\n * read-only for us (cross-tool convention files).\n */\n\nimport type { McpServerConfig } from '../types'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { parseJsonTolerant } from './mcps-discovery'\nimport { projectUserPaths } from './project-user-paths'\n\nexport type McpConfigScope = 'project' | 'user'\n\n/**\n * Resolve the CANONICAL write target for a scope — always the\n * `.{prefix}/mcps.json` flavor, never `.agents` (we don't own that\n * convention) and never `mcp.json` (Cursor's spelling is read-compat\n * only).\n */\nexport function mcpsWritePath(scope: McpConfigScope, opts?: { cwd?: string, home?: string, prefix?: string }): string {\n const prefix = (opts?.prefix ?? '.zidane').replace(/^\\./, '')\n const candidates = projectUserPaths({\n subPath: 'mcps.json',\n ...(opts?.cwd ? { cwd: opts.cwd } : {}),\n ...(opts?.home ? { home: opts.home } : {}),\n ...(opts?.prefix ? { prefix: opts.prefix } : {}),\n })\n const target = candidates.find(c => c.source === scope && c.path.includes(`.${prefix}`))\n if (!target)\n throw new Error(`No ${scope} mcps.json path resolved.`)\n return target.path\n}\n\nexport interface UpsertMcpResult {\n /** The file written. */\n path: string\n /** `updated` when an entry of the same name was replaced, else `added`. */\n action: 'added' | 'updated'\n}\n\n/**\n * Upsert `entry` (matched by `name`) into the mcps config at `filePath`.\n * Preserves the existing file's shape and every field the writer doesn't\n * own; creates a canonical flat-array file when none exists. Throws on\n * malformed JSON — silently rewriting a broken file the user is mid-edit\n * on would destroy their work.\n */\nexport function upsertMcpServer(filePath: string, entry: McpServerConfig): UpsertMcpResult {\n if (!existsSync(filePath)) {\n mkdirSync(dirname(filePath), { recursive: true })\n writeFileSync(filePath, `${JSON.stringify([entry], null, 2)}\\n`)\n return { path: filePath, action: 'added' }\n }\n\n // Tolerant parse (same retry as discovery's read path) — a file whose\n // servers LIST fine must also accept edits; strict JSON.parse would\n // reject the NBSP/zero-width artifacts discovery silently forgives.\n const raw: unknown = parseJsonTolerant(readFileSync(filePath, 'utf8'))\n\n // Flat array — the canonical zidane shape. Entries carry their `name`.\n if (Array.isArray(raw)) {\n const idx = raw.findIndex(e => isRecord(e) && e.name === entry.name)\n const next = [...raw]\n const action = idx >= 0 ? 'updated' as const : 'added' as const\n if (idx >= 0)\n next[idx] = entry\n else\n next.push(entry)\n writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\\n`)\n return { path: filePath, action }\n }\n\n if (isRecord(raw)) {\n // Claude/Cursor wrapper: mutate only the inner map, siblings survive.\n if (isRecord(raw.mcpServers)) {\n const map = raw.mcpServers\n const action = entry.name in map ? 'updated' as const : 'added' as const\n const next = { ...raw, mcpServers: { ...map, [entry.name]: stripName(entry) } }\n writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\\n`)\n return { path: filePath, action }\n }\n // Bare name-keyed map.\n const action = entry.name in raw ? 'updated' as const : 'added' as const\n const next = { ...raw, [entry.name]: stripName(entry) }\n writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\\n`)\n return { path: filePath, action }\n }\n\n throw new Error(`${filePath} is not a recognized mcps.json shape (array, map, or {\"mcpServers\": …}).`)\n}\n\nexport interface RemoveMcpResult {\n /** The file rewritten. */\n path: string\n}\n\n/**\n * Remove the entry named `name` from the mcps config at `filePath`,\n * preserving the file's shape and everything else in it — the removal\n * counterpart of {@link upsertMcpServer}. Throws when the file is\n * missing, malformed, an unrecognized shape, or has no entry of that\n * name (the caller shows the message on the settings op line; silently\n * \"succeeding\" on a no-op would lie about what happened).\n */\nexport function removeMcpServer(filePath: string, name: string): RemoveMcpResult {\n if (!existsSync(filePath))\n throw new Error(`${filePath} does not exist.`)\n\n // Same tolerant parse as upsert — see the note there.\n const raw: unknown = parseJsonTolerant(readFileSync(filePath, 'utf8'))\n\n if (Array.isArray(raw)) {\n const next = raw.filter(e => !(isRecord(e) && e.name === name))\n if (next.length === raw.length)\n throw new Error(`no entry named \"${name}\" in ${filePath}.`)\n writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\\n`)\n return { path: filePath }\n }\n\n if (isRecord(raw)) {\n if (isRecord(raw.mcpServers)) {\n if (!(name in raw.mcpServers))\n throw new Error(`no entry named \"${name}\" in ${filePath}.`)\n const { [name]: _dropped, ...rest } = raw.mcpServers\n const next = { ...raw, mcpServers: rest }\n writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\\n`)\n return { path: filePath }\n }\n if (!(name in raw))\n throw new Error(`no entry named \"${name}\" in ${filePath}.`)\n const { [name]: _dropped, ...next } = raw\n writeFileSync(filePath, `${JSON.stringify(next, null, 2)}\\n`)\n return { path: filePath }\n }\n\n throw new Error(`${filePath} is not a recognized mcps.json shape (array, map, or {\"mcpServers\": …}).`)\n}\n\n/** Map-shaped files key entries by name — the inner object must not repeat it. */\nfunction stripName(entry: McpServerConfig): Omit<McpServerConfig, 'name'> {\n const { name: _name, ...rest } = entry\n return rest\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","/**\n * One-shot IMPORT from an existing Claude Code setup — the materializing\n * counterpart to `foreign-configs.ts`'s read-only discovery.\n *\n * Three pieces, each independently skippable:\n *\n * - Sessions — `~/.claude/projects/<slug>/*.jsonl` transcripts convert\n * to zidane `SessionData` and land in the session store. Idempotent:\n * the zidane session REUSES the Claude session UUID, so a re-import\n * skips everything the store already has.\n * - MCP servers — Claude's `.mcp.json` + `~/.claude.json` entries are\n * COPIED into zidane-owned `mcps.json` files (via `upsertMcpServer`).\n * Names already present in any native zidane/agents config are\n * skipped — imports never shadow what the user configured natively.\n * - Skills — `.claude/skills/<name>` directories are copied into the\n * corresponding `.{prefix}/skills`, skipping names that already\n * exist in any native scan path.\n * - Commands and subagents — `.claude/commands/**.md` and\n * `.claude/agents/**.md` are copied into `.{prefix}/commands` and\n * `.{prefix}/agents`, keeping their folders and skipping names a native\n * root already defines. Copied, they load without the\n * `importForeignConfigs` toggle that otherwise reads them in place.\n *\n * Claude's `settings.json` (permissions / hooks / plugins) has no zidane\n * equivalent and `CLAUDE.md` is already read natively (`agents-md.ts`),\n * so neither is imported — the UI reports that instead of pretending.\n */\n\nimport type { SessionData, SessionStore } from '../session'\nimport type { McpServerConfig, SessionContentBlock, SessionTurn, ToolResultContent, TurnUsage } from '../types'\nimport { Buffer } from 'node:buffer'\nimport { closeSync, cpSync, existsSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, realpathSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { basename, dirname, join, relative, resolve } from 'node:path'\nimport { markdownDefRoots } from '../markdown-defs/roots'\nimport { listMarkdownDefFiles } from '../markdown-defs/scan'\nimport { parseClaudeState } from './foreign-configs'\nimport { defaultMcpsConfigPaths, parseJsonTolerant, parseMcpsFile } from './mcps-discovery'\nimport { mcpsWritePath, upsertMcpServer } from './mcps-write'\nimport { findGitRoot, projectRootOf } from './project-root'\nimport { projectUserPaths } from './project-user-paths'\n\nexport interface ClaudeImportOptions {\n /** Discovery cwd. Default: `process.cwd()`. */\n cwd?: string\n /** User home directory. Default: `os.homedir()`. */\n home?: string\n /** Storage prefix for write targets. Default: `'.zidane'`. */\n prefix?: string\n /** Import sessions from every Claude project dir, not just the current project's. */\n allProjects?: boolean\n}\n\nfunction roots(opts: ClaudeImportOptions): { projectRoot: string, home: string } {\n const cwd = opts.cwd ?? process.cwd()\n return {\n projectRoot: findGitRoot(cwd) ?? cwd,\n home: opts.home ?? homedir(),\n }\n}\n\n/** `~/.claude` — presence gates the settings action row. */\nexport function hasClaudeCodeSetup(opts: ClaudeImportOptions = {}): boolean {\n return existsSync(resolve(roots(opts).home, '.claude'))\n}\n\n// ---------------------------------------------------------------------------\n// Sessions\n// ---------------------------------------------------------------------------\n\n/**\n * Claude Code names each `~/.claude/projects/` subdirectory after the\n * project path with every non-alphanumeric character flattened to `-`\n * (`/Users/me/.claude/wt` → `-Users-me--claude-wt`). Lossy, so matching\n * goes slug → slug rather than trying to reverse it.\n */\nexport function claudeProjectSlug(path: string): string {\n return path.replace(/[^a-z0-9]/gi, '-')\n}\n\nexport interface ClaudeSessionFile {\n path: string\n /** The `~/.claude/projects/<slug>` directory the file came from. */\n projectDir: string\n}\n\n/**\n * Session transcripts for the current project, or every project when\n * `allProjects` is set.\n *\n * Claude Code slugs by LAUNCH directory, so a session started in a\n * monorepo subdir (`repo/packages/foo`) lands in a different dir than\n * one started at the repo root. Scoped listing therefore accepts both\n * the exact slug of the resolved git root (realpath variants included)\n * AND any dir whose slug extends it — but because slugs are lossy\n * (`repo/foo` and a sibling `repo-foo` collide), prefix-matched dirs\n * are confirmed per-file against the transcript's recorded `cwd`\n * (resolved to its git root), mirroring how the converted session's\n * `projectRoot` is derived.\n */\nexport function listClaudeSessionFiles(opts: ClaudeImportOptions = {}): ClaudeSessionFile[] {\n const out: ClaudeSessionFile[] = []\n walkClaudeSessionFiles(opts, opts.allProjects\n ? file => out.push(file)\n : (file, scoped) => {\n if (scoped())\n out.push(file)\n })\n return out\n}\n\n/**\n * Detection-preview counts — scoped and all-projects figures from ONE\n * directory walk (the naive two-listing approach reads every project dir\n * twice). The scoped classification (with its per-file cwd peek for\n * candidate dirs) runs at most once per file via the lazy `scoped()`\n * thunk.\n */\nexport function countClaudeSessionFiles(opts: ClaudeImportOptions = {}): { project: number, all: number } {\n let project = 0\n let all = 0\n walkClaudeSessionFiles({ ...opts, allProjects: false }, (_file, scoped) => {\n all++\n if (scoped())\n project++\n }, /* visitAllDirs */ true)\n return { project, all }\n}\n\n/**\n * Shared walk under `~/.claude/projects`. `visit` receives every\n * transcript of every CANDIDATE dir (scoped mode) or every dir\n * (`allProjects` / `visitAllDirs`), plus a lazy `scoped()` thunk that\n * answers \"does this file belong to the current project?\" — lazy because\n * the answer can cost a `transcriptProjectRoot` peek (up to the whole\n * file), which pure all-projects listings never need.\n */\nfunction walkClaudeSessionFiles(\n opts: ClaudeImportOptions,\n visit: (file: ClaudeSessionFile, scoped: () => boolean) => void,\n visitAllDirs = false,\n): void {\n const { projectRoot, home } = roots(opts)\n const projectsDir = resolve(home, '.claude/projects')\n if (!existsSync(projectsDir))\n return\n const slugs = [claudeProjectSlug(projectRoot), claudeProjectSlug(realpathOr(projectRoot))]\n const exact = new Set(slugs)\n const prefixes = [...new Set(slugs.map(s => `${s}-`))]\n const wantedRoots = new Set([projectRoot, realpathOr(projectRoot)])\n for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {\n if (!entry.isDirectory())\n continue\n const exactMatch = exact.has(entry.name)\n const candidate = exactMatch || prefixes.some(p => entry.name.startsWith(p))\n if (!opts.allProjects && !visitAllDirs && !candidate)\n continue\n const projectDir = join(projectsDir, entry.name)\n for (const file of readdirSync(projectDir)) {\n if (!file.endsWith('.jsonl'))\n continue\n const path = join(projectDir, file)\n // Slugs are lossy even on exact match (`/a/b-c` and `/a/b/c` both\n // slug to `-a-b-c`), so EVERY scoped file is confirmed against its\n // recorded cwd. A transcript with no cwd at all (torn/empty file)\n // gets the benefit of the doubt only in the exact-slug dir —\n // prefix matches must prove their subdir claim.\n const scoped = (): boolean => {\n if (!candidate)\n return false\n const root = transcriptProjectRoot(path)\n return root === null ? exactMatch : wantedRoots.has(root) || wantedRoots.has(realpathOr(root))\n }\n visit({ path, projectDir }, scoped)\n }\n }\n}\n\n/**\n * Peek a transcript's project root: scan the first chunk for the first\n * record carrying a `cwd` and resolve it the same way\n * `convertClaudeSession` does. When the chunk was truncated (giant first\n * records — e.g. pasted base64 images) and held no cwd, fall back to the\n * full file: the import reads it in full anyway, so correctness beats the\n * shortcut. Null when no cwd exists at all (empty/torn file) or the file\n * is unreadable.\n */\nfunction transcriptProjectRoot(path: string): string | null {\n let text: string\n let truncated = false\n try {\n const fd = openSync(path, 'r')\n try {\n const buf = Buffer.alloc(256 * 1024)\n const n = readSync(fd, buf, 0, buf.length, 0)\n text = buf.subarray(0, n).toString('utf8')\n truncated = n === buf.length\n }\n finally {\n closeSync(fd)\n }\n }\n catch {\n return null\n }\n const fromChunk = scanForCwd(text)\n if (fromChunk !== null || !truncated)\n return fromChunk\n try {\n return scanForCwd(readFileSync(path, 'utf8'))\n }\n catch {\n return null\n }\n}\n\nfunction scanForCwd(text: string): string | null {\n for (const line of text.split('\\n')) {\n if (!line.trim())\n continue\n try {\n const record = JSON.parse(line) as { cwd?: unknown }\n if (typeof record.cwd === 'string')\n return findGitRoot(record.cwd) ?? record.cwd\n }\n catch {\n continue // torn chunk boundary / artifact line\n }\n }\n return null\n}\n\nfunction realpathOr(path: string): string {\n try {\n return realpathSync(path)\n }\n catch {\n return path\n }\n}\n\nexport interface ConvertedClaudeSession {\n session: SessionData\n claudeSessionId: string\n}\n\ninterface ClaudeRecord {\n type?: string\n uuid?: string\n timestamp?: string\n isSidechain?: boolean\n isMeta?: boolean\n cwd?: string\n sessionId?: string\n customTitle?: string\n summary?: string\n message?: {\n id?: string\n role?: string\n content?: unknown\n usage?: {\n input_tokens?: number\n output_tokens?: number\n cache_creation_input_tokens?: number\n cache_read_input_tokens?: number\n }\n model?: string\n }\n}\n\n/**\n * Convert one Claude Code session transcript (JSONL text) to a zidane\n * `SessionData`. Returns null when no conversational turns survive the\n * filter (hook noise, sidechains, queue bookkeeping).\n *\n * Kept-vs-dropped:\n * - `user` / `assistant` records with a `message` → turns. Consecutive\n * assistant records sharing a `message.id` merge into ONE turn (Claude\n * writes text and tool_use as separate records of the same API message).\n * - Consecutive tool_result-only user records merge into ONE user turn:\n * Claude writes one record per result of a parallel tool batch, but\n * zidane persists a batch as a single user turn and\n * `ensureToolResultPairing` enforces strict adjacency — split turns\n * would be \"repaired\" into orphan markers + error placeholders on resume.\n * - `custom-title` / `summary` records → `metadata.title`.\n * - Sidechains (subagent transcripts), `isMeta` records, `attachment`,\n * `system`, `queue-operation`, `last-prompt` → dropped.\n * - Thinking blocks → dropped (provider-bound signatures, not replayable).\n */\nexport function convertClaudeSession(jsonl: string, opts: { fallbackId?: string } = {}): ConvertedClaudeSession | null {\n const turns: SessionTurn[] = []\n let title: string | undefined\n let claudeSessionId: string | undefined\n let cwd: string | undefined\n let lastAssistantMessageId: string | undefined\n\n for (const line of jsonl.split('\\n')) {\n if (!line.trim())\n continue\n let record: ClaudeRecord\n try {\n record = JSON.parse(line) as ClaudeRecord\n }\n catch {\n continue // torn tail line, editor artifact — skip, don't fail the file\n }\n if (record.type === 'custom-title' && typeof record.customTitle === 'string') {\n title = record.customTitle\n continue\n }\n if (record.type === 'summary' && typeof record.summary === 'string') {\n title ??= record.summary\n continue\n }\n if (record.type !== 'user' && record.type !== 'assistant')\n continue\n if (record.isSidechain || record.isMeta || !record.message)\n continue\n claudeSessionId ??= record.sessionId\n cwd ??= record.cwd\n // Malformed timestamps parse to NaN — don't let that poison\n // createdAt/updatedAt (sort keys in the sessions list).\n const parsedTs = record.timestamp ? Date.parse(record.timestamp) : Number.NaN\n const createdAt = Number.isNaN(parsedTs) ? Date.now() : parsedTs\n\n if (record.type === 'assistant') {\n const content = claudeBlocksToContent(record.message.content)\n if (content.length === 0)\n continue\n const messageId = record.message.id\n const previous = turns[turns.length - 1]\n // Merge continuation records of the same API message into the open\n // turn. Claude repeats the SAME usage object on every record of a\n // message, so the latest snapshot replaces — summing would N-count\n // the message's tokens.\n if (messageId && messageId === lastAssistantMessageId && previous?.role === 'assistant') {\n previous.content.push(...content)\n const usage = claudeUsage(record.message.usage, record.message.model)\n if (usage)\n previous.usage = usage\n continue\n }\n lastAssistantMessageId = messageId\n const usage = claudeUsage(record.message.usage, record.message.model)\n turns.push({\n id: record.uuid ?? crypto.randomUUID(),\n role: 'assistant',\n content,\n createdAt,\n ...(usage ? { usage } : {}),\n })\n continue\n }\n\n lastAssistantMessageId = undefined\n const content = claudeBlocksToContent(record.message.content)\n if (content.length === 0)\n continue\n // One record per tool_result of a parallel batch → one zidane user\n // turn — see the doc comment (ensureToolResultPairing adjacency).\n const previous = turns[turns.length - 1]\n if (previous?.role === 'user' && isToolResultOnly(content) && isToolResultOnly(previous.content)) {\n previous.content.push(...content)\n continue\n }\n turns.push({ id: record.uuid ?? crypto.randomUUID(), role: 'user', content, createdAt })\n }\n\n if (turns.length === 0)\n return null\n // Identity PREFERS the caller's `fallbackId` (the file basename —\n // Claude's own per-file uniqueness key) over the records' `sessionId`:\n // resume/fork lineages copy prior records verbatim, so a forked\n // transcript's early records still carry the ORIGINAL session's id —\n // keying on that would dedupe the fork against its ancestor and\n // silently never import the continuation.\n const id = opts.fallbackId ?? claudeSessionId ?? crypto.randomUUID()\n // Identity, like every session: a Claude transcript recorded in a linked\n // worktree belongs to the main checkout's project.\n const projectRoot = cwd ? projectRootOf(cwd) : undefined\n const session: SessionData = {\n id,\n ...(projectRoot ? { projectRoot } : {}),\n turns,\n runs: [],\n status: 'idle',\n metadata: {\n ...(title ? { title } : {}),\n importedFrom: 'claude-code',\n claudeSessionId: id,\n // Lineage breadcrumb: differs from `claudeSessionId` on forked /\n // resumed transcripts whose records carry the ancestor's id.\n ...(claudeSessionId && claudeSessionId !== id ? { claudeLineageId: claudeSessionId } : {}),\n },\n createdAt: turns[0]!.createdAt,\n updatedAt: turns[turns.length - 1]!.createdAt,\n }\n return { session, claudeSessionId: id }\n}\n\n/** Map Claude/Anthropic content blocks to zidane `SessionContentBlock`s. */\nfunction claudeBlocksToContent(content: unknown): SessionContentBlock[] {\n if (typeof content === 'string')\n return content.trim() ? [{ type: 'text', text: content }] : []\n if (!Array.isArray(content))\n return []\n const out: SessionContentBlock[] = []\n for (const raw of content) {\n if (!raw || typeof raw !== 'object')\n continue\n const block = raw as Record<string, unknown>\n switch (block.type) {\n case 'text':\n if (typeof block.text === 'string' && block.text.trim())\n out.push({ type: 'text', text: block.text })\n break\n case 'tool_use':\n if (typeof block.id === 'string' && typeof block.name === 'string') {\n const input = block.input && typeof block.input === 'object' && !Array.isArray(block.input)\n ? block.input as Record<string, unknown>\n : {}\n out.push({ type: 'tool_call', id: block.id, name: block.name, input })\n }\n break\n case 'tool_result':\n if (typeof block.tool_use_id === 'string') {\n out.push({\n type: 'tool_result',\n callId: block.tool_use_id,\n output: claudeToolResultOutput(block.content),\n ...(block.is_error === true ? { isError: true } : {}),\n })\n }\n break\n case 'image': {\n const image = claudeImage(block)\n if (image)\n out.push(image)\n break\n }\n // thinking / redacted_thinking: provider-bound signatures — dropped.\n }\n }\n return out\n}\n\nfunction claudeImage(block: Record<string, unknown>): SessionContentBlock | null {\n const source = block.source as Record<string, unknown> | undefined\n if (!source || source.type !== 'base64' || typeof source.media_type !== 'string' || typeof source.data !== 'string')\n return null\n return { type: 'image', mediaType: source.media_type, data: source.data }\n}\n\nfunction claudeToolResultOutput(content: unknown): string | ToolResultContent[] {\n if (typeof content === 'string')\n return content\n if (!Array.isArray(content))\n return ''\n const parts: ToolResultContent[] = []\n for (const raw of content) {\n if (!raw || typeof raw !== 'object')\n continue\n const block = raw as Record<string, unknown>\n if (block.type === 'text' && typeof block.text === 'string') {\n parts.push({ type: 'text', text: block.text })\n }\n else if (block.type === 'image') {\n const image = claudeImage(block)\n if (image?.type === 'image' && image.data)\n parts.push({ type: 'image', mediaType: image.mediaType, data: image.data })\n }\n }\n // Collapse the common all-text case to a plain string.\n if (parts.every(p => p.type === 'text'))\n return parts.map(p => (p as { text: string }).text).join('\\n')\n return parts\n}\n\ntype ClaudeUsage = NonNullable<NonNullable<ClaudeRecord['message']>['usage']>\n\nfunction claudeUsage(usage: ClaudeUsage | undefined, model?: string): TurnUsage | undefined {\n if (!usage || typeof usage !== 'object')\n return undefined\n return {\n input: usage.input_tokens ?? 0,\n output: usage.output_tokens ?? 0,\n ...(usage.cache_creation_input_tokens ? { cacheCreation: usage.cache_creation_input_tokens } : {}),\n ...(usage.cache_read_input_tokens ? { cacheRead: usage.cache_read_input_tokens } : {}),\n ...(model ? { modelId: model } : {}),\n }\n}\n\nfunction isToolResultOnly(blocks: readonly SessionContentBlock[]): boolean {\n return blocks.length > 0 && blocks.every(b => b.type === 'tool_result')\n}\n\nexport interface ClaudeSessionImportResult {\n imported: number\n /** Already in the store (same Claude session UUID) — idempotent re-run. */\n skipped: number\n /** Nothing conversational in the file (hook noise, queue bookkeeping only). */\n empty: number\n /** Files that failed to parse/convert, with the reason. */\n failed: { path: string, error: string }[]\n}\n\n/** Import Claude Code session transcripts into `store`. */\nexport async function importClaudeSessions(store: SessionStore, opts: ClaudeImportOptions = {}): Promise<ClaudeSessionImportResult> {\n const result: ClaudeSessionImportResult = { imported: 0, skipped: 0, empty: 0, failed: [] }\n for (const file of listClaudeSessionFiles(opts)) {\n try {\n // Session id = the file's basename (Claude names each transcript\n // after ITS session UUID). `convertClaudeSession` prefers this over\n // the records' `sessionId`, which on forked/resumed lineages still\n // carries the ancestor's id — see the identity comment there.\n const fallbackId = basename(file.path, '.jsonl')\n // Idempotence: a store hit on the basename means this transcript\n // already imported — checked BEFORE reading/converting, so a\n // re-import doesn't re-parse the whole Claude history just to\n // count skips.\n if (await store.load(fallbackId)) {\n result.skipped++\n continue\n }\n const converted = convertClaudeSession(readFileSync(file.path, 'utf8'), { fallbackId })\n if (!converted) {\n result.empty++\n continue\n }\n await store.save(converted.session)\n result.imported++\n }\n catch (err) {\n result.failed.push({ path: file.path, error: err instanceof Error ? err.message : String(err) })\n }\n }\n return result\n}\n\n// ---------------------------------------------------------------------------\n// MCP servers\n// ---------------------------------------------------------------------------\n\nexport interface ClaudeCopyResult {\n copied: string[]\n /** Names already present natively — never overwritten. */\n skipped: string[]\n failed: { name: string, error: string }[]\n /**\n * Names that appeared in MORE THAN ONE Claude source (e.g. `.mcp.json`\n * AND `~/.claude.json`) — the first occurrence (highest-precedence\n * source, matching Claude's own project → local → user order) was\n * processed, later ones dropped. Surfaced so a differently-configured\n * duplicate doesn't vanish from the accounting. MCP import only.\n */\n duplicates?: string[]\n}\n\n/**\n * Copy Claude Code's MCP servers into zidane-owned `mcps.json` files.\n * The repo-shared `.mcp.json` writes to `<root>/.{prefix}/mcps.json`;\n * BOTH `~/.claude.json` scopes write to `~/.{prefix}/mcps.json` —\n * Claude's \"local\" scope (the per-project map inside the user state\n * file) is private-by-design and routinely carries tokens in\n * `env`/`headers`, so materializing it into a committable project file\n * would leak credentials. User scope loses the per-project activation\n * (zidane has no user-private per-project config), which is the safer\n * direction to err. Collisions with names in ANY native config path are\n * skipped.\n */\nexport function importClaudeMcps(opts: ClaudeImportOptions = {}): ClaudeCopyResult {\n const { projectRoot, home } = roots(opts)\n const result: ClaudeCopyResult = { copied: [], skipped: [], failed: [], duplicates: [] }\n\n // Collision guard — collected from the RAW file shape, NOT from\n // `parseMcpsFile`: the normalized view drops `enabled: false` entries\n // and can reject a file over one invalid entry, while `upsertMcpServer`\n // walks the raw JSON. Guarding on the normalized view would let the\n // import overwrite a native entry the user disabled (or one sitting\n // next to a malformed sibling). Raw names = exactly what upsert sees,\n // so an import can only ever ADD.\n const nativeNames = new Set<string>()\n for (const candidate of defaultMcpsConfigPaths({ ...(opts.cwd ? { cwd: opts.cwd } : {}), home, ...(opts.prefix ? { prefix: opts.prefix } : {}) })) {\n if (!existsSync(candidate.path))\n continue\n for (const name of rawMcpNames(readFileSync(candidate.path, 'utf8')))\n nativeNames.add(name)\n }\n\n const sources: { servers: McpServerConfig[], scope: 'project' | 'user' }[] = []\n const mcpJson = resolve(projectRoot, '.mcp.json')\n if (existsSync(mcpJson)) {\n try {\n sources.push({ servers: parseMcpsFile(readFileSync(mcpJson, 'utf8')), scope: 'project' })\n }\n catch (err) {\n result.failed.push({ name: mcpJson, error: err instanceof Error ? err.message : String(err) })\n }\n }\n const claudeState = resolve(home, '.claude.json')\n if (existsSync(claudeState)) {\n try {\n const state: unknown = JSON.parse(readFileSync(claudeState, 'utf8'))\n // User scope on purpose — see the doc comment (credential leak).\n sources.push({ servers: parseClaudeState(state, 'claude-project-state', projectRoot), scope: 'user' })\n sources.push({ servers: parseClaudeState(state, 'claude-user-state'), scope: 'user' })\n }\n catch (err) {\n result.failed.push({ name: claudeState, error: err instanceof Error ? err.message : String(err) })\n }\n }\n\n const seen = new Set<string>()\n for (const { servers, scope } of sources) {\n for (const server of servers) {\n if (seen.has(server.name)) {\n // Same name in a lower-precedence source — report, don't vanish:\n // its config may differ from the occurrence that won.\n result.duplicates!.push(server.name)\n continue\n }\n seen.add(server.name)\n if (nativeNames.has(server.name)) {\n result.skipped.push(server.name)\n continue\n }\n try {\n const target = mcpsWritePath(scope, { ...(opts.cwd ? { cwd: opts.cwd } : {}), home, ...(opts.prefix ? { prefix: opts.prefix } : {}) })\n const { action } = upsertMcpServer(target, server)\n if (action === 'updated') {\n // Unreachable while `nativeNames` raw-walks every candidate file\n // (the write targets included) — but if a concurrent writer or a\n // future shape drift ever slips past the guard, say so honestly\n // instead of counting an overwrite as a copy.\n result.failed.push({ name: server.name, error: `overwrote an existing entry in ${target}. Restore it from version control if unintended` })\n continue\n }\n result.copied.push(server.name)\n }\n catch (err) {\n result.failed.push({ name: server.name, error: err instanceof Error ? err.message : String(err) })\n }\n }\n }\n return result\n}\n\n/**\n * Names physically present in an mcps config file, from the raw parsed\n * shape — mirrors `upsertMcpServer`'s walk (flat array `name`s, wrapper\n * `mcpServers` keys, bare-map keys) with none of discovery's filtering.\n * Unreadable/malformed files yield no names; `upsertMcpServer` throws on\n * those before writing, so they still can't be overwritten.\n */\nfunction rawMcpNames(text: string): string[] {\n let raw: unknown\n try {\n raw = parseJsonTolerant(text)\n }\n catch {\n return []\n }\n if (Array.isArray(raw)) {\n return raw.flatMap(entry =>\n entry && typeof entry === 'object' && typeof (entry as { name?: unknown }).name === 'string'\n ? [(entry as { name: string }).name]\n : [])\n }\n if (raw && typeof raw === 'object') {\n const record = raw as Record<string, unknown>\n const map = record.mcpServers && typeof record.mcpServers === 'object' && !Array.isArray(record.mcpServers)\n ? record.mcpServers as Record<string, unknown>\n : record\n return Object.keys(map)\n }\n return []\n}\n\n// ---------------------------------------------------------------------------\n// Skills\n// ---------------------------------------------------------------------------\n\n/**\n * Copy `.claude/skills/<name>` directories (project + user) into the\n * corresponding `.{prefix}/skills`. A skill \"exists natively\" when a\n * directory of the same name sits in any native scan path — those are\n * skipped, not overwritten.\n */\nexport function importClaudeSkills(opts: ClaudeImportOptions = {}): ClaudeCopyResult {\n const { projectRoot, home } = roots(opts)\n const prefix = (opts.prefix ?? '.zidane').replace(/^\\./, '')\n const result: ClaudeCopyResult = { copied: [], skipped: [], failed: [] }\n\n const nativeNames = new Set<string>()\n for (const scan of projectUserPaths({ subPath: 'skills', ...(opts.cwd ? { cwd: opts.cwd } : {}), home, ...(opts.prefix ? { prefix: opts.prefix } : {}) })) {\n if (!existsSync(scan.path))\n continue\n for (const entry of readdirSync(scan.path, { withFileTypes: true })) {\n if (entry.isDirectory())\n nativeNames.add(entry.name)\n }\n }\n\n const pairs: { from: string, to: string }[] = [\n { from: resolve(projectRoot, '.claude/skills'), to: resolve(projectRoot, `.${prefix}/skills`) },\n { from: resolve(home, '.claude/skills'), to: resolve(home, `.${prefix}/skills`) },\n ]\n for (const { from, to } of pairs) {\n if (!existsSync(from))\n continue\n for (const entry of readdirSync(from, { withFileTypes: true })) {\n if (!entry.isDirectory())\n continue\n if (!existsSync(join(from, entry.name, 'SKILL.md')))\n continue\n if (nativeNames.has(entry.name)) {\n result.skipped.push(entry.name)\n continue\n }\n try {\n cpSync(join(from, entry.name), join(to, entry.name), { recursive: true, errorOnExist: true, force: false })\n nativeNames.add(entry.name)\n result.copied.push(entry.name)\n }\n catch (err) {\n result.failed.push({ name: entry.name, error: err instanceof Error ? err.message : String(err) })\n }\n }\n }\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Commands and subagents\n// ---------------------------------------------------------------------------\n\n/**\n * Copy `.claude/<kind>` markdown files (project + user) into the matching\n * `.{prefix}/<kind>`, keeping nested folders (`git/commit.md` stays\n * `/git:commit`). A name any native root already defines is skipped, never\n * overwritten. Names come from the file path, as the loader derives them; an\n * agent renamed by its `name:` frontmatter is compared by file name.\n */\nexport function importClaudeMarkdownDefs(kind: 'commands' | 'agents', opts: ClaudeImportOptions = {}): ClaudeCopyResult {\n const { projectRoot, home } = roots(opts)\n const prefix = (opts.prefix ?? '.zidane').replace(/^\\./, '')\n const result: ClaudeCopyResult = { copied: [], skipped: [], failed: [] }\n const native = markdownDefRoots({ kind, ...(opts.cwd ? { cwd: opts.cwd } : {}), home, prefix: `.${prefix}`, includeForeign: false })\n const nativeNames = new Set(listMarkdownDefFiles(native).map(file => file.name))\n\n const pairs: { from: string, to: string, source: 'project' | 'user' }[] = [\n { from: resolve(projectRoot, `.claude/${kind}`), to: resolve(projectRoot, `.${prefix}/${kind}`), source: 'project' },\n { from: resolve(home, `.claude/${kind}`), to: resolve(home, `.${prefix}/${kind}`), source: 'user' },\n ]\n for (const { from, to, source } of pairs) {\n for (const file of listMarkdownDefFiles([{ path: from, source, foreign: true }])) {\n if (nativeNames.has(file.name)) {\n result.skipped.push(file.name)\n continue\n }\n try {\n const target = join(to, relative(from, file.path))\n mkdirSync(dirname(target), { recursive: true })\n cpSync(file.path, target, { errorOnExist: true, force: false })\n nativeNames.add(file.name)\n result.copied.push(file.name)\n }\n catch (err) {\n result.failed.push({ name: file.name, error: err instanceof Error ? err.message : String(err) })\n }\n }\n }\n return result\n}\n\n// ---------------------------------------------------------------------------\n// Combined runner\n// ---------------------------------------------------------------------------\n\nexport interface ClaudeImportSummary {\n /**\n * Where the import landed: always this computer (its session store and\n * its `.zidane` files). Claude Code's data is read from this machine, so\n * the import never targets a remote host.\n */\n target: 'this-computer'\n sessions?: ClaudeSessionImportResult\n mcps?: ClaudeCopyResult\n skills?: ClaudeCopyResult\n commands?: ClaudeCopyResult\n agents?: ClaudeCopyResult\n /** What is deliberately NOT imported, spelled out for the UI. */\n notes: string[]\n}\n\n/** The host a window is using, as far as the import note cares. */\nexport interface ClaudeImportActiveHost {\n kind: 'in-process' | 'daemon' | 'server'\n name: string\n}\n\n/**\n * What to tell the user when the window's sessions live on a remote host:\n * the import went to this computer, so the host's list won't show it.\n * `null` for a host on this machine (it shares the store).\n */\nexport function claudeImportHostNote(activeHost: ClaudeImportActiveHost | null | undefined): string | null {\n if (activeHost?.kind !== 'server')\n return null\n return `Imported to this computer, not to ${activeHost.name}: the sessions show in this computer's session list.`\n}\n\n/**\n * Import Claude Code data from THIS machine into THIS machine: `store` must\n * be the local session store (never a remote host's), MCP servers, skills,\n * commands and subagents go to this machine's `.zidane` files. Pass `activeHost` (the\n * window's host) to get the remote-host note in `notes`.\n */\nexport async function importFromClaudeCode(\n store: SessionStore,\n opts: ClaudeImportOptions & { sessions?: boolean, mcps?: boolean, skills?: boolean, commands?: boolean, agents?: boolean, activeHost?: ClaudeImportActiveHost | null } = {},\n): Promise<ClaudeImportSummary> {\n const hostNote = claudeImportHostNote(opts.activeHost)\n const summary: ClaudeImportSummary = {\n target: 'this-computer',\n notes: [\n ...(hostNote ? [hostNote] : []),\n 'CLAUDE.md is read natively, nothing to import.',\n 'Claude permissions/hooks/plugins have no zidane equivalent, not imported.',\n ],\n }\n if (opts.sessions !== false)\n summary.sessions = await importClaudeSessions(store, opts)\n if (opts.mcps !== false)\n summary.mcps = importClaudeMcps(opts)\n if (opts.skills !== false)\n summary.skills = importClaudeSkills(opts)\n if (opts.commands !== false)\n summary.commands = importClaudeMarkdownDefs('commands', opts)\n if (opts.agents !== false)\n summary.agents = importClaudeMarkdownDefs('agents', opts)\n return summary\n}\n","/**\n * Prompt autocompletion framework — React hook.\n *\n * The provider contract types + pure span/reference helpers live in\n * `./completion-core` (node-free + react-free, re-exported here for\n * back-compat). This module adds the `useCompletion()` React hook on top.\n *\n * The TUI consumes `useCompletion()` to drive a popover above the textarea.\n * A GUI consumes the same hook to drive a dropdown. The popup component\n * itself only reads `label` + `description` on each item, so provider-\n * specific typing (`TItem`) stays at the registration boundary and never\n * leaks into the renderer.\n */\n\nimport type {\n ActiveTrigger,\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n} from './completion-core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { applyInsert, collectReferences, findActiveTriggers, mergeSuggestions } from './completion-core'\n\nexport type {\n ActiveTrigger,\n CompletionContext,\n CompletionItem,\n CompletionProvider,\n CompletionReference,\n CompletionSubmitContext,\n} from './completion-core'\nexport { applyInsert, collectReferences, findActiveTrigger, findActiveTriggers, mergeReferences, mergeSuggestions, resolveCompletionSubmit } from './completion-core'\n\n/**\n * Shared sentinel returned by `useCompletion` when no references are\n * present in the buffer. Stable identity lets consumers' `useEffect`\n * dep arrays bail out on chip-less keystrokes — see `useChipHighlights`.\n */\nconst EMPTY_REFS: readonly CompletionReference<unknown>[] = Object.freeze([])\n\n// ---------------------------------------------------------------------------\n// React hook\n// ---------------------------------------------------------------------------\n\n/** State surface returned by `useCompletion()`. */\nexport interface CompletionState<TItem = unknown> {\n /** Active trigger, or null when the cursor doesn't sit in a completable span. */\n active: ActiveTrigger<TItem> | null\n /** Items for the active query. Empty when no trigger is active. */\n items: readonly CompletionItem<TItem>[]\n /** True while the provider's `suggest` promise is pending. */\n loading: boolean\n /** Index of the highlighted item inside `items`. */\n selectedIndex: number\n /** Move the highlight. Wraps at the ends. No-op when `items` is empty. */\n selectNext: () => void\n selectPrev: () => void\n /**\n * Commit the highlighted item. Returns the new text + cursor pair, or\n * `null` when there's nothing to commit (no active trigger, empty list).\n */\n commit: () => { text: string, cursor: number } | null\n /** Force-close the popover until the user types again. */\n dismiss: () => void\n /** All references in the current buffer, regardless of provider. */\n references: readonly CompletionReference<TItem>[]\n}\n\n/**\n * Drive a prompt-completion popover from React state.\n *\n * Inputs are pull-style — the caller owns `text` + `cursor` (typically\n * mirroring an `OpenTUI TextareaRenderable` or a `<textarea>` element) and\n * passes them in each render. Providers are matched by their `trigger`\n * character; the engine picks at most one active provider per cursor\n * position.\n *\n * Asynchronous suggest calls are aborted when the query changes or the\n * popover closes, so providers that hit a backend don't leak.\n */\nexport function useCompletion<TItem = unknown>(\n input: { text: string, cursor: number },\n providers: readonly CompletionProvider<TItem>[],\n options: { maxQueryLength?: number } = {},\n): CompletionState<TItem> {\n const { text, cursor } = input\n // Destructure primitives up front so the `useMemo` dep array reads them\n // by value (not by `options` reference, which is a fresh object literal\n // on every call from most hosts).\n const { maxQueryLength } = options\n // `dismissed` is keyed by the trigger's `span.start` — the buffer\n // position of the `@` / `/` glyph that opened the popover. Staying\n // dismissed *while the user keeps typing into the same trigger span*\n // is the whole point of Esc; a stricter `${text.length}:${cursor}`\n // key re-opened on the very next keystroke, which made the \"esc\n // dismiss\" hint a lie. The effect below resets this when the trigger\n // goes away entirely (user backspaced past `@`) so retyping `@` at\n // the same position works.\n const [dismissedTriggerStart, setDismissedTriggerStart] = useState<number | null>(null)\n\n const rawTrigger = useMemo(\n () => findActiveTriggers(text, cursor, providers, { maxQueryLength }),\n [text, cursor, providers, maxQueryLength],\n )\n\n const activeMulti = useMemo(() => {\n if (!rawTrigger)\n return null\n if (rawTrigger.span.start === dismissedTriggerStart)\n return null\n return rawTrigger\n }, [rawTrigger, dismissedTriggerStart])\n\n // `active` stays a single-provider ActiveTrigger (first bound provider) so\n // the popup's title/commit contract is unchanged; multi-provider merging\n // happens in the suggest effect below and surfaces as `item.section`.\n const active = useMemo<ActiveTrigger<TItem> | null>(\n () => activeMulti\n ? { provider: activeMulti.providers[0], query: activeMulti.query, span: activeMulti.span }\n : null,\n [activeMulti],\n )\n\n // Forget the dismissal once the trigger disappears — otherwise a\n // fresh `@` typed at the same byte position would inherit the prior\n // dismiss and the popover would never come back without scrolling\n // the trigger elsewhere first.\n useEffect(() => {\n if (!rawTrigger)\n setDismissedTriggerStart(null)\n }, [rawTrigger])\n\n const [items, setItems] = useState<readonly CompletionItem<TItem>[]>([])\n const [loading, setLoading] = useState(false)\n const [selectedIndex, setSelectedIndex] = useState(0)\n\n // Cancel any in-flight suggest when the query changes / popover closes.\n const abortRef = useRef<AbortController | null>(null)\n\n useEffect(() => {\n abortRef.current?.abort()\n if (!activeMulti) {\n setItems([])\n setLoading(false)\n setSelectedIndex(0)\n return\n }\n const controller = new AbortController()\n abortRef.current = controller\n const ctx: CompletionContext = { text, cursor }\n let cancelled = false\n const outs = activeMulti.providers.map(provider => ({\n provider,\n out: provider.suggest(activeMulti.query, ctx, controller.signal),\n }))\n // Sync fast path — every provider returned synchronously (the common\n // single-provider case, e.g. `@` files). Merge without a loading flash.\n if (outs.every(o => Array.isArray(o.out))) {\n setItems(mergeSuggestions(outs.map(o => ({ provider: o.provider, items: o.out as CompletionItem<TItem>[] })), activeMulti.providers.length))\n setSelectedIndex(0)\n setLoading(false)\n return\n }\n setLoading(true)\n // allSettled, not all: with several providers on one trigger, a single\n // provider whose async suggest rejects (e.g. a failed catalog scan) must\n // not blank its siblings' results. Fulfilled groups merge; rejected ones\n // are dropped. (All rejecting → empty items, matching the old behavior.)\n void Promise.allSettled(outs.map(async o => ({ provider: o.provider, items: await o.out }))).then(\n (results) => {\n if (cancelled)\n return\n setItems(mergeSuggestions(results.flatMap(r => r.status === 'fulfilled' ? [r.value] : []), activeMulti.providers.length))\n setSelectedIndex(0)\n setLoading(false)\n },\n )\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [activeMulti, text, cursor])\n\n // References don't depend on `cursor` — both built-in providers ignore\n // `ctx.cursor` in `parseReferences`, and the consumers (chip highlighting,\n // submit-time activation) only care about positions of references, not\n // about where the caret happens to sit. Dropping `cursor` from the dep\n // array avoids re-walking every provider regex on each arrow-key press.\n // `cursor` is still forwarded so a future provider that wants the cursor\n // can opt in — at the cost of choosing its own memoization strategy.\n //\n // Empty results collapse to a shared `EMPTY_REFS` constant so the prompt\n // textarea's `useChipHighlights` effect doesn't fire on every keystroke\n // of a chip-less buffer (each keystroke would otherwise allocate a fresh\n // `[]`, change identity, and trigger a `clearAllHighlights` repaint).\n const references = useMemo(\n () => {\n const refs = collectReferences(text, providers, cursor)\n return refs.length === 0 ? (EMPTY_REFS as readonly CompletionReference<TItem>[]) : refs\n },\n [text, providers],\n )\n\n const selectNext = useCallback(() => {\n setSelectedIndex(i => (items.length === 0 ? 0 : (i + 1) % items.length))\n }, [items.length])\n const selectPrev = useCallback(() => {\n setSelectedIndex(i => (items.length === 0 ? 0 : (i - 1 + items.length) % items.length))\n }, [items.length])\n const dismiss = useCallback(() => {\n // Pull from `rawTrigger`, not `active`, so dismiss-while-dismissed\n // (a no-op now but reasonable to support) keeps the right anchor.\n if (rawTrigger)\n setDismissedTriggerStart(rawTrigger.span.start)\n }, [rawTrigger])\n const commit = useCallback((): { text: string, cursor: number } | null => {\n if (!active || items.length === 0)\n return null\n const item = items[Math.min(selectedIndex, items.length - 1)]\n return applyInsert(text, active.span, item.insertText)\n }, [active, items, selectedIndex, text])\n\n // Memoize the returned bag so consumers placing it in a `useEffect`\n // dep array don't observe a fresh reference every render. Same pattern\n // (and rationale) as `useStreamBuffer.return` — see streaming.ts.\n return useMemo<CompletionState<TItem>>(\n () => ({ active, items, loading, selectedIndex, selectNext, selectPrev, commit, dismiss, references }),\n [active, items, loading, selectedIndex, selectNext, selectPrev, commit, dismiss, references],\n )\n}\n","/**\n * Completion provider for session artifacts. Trigger: `#` (shared with the\n * chats provider — the renderer groups both under one popup).\n *\n * `#pr` → \"acme/widgets#42 · open\" → inserts the PR URL. Unlike chats there\n * is no token grammar: the inserted text IS the locator (URL, `git:…`,\n * path), which the model can act on directly and a human can read. No\n * `parseReferences` — a pasted URL is not a reference to resolve.\n *\n * Catalog getter is host-owned and sync; the host keeps it fresh off the\n * `artifact:recorded` / `artifact:changed` signals the same way it keeps\n * the chats catalog. `ensureCatalog` covers the cold first `#` keystroke.\n */\n\nimport type { ExtensionArtifactRow } from '../extensions/types'\nimport type { SessionArtifact } from '../session/artifacts'\nimport type { CompletionItem, CompletionProvider } from './completion-core'\nimport { Fzf } from 'fzf'\nimport { ageString } from './format'\n\nexport const ARTIFACTS_COMPLETION_PROVIDER_ID = 'artifacts'\n\nexport interface ArtifactReferenceEntry {\n artifact: SessionArtifact\n /** Pre-rendered row (`renderArtifactRow`) — kind registry stays host-side. */\n row: ExtensionArtifactRow\n /** Human kind label for the description (`Pull request`). */\n kindLabel: string\n}\n\nexport interface ArtifactReferenceData {\n entry: ArtifactReferenceEntry\n /** What gets inserted: `row.href` when present, else the raw `uri`. */\n locator: string\n}\n\nconst DEFAULT_RESULT_LIMIT = 30\n\n/** Kind → short query aliases so `#pr` and `#branch` hit without typing the label. */\nconst KIND_ALIASES: Record<string, readonly string[]> = {\n pull_request: ['pr', 'pull', 'mr'],\n branch: ['branch', 'br'],\n commit: ['commit', 'sha'],\n file: ['file', 'path'],\n}\n\nfunction locatorFor(entry: ArtifactReferenceEntry): string {\n return entry.row.href ?? entry.artifact.uri\n}\n\nfunction haystack(entry: ArtifactReferenceEntry): string {\n const aliases = KIND_ALIASES[entry.artifact.kind] ?? [entry.artifact.kind]\n return [entry.row.title, entry.row.subtitle ?? '', entry.artifact.label, entry.kindLabel, ...aliases].join(' ')\n}\n\nfunction descriptionFor(entry: ArtifactReferenceEntry): string {\n const bits = [entry.kindLabel]\n if (entry.row.status)\n bits.push(entry.row.status)\n bits.push(ageString(entry.artifact.updatedAt))\n const loc = locatorFor(entry)\n if (loc !== entry.row.title)\n bits.push(loc)\n return bits.join(' · ')\n}\n\nexport function scoreArtifacts(\n catalog: readonly ArtifactReferenceEntry[],\n query: string,\n limit = DEFAULT_RESULT_LIMIT,\n): CompletionItem<ArtifactReferenceData>[] {\n const q = query.trim().toLowerCase()\n const fuzzy = q.length > 0\n ? new Set(new Fzf(catalog, { selector: haystack, casing: 'case-insensitive' }).find(q).map(r => r.item))\n : null\n const scored: { entry: ArtifactReferenceEntry, rank: number }[] = []\n for (const entry of catalog) {\n if (q.length === 0) {\n scored.push({ entry, rank: 5 })\n continue\n }\n const title = entry.row.title.toLowerCase()\n const aliases = (KIND_ALIASES[entry.artifact.kind] ?? [entry.artifact.kind]).map(a => a.toLowerCase())\n const kindLabel = entry.kindLabel.toLowerCase()\n if (aliases.some(a => a === q || a.startsWith(q)) || kindLabel.startsWith(q)) {\n scored.push({ entry, rank: 0 })\n continue\n }\n if (title.startsWith(q)) {\n scored.push({ entry, rank: 1 })\n continue\n }\n if (title.includes(q) || locatorFor(entry).toLowerCase().includes(q)) {\n scored.push({ entry, rank: 2 })\n continue\n }\n if (fuzzy?.has(entry))\n scored.push({ entry, rank: 4 })\n }\n scored.sort((a, b) => a.rank - b.rank || b.entry.artifact.updatedAt - a.entry.artifact.updatedAt)\n return scored.slice(0, limit).map<CompletionItem<ArtifactReferenceData>>(({ entry }) => {\n const locator = locatorFor(entry)\n return {\n id: `artifact:${entry.artifact.id}`,\n label: entry.row.title,\n description: descriptionFor(entry),\n insertText: `${locator} `,\n data: { entry, locator },\n }\n })\n}\n\nexport function createArtifactsCompletionProvider(opts: {\n getCatalog: () => readonly ArtifactReferenceEntry[]\n ensureCatalog?: () => Promise<readonly ArtifactReferenceEntry[]>\n limit?: number\n}): CompletionProvider<ArtifactReferenceData> {\n const limit = opts.limit ?? DEFAULT_RESULT_LIMIT\n return {\n id: ARTIFACTS_COMPLETION_PROVIDER_ID,\n trigger: '#',\n label: 'Artifacts',\n suggest(query) {\n const current = opts.getCatalog()\n if (current.length > 0 || !opts.ensureCatalog)\n return scoreArtifacts(current, query, limit)\n return opts.ensureCatalog().then(loaded => scoreArtifacts(loaded, query, limit))\n },\n // Inserted text is a plain locator, not a token: nothing to parse back.\n parseReferences: () => [],\n }\n}\n","/**\n * User-level config at `~/.{prefix}/config.json`. Holds global flags\n * that need to persist across projects — distinct from `state.json`\n * which can live PER-PROJECT under `<git-root>/.{prefix}/`.\n *\n * Single field today (`projectDb` opt-out); easy to grow without\n * threading every new flag through `runTui()`'s call site.\n *\n * Tolerant on disk errors: missing file → empty config (defaults\n * apply), malformed JSON → empty config (logged under `ZIDANE_DEBUG`).\n * Never throws on read — the host's bootstrap path can't afford it.\n */\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { errorMessage } from '../errors'\n\nexport interface UserConfig {\n /**\n * Master switch for project-scoped storage. Off by default; when set\n * to `true`, launching inside a git repo auto-creates\n * `<git-root>/.{prefix}/` and stores `sessions.db` + `state.json`\n * there. When absent or `false`, everything stays at the user level\n * (`~/.{prefix}/`) regardless of git presence — the classic\n * single-store behavior. Overridden by `ZIDANE_PROJECT_DB` and the\n * host's `ChatOptions.projectDb` (see `resolveStoragePaths`).\n */\n projectDb?: boolean\n}\n\n/**\n * Build the absolute path to `~/.{prefix}/config.json` given a user\n * directory (`<storageDir>/<prefix>`). Exported so callers debugging a\n * \"why isn't my override taking effect?\" can print the resolved path.\n */\nexport function userConfigPath(userDir: string): string {\n return resolve(userDir, 'config.json')\n}\n\n/**\n * Read + parse the user config file. Returns an empty config (defaults\n * apply) on any failure — the function never throws. Set `ZIDANE_DEBUG`\n * to surface parse failures to stderr.\n */\nexport function loadUserConfig(userDir: string): UserConfig {\n const path = userConfigPath(userDir)\n if (!existsSync(path))\n return {}\n try {\n const raw = readFileSync(path, 'utf8')\n const parsed = JSON.parse(raw)\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))\n return {}\n return normalizeUserConfig(parsed as Record<string, unknown>)\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] user-config: failed to read \"${path}\": ${errorMessage(err)}\\n`)\n return {}\n }\n}\n\n/**\n * Narrow an arbitrary JSON object to the `UserConfig` shape. Drops\n * unknown keys (so a future zidane version's config field doesn't\n * leak into the typed surface) and validates types per-field.\n */\nfunction normalizeUserConfig(raw: Record<string, unknown>): UserConfig {\n const out: UserConfig = {}\n if (typeof raw.projectDb === 'boolean')\n out.projectDb = raw.projectDb\n return out\n}\n","import type { ExtensionConfigCategory, ExtensionRegistry, StoredExtensionConfigItem } from '../extensions'\nimport type { Preset } from '../presets'\nimport type { Provider } from '../providers'\nimport type { SessionStore } from '../session'\nimport type { StartLocalOptions } from '../start/shared-options'\nimport type { SubagentOverride, SubagentRegistry } from '../tools'\nimport type { AgentRegistry } from './agents'\nimport type { ProviderAuth, ProviderKey } from './auth'\nimport type { KeyBindings, ResolvedExtensionKeybinding } from './keybindings'\nimport type { ModelInfo, ProviderDescriptor } from './providers'\nimport type { StateStoreApi, TuiState } from './store'\nimport type { Picked, Settings } from './types'\nimport type { StorageMode } from './xdg'\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { resolve } from 'node:path'\nimport { errorMessage } from '../errors'\nimport { buildExtensionPreset, EMPTY_EXTENSION_REGISTRY } from '../extensions'\nimport { migrateSessionArtifactDirs } from '../loop-persistence'\nimport { BUILTIN_AGENTS, DEFAULT_AGENT_ID, resolveAgentId, singleAgentRegistry } from './agents'\nimport { detectAuth } from './auth'\nimport { applyApiKeyEnv, credentialsPath } from './credentials'\nimport { mergeKeybindings, readKeybindingsRaw, resolveExtensionKeybindings } from './keybindings'\nimport { restoreChainFallbacks } from './model-chain'\nimport { findProjectRoot } from './project-root'\nimport { BUILTIN_PROVIDERS, modelsForDescriptor, modelSupportsReasoning, restoreModelOptions } from './providers'\nimport { createStateStore } from './store'\nimport { loadUserConfig } from './user-config'\nimport { resolveStorageDirs } from './xdg'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** Re-exported for callers who want `ModelInfo` from the same module as `ChatOptions`. */\nexport type { ModelInfo }\n\n/**\n * Provider registry — a map keyed by `descriptor.key`. Passed verbatim to the\n * chat engine; there is no implicit merge with built-ins. Hosts that want the\n * four default providers spread {@link BUILTIN_PROVIDERS}; hosts that only\n * want their own pass exactly their own.\n */\nexport type ProviderRegistry = Readonly<Record<string, ProviderDescriptor>>\n\n/**\n * Options accepted by `resolveConfig()` (and, transitively, by `runTui()` and\n * any future GUI launcher). Every field is optional — defaults boot a working\n * chat against the built-in providers with sessions stored under `~/.zidane/`.\n */\nexport interface ChatOptions {\n /**\n * Directory name used under `storageDir` for sessions + state.\n * Default: `'.zidane'` → `~/.zidane/sessions.db` + `~/.zidane/state.json`.\n * Pass e.g. `'.myapp'` for `~/.myapp/...`, or `'myapp'` for a visible dir.\n */\n prefix?: string\n /**\n * Storage root. Defaults to the user's home directory. Combined with\n * `prefix` to form the data directory.\n */\n storageDir?: string\n /**\n * Provider registry. Each value is a {@link ProviderDescriptor} carrying\n * label + factory + credential metadata. **No automatic merge** — hosts\n * pass exactly what they want.\n *\n * - Omitted → {@link BUILTIN_PROVIDERS} (anthropic + openai + openrouter + cerebras).\n * - `providers: BUILTIN_PROVIDERS` → same as omitted, but explicit.\n * - `providers: { anthropic: anthropicDescriptor }` → only Anthropic.\n * - `providers: { ...BUILTIN_PROVIDERS, mine: customDescriptor }` → built-ins + custom.\n * - `providers: { mine: customDescriptor }` → custom-only, **no built-ins**.\n */\n providers?: ProviderRegistry\n /**\n * Legacy single-agent preset (tools, system prompt, behavior). When set\n * **without** {@link ChatOptions.agents}, the resolver wraps this preset\n * into a one-entry {@link AgentRegistry} keyed `default` so existing\n * callers keep working and the picker is effectively hidden.\n *\n * Prefer `agents` for any multi-profile setup. Passing both throws.\n */\n preset?: Preset\n /**\n * Agent profile registry — keyed by `profile.id`. Each profile bundles a\n * preset with display metadata (label, description, accent). The TUI\n * shows a picker (Ctrl+A) when more than one profile is registered.\n *\n * - Omitted (and `preset` omitted) → {@link BUILTIN_AGENTS} (Build + Plan).\n * - Omitted but `preset` provided → single-entry registry around the preset.\n * - Provided → host owns the registry; pass exactly what you want.\n *\n * Hosts mixing built-ins with their own typically spread:\n * `agents: { ...BUILTIN_AGENTS, debug: myDebugProfile }`.\n */\n agents?: AgentRegistry\n /**\n * Id of the profile every fresh session (and the initial launch) starts\n * in. Resolved against `agents`; unknown ids fall through to\n * `DEFAULT_AGENT_ID`, then the registry's first key. Sessions remember\n * the profile they were created with; this is never overridden by a\n * previously picked profile.\n */\n defaultAgent?: string\n /**\n * Session store — either an instance or a factory called with the\n * resolved storage paths. **Required** at the chat layer so this module\n * stays platform-agnostic (no `bun:sqlite` baked in). Terminal hosts use\n * `createTuiStore` from `zidane/session/sqlite`; a future GUI host can\n * supply a different adapter (IndexedDB, remote API, in-memory) without\n * touching this layer.\n *\n * ```ts\n * import { createTuiStore } from 'zidane/session/sqlite'\n *\n * // Either pass a factory…\n * resolveConfig({ store: paths => createTuiStore(paths.db) })\n *\n * // …or an instance built ahead of time.\n * const store = createTuiStore('/path/to/sessions.db')\n * resolveConfig({ store })\n * ```\n */\n store: SessionStore | ((paths: ResolvedPaths) => SessionStore)\n /**\n * Project-scoped session storage. Off by default; when it resolves\n * to `true` and the launch happens inside a git repo, zidane\n * auto-creates `<git-root>/.{prefix}/` and stores `sessions.db` +\n * `state.json` there — so sessions, mcps.json, and skills all live\n * alongside the project they belong to. Credentials and the\n * cross-project safelist stay at `~/.{prefix}/` regardless.\n *\n * Precedence (most → least specific): `options.projectDb` >\n * `ZIDANE_PROJECT_DB` env var (`0`/`false`/`off`/`no` → off,\n * `1`/`true`/`on`/`yes` → on) > `~/.{prefix}/config.json`\n * `projectDb` > `false`. Note the host option beats the env var —\n * setting `ZIDANE_PROJECT_DB` has no effect when the host passes an\n * explicit `projectDb`.\n *\n * When it resolves to `false`, OR when not inside a git repo,\n * everything lives at `~/.{prefix}/` — the classic single-store\n * layout.\n */\n projectDb?: boolean\n /**\n * Override for the project root. Defaults to `process.cwd()`. Hosts\n * embedding the TUI from a non-CLI context (tests, daemons) can pin\n * the cwd here so the git-root walk produces a stable result. Has no\n * effect when `projectDb` resolves to `false`.\n */\n cwd?: string\n /**\n * Optional one-shot launch request used by CLI shells such as `zidane run`.\n * The TUI opens/creates the requested session and submits the prompt after\n * the first provider/session activation, while keeping the normal renderer\n * and persistence behavior.\n */\n launch?: StartLocalOptions\n /**\n * Auto-update wiring. When set, the App quietly checks the npm registry\n * for a newer release of `packageName` (matching the host's package),\n * caches the result for a day under `userDir/`, and surfaces a passive\n * `↑ vX.Y.Z` chip in the footer when one is available.\n *\n * Consumers wrapping `runTui` for their own CLI inline their own\n * `package.json` version at build time and pass it here. The bundled\n * `zidane-tui` binary wires this automatically in `tui/src/cli.ts`.\n *\n * Defaults to `null` — no auto-update plumbing, no network calls,\n * no chip.\n */\n autoUpdate?: AutoUpdateConfig | null\n /**\n * Pre-built {@link ExtensionRegistry}. The `resolveConfig` surface is\n * synchronous; extension `setup()` can be async, so the host must\n * build the registry ahead of time and pass it here verbatim.\n *\n * Typical wiring (matches `runTui`):\n *\n * ```ts\n * import {\n * buildExtensionRegistry,\n * discoverExtensions,\n * inlineLoadedExtension,\n * resolveConfig,\n * } from 'zidane'\n *\n * const registry = await buildExtensionRegistry([\n * // Project-scoped extensions run arbitrary local code — they stay\n * // off unless the host establishes trust explicitly (or the user\n * // sets ZIDANE_TRUST_PROJECT_EXTENSIONS=1).\n * ...await discoverExtensions({ cwd, prefix, trustProjectExtensions: hostTrustsProject }),\n * ...inlineDefinitions.map(inlineLoadedExtension),\n * ])\n * const config = resolveConfig({ ...opts, extensionRegistry: registry })\n * ```\n *\n * Omitted → empty registry (no contributions).\n */\n extensionRegistry?: ExtensionRegistry\n /**\n * Extra extension scan roots the host used (or wants runtime re-discovery\n * to use). Each path is a root containing extension dirs/packages:\n * `<root>/<name>/index.ts`. `runTui` wires this from\n * `ZIDANE_EXTENSION_DIRS` when omitted.\n */\n extensionScanPaths?: readonly string[]\n /**\n * Extra Agent Plugin scan roots. Each path is a root containing plugin\n * directories: `<root>/<name>/plugin.json`. `runTui` wires this from\n * `ZIDANE_PLUGIN_DIRS` when omitted.\n *\n * Appended after the four default roots, so a project or user plugin still\n * wins a name collision against a dev root.\n */\n pluginScanPaths?: readonly string[]\n /**\n * Whether project-scoped extensions are trusted to run their (arbitrary,\n * local) code. Off by default unless the embedding host has established\n * project trust; falls back to `ZIDANE_TRUST_PROJECT_EXTENSIONS=1`.\n *\n * Surfaced on {@link ResolvedConfig.trustProjectExtensions} so a host\n * that re-discovers extensions at runtime (e.g. the TUI on a working-\n * directory change) reuses the same trust decision as boot.\n */\n trustProjectExtensions?: boolean\n}\n\n/**\n * Host-supplied auto-update settings. The check itself is gated on\n * `Settings.checkForUpdates`; passing a config wires the React plumbing.\n *\n * Hosts that want to publish their own consumer-facing package can pass\n * different values without forking anything — the registry / channel /\n * platform-package-prefix are all knobs.\n */\nexport interface AutoUpdateConfig {\n /** Top-level npm package the user installs (`zidane-tui`, `my-app`, …). */\n packageName: string\n /** Inlined at build time — usually `pkg.version`. */\n currentVersion: string\n /** dist-tag. Defaults to `'latest'`. */\n channel?: string\n /** Registry base URL. Defaults to `'https://registry.npmjs.org'`. */\n registry?: string\n /**\n * Override the read-through cache lifetime in ms for the in-TUI hook.\n * Defaults to `0` — every TUI launch fetches fresh, so the chip\n * never lies. Pass a positive value (e.g. `3_600_000` for 1 h) to\n * throttle the registry-poll rate at the cost of staleness.\n *\n * The on-disk cache is always WRITTEN, regardless of this value, so\n * `zidane upgrade` and other tooling read paths benefit immediately.\n */\n cacheTtlMs?: number\n /**\n * Platform-package prefix used by the in-place self-update flow when\n * resolving the per-arch tarball name. Defaults to `'<packageName>-'`\n * (i.e. `zidane-tui-darwin-arm64` when `packageName === 'zidane-tui'`).\n * Override only when your platform packages don't follow the `<name>-<key>`\n * convention.\n */\n platformPackagePrefix?: string\n /**\n * Executable name on PATH for `packageName`, used to probe the version\n * installed on disk (the `↻ vX` \"restart to update\" chip). Defaults to\n * `packageName`; the TUI passes `'zidane'` for `zidane-tui`.\n */\n binName?: string\n}\n\n/** Resolved on-disk layout produced by {@link resolveConfig}. */\nexport interface ResolvedPaths {\n /**\n * Effective data root — equals `userDir` (configDir) when project\n * mode is off, `projectDir` when it's on. Kept for callers that\n * wrote against the pre-project-db API; new code should reference\n * the explicit slots (`configDir` / `dataDir` / `cacheDir` /\n * `stateDir`) or `projectDir` / `db` / `state` instead.\n */\n dir: string\n /**\n * User-scoped config root — credentials, mcp-credentials, keybindings,\n * `config.json`, `mcps.json`, skills. Legacy alias for `configDir`;\n * existing call sites still reference `userDir`. In XDG mode this\n * lands at `$XDG_CONFIG_HOME/zidane`; in legacy mode the four slots\n * (config / data / state / cache) collapse to a single\n * `<storageDir>/<prefix>` directory.\n */\n userDir: string\n /**\n * Project-scoped data root. Set to `<git-root>/<prefix>` when project\n * mode resolved to ON and a git root was found. `null` otherwise.\n */\n projectDir: string | null\n /** Resolved `sessions.db` path. Lives under `projectDir` when active, else `dataDir`. */\n db: string\n /** Resolved `state.json` path. Lives under `projectDir` when active, else `stateDir`. */\n state: string\n /**\n * XDG config slot — `$XDG_CONFIG_HOME/zidane` on a fresh Linux install,\n * `<storageDir>/<prefix>` (e.g. `~/.zidane/`) in legacy mode. Holds\n * user-editable surface (`credentials.json`, `mcps.json`, …).\n */\n configDir: string\n /**\n * XDG data slot — `$XDG_DATA_HOME/zidane` on Linux, single-dir\n * elsewhere. Holds long-lived chat history (`sessions.db`).\n */\n dataDir: string\n /**\n * XDG state slot — `$XDG_STATE_HOME/zidane` on Linux, single-dir\n * elsewhere. Holds per-machine UI bookkeeping (`state.json`).\n */\n stateDir: string\n /**\n * XDG cache slot — `$XDG_CACHE_HOME/zidane` on Linux, single-dir\n * elsewhere. Holds regenerable data: persisted tool results,\n * background-task logs, auto-update registry cache.\n */\n cacheDir: string\n /**\n * Which resolution branch produced the layout. `'xdg'` when split\n * across the four XDG dirs; one of `'legacy-explicit'`,\n * `'legacy-existing'`, or `'default'` when the slots collapse to a\n * single directory. Surfaced for diagnostics + tests.\n */\n storageMode: StorageMode\n}\n\n// ---------------------------------------------------------------------------\n// Resolved config\n// ---------------------------------------------------------------------------\n\nexport interface ResolvedConfig {\n prefix: string\n storageDir: string\n paths: ResolvedPaths\n providers: ProviderRegistry\n /**\n * Resolved profile registry. Always non-empty; the resolver throws when\n * the host passes an empty `agents` map (same contract as `providers`).\n */\n agents: AgentRegistry\n /** Id of the profile to activate on mount. Guaranteed to key into `agents`. */\n initialAgentId: string\n store: SessionStore\n stateStore: StateStoreApi\n /** Lookup by `ProviderKey` returning the available models for the picker. */\n modelsFor: (key: ProviderKey) => readonly ModelInfo[]\n initialState: TuiState\n initialSettings: Partial<Settings>\n resumeProvider: ProviderAuth | null\n initialPicked: Picked | null\n /**\n * Effective keybindings — defaults merged with the user-level\n * `<userDir>/keybindings.json` (when present). Always fully-resolved\n * so consumers can treat the record as total. See `./keybindings.ts`\n * for the action catalog + spec format.\n */\n keybindings: KeyBindings\n /**\n * Resolved extension-contributed keybindings. Each entry pairs the\n * extension's binding definition with the user's effective spec\n * (override from `keybindings.json` when present, default\n * otherwise). The TUI dispatcher iterates these alongside the\n * built-in action catalog; the GUI host can do the same.\n *\n * Empty when no extension contributed a keybinding.\n */\n extensionKeybindings: readonly ResolvedExtensionKeybinding[]\n /**\n * Resolved auto-update knobs (forwarded verbatim from `ChatOptions.autoUpdate`)\n * — `null` when the host didn't wire one. The TUI feeds this into\n * `useUpdateCheck` so the footer chip + the `zidane upgrade` subcommand\n * share a single source of truth.\n */\n autoUpdate: AutoUpdateConfig | null\n /**\n * Merged extension contributions — the registry passed via\n * {@link ChatOptions.extensionRegistry}, returned verbatim, or\n * {@link EMPTY_EXTENSION_REGISTRY} when the host didn't pass one.\n * `resolveConfig` is synchronous, so it never runs `setup()` itself;\n * the host pre-builds the registry with `buildExtensionRegistry`.\n *\n * Renderer-side wiring reads `tuiContributions` / `guiContributions`\n * to mount keybindings / footer hints / modals / panels. The\n * `extensionPreset` field below carries the agent-side surface\n * (tools / hooks / mcpServers / skills) ready to spread.\n */\n extensions: ExtensionRegistry\n /**\n * Extra extension scan roots used at boot. Runtime re-discovery (TUI cwd\n * changes, future hosts) feeds these back into the shared discovery helper so\n * local/dev package roots stay active after the initial launch.\n */\n extensionScanPaths: readonly string[]\n /**\n * Extra Agent Plugin scan roots used at boot. Threaded into the discovery\n * shell so a dev root stays active across project/cwd changes, same as\n * {@link ResolvedConfig.extensionScanPaths}.\n */\n pluginScanPaths: readonly string[]\n /**\n * Single {@link Preset} folded together from every extension's\n * agent-side contributions. Hosts spread it into `createAgent()`\n * alongside the active profile's preset:\n *\n * ```ts\n * const profile = composePresets(extensionPreset, agentProfile.preset)\n * const agent = createAgent({ ...profile, provider })\n * ```\n *\n * Extension hooks are bucketed per event so every handler fires;\n * tools and mcpServers compose with profile contributions via the\n * usual `composePresets` rules. System-prompt fragments land as a\n * trailing block on `preset.system` (host profiles that re-derive\n * `system` per session — Build / Plan — append the fragments via\n * the `system:transform` hook so the live system always carries\n * them).\n */\n extensionPreset: Preset\n /**\n * System-prompt fragments contributed by extensions, in registration\n * order. Surfaced separately from {@link extensionPreset} so hosts\n * that re-derive `system` per session (Build / Plan in the TUI) can\n * append them on `system:transform` instead of trying to merge two\n * `preset.system` strings.\n */\n extensionSystemFragments: readonly string[]\n /**\n * Spawnable subagents (adds) contributed by extensions, keyed by name.\n * Surfaced separately from {@link extensionPreset} (like\n * {@link extensionSystemFragments}) because subagents don't ride the\n * preset path — the host merges them onto the spawn tool's base\n * registry via `spawn.withSubagents(...)` at agent build time.\n */\n extensionSubagents: SubagentRegistry\n /**\n * Subagent edits contributed by extensions, keyed by target name and\n * composed in registration order. Applied (after the adds above) by\n * the host's `spawn.withSubagents(...)` call so extensions can edit or\n * delete host- / extension-provided subagents by name.\n */\n extensionSubagentOverrides: Record<string, SubagentOverride>\n /**\n * Merged extension-contributed config categories, keyed by category id.\n * Surfaced (alongside {@link extensionConfigItems}) so the TUI can read\n * the schema in-process — same way it reads `extensions.themes` — and\n * the GUI's `extensions:configSchema` IPC can serialize it.\n */\n extensionConfigCategories: Readonly<Record<string, ExtensionConfigCategory>>\n /**\n * Merged extension-contributed config items, namespaced\n * `extName → itemKey → item`. Each item carries its resolved\n * `category`; values are read default-first via the core resolver.\n */\n extensionConfigItems: Readonly<Record<string, Readonly<Record<string, StoredExtensionConfigItem>>>>\n /**\n * Resolved project-extension trust decision (option + env fallback).\n * Hosts that re-discover extensions at runtime feed this back into\n * {@link discoverAndBuildExtensionRegistry} so the rebuild trusts the\n * same scopes boot did.\n */\n trustProjectExtensions: boolean\n /**\n * Raw user `keybindings.json` object (post-JSONC-strip). Surfaced so a\n * host re-resolving {@link extensionKeybindings} at runtime (after an\n * extension registry rebuild) can reuse the same override source\n * without a second disk read.\n */\n rawKeybindings: Readonly<Record<string, unknown>>\n /** One-shot launch request forwarded from {@link ChatOptions.launch}. */\n launch: StartLocalOptions | null\n}\n\n/**\n * Resolve user options into a fully-bound runtime config.\n *\n * NOT pure: besides disk reads, this mutates `process.env` so the harness\n * providers pick up the chat engine's credential store — it sets\n * `ZIDANE_CREDENTIALS_PATH` and reconciles stored API keys / OAuth entries\n * into env via `applyApiKeyEnv` (which can overwrite or delete ambient keys\n * like `ANTHROPIC_API_KEY`; see its JSDoc for the precedence rationale).\n */\nexport function resolveConfig(options: ChatOptions): ResolvedConfig {\n const prefix = options.prefix ?? process.env.ZIDANE_PREFIX ?? '.zidane'\n // Distinguish \"user pinned storageDir\" (legacy-explicit mode) from\n // \"default behavior\" (let XDG kick in on Linux). Only the explicit\n // value is forwarded to the resolver; `ResolvedConfig.storageDir`\n // below falls back to `homedir()` for display / back-compat callers\n // that read it.\n const explicitStorageDir = options.storageDir ?? process.env.ZIDANE_STORAGE_DIR\n const storageDir = explicitStorageDir ?? homedir()\n const paths = resolveStoragePaths({\n prefix,\n ...(explicitStorageDir !== undefined ? { storageDir: explicitStorageDir } : {}),\n cwd: options.cwd ?? process.cwd(),\n projectDb: options.projectDb,\n })\n\n // Fold older artifact layouts into the session-first\n // `<cacheDir>/sessions/<sessionId>/<kind>/` shape the resolvers now emit —\n // otherwise a long-lived install keeps hundreds of per-session directories at\n // the top level of the storage dir forever. Sync, best-effort, idempotent\n // (see `migrateSessionArtifactDirs`): after the first run it costs one\n // readdir, and a failure can't break the bootstrap.\n const migration = migrateSessionArtifactDirs({ userDir: paths.cacheDir })\n if (process.env.ZIDANE_DEBUG && (migration.moved > 0 || migration.failed > 0)) {\n process.stderr.write(\n `[zidane/chat] session-dir migration: moved ${migration.moved}, removed ${migration.removed}, failed ${migration.failed}\\n`,\n )\n }\n\n // `options.store` is required at the chat layer — the renderer (TUI, GUI)\n // injects an adapter so this module stays free of platform-specific\n // session-storage code. Accepts an instance or a factory; the factory\n // form lets callers wire their adapter to the resolved storage paths\n // without duplicating the prefix/storageDir logic above.\n if (!options.store)\n throw new Error('resolveConfig: `store` is required. Pass a `SessionStore` instance, or a factory. Terminal hosts can use `createTuiStore` from `zidane/session/sqlite`.')\n const store: SessionStore = typeof options.store === 'function'\n ? options.store(paths)\n : options.store\n const stateStore = createStateStore(paths.state)\n const initialState = stateStore.load()\n\n // Extension registry — host pre-builds via `buildExtensionRegistry`\n // (sync `resolveConfig` can't drive async setup itself). `runTui`\n // does this for the terminal flow; SDK / GUI consumers do the same\n // before calling `resolveConfig`.\n const extensions: ExtensionRegistry = options.extensionRegistry ?? EMPTY_EXTENSION_REGISTRY\n\n // No implicit merge — host controls the registry entirely. Default is the\n // four built-ins; an explicit empty `{}` would mean \"no providers\" (the\n // wizard would have nothing to offer and the AuthScreen would refuse).\n // Extensions can contribute providers; host-supplied providers WIN on key\n // collision so an extension can't silently shadow the host's wiring.\n const baseProviders: ProviderRegistry = options.providers ?? BUILTIN_PROVIDERS\n const mergedProviders: ProviderRegistry = Object.keys(extensions.providers).length === 0\n ? baseProviders\n : { ...extensions.providers, ...baseProviders }\n const providers: ProviderRegistry = wrapProvidersWithExtensionMiddleware(mergedProviders, extensions)\n\n // Agent registry resolution. Three paths, mutually exclusive:\n // - `agents` + `preset` both set → throw. The legacy `preset` would\n // get silently ignored otherwise and the host wouldn't notice.\n // - `agents` set → use verbatim (host owns the picker contents).\n // - `preset` set without `agents` → wrap into a single-entry registry\n // so the legacy single-agent path keeps working without code change.\n // - neither set → BUILTIN_AGENTS (Build + Plan).\n if (options.agents && options.preset) {\n throw new Error(\n 'resolveConfig: pass either `preset` (single-agent legacy) or `agents` '\n + '(multi-profile registry), not both. Migrate `preset` into an entry '\n + 'inside `agents` if you want both worlds.',\n )\n }\n const baseAgents: AgentRegistry = options.agents\n ?? (options.preset ? singleAgentRegistry(options.preset) : BUILTIN_AGENTS)\n // Extension-contributed profiles compose under host profiles (host\n // wins on id collision) — same precedence rule as providers above.\n const agents: AgentRegistry = Object.keys(extensions.agents).length === 0\n ? baseAgents\n : { ...extensions.agents, ...baseAgents }\n if (Object.keys(agents).length === 0) {\n throw new Error('resolveConfig: `agents` registry is empty. Add at least one profile.')\n }\n\n // Wire credentials *before* anything that might read them (resume detection,\n // any factory call). Sets `ZIDANE_CREDENTIALS_PATH` so the harness providers\n // find the file the chat engine manages, and injects stored API keys into\n // env so factories that resolve credentials eagerly (like `anthropic()`)\n // see them. Credentials ALWAYS live under `userDir` — they're host-wide\n // secrets, not per-project data, and must never leak into a checked-in\n // project `.{prefix}/` directory.\n process.env.ZIDANE_CREDENTIALS_PATH = credentialsPath(paths.userDir)\n applyApiKeyEnv(paths.userDir, providers)\n\n const modelsFor = makeModelsResolver(providers)\n\n const launchProvider = options.launch\n ? resolveLaunchProvider(options.launch.provider, providers, paths.userDir)\n : null\n const resumeProvider = options.launch\n ? launchProvider\n : resolveResumeProvider(initialState, providers, paths.userDir)\n const initialPicked = launchProvider\n ? pickInitial(launchProvider, providers, initialState, {\n model: options.launch?.model,\n thinking: options.launch?.thinking,\n })\n : resumeProvider\n ? pickInitial(resumeProvider, providers, initialState)\n : null\n\n // The host's `defaultAgent`, then `DEFAULT_AGENT_ID` (= 'build'), then\n // the first registry key. Deliberately NOT `state.lastAgent`: the agent\n // profile is a per-session mode (each session remembers its own), and a\n // fresh launch / fresh chat must always start from the default — an\n // accidental switch into `plan` in one chat should never leak into the\n // next. `lastAgent` is still written by older builds; it is ignored here.\n const initialAgentId = resolveAgentId(\n agents,\n undefined,\n options.defaultAgent ?? DEFAULT_AGENT_ID,\n )\n if (!initialAgentId) {\n // Defensive — the empty-check above already guards, so this is unreachable.\n throw new Error('resolveConfig: failed to resolve an initial agent id from a non-empty registry.')\n }\n\n // Keybindings live at the user level only — shortcut muscle memory\n // is per-user, not per-project. Read the raw JSON file ONCE; the\n // built-in catalog merges via `mergeKeybindings`, extension-side\n // overrides via `resolveExtensionKeybindings`. Without this we'd\n // re-read the same file twice in the resolve path.\n const rawKeybindings = readKeybindingsRaw(paths.userDir)\n const keybindings = mergeKeybindings(rawKeybindings)\n const extensionKeybindings = extensions.tuiContributions.keybindings.length === 0\n ? []\n : resolveExtensionKeybindings(\n extensions.tuiContributions.keybindings,\n rawKeybindings,\n )\n\n return {\n prefix,\n storageDir,\n paths,\n providers,\n agents,\n initialAgentId,\n store,\n stateStore,\n modelsFor,\n initialState,\n initialSettings: migrateLegacySettings(initialState.settings ?? {}),\n resumeProvider,\n initialPicked,\n keybindings,\n extensionKeybindings,\n autoUpdate: options.autoUpdate ?? null,\n extensions,\n extensionScanPaths: options.extensionScanPaths ?? [],\n pluginScanPaths: options.pluginScanPaths ?? [],\n extensionPreset: buildExtensionPreset(extensions),\n extensionSystemFragments: extensions.systemFragments,\n extensionSubagents: extensions.subagents,\n extensionSubagentOverrides: extensions.subagentOverrides,\n extensionConfigCategories: extensions.configCategories,\n extensionConfigItems: extensions.configItems,\n trustProjectExtensions: options.trustProjectExtensions\n ?? (process.env.ZIDANE_TRUST_PROJECT_EXTENSIONS === '1'),\n rawKeybindings,\n launch: options.launch ?? null,\n }\n}\n\n/**\n * Compute the on-disk layout for a single TUI session. Public so hosts\n * (CLI tools, tests, scripted bootstraps) can ask \"where will sessions\n * land?\" without going through `resolveConfig`'s full machinery.\n *\n * Storage-slot resolution (config / data / state / cache) is delegated\n * to {@link resolveStorageDirs}. In legacy modes the four slots collapse\n * to a single `<storageDir>/<prefix>` directory; in XDG mode they fan\n * out into `$XDG_CONFIG_HOME/zidane`, `$XDG_DATA_HOME/zidane`,\n * `$XDG_STATE_HOME/zidane`, `$XDG_CACHE_HOME/zidane`. See the module\n * doc on `./xdg.ts` for the full precedence chain.\n *\n * Decision logic for project mode (least → most specific):\n *\n * 1. Default: OFF — sessions live in the user-scoped `dataDir`\n * and get scoped per-project via the `SessionData.projectRoot` tag.\n * 2. `<configDir>/config.json` `projectDb` flag (when present).\n * 3. `ZIDANE_PROJECT_DB` env var (`'0'` / `'false'` / `'off'` → off,\n * anything else true if set).\n * 4. `options.projectDb` (host call site).\n *\n * Project mode activates only when the resolution above lands on\n * `true` AND a git repo is found above `cwd`. Outside git or with the\n * flag off, sessions + state stay at the user-scoped slots.\n *\n * Auto-creates the project `.{prefix}/` directory when mode resolves\n * to ON (silent — mirrors `ensureStateDir`). User slots are created\n * lazily by the state-store + credentials writers; we don't pre-touch\n * them here so a read-only invocation stays read-only.\n */\nexport function resolveStoragePaths(opts: {\n prefix: string\n /** Explicit storage root. When set, forces legacy-explicit mode. */\n storageDir?: string\n cwd: string\n /** Host override for project mode. Beats the user-config + env-var sources. */\n projectDb?: boolean\n}): ResolvedPaths {\n const dirs = resolveStorageDirs({\n prefix: opts.prefix,\n ...(opts.storageDir !== undefined ? { storageDir: opts.storageDir } : {}),\n })\n\n // User-config + env-var are loaded eagerly so the precedence chain\n // is observable from a single call to this function; resolution is\n // cheap (one fs.existsSync + readFileSync at most). Reads from\n // `configDir` — `config.json` is user-editable surface, not data.\n const userConfig = loadUserConfig(dirs.configDir)\n const envFlag = parseEnvFlag(process.env.ZIDANE_PROJECT_DB)\n const projectDbEnabled = opts.projectDb\n ?? envFlag\n ?? userConfig.projectDb\n ?? false\n\n // The PROJECT root: a linked worktree shares its main checkout's project\n // store, so every worktree of a repo lists the same sessions.\n const gitRoot = projectDbEnabled ? findProjectRoot(opts.cwd) : null\n // Project-scoped storage uses the prefix verbatim — same shape as\n // pre-XDG callers expect (`prefix: '.zidane'` → `<repo>/.zidane/`,\n // `prefix: '.myapp'` → `<repo>/.myapp/`). XDG-mode users still get\n // the user-scoped slots split, but project dirs are a\n // checked-in-or-not concern, orthogonal to the XDG question.\n const projectDir = gitRoot ? resolve(gitRoot, opts.prefix) : null\n\n if (projectDir && !existsSync(projectDir)) {\n try {\n mkdirSync(projectDir, { recursive: true })\n }\n catch (err) {\n // Don't crash the bootstrap on mkdir failure (permissions, R/O\n // FS) — fall back to user-scoped storage. Surface the cause\n // under ZIDANE_DEBUG so the operator can diagnose if curious.\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] project-db: mkdir \"${projectDir}\" failed: ${errorMessage(err)}\\n`)\n return userOnlyPaths(dirs)\n }\n // Keep the whole dir out of git. `sessions.db` is a WAL-mode SQLite\n // trio (.db / -wal / -shm); a checkout, stash or clean that swaps one\n // of them under a live connection yields \"database disk image is\n // malformed\" and every session in it is lost. Written only when WE\n // create the dir, so a pre-existing `.zidane/` a team chose to track\n // is left alone. Best-effort: the dir is usable without it.\n try {\n writeFileSync(resolve(projectDir, '.gitignore'), '*\\n')\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] project-db: writing \"${projectDir}/.gitignore\" failed: ${errorMessage(err)}\\n`)\n }\n }\n\n if (projectDir) {\n return {\n dir: projectDir,\n userDir: dirs.configDir,\n projectDir,\n db: resolve(projectDir, 'sessions.db'),\n state: resolve(projectDir, 'state.json'),\n configDir: dirs.configDir,\n dataDir: dirs.dataDir,\n stateDir: dirs.stateDir,\n cacheDir: dirs.cacheDir,\n storageMode: dirs.mode,\n }\n }\n return userOnlyPaths(dirs)\n}\n\nfunction userOnlyPaths(dirs: {\n configDir: string\n dataDir: string\n stateDir: string\n cacheDir: string\n mode: StorageMode\n}): ResolvedPaths {\n return {\n dir: dirs.configDir,\n userDir: dirs.configDir,\n projectDir: null,\n db: resolve(dirs.dataDir, 'sessions.db'),\n state: resolve(dirs.stateDir, 'state.json'),\n configDir: dirs.configDir,\n dataDir: dirs.dataDir,\n stateDir: dirs.stateDir,\n cacheDir: dirs.cacheDir,\n storageMode: dirs.mode,\n }\n}\n\n/** Migrate legacy `state.json` settings without overriding modern keys. */\nfunction migrateLegacySettings(loaded: Partial<Settings> & Record<string, unknown>): Partial<Settings> {\n const migrated: Record<string, unknown> = { ...loaded }\n\n if ('allowInteraction' in migrated && !('interactionMode' in migrated))\n migrated.interactionMode = migrated.allowInteraction === false ? 'disabled' : 'ask'\n delete migrated.allowInteraction\n\n if ('showToolCalls' in migrated && !('toolCallDisplay' in migrated))\n migrated.toolCallDisplay = migrated.showToolCalls === false ? 'hidden' : 'formatted'\n delete migrated.showToolCalls\n\n return migrated as Partial<Settings>\n}\n\n/** Tri-state parse for env-var bools — explicit `undefined` keeps absence from forcing a default. */\nfunction parseEnvFlag(raw: string | undefined): boolean | undefined {\n if (raw === undefined)\n return undefined\n const v = raw.trim().toLowerCase()\n if (v === '0' || v === 'false' || v === 'off' || v === 'no')\n return false\n if (v === '1' || v === 'true' || v === 'on' || v === 'yes')\n return true\n process.stderr.write(`[zidane/chat] ZIDANE_PROJECT_DB=\"${raw}\" is not a recognized boolean (use 0/1, true/false, on/off, yes/no), ignoring it.\\n`)\n return undefined\n}\n\nfunction makeModelsResolver(registry: ProviderRegistry): (key: ProviderKey) => readonly ModelInfo[] {\n return (key) => {\n const descriptor = registry[key]\n return descriptor ? modelsForDescriptor(descriptor) : []\n }\n}\n\nfunction wrapProvidersWithExtensionMiddleware(\n providers: ProviderRegistry,\n extensions: ExtensionRegistry,\n): ProviderRegistry {\n if (extensions.providerMiddlewares.length === 0)\n return providers\n const out: Record<string, ProviderDescriptor> = {}\n for (const [key, descriptor] of Object.entries(providers)) {\n out[key] = {\n ...descriptor,\n factory: () => {\n let provider = descriptor.factory()\n for (const entry of extensions.providerMiddlewares) {\n try {\n const next = entry.value(provider, {\n extensionName: entry.extensionName,\n source: entry.source,\n descriptor,\n })\n // A middleware that returns nothing (or a malformed value from a\n // JS extension) is pass-through rather than poisoning the provider\n // for later middlewares and the caller.\n if (isProviderLike(next))\n provider = next\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/extensions] ${entry.extensionName} provider middleware failed: ${errorMessage(err)}\\n`)\n }\n }\n return provider\n },\n }\n }\n return out\n}\n\nfunction isProviderLike(value: unknown): value is Provider {\n if (!value || typeof value !== 'object')\n return false\n const provider = value as Partial<Provider>\n return typeof provider.name === 'string'\n && !!provider.meta\n && typeof provider.meta === 'object'\n && typeof provider.formatTools === 'function'\n && typeof provider.userMessage === 'function'\n && typeof provider.assistantMessage === 'function'\n && typeof provider.toolResultsMessage === 'function'\n && typeof provider.stream === 'function'\n}\n\nfunction resolveResumeProvider(\n state: TuiState,\n providers: ProviderRegistry,\n storageDir: string,\n): ProviderAuth | null {\n // Three independent reasons a resume can fail to materialize — each one\n // sends the TUI to the auth screen as if it were a fresh install. Under\n // `ZIDANE_DEBUG` we tag the specific cause so a \"had to rewrite my API\n // key after reinstall\" report points at the actual culprit instead of\n // forcing the operator to guess between (a) a wiped state file,\n // (b) a renamed provider key, and (c) a credentials file that exists\n // but doesn't contain the previous provider.\n if (!state.lastProvider) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] resume: no \\`lastProvider\\` in state, showing the auth screen. (Has \\`${storageDir}/state.json\\` been deleted or never written?)\\n`)\n return null\n }\n if (!providers[state.lastProvider]) {\n if (process.env.ZIDANE_DEBUG) {\n const known = Object.keys(providers).join(', ') || '<none>'\n process.stderr.write(`[zidane/chat] resume: \\`state.lastProvider=\"${state.lastProvider}\"\\` is not in the registry. Known providers: ${known}.\\n`)\n }\n return null\n }\n const detected = detectAuth(storageDir, providers)\n const match = detected.find(p => p.key === state.lastProvider && p.available)\n if (!match && process.env.ZIDANE_DEBUG) {\n const entry = detected.find(p => p.key === state.lastProvider)\n process.stderr.write(`[zidane/chat] resume: \\`${state.lastProvider}\\` is in the registry but has no available auth method (apikey / env / oauth). Detection: ${entry ? JSON.stringify(entry.methods) : '<provider missing from detection>'}.\\n`)\n }\n return match ?? null\n}\n\nfunction resolveLaunchProvider(\n key: ProviderKey,\n providers: ProviderRegistry,\n storageDir: string,\n): ProviderAuth | null {\n if (!providers[key])\n return null\n return detectAuth(storageDir, providers).find(p => p.key === key && p.available) ?? null\n}\n\nfunction pickInitial(\n auth: ProviderAuth,\n providers: ProviderRegistry,\n state: TuiState,\n overrides: { model?: string, thinking?: Picked['effort'] } = {},\n): Picked | null {\n const descriptor = providers[auth.key]\n if (!descriptor)\n return null\n const remembered = state.lastModelByProvider?.[auth.key]\n // Prefer the remembered model, then the descriptor's declared default.\n // Only construct the provider as a last resort — some factories throw on\n // missing credentials, and we never want that to block the wizard.\n const model = overrides.model ?? remembered ?? descriptor.defaultModel ?? safeFactoryDefault(descriptor)\n if (!model)\n return null\n // Restore the per-model reasoning effort + enabled options so a relaunch\n // lands on the same knobs the user last set (parity with the in-session\n // `onPickModel` path). Both are keyed by model id in `TuiState`.\n const effort = overrides.thinking ?? (modelSupportsReasoning(descriptor, model)\n ? (state.lastEffortByModel?.[model] ?? 'medium')\n : undefined)\n const modelOptions = restoreModelOptions(descriptor, model, state.lastModelOptionsByModel)\n // Fallback chain restore — primary-match, registration, and dedup\n // filtering live in the helper; unauthed providers are skipped later\n // by the TUI's agent build.\n const fallbacks = restoreChainFallbacks(\n state.lastModelChain,\n { provider: auth.key, model },\n k => providers[k] !== undefined,\n )\n return {\n provider: auth,\n model,\n ...(fallbacks.length > 0 ? { fallbacks } : {}),\n ...(effort ? { effort } : {}),\n ...(modelOptions ? { modelOptions } : {}),\n }\n}\n\nfunction safeFactoryDefault(descriptor: ProviderDescriptor): string | undefined {\n try {\n return descriptor.factory().meta.defaultModel\n }\n catch {\n return undefined\n }\n}\n","import type { ReactNode } from 'react'\nimport type { ResolvedConfig } from './config'\nimport { createContext, useContext } from 'react'\n\n// ---------------------------------------------------------------------------\n// ConfigContext — renderer-agnostic React context that hands a fully-resolved\n// chat config down to deep consumers (modals, pickers, screens). Kept in its\n// own file so callers that only want `resolveConfig()` don't pay the\n// `import 'react'` cost.\n// ---------------------------------------------------------------------------\n\nconst ConfigContext = createContext<ResolvedConfig | null>(null)\n\nexport function ConfigProvider({ config, children }: { config: ResolvedConfig, children: ReactNode }) {\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>\n}\n\nexport function useConfig(): ResolvedConfig {\n const ctx = useContext(ConfigContext)\n if (!ctx)\n throw new Error('useConfig must be used inside <ConfigProvider>')\n return ctx\n}\n","/**\n * Live catalogs for files / skills / MCPs surfaced through React\n * context.\n *\n * **Why context, not props.** The modal layer stores its open node in\n * `useState`. React's element-identity reconciliation skips re-rendering\n * a subtree when the element reference hasn't changed — so passing\n * `skillsCatalog` as a prop into `modal.open(<SettingsModal …>)` bakes\n * the snapshot at open time and any subsequent `setSkillsCatalog`\n * doesn't reach the modal. Context propagation IS forwarded through\n * the modal layer regardless of element identity (same path the MCP\n * auth state uses), so reading via `useDiscovery()` gives the modal\n * live state.\n *\n * **Shape.** The provider exposes three groups:\n *\n * - **Catalogs** — the current state. Consumers re-render on every\n * update.\n * - **Ensure thunks** — kick the first load (idempotent). Wired into\n * completion providers; also called by the settings modal on mount\n * to fire-load lazy catalogs (currently `files`) on demand.\n * - **Refresh thunks** — force a rescan, bypassing the SWR throttle.\n * Wired into the settings modal's `ctrl+R`.\n *\n * Renderer-agnostic by design: the context only carries data + thunks.\n * The discovery work itself lives in `*-discovery.ts` modules; the\n * stale-while-revalidate machinery lives in `discovery-slot.ts`. The\n * provider's caller (AppShell for the TUI) owns where the slots live\n * and how their state propagates to `<DiscoveryProvider value>`.\n */\n\nimport type { ReactNode } from 'react'\nimport type { McpToolSchema } from '../mcp'\nimport type { SkillConfig } from '../skills'\nimport type { FileEntry } from './files-discovery'\nimport type { DiscoveredMcp, DiscoveryError } from './mcps-discovery'\nimport type { DiscoveredPlugin } from './plugins-discovery'\nimport { createContext, useContext } from 'react'\n\nexport interface DiscoveryContextValue {\n /** Parsed `SkillConfig[]` from project + user scan paths. */\n skillsCatalog: readonly SkillConfig[]\n /**\n * Agent Plugins loaded from `.agents/plugins` / `.{prefix}/plugins`\n * (project + user). Includes rejected plugins — they render as read-only\n * diagnostics rather than vanishing.\n */\n pluginsCatalog: readonly DiscoveredPlugin[]\n /** Parsed `mcps.json` entries. */\n mcpsCatalog: readonly DiscoveredMcp[]\n /** Non-fatal parse errors from `mcps.json` lookups. */\n mcpsErrors: readonly DiscoveryError[]\n /**\n * Per-server full tool catalog from the on-disk cache (see\n * `chat/mcp-tools-cache.ts`). Updated as MCP servers bootstrap and\n * fire the `mcp:tools:list` hook. Missing key → no cache yet; the\n * settings UI surfaces an empty-state row under the expanded server.\n */\n mcpToolsByServer: Record<string, readonly McpToolSchema[]>\n /** Current file walk results — empty until lazy-load lands. */\n filesCatalog: readonly FileEntry[]\n\n /** Force a fresh skills rescan. Resolves once state is committed. */\n refreshSkills: () => Promise<void>\n /** Force a fresh plugin rescan. Resolves once state is committed. */\n refreshPlugins: () => Promise<void>\n /**\n * Re-parse `mcps.json`. Sync-shaped under the hood, async for symmetry.\n * Resolves `true` when the catalog actually changed (a publish that\n * schedules downstream agent rebuilds), `false` on a fingerprint no-op\n * or scan failure — callers that arm rebuild-coupled state (e.g. the\n * add-MCP auto-login) disarm on `false`.\n */\n refreshMcps: () => Promise<boolean>\n /** Force a fresh file walk. Wired into a future \"refresh files\" affordance. */\n refreshFiles: () => Promise<void>\n\n /** Idempotent first-load trigger for skills (used by `/` popover + modal mount). */\n ensureSkills: () => Promise<readonly SkillConfig[]>\n /** Idempotent first-load trigger for files (used by `@` popover). */\n ensureFiles: () => Promise<readonly FileEntry[]>\n}\n\nconst DiscoveryContext = createContext<DiscoveryContextValue | null>(null)\n\nexport function DiscoveryProvider({\n value,\n children,\n}: {\n value: DiscoveryContextValue\n children: ReactNode\n}) {\n return (\n <DiscoveryContext.Provider value={value}>\n {children}\n </DiscoveryContext.Provider>\n )\n}\n\n/**\n * Read live discovery state + actions. Throws if used outside a\n * `<DiscoveryProvider>` — discovery is a load-bearing dependency for\n * settings + completion popovers; bailing loud here surfaces wiring\n * mistakes at mount instead of producing empty catalogs at first\n * keystroke.\n */\nexport function useDiscovery(): DiscoveryContextValue {\n const ctx = useContext(DiscoveryContext)\n if (!ctx)\n throw new Error('useDiscovery must be used inside <DiscoveryProvider>')\n return ctx\n}\n\n/**\n * Non-throwing variant — returns `null` when no provider is mounted.\n * Used by composable modals (`<SettingsModal>`, …) that accept catalog\n * props as a fallback for embedders who don't wire the full TUI\n * shell. The in-app flow always mounts `<DiscoveryProvider>` so the\n * modal sees live state; standalone embeds get the prop snapshot.\n */\nexport function useDiscoveryOptional(): DiscoveryContextValue | null {\n return useContext(DiscoveryContext)\n}\n","/**\n * Stale-while-revalidate catalog slot.\n *\n * One slot per (catalog kind, projectDir) pin. Holds the first-load\n * promise + a `lastScannedAt` timestamp + an in-flight `refreshing`\n * promise. Idempotent across concurrent callers, safe to rotate when\n * the project changes (the slot's `abort` controller cancels in-flight\n * walks and the `.then` guards drop stale results).\n *\n * Renderer-agnostic. AppShell wraps it in React refs so React closures\n * stay stable; a non-TUI shell can use it directly against its own\n * state propagation.\n *\n * Contract:\n * - `ensure()` — kick the first load if not started; return the\n * cached promise. On subsequent calls, if `Date.now() -\n * lastScannedAt >= throttleMs` and no refresh is in flight, kick\n * a background revalidate that calls `onLoad(fresh)` when it\n * resolves. The original first-load promise still resolves with\n * the first walk's contents — consumers reading live state\n * elsewhere (React state) see the refreshed catalog.\n * - `refresh()` — force a rescan now, bypassing the throttle.\n * De-duplicates: if a refresh is already in flight, returns the\n * same promise.\n * - `abort()` — cancel any in-flight walk and detach. After this\n * the slot is dead; callers should rotate to a new slot.\n * - `dispose()` — alias of `abort()`, named for symmetry with\n * cleanup callbacks.\n *\n * No state is exposed except through promises + the host's `onLoad`\n * callback; the slot doesn't try to be a store, only a coordinator.\n */\n\n/** Walk function — takes an abort signal, returns the discovered list. */\nexport type Walk<T> = (signal: AbortSignal) => Promise<readonly T[]>\n\n/** Notification: a fresh walk has resolved. Host is expected to commit to its own state store. */\nexport type Commit<T> = (items: readonly T[]) => void\n\nexport interface DiscoverySlotOptions<T> {\n /** Discover function — runs the actual FS / network walk. */\n walk: Walk<T>\n /** Commit hook — receives every successful walk's result (first + refreshes). */\n onLoad: Commit<T>\n /**\n * Min interval between background refreshes triggered by `ensure()`.\n * Default: 3_000ms. `refresh()` ignores this — it's the user's\n * explicit-intent path.\n */\n throttleMs?: number\n /** Optional error sink. Defaults to no-op; useful for `debugLog`. */\n onError?: (err: unknown, phase: 'first-load' | 'refresh') => void\n}\n\nexport interface DiscoverySlot<T> {\n /**\n * Kick the first load (idempotent). Returns the first-load promise\n * once it exists. Schedules a background refresh if past throttle.\n */\n ensure: () => Promise<readonly T[]>\n /** Force-refresh now. De-duped across concurrent callers. */\n refresh: () => Promise<void>\n /** True if a refresh is currently running. */\n isRefreshing: () => boolean\n /** Cancel in-flight work + detach. Idempotent. */\n abort: () => void\n}\n\nexport function createDiscoverySlot<T>(options: DiscoverySlotOptions<T>): DiscoverySlot<T> {\n const throttleMs = options.throttleMs ?? 3_000\n const abortCtrl = new AbortController()\n let firstLoad: Promise<readonly T[]> | null = null\n let refreshing: Promise<void> | null = null\n let lastScannedAt = 0\n let aborted = false\n\n const handleError = (err: unknown, phase: 'first-load' | 'refresh'): void => {\n options.onError?.(err, phase)\n }\n\n const startRefresh = (): Promise<void> => {\n lastScannedAt = Date.now()\n const run = options.walk(abortCtrl.signal)\n .then((items) => {\n if (aborted)\n return\n options.onLoad(items)\n })\n .catch((err) => {\n if (aborted)\n return\n handleError(err, 'refresh')\n })\n .finally(() => {\n if (refreshing === run)\n refreshing = null\n })\n refreshing = run\n return run\n }\n\n const slot: DiscoverySlot<T> = {\n ensure() {\n if (aborted)\n return Promise.resolve([] as readonly T[])\n if (!firstLoad) {\n lastScannedAt = Date.now()\n firstLoad = options.walk(abortCtrl.signal)\n .then((items) => {\n if (aborted)\n return [] as readonly T[]\n options.onLoad(items)\n return items\n })\n .catch((err) => {\n if (!aborted)\n handleError(err, 'first-load')\n return [] as readonly T[]\n })\n return firstLoad\n }\n // SWR: revalidate in the background if stale and not already running.\n if (!refreshing && Date.now() - lastScannedAt >= throttleMs)\n void startRefresh()\n return firstLoad\n },\n refresh() {\n if (aborted)\n return Promise.resolve()\n if (refreshing)\n return refreshing\n // Forced refresh from a user-initiated path (e.g. settings\n // modal `ctrl+R`). If the first load hasn't happened yet,\n // bootstrap through `ensure` so subsequent ensure callers see\n // the right `firstLoad` promise.\n if (!firstLoad)\n return slot.ensure().then(() => {})\n return startRefresh()\n },\n isRefreshing() {\n return refreshing !== null\n },\n abort() {\n if (aborted)\n return\n aborted = true\n abortCtrl.abort()\n },\n }\n return slot\n}\n","/**\n * `$EDITOR` / `$VISUAL` command parsing.\n *\n * These variables conventionally hold a command LINE, not a bare executable —\n * `code --wait`, `cursor --wait`, `subl -w`, `emacsclient -nw` are all normal\n * values. Spawning the whole string as argv[0] looks for a file literally named\n * `cursor --wait` and fails with ENOENT, so the flags have to be split off.\n *\n * Kept out of the TUI (and free of `node:child_process`) so the\n * tokenizer is unit-testable without pulling in the TUI.\n */\n\n/**\n * Split an editor command line into `[executable, ...args]`.\n *\n * Whitespace-separated, with single and double quotes honored so an editor\n * living under a path with spaces still works\n * (`\"/Applications/My App/bin/ed\" -w`). Quotes group and are stripped;\n * backslash escaping is deliberately NOT implemented, because on Windows\n * backslash is the path separator and treating `C:\\tools\\ed` as escapes would\n * corrupt far more command lines than it would rescue.\n *\n * Returns `[]` for an empty or whitespace-only spec, so callers can fall back\n * to the platform opener rather than spawning `''`.\n */\nexport function parseEditorCommand(spec: string): string[] {\n const tokens: string[] = []\n let current = ''\n // The quote character we're inside, or null at top level. Tracked (rather\n // than a boolean) so a double quote inside single quotes stays literal.\n let quote: '\"' | '\\'' | null = null\n // Distinct from `current !== ''` so `\"\"` yields an empty-string token instead\n // of vanishing — an explicitly quoted empty argument was still an argument.\n let quoted = false\n\n for (const ch of spec) {\n if (quote) {\n if (ch === quote)\n quote = null\n else\n current += ch\n continue\n }\n if (ch === '\"' || ch === '\\'') {\n quote = ch\n quoted = true\n continue\n }\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n if (current !== '' || quoted) {\n tokens.push(current)\n current = ''\n quoted = false\n }\n continue\n }\n current += ch\n }\n if (current !== '' || quoted)\n tokens.push(current)\n return tokens\n}\n\n/**\n * Re-quote a single argv token for a shell that will re-parse the joined command\n * line — i.e. `spawn(..., { shell: true })`, which Node uses on Windows so that\n * `.cmd` / `.bat` wrappers (how `code`, `cursor` and friends ship there) resolve.\n *\n * Node does NOT re-quote when `shell` is set: it joins `[cmd, ...args]` with\n * spaces and hands the string over. Since {@link parseEditorCommand} has already\n * STRIPPED the user's quotes, handing tokens back unquoted would split\n * `C:\\Program Files\\ed.exe` at the space and try to run `C:\\Program`. This puts\n * the quotes back.\n *\n * Only tokens that need it are quoted, so a plain `code` stays `code`. A literal\n * double quote is doubled, which is how `cmd.exe` escapes one inside a quoted\n * run.\n *\n * The test covers `cmd.exe` METACHARACTERS, not just whitespace: `&`, `|`, `^`,\n * `<`, `>` and friends carry none of the obvious \"needs quoting\" signals, so a\n * repo cloned into `C:\\work\\a&b` would otherwise hand `C:\\work\\a&b\\AGENTS.md`\n * over bare, and cmd would split it at the `&` and run the tail as a second\n * command.\n *\n * `%` and `!` are in the class so such a token is quoted rather than passed\n * bare — but be clear about the limit: quoting does NOT stop cmd.exe expanding\n * `%VAR%`, nor `!VAR!` where delayed expansion is on. Double quotes suppress\n * splitting and other syntax, not expansion. That is a property of the shell\n * which no amount of quoting can close; the worst case is a wrong path, not an\n * injected command.\n */\nexport function quoteForShell(token: string): string {\n if (token === '')\n return '\"\"'\n if (!/[\\s\"&|^<>%()!]/.test(token))\n return token\n return `\"${token.replace(/\"/g, '\"\"')}\"`\n}\n","/**\n * Renderer-agnostic state machine for an \"enabled allowlist\" — the shape\n * used by `settings.enabledSkills` / `settings.enabledMcps` (and any future\n * `enabledX` toggle backed by a `Settings` field).\n *\n * Semantics, kept identical across all three call sites:\n * - `undefined` → every catalog entry is enabled (default — user has\n * never opened the picker; new entries flow in).\n * - `[]` → the whole subsystem is off.\n * - `[names]` → explicit allowlist; the persisted shape stays a\n * concrete array once the user has toggled anything.\n *\n * The hook exposes a live `enabledSet` (Set<string>) + a `toggle(name)`\n * callback that persists the result through `useSettings().setSetting`.\n * The first toggle seeds the persisted allowlist from the current catalog\n * so newly-added entries don't silently drop on the next launch.\n *\n * Renderer-neutral: works for the TUI's `<ToggleListModal>`, a GUI\n * checkbox list, a CLI flag tool. Hook tests live alongside the chat\n * suite; the rendering layer is tested where it lives.\n */\n\nimport { useCallback, useMemo } from 'react'\nimport { useSettings } from './settings-context'\n\n/** Settings keys whose value type is `readonly string[] | undefined`. */\nexport type EnabledAllowlistKey = 'enabledSkills' | 'enabledMcps' | 'enabledExtensions' | 'enabledPlugins'\n\nexport interface EnabledToggleSet {\n /** Live set of enabled names — `Set` for O(1) `has`. */\n enabledSet: ReadonlySet<string>\n /** Toggle one name on/off; persists immediately via `setSetting`. */\n toggle: (name: string) => void\n}\n\n/**\n * Bind an \"enabled allowlist\" setting to a discovered catalog.\n *\n * `keyOf` extracts the persisted identity from a catalog entry (skill name,\n * MCP server name, …). Pass a stable, collision-free key — the persisted\n * allowlist is keyed against it forever.\n */\nexport function useEnabledToggleSet<T>(opts: {\n catalog: readonly T[]\n keyOf: (entry: T) => string\n settingKey: EnabledAllowlistKey\n /**\n * Names that survive the persisted-allowlist GC even when absent from\n * `catalog`. Use when the catalog deliberately hides entries that are\n * still known to exist — e.g. errored / untrusted extensions are kept\n * out of the toggle list but must not be dropped from the allowlist\n * by an unrelated toggle. Defaults to the catalog keys.\n */\n gcKeys?: readonly string[]\n}): EnabledToggleSet {\n const { settings, setSetting } = useSettings()\n const { catalog, keyOf, settingKey, gcKeys } = opts\n const persisted = settings[settingKey]\n\n const enabledSet = useMemo<ReadonlySet<string>>(() => {\n if (persisted === undefined)\n return new Set(catalog.map(keyOf))\n return new Set(persisted)\n }, [persisted, catalog, keyOf])\n\n // Live catalog membership — used to garbage-collect stale persisted\n // names on every write. Without this, a skill / MCP that was once\n // enabled and then removed from disk lingers in the JSON forever\n // (the next toggle round-trips it back into the array). Functionally\n // harmless today (the agent ignores unknown names) but it lets the\n // persisted state drift away from reality. `gcKeys` widens the\n // \"known\" set beyond the rendered catalog (see its JSDoc).\n const catalogKeys = useMemo(\n () => new Set(gcKeys ?? catalog.map(keyOf)),\n [gcKeys, catalog, keyOf],\n )\n\n const toggle = useCallback((name: string) => {\n // Seed from the current `enabledSet` (covers both the seeded-from-catalog\n // and explicit-allowlist branches). Persist as a sorted array filtered\n // against the live catalog so stale names — entries deleted from disk\n // between launches — don't linger forever in the persisted allowlist.\n // `undefined` is reserved for \"fresh install, accept new discoveries\";\n // once the user toggles once the persistence shape stays a concrete list.\n const next = new Set(enabledSet)\n if (next.has(name))\n next.delete(name)\n else\n next.add(name)\n const persisted = [...next]\n .filter(n => catalogKeys.has(n))\n .sort()\n setSetting(settingKey, persisted)\n }, [enabledSet, catalogKeys, settingKey, setSetting])\n\n return { enabledSet, toggle }\n}\n","/**\n * The standard {@link ExtensionMcpHost} behind `ctx.mcp`: the servers a\n * session in `cwd` would get (discovered `mcps.json` entries through the\n * user's allowlist, the same `discoverSessionMcpServers` the agent build\n * uses), and calls into their tools on connections this host owns.\n *\n * Connections are opened on first call per `(cwd, server config)`, shared\n * by every extension of the process, and closed after `idleMs` without a\n * call. OAuth servers reuse the stored credentials non-interactively; a\n * server that needs a login the user hasn't done fails to connect, and the\n * call rejects (the login itself stays a host UI flow). `scope: 'context'`\n * servers run inside a session's execution and are not offered.\n */\n\nimport type { ExtensionMcpHost } from '../extensions/mcp-host'\nimport type { ExtensionMcpServerInfo } from '../extensions/types'\nimport type { McpConnection, McpServerConfig } from '../mcp'\nimport type { McpCredentialStore } from '../mcp/oauth-provider'\nimport type { ToolContext } from '../tools/types'\nimport type { HostSettings } from './host/signals'\nimport type { Settings } from './types'\nimport { connectMcpServers } from '../mcp'\nimport { McpOAuthProvider } from '../mcp/oauth-provider'\nimport { toolResultToText } from '../types'\nimport { discoverSessionMcpServers } from './host/mcp'\nimport { withSessionStdioCwd } from './mcps-discovery'\n\nexport interface CreateExtensionMcpHostOptions {\n /** Storage prefix (`.zidane`) the discovery reads `mcps.json` under. */\n prefix: string\n /** Live settings: the allowlist (`enabledMcps`) and import toggles. */\n readSettings: () => Partial<Settings> | undefined\n /** Stored MCP OAuth credentials; omitted → OAuth servers can't connect. */\n credentialStore?: () => McpCredentialStore\n /** Close a connection after this long without a call. Default 60 s. */\n idleMs?: number\n /** How long a cwd's server list is reused. Default 10 s. */\n serversTtlMs?: number\n /** Test seam: replaces `connectMcpServers`. */\n connect?: (configs: McpServerConfig[], opts: { buildAuthProvider?: (config: McpServerConfig) => McpOAuthProvider | undefined }) => Promise<McpConnection>\n}\n\ninterface PoolEntry {\n connection: Promise<McpConnection>\n timer?: ReturnType<typeof setTimeout>\n busy: number\n}\n\nfunction info(config: McpServerConfig): ExtensionMcpServerInfo {\n return {\n name: config.name,\n transport: config.transport,\n ...(config.url ? { url: config.url } : {}),\n ...(config.command ? { command: config.command } : {}),\n toolPrefix: `mcp_${config.name}_`,\n }\n}\n\nexport function createExtensionMcpHost(options: CreateExtensionMcpHostOptions): ExtensionMcpHost {\n const idleMs = options.idleMs ?? 60_000\n const serversTtlMs = options.serversTtlMs ?? 10_000\n const pool = new Map<string, PoolEntry>()\n const listed = new Map<string, { at: number, configs: McpServerConfig[] }>()\n const connect = options.connect ?? ((configs, opts) => connectMcpServers(configs, undefined, undefined, opts))\n\n function configsFor(cwd: string): McpServerConfig[] {\n const hit = listed.get(cwd)\n if (hit && Date.now() - hit.at < serversTtlMs)\n return hit.configs\n const settings = (options.readSettings() ?? {}) as HostSettings\n const configs = discoverSessionMcpServers(cwd, options.prefix, settings).filter(c => c.scope !== 'context')\n listed.set(cwd, { at: Date.now(), configs })\n return configs\n }\n\n function release(key: string, entry: PoolEntry): void {\n entry.busy--\n if (entry.busy > 0)\n return\n entry.timer = setTimeout(() => {\n if (pool.get(key) !== entry)\n return\n pool.delete(key)\n entry.connection.then(c => c.close()).catch(() => undefined)\n }, idleMs)\n // Never keep a CLI process alive for an idle MCP connection.\n entry.timer.unref?.()\n }\n\n function acquire(cwd: string, config: McpServerConfig): { key: string, entry: PoolEntry } {\n const key = `${cwd}\\u0000${JSON.stringify(config)}`\n let entry = pool.get(key)\n if (!entry) {\n const store = options.credentialStore\n const connection = connect(withSessionStdioCwd([config], cwd), {\n ...(store ? { buildAuthProvider: (c: McpServerConfig) => new McpOAuthProvider({ name: c.name, store: store() }) } : {}),\n })\n entry = { connection, busy: 0 }\n pool.set(key, entry)\n // A rejected connect is not pooled either.\n connection.catch(() => {\n if (pool.get(key) === entry)\n pool.delete(key)\n })\n }\n if (entry.timer)\n clearTimeout(entry.timer)\n entry.busy++\n return { key, entry }\n }\n\n return {\n servers: async cwd => configsFor(cwd).map(info),\n callTool: async (cwd, server, tool, args, opts) => {\n const config = configsFor(cwd).find(c => c.name === server)\n if (!config)\n throw new Error(`MCP server \"${server}\" is not installed or not enabled`)\n const { key, entry } = acquire(cwd, config)\n try {\n const connection = await entry.connection\n const prefix = `mcp_${config.name}_`\n const def = connection.tools[`${prefix}${tool}`]\n if (!def) {\n // `connect` resolves with no tools when the server failed (it never\n // rejects for that): unpool it so the next call (after a login, say) retries.\n if (!Object.keys(connection.tools).some(name => name.startsWith(prefix)) && pool.get(key) === entry) {\n pool.delete(key)\n connection.close().catch(() => undefined)\n }\n throw new Error(`MCP server \"${server}\" offers no tool \"${tool}\" (not connected, a login is needed, or no such tool)`)\n }\n const signal = opts.timeout ? AbortSignal.any([AbortSignal.timeout(opts.timeout), ...(opts.signal ? [opts.signal] : [])]) : opts.signal\n // The MCP tool wrapper reads only the call identity and the abort\n // signal off its context; there is no agent turn behind this call.\n const ctx = { turnId: 'extension', callId: crypto.randomUUID(), ...(signal ? { signal } : {}) } as unknown as ToolContext\n try {\n return { text: toolResultToText(await def.execute(args, ctx)), isError: false }\n }\n catch (err) {\n // Connected and dispatched: the server (or the call's deadline) said no.\n return { text: err instanceof Error ? err.message : String(err), isError: true }\n }\n }\n finally {\n release(key, entry)\n }\n },\n dispose: async () => {\n const entries = [...pool.values()]\n pool.clear()\n listed.clear()\n await Promise.all(entries.map(async (e) => {\n if (e.timer)\n clearTimeout(e.timer)\n await e.connection.then(c => c.close()).catch(() => undefined)\n }))\n },\n }\n}\n","/**\n * Project file discovery for the `@`-prefixed files completion provider.\n *\n * Primary strategy — `git ls-files --cached --others --exclude-standard`.\n * Git already understands `.gitignore`, `.git/info/exclude`, and global\n * excludes, so we get correctness for free + sub-second performance on\n * even huge monorepos. Falls back to a depth-limited filesystem walk when\n * git isn't available or the directory isn't a repo.\n *\n * Pure: callers cache the returned list (e.g. in App state) and pass it\n * into the provider's `getCatalog`. The list is a snapshot — refresh on\n * cwd change or via a user-driven action.\n */\n\nimport type { Dirent, Stats } from 'node:fs'\nimport { spawn } from 'node:child_process'\nimport { readdir, stat } from 'node:fs/promises'\nimport { resolve, sep } from 'node:path'\nimport { errorMessage } from '../errors'\n\n/** One row in the project file catalog. `path` is forward-slashed + relative to `cwd`. */\nexport interface FileEntry {\n /** Forward-slashed relative path from the discovery cwd. Stable across OSes. No trailing slash for dirs. */\n path: string\n /** Basename — used for prefix ranking in the completion provider. */\n name: string\n /** Source — `git` when listed via `git ls-files`, `fs` from the walk fallback. */\n source: 'git' | 'fs'\n /**\n * Entry kind. Directories are derived from the discovered file paths\n * (every ancestor of a listed file), so only directories that contain\n * at least one non-ignored file appear — mirroring `git ls-files`\n * semantics, which never lists empty or fully-ignored dirs.\n */\n kind: 'file' | 'dir'\n}\n\n/**\n * Hard cap on the discovered file count. Bigger than any reasonable repo's\n * source tree, small enough that a runaway scan can't pin the renderer's\n * filter. Provider's substring match runs over the full list per\n * keystroke; 10k entries × cheap `.includes()` is well under one frame.\n */\nconst DEFAULT_MAX_FILES = 10_000\n\n/**\n * Names skipped during the fs-walk fallback. Mirrors what `git ls-files`\n * would exclude via the default `.gitignore` shipped in most repos —\n * `node_modules`, `dist`, build caches — plus the `.git` dir itself.\n * Best-effort; the git path is the authoritative one.\n */\nconst FS_WALK_SKIP = new Set<string>([\n '.git',\n '.hg',\n '.svn',\n 'node_modules',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.next',\n '.nuxt',\n '.cache',\n '.turbo',\n '.parcel-cache',\n '.vercel',\n '.svelte-kit',\n '.expo',\n '.gradle',\n 'target',\n '__pycache__',\n '.pytest_cache',\n '.venv',\n 'venv',\n '.idea',\n '.vscode-test',\n])\n\n/** Options for `listProjectFiles`. */\nexport interface ListProjectFilesOptions {\n /** Discovery root. Default: `process.cwd()`. */\n cwd?: string\n /**\n * Cap on discovered files. Default: 10,000. Bigger lists fall back to\n * a truncated set. Derived directory entries are appended on top with\n * their own equal cap, so the returned array can exceed `maxFiles`\n * (bounded by 2×).\n */\n maxFiles?: number\n /** Aborts the scan early. Useful when re-running on rapid project switches. */\n signal?: AbortSignal\n}\n\n/**\n * Discover every non-ignored file under `cwd`, plus the directories that\n * contain them (derived from the file paths, `kind: 'dir'`). Tries\n * `git ls-files` first; on failure (no git, not a repo, abort) walks the\n * fs with a hand-rolled skip list.\n *\n * Errors are not thrown — the function always returns an array (possibly\n * empty). Callers wanting failure diagnostics can opt into them via\n * `ZIDANE_DEBUG`.\n */\nexport async function listProjectFiles(opts: ListProjectFilesOptions = {}): Promise<FileEntry[]> {\n const cwd = resolve(opts.cwd ?? process.cwd())\n const maxFiles = opts.maxFiles ?? DEFAULT_MAX_FILES\n const signal = opts.signal\n\n try {\n const paths = await listViaGit(cwd, signal)\n return toEntries(paths, 'git', maxFiles)\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] git ls-files failed (${errorMessage(err)}), walking the file system instead\\n`)\n try {\n const paths = await listViaFs(cwd, maxFiles, signal)\n return toEntries(paths, 'fs', maxFiles)\n }\n catch (fsErr) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/chat] fs walk failed: ${errorMessage(fsErr)}\\n`)\n return []\n }\n }\n}\n\n/**\n * Run `git ls-files --cached --others --exclude-standard` and return paths.\n *\n * - `--cached` — tracked files.\n * - `--others` — untracked but not ignored.\n * - `--exclude-standard` — apply `.gitignore`, `.git/info/exclude`, the\n * user's global excludes file, AND skip files marked `assume-unchanged`.\n *\n * Throws on non-zero exit (not a repo / no git) so the fallback path can\n * pick up. Aborts cleanly on `signal.aborted`.\n */\nasync function listViaGit(cwd: string, signal: AbortSignal | undefined): Promise<string[]> {\n return new Promise<string[]>((resolveP, rejectP) => {\n const child = spawn('git', ['ls-files', '--cached', '--others', '--exclude-standard', '-z'], {\n cwd,\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n // Buffered as chunk arrays — joining once at the end keeps GC quiet on\n // huge repos. A `let stdout += chunk` accumulator reallocates the whole\n // buffer per chunk; with a ~10MB `git ls-files` output that's quadratic\n // in chunk count.\n const stdoutChunks: string[] = []\n const stderrChunks: string[] = []\n const onAbort = () => child.kill('SIGTERM')\n if (signal) {\n if (signal.aborted) {\n child.kill('SIGTERM')\n rejectP(new Error('aborted'))\n return\n }\n signal.addEventListener('abort', onAbort, { once: true })\n }\n child.stdout.setEncoding('utf8')\n child.stderr.setEncoding('utf8')\n child.stdout.on('data', chunk => stdoutChunks.push(chunk))\n child.stderr.on('data', chunk => stderrChunks.push(chunk))\n child.on('error', (err) => {\n signal?.removeEventListener('abort', onAbort)\n rejectP(err)\n })\n child.on('close', (code) => {\n signal?.removeEventListener('abort', onAbort)\n if (signal?.aborted) {\n rejectP(new Error('aborted'))\n return\n }\n if (code !== 0) {\n rejectP(new Error(`git ls-files exited ${code}: ${stderrChunks.join('').trim()}`))\n return\n }\n // `-z` separates with NUL so paths containing newlines stay intact.\n const paths = stdoutChunks.join('').split('\\0').filter(p => p.length > 0)\n resolveP(paths)\n })\n })\n}\n\n/**\n * Depth-first fs walk fallback. Used when git is unavailable. Honors a\n * hard-coded skip list; doesn't read `.gitignore`. Acceptable for hosts\n * outside a git checkout (e.g. a freshly-`unzip`ped project).\n */\nasync function listViaFs(\n cwd: string,\n maxFiles: number,\n signal: AbortSignal | undefined,\n): Promise<string[]> {\n const out: string[] = []\n const stack: string[] = ['.']\n while (stack.length > 0) {\n if (signal?.aborted)\n throw new Error('aborted')\n const rel = stack.pop()!\n const abs = rel === '.' ? cwd : resolve(cwd, rel)\n let entries: Dirent[]\n try {\n entries = await readdir(abs, { withFileTypes: true })\n }\n catch {\n // Unreadable dir — skip silently. EACCES / ENOENT during a walk\n // shouldn't fail the whole discovery.\n continue\n }\n for (const e of entries) {\n if (FS_WALK_SKIP.has(e.name))\n continue\n const childRel = rel === '.' ? e.name : `${rel}${sep}${e.name}`\n if (e.isDirectory()) {\n stack.push(childRel)\n }\n else if (e.isFile()) {\n out.push(toForwardSlash(childRel))\n if (out.length >= maxFiles)\n return out\n }\n else if (e.isSymbolicLink()) {\n // Resolve once; ignore broken links and follow only if it points\n // to a regular file. We don't recurse into symlinked dirs to\n // avoid cycles.\n let st: Stats\n try {\n st = await stat(resolve(abs, e.name))\n }\n catch {\n continue\n }\n if (st.isFile()) {\n out.push(toForwardSlash(childRel))\n if (out.length >= maxFiles)\n return out\n }\n }\n }\n }\n return out\n}\n\nfunction toForwardSlash(p: string): string {\n return sep === '/' ? p : p.replaceAll(sep, '/')\n}\n\n/**\n * File entries (plus their ancestor dirs) from relative paths — what\n * {@link listProjectFiles} returns, for lists produced elsewhere (a remote\n * sandbox's `git ls-files`).\n */\nexport function fileEntriesFromPaths(paths: readonly string[], source: 'git' | 'fs' = 'git', maxFiles = DEFAULT_MAX_FILES): FileEntry[] {\n return toEntries(paths, source, maxFiles)\n}\n\nfunction toEntries(paths: readonly string[], source: 'git' | 'fs', maxFiles: number): FileEntry[] {\n const seen = new Set<string>()\n const out: FileEntry[] = []\n for (const raw of paths) {\n const path = toForwardSlash(raw)\n if (path.length === 0 || seen.has(path))\n continue\n seen.add(path)\n const lastSlash = path.lastIndexOf('/')\n const name = lastSlash >= 0 ? path.slice(lastSlash + 1) : path\n out.push({ path, name, source, kind: 'file' })\n if (out.length >= maxFiles)\n break\n }\n // Directory pass — derive every ancestor dir of the (possibly capped)\n // file list so `@` can also reference directories. Appended after the\n // files with its own `maxFiles` cap (deep trees can yield more dirs\n // than files) so a truncated file list never crowds out the dirs and\n // the total stays bounded at 2×`maxFiles`.\n const dirs = new Set<string>()\n for (const entry of out) {\n let p = entry.path\n for (let idx = p.lastIndexOf('/'); idx > 0; idx = p.lastIndexOf('/')) {\n p = p.slice(0, idx)\n if (dirs.has(p))\n break // ancestors of an already-seen dir are seen too\n dirs.add(p)\n }\n }\n let dirCount = 0\n for (const path of dirs) {\n const lastSlash = path.lastIndexOf('/')\n const name = lastSlash >= 0 ? path.slice(lastSlash + 1) : path\n out.push({ path, name, source, kind: 'dir' })\n if (++dirCount >= maxFiles)\n break\n }\n return out\n}\n","// ---------------------------------------------------------------------------\n// Footer hint composition.\n//\n// Pure presentation logic — given the current screen, run state, and a\n// resolved keybinding map, produce the ordered list of {@link Hint}s\n// the bottom-bar Footer should render. Lives in `zidane/chat` (not\n// `zidane/tui`) because it's renderer-agnostic: the only types involved\n// are `Hint`, `Screen`, `Settings['uiMode']`, and `KeyBindings`. A GUI\n// shell can consume the same list and paint it however it likes.\n//\n// Priority order is intentional and load-bearing:\n//\n// pending approval > live pending interaction > resumed pending\n// interaction > busy (streaming) > auth screen > sessions screen >\n// chat screen (idle).\n//\n// The first four return state-specific hint sets unconditionally —\n// `uiMode` is ignored there because those affordances (approve / abort\n// / navigate) are not the noise the minimal mode is targeting. Minimal\n// mode only collapses the chat-idle row.\n// ---------------------------------------------------------------------------\n\nimport type { Hint } from './hints'\nimport type { KeyBindings } from './keybindings'\nimport type { Screen, SessionMeta, Settings } from './types'\nimport { formatBindingForDisplay } from './keybindings'\n\n/**\n * Options bag for {@link buildHints}. Flat shape so call sites read as a\n * checklist of \"what state do I have to surface\" — easy to thread\n * through React `useMemo` deps and to construct fresh in tests.\n */\nexport interface BuildHintsOptions {\n screen: Screen\n busy: boolean\n pending: boolean\n /**\n * True when a LIVE pending interaction is on screen (agent is mid-run,\n * awaiting the tool's Promise). Same nav hints as the safe-mode\n * approval picker — `abortRun` aborts the run.\n */\n pendingInteractionLive: boolean\n /**\n * True when the chat screen is showing a resumed (not live) pending\n * interaction. The agent isn't running; esc leaves the form without\n * persisting a response, so the hint reads \"leave for later\" — the\n * session re-enqueues the same interaction on next activation.\n */\n pendingInteractionResumed: boolean\n currentSession: SessionMeta | null\n hasMultipleAgents: boolean\n /**\n * Chat-screen chrome density — `'minimal'` collapses the idle chat\n * hint row to just `agent / model / keybindings`. Busy / pending /\n * select-turn / queue states keep their full hint sets because those\n * affordances are load-bearing (abort, navigate, approve).\n */\n uiMode: Settings['uiMode']\n modelLabel: string | null\n modelColor: string\n /** Current reasoning effort label, or `null` when the model has no reasoning knob. */\n effortLabel: string | null\n effortColor: string\n /** Foreground for the `/n` chord that introduces the effort label. */\n effortKeyColor: string\n /**\n * Comma-joined labels of the enabled model options (e.g. `'fast'`), or `null`\n * when none are on. Appended after the effort label in the model chord — when\n * the model has no reasoning knob, it rides the chord on its own.\n */\n modelOptionsLabel?: string | null\n agentLabel: string\n agentColor: string\n /**\n * Resolved keybindings — every hint key string flows through this so\n * a user-level rebind (e.g. `\"openSettings\": \"ctrl+p\"`) shows up live\n * in the bottom bar without us hard-coding `'ctrl+o'`.\n */\n keybindings: KeyBindings\n /**\n * Number of currently-dispatching tool calls. Drives the\n * `<cancelToolCall> cancel tool` chip in the `busy` hint row — without\n * it, the binding stays inert and there's no point advertising the\n * shortcut. Falls back to \"no chip\" when no tools are in flight\n * (model is mid-stream but hasn't dispatched yet).\n */\n inFlightToolCount: number\n /**\n * Number of currently-active skills. Drives the footer's\n * `✦ N skill(s)` chip on the chat screen — purely informational,\n * a passive surface for \"tool restrictions are in effect\". Hidden\n * when `0` so the row stays uncluttered for the common case.\n */\n activeSkillCount: number\n /** Foreground for the skills chip (typically `COLOR.brand`). */\n skillsChipColor: string\n /**\n * Progress label for the todo chip (`\"2/5\"` from `todoProgressLabel`), or\n * `null` to hide it.\n *\n * This replaced a full-width bar that printed the in-progress todo's TITLE\n * ABOVE the prompt. As a `Hint` it inherits the row's click-to-keypress\n * contract for free (`dispatchHintKey`), so clicking it opens the list the\n * same way `ctrl+t` does — and it sits below the prompt like every other\n * control instead of pushing the prompt down.\n */\n todoProgress: string | null\n /**\n * Pre-built `↑ vX.Y.Z` chip from `buildUpdateHint(useUpdateCheck())`,\n * or `null` when no update is available. Always last in the chat-screen\n * row so it's the first to drop when the terminal narrows.\n */\n updateHint: Hint | null\n /**\n * Pre-built prompt-cache toast, non-null only for a few seconds after a\n * `'cache:break'` hook fired (the host owns the visibility timer and the\n * severity split): warn-colored `⚡ cache break · <culprit> · +Nk tok · ~$0.48`\n * for attributable breaks, dim `⚡ cache expired · +Nk tok · ~$0.48` for\n * byte-stable TTL expiry — routine across human think-time, so it must not\n * cry wolf. Sits beside `updateHint` at the droppable end of the row: a\n * transient cost signal, not an action.\n */\n cacheBreakHint?: Hint | null\n /**\n * Sessions-screen list scope — `true` when the list spans all\n * projects. Drives the `tab` hint's label, which advertises the scope\n * the toggle switches TO. Optional so non-sessions callers can omit it.\n */\n sessionsScopeAll?: boolean\n}\n\n/**\n * Build the footer's shortcut hints for the current screen. On the chat\n * screen the model id rides next to its `ctrl+m` shortcut and the agent\n * label rides next to `shift+tab`, each in its accent color — the bar\n * doubles as the status display without needing separate badges. When\n * the active model exposes reasoning, the `ctrl+m` hint grows a\n * secondary `/n` chord with the current effort label, surfacing the\n * effort picker as a discoverable, in-place affordance.\n */\nexport function buildHints(options: BuildHintsOptions): Hint[] {\n const {\n screen,\n busy,\n pending,\n pendingInteractionLive,\n pendingInteractionResumed,\n currentSession,\n hasMultipleAgents,\n uiMode,\n modelLabel,\n modelColor,\n effortLabel,\n effortColor,\n effortKeyColor,\n modelOptionsLabel,\n agentLabel,\n agentColor,\n keybindings,\n inFlightToolCount,\n activeSkillCount,\n skillsChipColor,\n todoProgress,\n updateHint,\n cacheBreakHint = null,\n sessionsScopeAll,\n } = options\n\n // Todo progress chip. Built BEFORE the priority branches below because it is\n // STATUS, not a shortcut: it has to survive every one of them. The bar it\n // replaced (`TodoIndicator`) rendered on its own line above the prompt\n // whenever an `in_progress` item existed, entirely independent of `busy` —\n // and `in_progress` is set precisely while the agent is working and calling\n // `todowrite`. Building it after the early returns would hide it for the\n // whole window it exists to cover.\n //\n // Appended LAST in each branch so `clipHintsToWidth` (which drops from the\n // right) sheds it before the abort/navigate affordances, which must stay.\n const todosChip: Hint | null = todoProgress !== null\n ? { key: keybindings.openTodos, label: `${todoProgress} todos` }\n : null\n const withTodos = (hints: Hint[]): Hint[] => todosChip ? [...hints, todosChip] : hints\n\n // Priority: safe-mode approval > live interaction > resumed\n // interaction > plain streaming. All three pending shapes share the\n // ↑↓ / ↵ nav prefix; only the esc semantics differ.\n if (pending)\n return withTodos([{ key: '↑↓', label: 'navigate' }, { key: '↵', label: 'select' }, { key: formatBindingForDisplay(keybindings.abortRun), label: 'abort run' }])\n if (pendingInteractionLive)\n return withTodos([{ key: '↑↓', label: 'navigate' }, { key: '↵', label: 'select' }, { key: formatBindingForDisplay(keybindings.abortRun), label: 'abort run' }])\n if (pendingInteractionResumed)\n return withTodos([{ key: '↑↓', label: 'navigate' }, { key: '↵', label: 'select' }, { key: 'esc', label: 'leave for later' }])\n if (busy) {\n // When tools are dispatching OR background tasks are running,\n // advertise the per-call cancel shortcut alongside the run-wide\n // `esc abort`. Order: cancel-tool first (active affordance for\n // the visible tool/task rows) → esc (broader scope).\n const baseBusyHints: Hint[] = []\n if (inFlightToolCount > 0) {\n baseBusyHints.push({\n key: keybindings.cancelToolCall,\n label: inFlightToolCount === 1 ? 'cancel' : `cancel (${inFlightToolCount})`,\n })\n }\n baseBusyHints.push({ key: formatBindingForDisplay(keybindings.abortRun), label: 'abort' })\n baseBusyHints.push({ key: 'esc', label: 'sessions' })\n // The model stays in view during the run it serves (a fallback shows in\n // its warn colour exactly then); no key, since the picker waits for idle.\n if (modelLabel)\n baseBusyHints.push({ key: '', label: modelLabel, labelColor: modelColor })\n return withTodos(baseBusyHints)\n }\n if (screen === 'auth')\n return [{ key: '↑↓', label: 'navigate' }, { key: '↵', label: 'select' }, { key: 'esc', label: 'exit' }]\n if (screen === 'sessions') {\n return [\n { key: '↑↓', label: 'navigate' },\n { key: '↵', label: 'open' },\n { key: 'tab', label: sessionsScopeAll ? 'current project' : 'all projects' },\n { key: keybindings.openSessionDetails, label: 'session' },\n { key: keybindings.openSettings, label: 'settings' },\n { key: 'esc', label: currentSession ? 'back' : 'exit' },\n ]\n }\n // Chat screen. Prompt-input shortcuts (`↵ send`, `shift+↵ newline`,\n // `↑↓ history`) live in the prompt box's overlay title — the bottom\n // bar only carries the most common agent / model / global affordances. The\n // `cycleAgent` binding shows the active label inline; the\n // `openModelPicker` binding shows the active model id inline; etc.\n // `cycleAgent` is suppressed when there's only one profile and\n // `openSessionDetails` only renders once a session exists.\n //\n // Minimal UI mode: strip the chat-idle bottom bar to just `agent`\n // (when there's >1 profile), `model/effort`, and `settings`. The\n // full keybinding catalog stays reachable from inside settings.\n // Busy / pending / select-turn / queue branches above already exited\n // before this point — minimal only affects the resting chat row.\n //\n // Compose the model hint. When the active model supports reasoning,\n // the primary `<openModelPicker> model` pair grows a secondary\n // `/n effort` chord that doubles as the discoverability hint for the\n // effort picker (`openEffortPicker`) and the status display for the\n // current effort. The chord shares the model accent so the pair\n // reads as one keyboard binding across every theme.\n // The `/l` chord carries reasoning effort plus any enabled model options,\n // all space-separated so they read as one model-info run (e.g.\n // `claude-opus-4-8 medium fast`). When the model has no reasoning knob, the\n // options ride the chord on their own.\n const chordLabel = [effortLabel, modelOptionsLabel].filter(Boolean).join(' ') || null\n const modelHint: Hint | null = modelLabel\n ? {\n key: keybindings.openModelPicker,\n label: modelLabel,\n labelColor: modelColor,\n ...(chordLabel\n ? { extra: { key: shortChord(keybindings.openEffortPicker), keySpec: keybindings.openEffortPicker, keyColor: effortKeyColor, label: chordLabel, labelColor: effortColor } }\n : {}),\n }\n : null\n // Skills chip — purely informational, no shortcut wired. We re-use\n // the Hint shape's `key` slot to render the glyph (`✦`) so the row\n // layout (key + label, padded breakpoints) stays consistent with\n // every other entry. The chip is omitted when no skills are active\n // so the row stays uncluttered for the common case.\n const skillsChip: Hint | null = activeSkillCount > 0\n ? {\n key: '✦',\n keyColor: skillsChipColor,\n label: activeSkillCount === 1 ? '1 skill' : `${activeSkillCount} skills`,\n labelColor: skillsChipColor,\n }\n : null\n // Background-task chip — fires when the user is idle (not `busy`)\n // but a task is still running. Gives them a discoverable way to\n // reach `ctrl+k` for kill. The `busy` branch above already covers\n // the dispatching case; this one is for \"agent finished its turn,\n // task still chugging\".\n const cancelTaskChip: Hint | null = inFlightToolCount > 0\n ? {\n key: keybindings.cancelToolCall,\n label: inFlightToolCount === 1 ? 'cancel task' : `cancel task (${inFlightToolCount})`,\n }\n : null\n // Minimal mode short-circuits the full composition. Same agent / model\n // hints as the full row (so a multi-agent setup still cycles, and the\n // model + effort chord stays visible), plus `settings` as the\n // discoverability anchor for everything we just dropped (keybindings\n // included — they have a tab in there).\n if (uiMode === 'minimal') {\n return [\n ...(hasMultipleAgents ? [{ key: keybindings.cycleAgent, label: agentLabel, labelColor: agentColor }] : []),\n ...(modelHint ? [modelHint] : []),\n { key: keybindings.openSettings, label: 'settings' },\n ]\n }\n return [\n ...(hasMultipleAgents ? [{ key: keybindings.cycleAgent, label: agentLabel, labelColor: agentColor }] : []),\n ...(modelHint ? [modelHint] : []),\n ...(skillsChip ? [skillsChip] : []),\n ...(todosChip ? [todosChip] : []),\n ...(cancelTaskChip ? [cancelTaskChip] : []),\n ...(currentSession ? [{ key: keybindings.openSessionDetails, label: 'session' }] : []),\n { key: keybindings.openSettings, label: 'settings' },\n { key: 'esc', label: 'sessions' },\n // Update chip lives at the right-most position so `clipHintsToWidth`\n // drops it first on narrow terminals — discoverability is nice but\n // the action shortcuts must stay.\n ...(cacheBreakHint ? [cacheBreakHint] : []),\n ...(updateHint ? [updateHint] : []),\n ]\n}\n\n/**\n * Shorten a binding spec for display as a \"chord continuation\" — the\n * `/n` after `ctrl+m model` in the chat footer. We only strip the\n * `ctrl+` prefix so user-customized chords (`alt+n`, `meta+shift+n`)\n * still render in full. Falls back to the verbatim spec when no\n * `ctrl+` prefix is found, which keeps the visual contract honest:\n * the rendered key always matches the bound trigger.\n */\nexport function shortChord(spec: string): string {\n return spec.startsWith('ctrl+') ? `/${spec.slice('ctrl+'.length)}` : spec\n}\n","// ---------------------------------------------------------------------------\n// Footer / title hint primitives.\n//\n// Pure data + width-estimation helpers consumed by the TUI's bottom-bar\n// footer, the prompt-box overlay, the sessions header, and any future\n// GUI shell that wants to render the same `<key> <label> · …` hint\n// strings. Plain-text math only — no renderer primitives, no colour\n// resolution, no React. Width estimates are intentionally `.length`-\n// based (assumes ASCII / single-cell glyphs); the consumer's renderer\n// is responsible for the actual painting and any wide-glyph accounting\n// it needs.\n// ---------------------------------------------------------------------------\n\n/**\n * Single hint entry — `<key> <label>`, optionally followed by an inline\n * secondary chord (`<key><extra.key> <label> <extra.label>`) for compound\n * shortcuts like `ctrl+m/n model effort`.\n *\n * Colour fields are advisory hex strings (resolved against the active\n * theme by the renderer); leaving them undefined lets the renderer pick\n * its conventional fallback (e.g. `warn` for keys, `dim` for labels,\n * `mute` for secondary).\n */\nexport interface Hint {\n key: string\n label: string\n /** Optional override for the key color. Renderer default: warn. */\n keyColor?: string\n /** Optional override for the label color. Renderer default: dim. */\n labelColor?: string\n /**\n * Optional secondary chord + value rendered inline after the primary\n * pair: `<key><extra.key> <label> <extra.label>`. Lets one hint advertise\n * a compound shortcut (e.g. `ctrl+m/n model effort`) without forcing\n * callers into a parallel struct or a custom renderer.\n */\n extra?: {\n key: string\n label: string\n /**\n * Dispatchable binding spec behind `extra.key` when the displayed\n * chord is an abbreviation (`/l` for `ctrl+l` — see `shortChord`).\n * The abbreviation itself doesn't parse as a keypress, so a renderer\n * that makes the secondary chord independently clickable needs the\n * full spec. Defaults to `extra.key` when omitted.\n */\n keySpec?: string\n /** Defaults to mute on the renderer side. */\n keyColor?: string\n /** Defaults to dim on the renderer side. */\n labelColor?: string\n }\n}\n\n/**\n * Truncate `text` to at most `max` characters, replacing the trailing\n * overflow with `…`. Edge cases:\n * - `max <= 0` → empty string (no room to render at all).\n * - `max === 1` → just the ellipsis glyph.\n * - `text.length <= max` → unchanged.\n *\n * Trailing-style truncation matches the natural read order of titles:\n * the prefix carries enough signal to identify the surface.\n */\nexport function truncateTrailing(text: string, max: number): string {\n if (max <= 0)\n return ''\n if (text.length <= max)\n return text\n if (max === 1)\n return '…'\n return `${text.slice(0, max - 1)}…`\n}\n\n// ---------------------------------------------------------------------------\n// Plain-text width estimates for responsive tiering.\n//\n// We approximate with `.length` instead of `stringWidth` because every glyph\n// involved (hint keys, provider names, model ids, token counts) is either\n// ASCII or a 1-cell symbol. The estimates only need to be precise enough to\n// pick a layout tier — being off by a column at the breakpoint is harmless.\n// ---------------------------------------------------------------------------\n\n/**\n * Plain-text width estimate for a list of {@link Hint}s rendered as\n * `<key> <label> · <key> <label> · …`. Exported so prompt-box overlays\n * can run the same responsive math as the bottom-bar footer when\n * deciding whether trigger hints fit. Pure / total.\n */\nexport function hintsLength(hints: readonly Hint[]): number {\n if (hints.length === 0)\n return 0\n return hints.reduce((sum, h, i) => sum + hintLength(h) + (i > 0 ? 3 : 0), 0)\n}\n\n/** Plain-text width of a single hint as rendered by `renderHintSpans`. */\nfunction hintLength(h: Hint): number {\n const base = h.key.length + 1 + h.label.length\n const extra = h.extra ? h.extra.key.length + 1 + h.extra.label.length : 0\n return base + extra\n}\n\n/**\n * Stable empty list so callers can compare by reference. Exported so\n * any consumer that needs to feed \"no primary hints\" into the same\n * `clipHintsToWidth` / `renderHintSpans` pipeline (e.g. the TUI's\n * minimal UI mode, where the prompt overlay shows only `@` / `/`\n * triggers) reuses the same frozen array instead of allocating a new\n * one each render.\n */\nexport const EMPTY_HINTS: readonly Hint[] = Object.freeze([])\n\n/**\n * Return the longest prefix of `hints` whose rendered width fits within\n * `budget`. Used to degrade hint rows gracefully at narrow terminal\n * widths instead of letting an absolutely-positioned hint row wrap\n * mid-segment (which paints the overflow over surrounding borders and\n * looks like garbled glyphs in a TUI).\n *\n * Prefix-only (no reordering, no last-hint priority) so the survivors\n * keep their authored order — the user's muscle memory for \"leftmost\n * hint = primary action\" stays intact as the terminal shrinks.\n */\nexport function clipHintsToWidth(hints: readonly Hint[], budget: number): readonly Hint[] {\n if (budget <= 0 || hints.length === 0)\n return EMPTY_HINTS\n const out: Hint[] = []\n let used = 0\n for (let i = 0; i < hints.length; i++) {\n const h = hints[i]!\n const cost = (i > 0 ? 3 : 0) + hintLength(h)\n if (used + cost > budget)\n break\n out.push(h)\n used += cost\n }\n if (out.length === 0)\n return EMPTY_HINTS\n return out.length === hints.length ? hints : out\n}\n","/**\n * React provider for the MCP per-server OAuth state map.\n *\n * `ModalRoot.open(node)` captures the modal contents as a snapshot — naive\n * prop-passing would freeze the auth badge at whatever status existed when\n * the user opened the picker, and a `mcp:auth:url` arriving mid-login\n * would never reach the rendered modal. Routing the state through a\n * context provider mounted ABOVE `ModalRoot` fixes that: a state update\n * re-renders the provider, which re-renders `ModalRoot`, which re-renders\n * the (referentially-stable) modal child node — and consumers calling\n * `useMcpAuthState()` see the fresh value.\n *\n * Two contexts on purpose:\n *\n * - `StateContext` carries the live map. Consumers re-render on every\n * auth event.\n * - `DispatchContext` carries the reducer entry point. Identity is stable\n * across renders, so AppShell's hook handlers don't re-bind when the\n * state changes — they grab `dispatch` once and fire events for the\n * lifetime of the agent.\n *\n * Actions (login / logout / cancel) deliberately do NOT live in context —\n * they depend on AppShell-scoped resources (credential store, catalog ref,\n * agent ref), close over those via refs, and stay stable across renders.\n * Passing them as modal props at `modal.open` time is fine because the\n * captured reference reads from refs internally; the snapshot doesn't go\n * stale even though it was taken at open time.\n */\n\nimport type { ReactNode } from 'react'\nimport type { McpAuthEvent, McpAuthStateMap } from './mcp-auth-state'\nimport { createContext, useCallback, useContext, useState } from 'react'\nimport { reduceMcpAuth } from './mcp-auth-state'\n\nconst StateContext = createContext<McpAuthStateMap>({})\nconst DispatchContext = createContext<((event: McpAuthEvent) => void) | null>(null)\n\n/**\n * Mount once near the top of the React tree (above `ModalRoot`). Children\n * use `useMcpAuthState()` to read and `useMcpAuthDispatch()` to fire events.\n */\nexport function McpAuthProvider({ children }: { children: ReactNode }) {\n const [state, setState] = useState<McpAuthStateMap>({})\n const dispatch = useCallback((event: McpAuthEvent) => {\n setState(prev => reduceMcpAuth(prev, event))\n }, [])\n return (\n <StateContext.Provider value={state}>\n <DispatchContext.Provider value={dispatch}>\n {children}\n </DispatchContext.Provider>\n </StateContext.Provider>\n )\n}\n\nexport function useMcpAuthState(): McpAuthStateMap {\n return useContext(StateContext)\n}\n\nexport function useMcpAuthDispatch(): (event: McpAuthEvent) => void {\n const dispatch = useContext(DispatchContext)\n if (!dispatch)\n throw new Error('useMcpAuthDispatch must be used inside <McpAuthProvider>')\n return dispatch\n}\n","/**\n * Renderer-agnostic data model for the MCP settings list when it\n * supports per-server expand / collapse with nested tool rows.\n *\n * Lives in `chat/` (not `tui/`) because both the standalone\n * `McpsSettingsModal` and the inline `<McpsList>` inside the unified\n * `SettingsModal` consume the exact same flattening + cursor\n * arithmetic — re-deriving it in two places would let the two\n * surfaces drift on edge cases (empty tool catalogs, freshly-removed\n * servers, stale expansion state).\n *\n * The model is a flat `VisibleMcpRow[]` so renderers can iterate once,\n * and the cursor is a single integer that walks both kinds (server\n * headers AND tool checkboxes) without separate \"which server am I\n * on / which tool inside it\" state.\n */\n\nimport type { McpToolSchema } from '../mcp'\nimport type { DiscoveredMcp } from './mcps-discovery'\n\n/**\n * One row in the flattened MCP settings list. Three kinds:\n *\n * - `'server'` — server header with the chevron + checkbox +\n * transport detail. Always present.\n * - `'tool'` — checkbox + description for a tool advertised\n * by the parent server. Present only when the\n * server is expanded AND its tool cache is\n * populated.\n * - `'tool-empty'` — placeholder shown when an expanded server\n * has no cached tool list yet (first launch\n * before any session has bootstrapped the\n * server). Lets the renderer surface a\n * one-line \"send a prompt to populate\" hint\n * WITHOUT changing the server's expand\n * affordance.\n */\nexport type VisibleMcpRow\n = | { kind: 'server', entry: DiscoveredMcp }\n | { kind: 'tool', serverName: string, tool: McpToolSchema }\n | { kind: 'tool-empty', serverName: string }\n\n/**\n * Flatten a server catalog plus the per-server expanded set into the\n * visible-row list a renderer cycles through.\n *\n * - `catalog` — filtered / ordered server list (post-search,\n * post-allow-list).\n * - `expanded` — names of servers whose tool list is open.\n * Servers not in this set render as a single\n * server-header row.\n * - `toolsByServer` — per-server full tool catalog (from\n * `chat/mcp-tools-cache.ts`). Missing key →\n * `'tool-empty'` placeholder under the\n * expanded server.\n */\nexport function buildVisibleMcpRows(\n catalog: readonly DiscoveredMcp[],\n expanded: ReadonlySet<string>,\n toolsByServer: Record<string, readonly McpToolSchema[]>,\n): VisibleMcpRow[] {\n const out: VisibleMcpRow[] = []\n for (const entry of catalog) {\n out.push({ kind: 'server', entry })\n if (!expanded.has(entry.config.name))\n continue\n const tools = toolsByServer[entry.config.name] ?? []\n if (tools.length === 0) {\n out.push({ kind: 'tool-empty', serverName: entry.config.name })\n continue\n }\n for (const tool of tools)\n out.push({ kind: 'tool', serverName: entry.config.name, tool })\n }\n return out\n}\n\n/**\n * Server name a row \"belongs to\" for catalog / toggle / auth lookups.\n * For a server row that's its own name; for tool / tool-empty rows\n * it's the parent server's name.\n */\nexport function parentServerName(row: VisibleMcpRow): string {\n return row.kind === 'server' ? row.entry.config.name : row.serverName\n}\n\n/**\n * Index in `rows` of the server header for the given parent name. `-1`\n * when not present. Used by collapse handlers to snap the cursor up\n * to the parent BEFORE shrinking the row list — otherwise the cursor\n * would land on whichever sibling row now occupies the same flat\n * index.\n */\nexport function indexOfServerRow(rows: readonly VisibleMcpRow[], parentName: string): number {\n return rows.findIndex(\n r => r.kind === 'server' && r.entry.config.name === parentName,\n )\n}\n","/**\n * Renderer-agnostic per-tool toggle for MCP servers. Sibling of\n * {@link useEnabledToggleSet} — same shape, opposite polarity:\n *\n * - `useEnabledToggleSet` is an **allowlist** (`enabledMcps` / etc.),\n * `undefined` = everything enabled, toggle moves to an explicit list.\n * - `useMcpToolToggleSet` is a **deny-list** (`disabledMcpTools`),\n * missing entry = everything enabled, toggle moves to an explicit\n * list of NAMES TO HIDE.\n *\n * The polarity flip is intentional and documented on the setting itself\n * (`Settings.disabledMcpTools`): when an MCP server ships a new tool in\n * a later release, a user who has already opted out of `big_tool` still\n * gets the new one — opposite preference from server-level toggles\n * where a new server should NOT silently appear in the catalog.\n *\n * Two hook flavors:\n *\n * - {@link useMcpToolToggleSet} — one server. Convenience for hosts\n * that render a single server's tool list at a time.\n * - {@link useMcpToolToggleMap} — every server's toggle handler in\n * one call. Required by hosts that dispatch toggles from a shared\n * keyboard handler at the top of the tree (`mcps-settings.tsx`)\n * where calling the single-server hook in a loop would violate\n * rules-of-hooks the moment a server is added or removed.\n *\n * Both flavors route through the same {@link buildToolToggle} factory\n * so semantics stay byte-identical regardless of entry point.\n *\n * Garbage-collects on every write: stale names (tools that disappeared\n * from the server's catalog between launches) are dropped so the\n * persisted deny-list doesn't grow unbounded. Same invariant as the\n * sibling hook for `enabledX` allowlists.\n */\n\nimport type { McpToolSchema } from '../mcp'\nimport type { Settings } from './types'\nimport { useCallback, useMemo } from 'react'\nimport { useSettings } from './settings-context'\n\nexport interface McpToolToggleSet {\n /** Live set of ENABLED tool names — `Set` for O(1) `has`. */\n enabledSet: ReadonlySet<string>\n /** Flip one tool on/off; persists immediately via `setSetting`. */\n toggle: (toolName: string) => void\n}\n\n/**\n * Bind a single MCP server's per-tool toggle to\n * `Settings.disabledMcpTools[serverName]`.\n *\n * `catalog` is the FULL list of tools the server advertises (i.e. the\n * cached `listTools()` payload from `chat/mcp-tools-cache.ts`). The\n * hook needs it both to render `enabledSet` (every catalog tool not in\n * the persisted deny-list) and to garbage-collect stale deny-list\n * entries on every write.\n */\nexport function useMcpToolToggleSet(opts: {\n serverName: string\n catalog: readonly McpToolSchema[]\n}): McpToolToggleSet {\n const { settings, setSetting } = useSettings()\n const setDisabled = useCallback(\n (next: Settings['disabledMcpTools']) => setSetting('disabledMcpTools', next),\n [setSetting],\n )\n\n const catalogNames = useMemo(() => opts.catalog.map(t => t.name), [opts.catalog])\n const persistedDenyAll = settings.disabledMcpTools\n\n return useMemo(\n () => buildToolToggle({\n serverName: opts.serverName,\n catalogNames,\n persistedDenyAll,\n setDisabledMcpTools: setDisabled,\n }),\n [opts.serverName, catalogNames, persistedDenyAll, setDisabled],\n )\n}\n\n/**\n * Bind every server in `catalogByServer` to its own per-tool toggle in\n * a single hook call. Returns a `serverName → McpToolToggleSet` map.\n *\n * Use this when a host needs handlers for multiple servers at once\n * (the TUI's MCP settings panel keyboard dispatcher is the canonical\n * example) — calling {@link useMcpToolToggleSet} in a `for` / `.map`\n * over a dynamic catalog would change the hook-call order whenever a\n * server is added or removed, violating React's rules-of-hooks. This\n * hook calls `useMemo` exactly once regardless of server count.\n *\n * Servers absent from `catalogByServer` get no entry in the result.\n * The persisted deny-list still keeps their entries on disk — they\n * just stay invisible to this consumer until the catalog re-includes\n * them.\n */\nexport function useMcpToolToggleMap(opts: {\n catalogByServer: Record<string, readonly McpToolSchema[]>\n}): Record<string, McpToolToggleSet> {\n const { settings, setSetting } = useSettings()\n const setDisabled = useCallback(\n (next: Settings['disabledMcpTools']) => setSetting('disabledMcpTools', next),\n [setSetting],\n )\n const persistedDenyAll = settings.disabledMcpTools\n\n return useMemo(() => {\n const out: Record<string, McpToolToggleSet> = {}\n for (const [serverName, catalog] of Object.entries(opts.catalogByServer)) {\n out[serverName] = buildToolToggle({\n serverName,\n catalogNames: catalog.map(t => t.name),\n persistedDenyAll,\n setDisabledMcpTools: setDisabled,\n })\n }\n return out\n }, [opts.catalogByServer, persistedDenyAll, setDisabled])\n}\n\n/**\n * Pure factory shared by both hook flavors. Captures `persistedDenyAll`\n * + `setDisabledMcpTools` at the call site so toggle handlers stay\n * referentially stable across renders that don't touch the underlying\n * settings entry — important for `useKeyboard` to avoid re-binding on\n * every catalog change.\n *\n * Exported for direct use by non-React consumers (CLI, GUI shells)\n * that want the same write semantics without the hook plumbing.\n */\nexport function buildToolToggle(args: {\n serverName: string\n catalogNames: readonly string[]\n persistedDenyAll: Settings['disabledMcpTools']\n setDisabledMcpTools: (next: Settings['disabledMcpTools']) => void\n}): McpToolToggleSet {\n const { serverName, catalogNames, persistedDenyAll, setDisabledMcpTools } = args\n const persistedDeny = persistedDenyAll?.[serverName]\n const catalogSet = new Set(catalogNames)\n\n const enabledSet: ReadonlySet<string> = (() => {\n if (!persistedDeny || persistedDeny.length === 0)\n return new Set(catalogNames)\n const deny = new Set(persistedDeny)\n return new Set(catalogNames.filter(name => !deny.has(name)))\n })()\n\n const toggle = (toolName: string): void => {\n // Compute the next deny-list against the persisted state (NOT\n // `enabledSet`) so we never accidentally promote \"implicit-enabled-\n // because-no-entry\" tools into an explicit list on the first\n // toggle. GC stale names at the same time so the persisted file\n // tracks reality.\n const currentDeny = new Set(persistedDeny ?? [])\n if (currentDeny.has(toolName))\n currentDeny.delete(toolName)\n else\n currentDeny.add(toolName)\n\n const nextForServer = [...currentDeny]\n .filter(n => catalogSet.has(n))\n .sort()\n\n const prevMap = persistedDenyAll ?? {}\n const nextMap: Record<string, readonly string[]> = { ...prevMap }\n if (nextForServer.length === 0) {\n // Empty entry collapses back to \"no customization\" so the\n // persisted file stays tidy when a user re-enables every tool\n // they previously disabled.\n delete nextMap[serverName]\n }\n else {\n nextMap[serverName] = nextForServer\n }\n\n // Top-level `undefined` represents \"no per-tool prefs anywhere\".\n // Restore that when the last server entry empties out so the\n // diff against defaults stays minimal.\n const next: Settings['disabledMcpTools']\n = Object.keys(nextMap).length === 0 ? undefined : nextMap\n setDisabledMcpTools(next)\n }\n\n return { enabledSet, toggle }\n}\n","/**\n * OAuth login flow exposed to the TUI.\n *\n * Driven by each {@link ProviderDescriptor}'s `oauthProvider` field. Built-in\n * descriptors wire pi-ai's `anthropicOAuthProvider` and `openaiCodexOAuthProvider`,\n * but hosts can pass any object conforming to `OAuthProviderInterface` — the\n * TUI is implementation-agnostic past the descriptor boundary.\n */\n\nimport type {\n OAuthCredentials,\n OAuthDeviceCodeInfo,\n OAuthLoginCallbacks,\n OAuthPrompt,\n OAuthSelectPrompt,\n} from '@earendil-works/pi-ai/oauth'\nimport type { ZidaneOAuthLoginCallbacks } from './oauth-page/server'\nimport type { ProviderDescriptor } from './providers'\nimport { tryOpenBrowser } from './browser'\n\nexport type {\n OAuthDeviceCodeInfo,\n OAuthPrompt,\n OAuthSelectOption,\n OAuthSelectPrompt,\n} from '@earendil-works/pi-ai/oauth'\n\nexport function supportsOAuth(descriptor: ProviderDescriptor): boolean {\n return descriptor.oauthProvider !== undefined\n}\n\n/** True when the provider's OAuth flow needs the user to paste a code back into the TUI (no loopback callback). */\nexport function oauthUsesManualCodePaste(descriptor: ProviderDescriptor): boolean {\n return descriptor.oauthProvider?.usesCallbackServer === false\n}\n\nexport interface OAuthFlowOptions {\n /** Called when the provider emits its login URL — typically right after the callback server starts. */\n onUrl: (url: string, instructions?: string) => void\n /**\n * Called when the provider needs a free-form input from the user (paste-the-code flows,\n * step-up confirmations, etc.). Mirrors pi-ai's `OAuthLoginCallbacks.onPrompt` verbatim\n * so callers don't lose `placeholder` / `allowEmpty` hints. Required for any provider\n * with `usesCallbackServer: false` (e.g. Anthropic Claude Pro/Max).\n */\n onPrompt?: (prompt: OAuthPrompt) => Promise<string>\n /**\n * Called when the provider initiates a device-code flow (e.g. GitHub Copilot).\n * Surface `userCode` + `verificationUri` so the user can complete the flow in\n * the browser. Required by pi-ai's `OAuthLoginCallbacks` since 0.75.5 — built-in\n * Anthropic / OpenAI Codex providers don't fire it today, but third-party\n * descriptors can.\n */\n onDeviceCode?: (info: OAuthDeviceCodeInfo) => void\n /**\n * Called when the provider needs the user to pick between multiple flow options\n * (e.g. browser vs device-code). Return the chosen option `id`, or `undefined`\n * to cancel. Required by pi-ai's `OAuthLoginCallbacks` since 0.75.5.\n */\n onSelect?: (prompt: OAuthSelectPrompt) => Promise<string | undefined>\n /** Called with each progress message from the OAuth flow (token exchange, etc.). */\n onProgress?: (message: string) => void\n /** Abort the in-flight login (e.g. user pressed esc). */\n signal?: AbortSignal\n /** The redirect URL (or a pasted code), racing the loopback listener (pi-ai's `onManualCodeInput`). */\n onManualCodeInput?: () => Promise<string>\n /**\n * `false`: the browser is on another machine (a client of a remote host).\n * zidane's providers bind no loopback listener here and read the redirect\n * from {@link onManualCodeInput}.\n */\n callbackServer?: false\n /** `false`: never launch a browser on this machine. Default true. */\n openBrowser?: boolean\n}\n\n/**\n * Run the OAuth login flow for a provider.\n *\n * Returns the OAuth credentials on success; caller persists them via\n * `setProviderCredential(dataDir, descriptor, { kind: 'oauth', ...credentials })`.\n * Throws when the descriptor has no `oauthProvider` configured.\n */\nexport async function runOAuthLogin(\n descriptor: ProviderDescriptor,\n options: OAuthFlowOptions,\n): Promise<OAuthCredentials> {\n if (!descriptor.oauthProvider) {\n throw new Error(\n `OAuth not supported for ${descriptor.label} (${descriptor.key}). Use an API key instead.`,\n )\n }\n\n // Set once a device flow surfaces its code. Providers may fire BOTH\n // callbacks for the same flow (Bolt does: `onDeviceCode` for the code panel,\n // then `onAuth` with the code-embedding verification URI). The device-code\n // handler already surfaced the URL and launched the browser, so the trailing\n // `onAuth` must not open a second tab — or push redirect-flow status copy\n // (\"paste the code below\") at a UI whose paste input device flows hide.\n let deviceFlowActive = false\n\n const callbacks: OAuthLoginCallbacks = {\n onAuth: (info) => {\n if (deviceFlowActive)\n return\n options.onUrl(info.url, info.instructions)\n // Best-effort browser launch. If `open`/`xdg-open` isn't available, the\n // user can still click the URL from the TUI — the callback server is\n // already listening either way.\n if (options.openBrowser !== false)\n void tryOpenBrowser(info.url)\n },\n onDeviceCode: (info) => {\n deviceFlowActive = true\n if (options.onDeviceCode) {\n options.onDeviceCode(info)\n return\n }\n // No handler wired — built-in providers (Anthropic, OpenAI Codex) never\n // hit this path, so it's only reachable for third-party descriptors.\n // Throwing here would crash mid-flow. Route through `onUrl` — the one\n // REQUIRED callback, so every host renders something visible even when\n // the best-effort browser launch below fails (headless boxes) — and\n // mirror it to progress for hosts that log rather than pin URLs.\n options.onUrl(info.verificationUri, `Enter code ${info.userCode} to authorize.`)\n options.onProgress?.(\n `Device code: ${info.userCode}. Open ${info.verificationUri}`,\n )\n if (options.openBrowser !== false)\n void tryOpenBrowser(info.verificationUri)\n },\n onPrompt: async (prompt) => {\n if (!options.onPrompt) {\n throw new Error(\n `OAuth provider \"${descriptor.label}\" requested user input (\"${prompt.message}\") but no onPrompt handler is wired.`,\n )\n }\n return options.onPrompt(prompt)\n },\n onSelect: async (prompt) => {\n if (options.onSelect)\n return options.onSelect(prompt)\n // Same fallback rationale as `onDeviceCode`. Default to the first option\n // so providers that gate the flow behind a choice don't deadlock the TUI.\n return prompt.options[0]?.id\n },\n onProgress: options.onProgress,\n signal: options.signal,\n ...(options.onManualCodeInput ? { onManualCodeInput: options.onManualCodeInput } : {}),\n }\n if (options.callbackServer === false)\n (callbacks as ZidaneOAuthLoginCallbacks).callbackServer = false\n\n return descriptor.oauthProvider.login(callbacks)\n}\n","/**\n * Manual OAuth redirect-URL handoff.\n *\n * Users who run zidane over SSH (or behind a proxy / firewall that blocks\n * loopback) can't have the local browser hit the in-process callback server.\n * They CAN, however, copy the URL their browser was redirected to —\n * `http://127.0.0.1:<port>/callback?code=...&state=...` — and paste it back\n * into the TUI.\n *\n * The trick: that URL IS the callback our local server is listening on. We\n * just `fetch()` it ourselves. The server runs in the same process; the\n * request hits its handler exactly as if a real browser had arrived, the\n * OAuth promise (`waitForCode` for pi-ai providers, `startOAuthCallback` for\n * MCP) resolves through the normal happy path, and the upstream flow\n * continues uninterrupted. No new code path inside the OAuth state machine.\n *\n * Defense in depth: we reject anything that isn't a loopback URL — fetching\n * an arbitrary user-pasted URL from inside the agent process would be a\n * trivial SSRF.\n */\n\nconst LOOPBACK_HOSTS = new Set(['127.0.0.1', 'localhost', '::1', '[::1]'])\n\n/**\n * The `redirect_uri` the authorization server was told to come back to,\n * read out of the authorization URL itself. That's our loopback callback\n * (`http://127.0.0.1:<port>/callback`) — the UI shows it so an SSH user\n * knows which address to fish out of the browser's URL bar, and\n * {@link normalizeRedirectPaste} uses it to rebuild a full callback URL\n * from a partial paste.\n *\n * Returns `null` when the URL doesn't parse or carries no usable\n * `redirect_uri` — callers degrade to \"paste the whole URL\".\n */\nexport function redirectUriFromAuthUrl(authUrl: string): URL | null {\n let parsed: URL\n try {\n parsed = new URL(authUrl)\n }\n catch {\n return null\n }\n const redirect = parsed.searchParams.get('redirect_uri')\n if (!redirect)\n return null\n try {\n return new URL(redirect)\n }\n catch {\n return null\n }\n}\n\n/**\n * Widen what counts as an acceptable paste. The happy path is the full\n * redirect URL out of the browser's address bar, but users on SSH\n * routinely end up holding less than that: some authorization servers\n * render the code on the page instead of redirecting, and copying from a\n * \"can't reach this site\" error page loses everything but the query.\n *\n * Accepted forms, given the authorization URL for context:\n *\n * - `http://127.0.0.1:5123/callback?code=x&state=y` — passthrough (any\n * absolute URL is returned untouched; the loopback guard in\n * {@link fetchOAuthRedirect} still has final say, so a pasted\n * `https://evil.test` is rejected there, not silently rewritten).\n * - `/callback?code=x&state=y` — path + query onto the callback origin.\n * - `?code=x&state=y` / `code=x&state=y` — query onto the callback URL.\n * - `x` — a bare authorization code; `state` is taken from the\n * authorization URL when it carried one (the loopback server forwards\n * `state` verbatim and the SDK owns verification, so a missing one is\n * not fatal). Anything with whitespace inside is prose (an error page\n * fragment), not a code — refused with a clearer error than a server\n * 400 would give.\n *\n * Throws when the input can't be turned into a URL — no `authUrl` context\n * for a partial paste, or an unusable authorization URL.\n */\nexport function normalizeRedirectPaste(pasted: string, authUrl?: string): string {\n const trimmed = pasted.trim()\n if (!trimmed)\n throw new Error('Paste the redirect URL from your browser.')\n // Absolute URL → caller's problem to validate. Checked by scheme rather\n // than `new URL()` success so a bare code like `abc` (which URL happily\n // rejects) and a scheme-ful `mcp://…` are told apart deterministically.\n if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(trimmed))\n return trimmed\n\n const callback = authUrl ? redirectUriFromAuthUrl(authUrl) : null\n if (!callback) {\n throw new Error(\n 'That doesn\\'t look like a URL. Paste the full address your browser tried to reach (starting with http://127.0.0.1).',\n )\n }\n\n // `/callback?code=…` — keep the pasted path, it may differ from the one\n // we registered (a server that normalized a trailing slash, say). Same\n // outcome guard as the query branch below: a bare `/callback` carries no\n // OAuth result, and fetching it would only produce an opaque server 400\n // where a targeted message tells the user exactly what to re-copy.\n if (trimmed.startsWith('/')) {\n const merged = new URL(trimmed, callback)\n if (!merged.searchParams.has('code') && !merged.searchParams.has('error'))\n throw new Error('That path has no \"code\" parameter. Paste the full address from your browser\\'s URL bar.')\n return merged.toString()\n }\n\n const target = new URL(callback.toString())\n const query = trimmed.startsWith('?') ? trimmed.slice(1) : trimmed\n // A bare authorization code is a single URL-legal token — including\n // base64 padding, so trailing `=` stays code-like (`abc==`). Any OTHER\n // placement of `=` means key/value pairs (`foo=bar`, `state=…&code=…`):\n // treat as a query string, never as a code — URL-encoding `foo=bar` into\n // `code=foo%3Dbar` would fire a doomed request where a targeted error\n // tells the user what to re-copy.\n const codeLike = /^[^=\\s]+=*$/.test(query)\n if (!codeLike && query.includes('=')) {\n const params = new URLSearchParams(query)\n if (!params.has('code') && !params.has('error'))\n throw new Error('That fragment has no \"code\" parameter. Paste the full address from your browser, or just the code.')\n for (const [key, value] of params)\n target.searchParams.set(key, value)\n return target.toString()\n }\n\n // Bare code. Whitespace-bearing pastes never reach here (`codeLike`\n // excludes them) except as pure prose without `=`, so keep the explicit\n // reject for those: sending `code=access%20denied` to the callback\n // server would 400 without explaining anything.\n if (/\\s/.test(query))\n throw new Error('That doesn\\'t look like an authorization code. Paste the full address from your browser, or just the code itself.')\n target.searchParams.set('code', query)\n const state = new URL(authUrl!).searchParams.get('state')\n if (state)\n target.searchParams.set('state', state)\n return target.toString()\n}\n\nexport interface FetchOAuthRedirectResult {\n /** Status code from the callback server. 2xx = success. */\n status: number\n /** Best-effort message extracted from the response body (HTML title or trimmed text). */\n message?: string\n}\n\n/**\n * Treat `pasted` as a callback-URL paste. Validates it's a loopback URL,\n * fires a GET, returns the status.\n *\n * Pass `authUrl` (the authorization URL currently on screen) to accept\n * partial pastes — a bare code, a query string, a path — via\n * {@link normalizeRedirectPaste}. Without it only a full absolute URL is\n * accepted, which is the pre-existing contract.\n *\n * Throws when:\n * - `pasted` doesn't parse as a URL (and can't be completed from `authUrl`).\n * - The URL host isn't loopback (rejects SSRF).\n * - The fetch errors out (network, timeout).\n *\n * Returns success/failure for non-2xx responses; the caller decides whether\n * a 4xx is fatal (state mismatch is a 400 the user can retry from).\n */\nexport async function fetchOAuthRedirect(\n pasted: string,\n options: { signal?: AbortSignal, timeoutMs?: number, authUrl?: string } = {},\n): Promise<FetchOAuthRedirectResult> {\n const trimmed = normalizeRedirectPaste(pasted, options.authUrl)\n\n let url: URL\n try {\n url = new URL(trimmed)\n }\n catch {\n throw new Error('That doesn\\'t look like a URL. Paste the full address from your browser.')\n }\n\n // Strip brackets that some browsers add around IPv6 hosts so the\n // comparison hits LOOPBACK_HOSTS regardless of textual form.\n const host = url.hostname.replace(/^\\[|\\]$/g, '')\n if (!LOOPBACK_HOSTS.has(host)) {\n throw new Error(\n `Expected a loopback URL (127.0.0.1 / localhost), got \"${url.hostname}\". The browser should have redirected to a localhost address.`,\n )\n }\n\n // Short timeout: the callback server is in-process, so any meaningful\n // delay means it's gone (closed by a prior abort) or never started.\n const timeoutMs = options.timeoutMs ?? 5000\n const ac = new AbortController()\n const timer = setTimeout(() => ac.abort(), timeoutMs)\n options.signal?.addEventListener('abort', () => ac.abort(), { once: true })\n\n let response: Response\n try {\n response = await fetch(url.toString(), { signal: ac.signal })\n }\n catch (err) {\n if ((err as Error).name === 'AbortError')\n throw new Error('No response from the local callback server. Was the login cancelled?')\n throw new Error(`Could not reach the local callback server: ${(err as Error).message}`)\n }\n finally {\n clearTimeout(timer)\n }\n\n const bodyText = await response.text().catch(() => '')\n return { status: response.status, message: extractMessage(bodyText) }\n}\n\n/**\n * Pick the most useful one-line message out of the callback server's HTML\n * response. pi-ai uses `<h1>` for the heading; the MCP callback uses\n * a leading `<p>`. We try both, then fall back to a stripped snippet.\n */\nfunction extractMessage(html: string): string | undefined {\n if (!html)\n return undefined\n const h1 = /<h1[^>]*>([\\s\\S]*?)<\\/h1>/i.exec(html)?.[1]\n if (h1)\n return stripTags(h1).trim() || undefined\n const p = /<p[^>]*>([\\s\\S]*?)<\\/p>/i.exec(html)?.[1]\n if (p)\n return stripTags(p).trim() || undefined\n return undefined\n}\n\nfunction stripTags(s: string): string {\n return s.replace(/<[^>]*>/g, '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '\"').replace(/'/g, '\\'')\n}\n","/**\n * @-completion path display formatter.\n *\n * The `@`-popover walks the project from the git root so the user sees\n * the whole tree regardless of where they launched the TUI. The\n * agent's CWD-resolving tools (`read_file`, `glob`, `edit`, …) read\n * relative paths against `process.cwd()`, which is frequently a\n * subdirectory of that root. Emitting the discovery's raw\n * project-root-relative path into the prompt produces a `<cwd>/<rel>`\n * miss — the bug this helper exists to close.\n *\n * Rule:\n *\n * - File at `cwd` itself → `.`.\n * - File under `cwd` (subtree) → forward-slashed CWD-relative,\n * no `..`.\n * - File above `cwd` but still inside the project → CWD-relative\n * with `..` traversal (e.g. `../EDIT_THIS.md`). Shorter and more\n * scannable than absolute, and the agent's tools resolve both.\n * - File outside the project (input was passed absolute) → returned\n * verbatim. Inputs that arrive as project-root-relative strings\n * are always inside the project by construction, so this branch\n * only kicks in when a direct caller hands the function an\n * absolute target.\n *\n * Pure, no I/O, deterministic.\n */\n\nimport { isAbsolute, posix, relative, resolve, sep } from 'node:path'\n\n/**\n * Convert a project-root-relative path (as emitted by `listProjectFiles`)\n * into the form the agent's tools — and the user — will actually find\n * given the current `cwd`.\n *\n * Inputs:\n * - `projectRelativePath` — forward-slashed, no leading slash. Returned\n * verbatim when it's empty or already absolute (defensive — the\n * absolute-input branch is the de-facto \"outside the project\"\n * escape; the catalog itself never emits absolute paths).\n * - `projectRoot` — absolute path of the discovery anchor.\n * - `cwd` — absolute path of `process.cwd()` at the moment of\n * insertion.\n *\n * Output is always either an absolute path (only when the input arrived\n * absolute) OR a CWD-relative path. The relative form may include\n * `../` segments when the target sits above `cwd` within the project,\n * which keeps cross-tree references short and scannable\n * (e.g. `../EDIT_THIS.md` instead of `/Users/.../zidane/EDIT_THIS.md`).\n */\nexport function formatPathForCwd(\n projectRelativePath: string,\n projectRoot: string,\n cwd: string,\n): string {\n if (projectRelativePath.length === 0)\n return projectRelativePath\n if (isAbsolute(projectRelativePath))\n return projectRelativePath\n const target = resolve(projectRoot, projectRelativePath)\n const here = resolve(cwd)\n if (target === here)\n return '.'\n const rel = relative(here, target)\n if (rel.length === 0)\n return '.'\n return sep === '/' ? rel : rel.split(sep).join(posix.sep)\n}\n","/**\n * Subscription usage for the providers we authenticate via OAuth, plus\n * OpenRouter's credits endpoint.\n *\n * Probes are keyed by CREDENTIAL FILE KEY, so any descriptor storing its tokens\n * under a known key resolves the right one:\n * - `anthropic` `GET api.anthropic.com/api/oauth/usage`\n * (OAuth bearer + `anthropic-beta: oauth-2025-04-20`, and\n * the `user:profile` scope the login flow requests)\n * - `openai-codex` `GET chatgpt.com/backend-api/wham/usage`\n * (Codex OAuth bearer + `ChatGPT-Account-Id`)\n * - `xai-oauth` `POST grok.com` gRPC-web billing probe. Best-effort: xAI\n * has no token-auth usage API and this endpoint is\n * cookie-oriented, so it often refuses a bearer.\n * - `openrouter` `GET openrouter.ai/api/v1/credits` (official, API key)\n *\n * Only the OpenRouter endpoint is official; the others can change without\n * notice. So every probe is read-only and never throws: failures normalize into\n * a snapshot with `status: 'unauthorized' | 'unavailable'` and a short `error`,\n * which callers render as a state rather than handle as an error.\n *\n * An expired access token is refreshed through the run path's own helper\n * (`resolveOAuthApiKey` in `providers/oauth.ts`), targeting the exact slot:\n * same cross-process lock, same in-process coalescing, same generation check\n * before persisting. Refresh tokens are single-use, so this is the only safe\n * way to do it, and skipping it is not an option any more: parked accounts\n * are never used by a run, so nothing else would ever renew them and they\n * would read `token expired` for good. A failed refresh reports\n * `'unauthorized'` without issuing the usage request.\n *\n * Consent is two-tiered, mirroring the update check: hosts gate automatic\n * probes on `Settings.subscriptionUsage`, and {@link usageChecksOptedOut}\n * (`ZIDANE_NO_USAGE_CHECK` / `CI`) disables every probe here, explicit\n * refreshes included.\n */\n\nimport type { ProviderCredential } from './credentials'\nimport type { ProviderUsageSnapshot, ProviderUsageWindow } from './provider-usage-format'\nimport type { ProviderDescriptor } from './providers'\nimport { resolveOAuthApiKey } from '../providers/oauth'\nimport { credentialsPath, oauthAccountLabel, readCredentials, storedCredentialsOf } from './credentials'\nimport { envOptedOut } from './env-opt-out'\nimport { credKeyOf } from './providers'\n\n// Wire types + presentation helpers live in the node-free sibling so the\n// Electron renderer can share them; re-exported here to keep one import path.\nexport type { ProviderUsageCredits, ProviderUsageSnapshot, ProviderUsageStatus, ProviderUsageWindow } from './provider-usage-format'\nexport { activeSnapshotFor, formatBalance, formatCredits, formatUsagePercent, mostConstrainedWindow, resetLabel, showsAccount, updatedLabel, type UsageTone, usageTone } from './provider-usage-format'\n\n/** Per-request timeout. Generous, since these endpoints are occasionally slow. */\nconst FETCH_TIMEOUT_MS = 15_000\n\n/** How long a snapshot stays fresh. Usage windows move in minutes, not seconds. */\nexport const USAGE_CACHE_TTL_MS = 60_000\n/** TTL after a failed probe kept the previous good snapshot: retry soon, not in a minute. */\nconst USAGE_RETRY_TTL_MS = 10_000\n\n/** Which probe a credential key maps to. */\ntype UsageSource = 'claude' | 'codex' | 'grok' | 'openrouter'\n\n/**\n * Credential-file key to probe. Keyed by credential key rather than provider\n * key so a custom descriptor reusing a builtin credential slot\n * (`credentialFileKey: 'anthropic'`) gets usage for free.\n */\nconst USAGE_SOURCE_BY_CRED_KEY: Readonly<Record<string, UsageSource>> = {\n 'anthropic': 'claude',\n 'openai-codex': 'codex',\n 'xai-oauth': 'grok',\n 'openrouter': 'openrouter',\n}\n\n/** Credential kind each probe authenticates with. */\nconst SOURCE_CRED_KIND: Readonly<Record<UsageSource, ProviderCredential['kind']>> = {\n claude: 'oauth',\n codex: 'oauth',\n grok: 'oauth',\n openrouter: 'apikey',\n}\n\n/** The probe for a descriptor, or `null` when it has no usage surface. */\nexport function usageSourceFor(descriptor: ProviderDescriptor): UsageSource | null {\n return USAGE_SOURCE_BY_CRED_KEY[credKeyOf(descriptor)] ?? null\n}\n\n/** Whether this provider can report subscription usage at all. */\nexport function providerUsageSupported(descriptor: ProviderDescriptor): boolean {\n return usageSourceFor(descriptor) !== null\n}\n\n// ---------------------------------------------------------------------------\n// Cache + entry points\n// ---------------------------------------------------------------------------\n\ninterface CacheEntry {\n expiresAt: number\n snapshot: ProviderUsageSnapshot\n}\n\n/** Keyed by credential slot + token: two descriptors sharing tokens share a snapshot. */\nconst cache = new Map<string, CacheEntry>()\n/** In-flight probes, so a footer read and a panel open share one request. */\nconst inFlight = new Map<string, Promise<ProviderUsageSnapshot>>()\n/**\n * Newest probe issued per cache key, as a monotonic ticket. `refresh`\n * skips both maps above, so two probes for one key can be outstanding at once\n * (panel refresh while the footer's post-run refresh is still in flight); only\n * the newest may write the cache, or a slow older probe would pin stale\n * numbers for a full TTL. Clearing the map also invalidates every outstanding\n * ticket, so a probe that spans `clearProviderUsageCache()` cannot repopulate\n * the cache it was meant to drop.\n */\nconst latestProbe = new Map<string, number>()\nlet probeTicket = 0\n\n/**\n * Drop every cached snapshot. Entries are keyed by credential KEY, not by the\n * token itself, so signing out and back in (or re-authing to another account)\n * would otherwise keep serving the previous account's numbers for the rest of\n * the TTL. The TUI calls this wherever it re-reads credentials.\n */\nexport function clearProviderUsageCache(): void {\n cache.clear()\n inFlight.clear()\n latestProbe.clear()\n}\n\n// ---------------------------------------------------------------------------\n// Env opt-outs\n//\n// Same shape as the update check's (see `chat/auto-update.ts`): these probes\n// are the only other background network calls the TUI makes, and they talk to\n// hosts that are not the ones inference goes to, so an air-gapped, CI, or\n// privacy-sensitive environment must be able to switch them off without\n// touching settings. `ZIDANE_NO_USAGE_CHECK` is the project knob; `CI` is set\n// by every major runner and skipping there avoids surprise chatter from build\n// pipelines. Unlike the setting, this is absolute: it also blocks the panel's\n// explicit refresh.\n// ---------------------------------------------------------------------------\n\nconst OPT_OUT_VARS = ['ZIDANE_NO_USAGE_CHECK', 'CI'] as const\n\n/** Whether the environment forbids usage probes outright. */\nexport function usageChecksOptedOut(env: NodeJS.ProcessEnv = process.env): boolean {\n return envOptedOut(OPT_OUT_VARS, env)\n}\n\nexport interface FetchProviderUsageOptions {\n /** Ignore (and replace) a still-fresh cached snapshot. */\n refresh?: boolean\n}\n\n/** One credential a probe can authenticate with, and the slot it came from. */\ninterface UsageCredential {\n /** Credentials-file key (`anthropic`, `anthropic#account:1`, …). */\n key: string\n cred: ProviderCredential\n /** Canonical slot, i.e. the credential requests use. */\n active: boolean\n}\n\n/**\n * Usage for one provider, probed with the credential requests use — or, when\n * that one is not the kind the probe needs (an API key in use, OAuth accounts\n * parked beside it), the first stored one that is. What the footer shows.\n *\n * `null` means there is nothing to show: the provider has no usage surface,\n * no credential of the kind its probe needs (file or, for API keys, env), or\n * the environment opted out (see {@link usageChecksOptedOut}).\n *\n * Never rejects. Transport and parse failures land in the snapshot.\n */\nexport async function fetchProviderUsage(\n dataDir: string,\n descriptor: ProviderDescriptor,\n opts: FetchProviderUsageOptions = {},\n): Promise<ProviderUsageSnapshot | null> {\n const source = usageSourceFor(descriptor)\n if (!source || usageChecksOptedOut())\n return null\n const [preferred] = resolveUsageCredentials(dataDir, descriptor, source)\n if (!preferred)\n return null\n return probeRenewed(dataDir, source, descriptor, preferred, opts)\n}\n\n/**\n * Usage for EVERY credential of a provider the probe can use — one snapshot\n * per stored OAuth account, the active one first. What the panel renders.\n * Empty under the same conditions {@link fetchProviderUsage} returns `null`.\n */\nexport async function fetchProviderUsageAccounts(\n dataDir: string,\n descriptor: ProviderDescriptor,\n opts: FetchProviderUsageOptions = {},\n): Promise<readonly ProviderUsageSnapshot[]> {\n const source = usageSourceFor(descriptor)\n if (!source || usageChecksOptedOut())\n return []\n const credentials = resolveUsageCredentials(dataDir, descriptor, source)\n return Promise.all(credentials.map(c => probeRenewed(dataDir, source, descriptor, c, opts)))\n}\n\n/**\n * {@link probeCached}, after renewing an expired OAuth token in its slot.\n * Stays synchronous up to the request when no renewal is needed, so callers\n * that start two probes back to back still see both requests issued at once.\n */\nfunction probeRenewed(\n dataDir: string,\n source: UsageSource,\n descriptor: ProviderDescriptor,\n credential: UsageCredential,\n opts: FetchProviderUsageOptions,\n): Promise<ProviderUsageSnapshot> {\n if (!needsRenewal(credential.cred))\n return probeCached(source, descriptor, credential, opts)\n return renewExpired(dataDir, descriptor, credential).then(renewed =>\n 'status' in renewed\n ? stampIdentity(renewed, descriptor, credential)\n : probeCached(source, descriptor, renewed, opts))\n}\n\n/**\n * An expired OAuth token that carries a refresh token. One without cannot be\n * renewed and reports `token expired` from the probe itself.\n */\nfunction needsRenewal(cred: ProviderCredential): boolean {\n return cred.kind === 'oauth' && typeof cred.expires === 'number' && cred.expires <= Date.now() && !!cred.refresh\n}\n\n/**\n * Rotate an expired OAuth token through the run path's refresh helper, keyed\n * to this credential's own slot, and hand back the credential as now stored.\n * A failed refresh becomes an `unauthorized` snapshot.\n */\nasync function renewExpired(\n dataDir: string,\n descriptor: ProviderDescriptor,\n credential: UsageCredential,\n): Promise<UsageCredential | ProviderUsageSnapshot> {\n try {\n await resolveOAuthApiKey({\n provider: descriptor.key,\n providerId: credKeyOf(descriptor),\n credentialKey: credential.key,\n credentialsPath: credentialsPath(dataDir),\n missingError: 'not signed in',\n refreshError: reason => reason,\n })\n }\n catch {\n // The reason is already surfaced by the next run (its refresh fails the\n // same way, with the full message); the panel just needs the state.\n return snapshot(\n { providerKey: descriptor.key, label: descriptor.label },\n { status: 'unauthorized', error: 'refresh failed' },\n )\n }\n // Re-read rather than trust a callback: another process may have rotated\n // the slot moments earlier, in which case the helper found a fresh token\n // and fired no refresh event, and the file is the only source of truth.\n const stored = readCredentials(dataDir)[credential.key]\n return stored?.kind === 'oauth' ? { ...credential, cred: stored } : credential\n}\n\n/** Probe one credential through the cache / in-flight coalescing. */\nfunction probeCached(\n source: UsageSource,\n descriptor: ProviderDescriptor,\n credential: UsageCredential,\n opts: FetchProviderUsageOptions,\n): Promise<ProviderUsageSnapshot> {\n // Keyed by the token, not the slot: promoting a parked account moves tokens\n // between slots, and a slot-keyed cache would then serve one account's\n // numbers under the other's name for the rest of the TTL.\n const cacheKey = `${credential.key}\\0${credential.cred.kind === 'oauth' ? credential.cred.access : credential.cred.value}`\n // Identity is re-stamped on every return path: a snapshot can come back from\n // a probe another descriptor started, and it must still name the provider\n // (and slot) the caller asked about.\n const identify = (snapshot: ProviderUsageSnapshot): ProviderUsageSnapshot => stampIdentity(snapshot, descriptor, credential)\n\n if (!opts.refresh) {\n const cached = cache.get(cacheKey)\n if (cached && cached.expiresAt > Date.now())\n return Promise.resolve(identify(cached.snapshot))\n const pending = inFlight.get(cacheKey)\n if (pending)\n return pending.then(identify)\n }\n\n const ticket = ++probeTicket\n latestProbe.set(cacheKey, ticket)\n const previous = cache.get(cacheKey)?.snapshot\n const probe = runProbe(source, descriptor, credential.cred)\n .then((fresh) => {\n // A transient failure (timeout, 5xx, parse error) must not replace\n // numbers that were fine a minute ago: the panel would flap between\n // real windows and \"unavailable\" on every hiccup. Keep the last good\n // snapshot, but only for a short while so the next probe retries soon.\n // `unauthorized` is a real state change and always shows.\n const keepPrevious = fresh.status === 'unavailable' && previous?.status === 'ok'\n const snapshot = keepPrevious ? previous : fresh\n if (latestProbe.get(cacheKey) === ticket)\n cache.set(cacheKey, { expiresAt: Date.now() + (keepPrevious ? USAGE_RETRY_TTL_MS : USAGE_CACHE_TTL_MS), snapshot })\n return snapshot\n })\n .finally(() => {\n if (inFlight.get(cacheKey) === probe)\n inFlight.delete(cacheKey)\n })\n inFlight.set(cacheKey, probe)\n return probe.then(identify)\n}\n\n/** Name the provider, slot, and account a snapshot belongs to. */\nfunction stampIdentity(snapshot: ProviderUsageSnapshot, descriptor: ProviderDescriptor, credential: UsageCredential): ProviderUsageSnapshot {\n return {\n ...snapshot,\n providerKey: descriptor.key,\n label: descriptor.label,\n credentialKey: credential.key,\n account: credential.cred.kind === 'oauth' ? oauthAccountLabel(credential.cred) : null,\n activeCredential: credential.active,\n }\n}\n\n/**\n * Every credential a probe can authenticate with, active slot first, then in\n * storage order. Empty when the provider isn't authenticated in a way the\n * probe can use.\n *\n * An API key is taken from the environment when the file has none: `detectAuth`\n * marks a provider available on a shell-set `envKey` alone, and the launcher\n * copies stored keys INTO env, so the two are the same signal. Reading only the\n * file would leave an env-authed user with no row at all, under an empty state\n * telling them they aren't signed in. OAuth tokens have no env equivalent, so\n * those probes stay file-only.\n */\nfunction resolveUsageCredentials(\n dataDir: string,\n descriptor: ProviderDescriptor,\n source: UsageSource,\n): UsageCredential[] {\n const kind = SOURCE_CRED_KIND[source]\n const credKey = credKeyOf(descriptor)\n // A stored API key with an empty value is a customFields-only credential\n // (see `ApiKeyCredential.value`), so fall through to env rather than probing\n // with nothing.\n const stored = storedCredentialsOf(readCredentials(dataDir), credKey)\n .filter(s => s.credential.kind === kind && (s.credential.kind !== 'apikey' || s.credential.value))\n .map(s => ({ key: s.key, cred: s.credential, active: s.active }))\n if (stored.length > 0)\n return stored\n if (kind === 'apikey' && descriptor.envKey) {\n const fromEnv = process.env[descriptor.envKey]\n if (fromEnv)\n return [{ key: credKey, cred: { kind: 'apikey', value: fromEnv }, active: true }]\n }\n return []\n}\n\n/**\n * Usage for every registered provider that has both a usage surface and a\n * usable credential, in registry order, every account included.\n */\nexport async function fetchAllProviderUsage(\n dataDir: string,\n registry: Readonly<Record<string, ProviderDescriptor>>,\n opts: FetchProviderUsageOptions = {},\n): Promise<readonly ProviderUsageSnapshot[]> {\n const candidates = Object.values(registry).filter(providerUsageSupported)\n const settled = await Promise.all(\n candidates.map(descriptor => fetchProviderUsageAccounts(dataDir, descriptor, opts)),\n )\n return settled.flat()\n}\n\n// ---------------------------------------------------------------------------\n// Probes\n// ---------------------------------------------------------------------------\n\nasync function runProbe(\n source: UsageSource,\n descriptor: ProviderDescriptor,\n cred: ProviderCredential,\n): Promise<ProviderUsageSnapshot> {\n const base = { providerKey: descriptor.key, label: descriptor.label }\n try {\n switch (source) {\n case 'claude':\n return await fetchClaudeUsage(base, cred)\n case 'codex':\n return await fetchCodexUsage(base, cred)\n case 'grok':\n return await fetchGrokUsage(base, cred)\n case 'openrouter':\n return await fetchOpenRouterUsage(base, cred)\n }\n }\n catch (err) {\n // Covers `AbortSignal.timeout` firing. A slow endpoint is unavailable, not\n // an error the caller should handle.\n return snapshot(base, { error: err instanceof Error ? err.message : 'request failed' })\n }\n}\n\n/** Identity half of a snapshot, resolved once per probe. */\ntype SnapshotBase = Pick<ProviderUsageSnapshot, 'providerKey' | 'label'>\n\n/**\n * Snapshot factory. Defaults to `unavailable` so failure paths stay one-liners.\n * The credential identity fields are placeholders here; `probeCached` stamps\n * the real ones on every return path.\n */\nfunction snapshot(base: SnapshotBase, partial: Partial<ProviderUsageSnapshot> = {}): ProviderUsageSnapshot {\n return {\n ...base,\n credentialKey: base.providerKey,\n account: null,\n activeCredential: true,\n status: 'unavailable',\n plan: null,\n windows: [],\n credits: null,\n fetchedAt: Date.now(),\n error: null,\n ...partial,\n }\n}\n\n/**\n * OAuth access token, or an `unauthorized` snapshot explaining why there isn't\n * one. Expiry is checked without refreshing (see the module header); the next\n * run refreshes it.\n */\nfunction accessTokenOr(\n base: SnapshotBase,\n cred: ProviderCredential,\n): { token: string } | { fail: ProviderUsageSnapshot } {\n if (cred.kind !== 'oauth' || !cred.access)\n return { fail: snapshot(base, { status: 'unauthorized', error: 'not signed in' }) }\n if (typeof cred.expires === 'number' && cred.expires <= Date.now())\n return { fail: snapshot(base, { status: 'unauthorized', error: 'token expired' }) }\n return { token: cred.access }\n}\n\n/**\n * 401/403 to unauthorized, other non-2xx to unavailable. `null` when the\n * response is fine.\n *\n * A rejected token reads in the same register as the local checks (`not signed\n * in`, `token expired`): it is the row a real user hits most, and the status\n * code tells them nothing. Other codes keep the number, where it is the useful\n * detail.\n */\nfunction httpFailure(base: SnapshotBase, res: Response): ProviderUsageSnapshot | null {\n if (res.status === 401 || res.status === 403)\n return snapshot(base, { status: 'unauthorized', error: 'token rejected' })\n if (!res.ok)\n return snapshot(base, { error: `HTTP ${res.status}` })\n return null\n}\n\n// --- Claude ----------------------------------------------------------------\n\ninterface ClaudeWindow { utilization?: number, resets_at?: string | null }\n\nconst CLAUDE_WINDOWS: readonly { key: string, id: string, label: string }[] = [\n { key: 'five_hour', id: 'five_hour', label: '5h' },\n { key: 'seven_day', id: 'seven_day', label: 'weekly' },\n { key: 'seven_day_opus', id: 'seven_day_opus', label: 'opus weekly' },\n { key: 'seven_day_sonnet', id: 'seven_day_sonnet', label: 'sonnet weekly' },\n]\n\nasync function fetchClaudeUsage(base: SnapshotBase, cred: ProviderCredential): Promise<ProviderUsageSnapshot> {\n const auth = accessTokenOr(base, cred)\n if ('fail' in auth)\n return auth.fail\n\n const res = await fetch('https://api.anthropic.com/api/oauth/usage', {\n headers: {\n 'Authorization': `Bearer ${auth.token}`,\n 'anthropic-beta': 'oauth-2025-04-20',\n 'Accept': 'application/json',\n },\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n })\n const failure = httpFailure(base, res)\n if (failure)\n return failure\n\n const data = await res.json().catch(() => null) as Record<string, unknown> | null\n if (!data)\n return snapshot(base, { error: 'invalid response' })\n\n const windows: ProviderUsageWindow[] = []\n for (const { key, id, label } of CLAUDE_WINDOWS) {\n const win = data[key] as ClaudeWindow | undefined\n if (win && typeof win.utilization === 'number') {\n windows.push({\n id,\n label,\n usedPercent: clampPercent(win.utilization),\n resetsAt: isoToEpoch(win.resets_at),\n })\n }\n }\n if (windows.length === 0)\n return snapshot(base, { error: 'no usage data' })\n return snapshot(base, { status: 'ok', windows })\n}\n\n// --- OpenAI Codex ----------------------------------------------------------\n\ninterface CodexWindow { used_percent?: number, reset_at?: number, limit_window_seconds?: number }\n\n/** Codex reports window length, not a name, so derive `5h` / `weekly` / `Nd`. */\nfunction codexWindowLabel(win: CodexWindow, fallback: string): string {\n const seconds = win.limit_window_seconds\n if (!seconds)\n return fallback\n if (seconds < 86_400)\n return `${Math.round(seconds / 3600)}h`\n const days = Math.round(seconds / 86_400)\n return days === 7 ? 'weekly' : `${days}d`\n}\n\nasync function fetchCodexUsage(base: SnapshotBase, cred: ProviderCredential): Promise<ProviderUsageSnapshot> {\n const auth = accessTokenOr(base, cred)\n if ('fail' in auth)\n return auth.fail\n const accountId = cred.kind === 'oauth' && typeof cred.accountId === 'string' ? cred.accountId : null\n\n const res = await fetch('https://chatgpt.com/backend-api/wham/usage', {\n headers: {\n 'Authorization': `Bearer ${auth.token}`,\n ...(accountId ? { 'ChatGPT-Account-Id': accountId } : {}),\n 'User-Agent': 'codex-cli',\n 'Accept': 'application/json',\n },\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n })\n const failure = httpFailure(base, res)\n if (failure)\n return failure\n\n const data = await res.json().catch(() => null) as {\n plan_type?: string\n rate_limit?: { primary_window?: CodexWindow, secondary_window?: CodexWindow }\n /** Some responses use the plural key. Both are accepted. */\n rate_limits?: { primary_window?: CodexWindow, secondary_window?: CodexWindow }\n credits?: { has_credits?: boolean, unlimited?: boolean, balance?: number }\n } | null\n if (!data)\n return snapshot(base, { error: 'invalid response' })\n\n const rateLimit = data.rate_limit ?? data.rate_limits\n const windows: ProviderUsageWindow[] = []\n const push = (win: CodexWindow | undefined, id: string, fallbackLabel: string) => {\n if (win && typeof win.used_percent === 'number') {\n windows.push({\n id,\n label: codexWindowLabel(win, fallbackLabel),\n usedPercent: clampPercent(win.used_percent),\n resetsAt: typeof win.reset_at === 'number' ? win.reset_at * 1000 : null,\n })\n }\n }\n push(rateLimit?.primary_window, 'primary', '5h')\n push(rateLimit?.secondary_window, 'secondary', 'weekly')\n\n const credits = data.credits && typeof data.credits.balance === 'number' && !data.credits.unlimited\n ? { remaining: data.credits.balance, total: null }\n : null\n\n if (windows.length === 0 && !credits)\n return snapshot(base, { error: 'no usage data' })\n return snapshot(base, {\n status: 'ok',\n plan: typeof data.plan_type === 'string' ? data.plan_type : null,\n windows,\n credits,\n })\n}\n\n// --- OpenRouter ------------------------------------------------------------\n\nasync function fetchOpenRouterUsage(base: SnapshotBase, cred: ProviderCredential): Promise<ProviderUsageSnapshot> {\n if (cred.kind !== 'apikey' || !cred.value)\n return snapshot(base, { status: 'unauthorized', error: 'no API key stored' })\n\n const res = await fetch('https://openrouter.ai/api/v1/credits', {\n headers: { Authorization: `Bearer ${cred.value}`, Accept: 'application/json' },\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n })\n const failure = httpFailure(base, res)\n if (failure)\n return failure\n\n const body = await res.json().catch(() => null) as { data?: { total_credits?: number, total_usage?: number } } | null\n const totals = body?.data\n if (!totals || typeof totals.total_credits !== 'number' || typeof totals.total_usage !== 'number')\n return snapshot(base, { error: 'invalid response' })\n\n const usedPercent = totals.total_credits > 0\n ? clampPercent((totals.total_usage / totals.total_credits) * 100)\n : 0\n return snapshot(base, {\n status: 'ok',\n windows: [{ id: 'credits', label: 'credits', usedPercent, resetsAt: null }],\n credits: { remaining: totals.total_credits - totals.total_usage, total: totals.total_credits },\n })\n}\n\n// --- Grok ------------------------------------------------------------------\n\nconst GROK_BILLING_URL = 'https://grok.com/grok_api_v2.GrokBuildBilling/GetGrokCreditsConfig'\nconst GROK_AUTH_FAILURE_RE = /access token|unauthenticated|expired/i\n\nasync function fetchGrokUsage(base: SnapshotBase, cred: ProviderCredential): Promise<ProviderUsageSnapshot> {\n const auth = accessTokenOr(base, cred)\n if ('fail' in auth)\n return auth.fail\n\n const res = await fetch(GROK_BILLING_URL, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${auth.token}`,\n 'Content-Type': 'application/grpc-web+proto',\n 'x-grpc-web': '1',\n 'x-user-agent': 'connect-es/2.1.1',\n 'Origin': 'https://grok.com',\n 'Referer': 'https://grok.com/?_s=usage',\n 'Accept': '*/*',\n },\n // Empty gRPC-web frame: flags byte + u32 length 0.\n body: new Uint8Array([0, 0, 0, 0, 0]),\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n })\n const failure = httpFailure(base, res)\n if (failure)\n return failure\n\n // gRPC carries its own status out-of-band, so HTTP 200 with `grpc-status: 16`\n // is an auth rejection. That is the common answer for a bearer here.\n const grpcStatus = res.headers.get('grpc-status')\n if (grpcStatus && grpcStatus !== '0') {\n const message = res.headers.get('grpc-message') ?? ''\n const unauthorized = grpcStatus === '16' || (grpcStatus === '7' && GROK_AUTH_FAILURE_RE.test(message))\n // Plain words for the expected case, the raw status for the rest: this\n // endpoint wants a session cookie, so a rejected bearer is routine, while\n // any other status is worth reporting verbatim.\n return unauthorized\n ? snapshot(base, { status: 'unauthorized', error: 'token not accepted' })\n : snapshot(base, { error: `gRPC ${grpcStatus}${message ? `: ${message}` : ''}` })\n }\n\n const parsed = parseGrokBillingResponse(new Uint8Array(await res.arrayBuffer()))\n if (!parsed)\n return snapshot(base, { error: 'unreadable response' })\n return snapshot(base, {\n status: 'ok',\n windows: [{\n id: 'credits',\n label: 'credits',\n usedPercent: clampPercent(parsed.usedPercent),\n resetsAt: parsed.resetsAt ? parsed.resetsAt.getTime() : null,\n }],\n })\n}\n\n// ---------------------------------------------------------------------------\n// Grok payload: tolerant protobuf scan\n//\n// The billing response is a protobuf whose schema we don't have. Rather than\n// vendor a generated client for an endpoint xAI can change at will, walk the\n// wire format and recover the two fields we need by shape. A wrong-shaped\n// payload yields `null`, which surfaces as an `unavailable` row.\n// ---------------------------------------------------------------------------\n\ninterface ScannedField { path: number[], order: number, value: number }\ninterface ProtobufScan { fixed32: ScannedField[], varint: ScannedField[] }\n\n/** Split a gRPC-web body into data frames. Flag bit 0x80 marks trailers. */\nexport function grpcWebDataFrames(bytes: Uint8Array): Uint8Array[] {\n const frames: Uint8Array[] = []\n let index = 0\n while (index < bytes.length) {\n if (index + 5 > bytes.length)\n return []\n const flags = bytes[index]!\n const length = (bytes[index + 1]! << 24) | (bytes[index + 2]! << 16) | (bytes[index + 3]! << 8) | bytes[index + 4]!\n const start = index + 5\n const end = start + length\n if (length < 0 || end > bytes.length)\n return []\n if ((flags & 0x80) === 0)\n frames.push(bytes.subarray(start, end))\n index = end\n }\n return frames\n}\n\nfunction looksLikeProtobuf(bytes: Uint8Array): boolean {\n if (bytes.length === 0)\n return false\n const fieldNumber = bytes[0]! >> 3\n const wireType = bytes[0]! & 0x07\n return fieldNumber > 0 && (wireType === 0 || wireType === 1 || wireType === 2 || wireType === 5)\n}\n\nfunction readVarint(bytes: Uint8Array, offset: number): { value: number, next: number } | null {\n let value = 0\n let shift = 0\n let index = offset\n while (index < bytes.length && shift < 64) {\n const byte = bytes[index]!\n // Float math is fine here: the values we care about (epoch seconds, small\n // enums) sit far below 2^53.\n value += (byte & 0x7F) * 2 ** shift\n index += 1\n if ((byte & 0x80) === 0)\n return { value, next: index }\n shift += 7\n }\n return null\n}\n\nfunction scanProtobuf(bytes: Uint8Array, path: number[], scan: ProtobufScan, orderRef: { n: number }, depth: number): void {\n if (depth > 6)\n return\n let index = 0\n while (index < bytes.length) {\n const tag = readVarint(bytes, index)\n if (!tag)\n return\n const fieldNumber = Math.floor(tag.value / 8)\n const wireType = tag.value % 8\n if (fieldNumber === 0)\n return\n index = tag.next\n const fieldPath = [...path, fieldNumber]\n switch (wireType) {\n case 0: { // varint\n const v = readVarint(bytes, index)\n if (!v)\n return\n scan.varint.push({ path: fieldPath, order: orderRef.n++, value: v.value })\n index = v.next\n break\n }\n case 1: { // fixed64, nothing we need is a double\n if (index + 8 > bytes.length)\n return\n index += 8\n break\n }\n case 5: { // fixed32 (float), where the used percent lives\n if (index + 4 > bytes.length)\n return\n const view = new DataView(bytes.buffer, bytes.byteOffset + index, 4)\n scan.fixed32.push({ path: fieldPath, order: orderRef.n++, value: view.getFloat32(0, true) })\n index += 4\n break\n }\n case 2: { // length-delimited, recurse when it looks like a nested message\n const len = readVarint(bytes, index)\n if (!len || len.next + len.value > bytes.length)\n return\n const sub = bytes.subarray(len.next, len.next + len.value)\n if (looksLikeProtobuf(sub))\n scanProtobuf(sub, fieldPath, scan, orderRef, depth + 1)\n index = len.next + len.value\n break\n }\n default:\n return // groups and unknown wire types: bail rather than misparse\n }\n }\n}\n\n/**\n * Recover `{ usedPercent, resetsAt }` from the billing protobuf without a\n * schema. The used percent is a fixed32 float in 0-100 whose path ends in field\n * 1 (shallowest, earliest wins); the reset is the nearest future epoch-second\n * varint, preferring path `[1,5,1]` (billing-cycle end).\n */\nexport function parseGrokBillingResponse(\n bytes: Uint8Array,\n now = new Date(),\n): { usedPercent: number, resetsAt: Date | null } | null {\n let frames = grpcWebDataFrames(bytes)\n if (frames.length === 0 && looksLikeProtobuf(bytes))\n frames = [bytes]\n if (frames.length === 0)\n return null\n\n const scan: ProtobufScan = { fixed32: [], varint: [] }\n const orderRef = { n: 0 }\n for (const frame of frames)\n scanProtobuf(frame, [], scan, orderRef, 0)\n\n const percentField = scan.fixed32\n .filter(f => f.path.at(-1) === 1 && Number.isFinite(f.value) && f.value >= 0 && f.value <= 100)\n .sort((a, b) => a.path.length === b.path.length ? a.order - b.order : a.path.length - b.path.length)[0]\n\n const epochFields = scan.varint\n .filter(f => f.value >= 1_700_000_000 && f.value <= 2_100_000_000)\n .map(f => ({ path: f.path, date: new Date(f.value * 1000) }))\n .filter(f => f.date > now)\n const preferred = epochFields.filter(\n f => f.path.length === 3 && f.path[0] === 1 && f.path[1] === 5 && f.path[2] === 1,\n )\n const resetsAt = (preferred.length > 0 ? preferred : epochFields)\n .map(f => f.date)\n .sort((a, b) => a.getTime() - b.getTime())[0] ?? null\n\n // Zero-usage periods omit the proto3 default percent field, so a billing\n // period with a future reset reads as 0% used.\n const hasUsagePeriod = scan.varint.some(f =>\n (f.path.length >= 2 && f.path[0] === 1 && f.path[1] === 6)\n || (f.path.length === 3 && f.path[0] === 1 && f.path[1] === 8 && f.path[2] === 1 && (f.value === 1 || f.value === 2)),\n )\n if (!percentField) {\n if (scan.fixed32.length === 0 && resetsAt && hasUsagePeriod)\n return { usedPercent: 0, resetsAt }\n return null\n }\n return { usedPercent: percentField.value, resetsAt }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction clampPercent(value: number): number {\n if (!Number.isFinite(value))\n return 0\n return Math.min(100, Math.max(0, Math.round(value * 10) / 10))\n}\n\nfunction isoToEpoch(value: string | null | undefined): number | null {\n if (typeof value !== 'string')\n return null\n const ts = new Date(value).getTime()\n return Number.isFinite(ts) ? ts : null\n}\n","/**\n * Safe-mode React context — bridges the agent's `tool:gate` / `mcp:tool:gate`\n * hooks (which run inside the harness loop) with the TUI's React tree (which\n * renders the approval picker).\n *\n * Flow:\n * 1. Hook handler in `tui/host/host-session-callbacks.ts` calls `requestApproval(tool, input)`.\n * 2. Context appends a pending entry to the queue, returns a Promise.\n * 3. Picker renders the queue's head, calls `resolve(decision)` on pick.\n * 4. Head is shifted off the queue; hook handler proceeds with the decision.\n *\n * The queue is FIFO so parallel tool calls prompt in arrival order.\n *\n * Two contexts on purpose:\n * - `SafeModeQueueContext` carries the live queue. Consumers re-render on\n * every push/pop.\n * - `SafeModeActionsContext` carries `{ requestApproval, resolveHead,\n * denyAll }` and never changes identity, so callbacks that depend on\n * these don't re-bind every time a tool call enters or leaves the queue.\n */\n\nimport type { ReactNode } from 'react'\nimport { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'\n\n/**\n * Outcome of an approval prompt. Four bulk decisions match the original\n * single-edit modal contract; `partial` is the multi-edit branch — the\n * user accepted a subset of an `edit` / `multi_edit` / `write_file` call.\n *\n * `partial.mask` is 1:1 with the call's hunks (in input order): `true`\n * means apply, `false` means deny. The gate handler walks the mask to\n * build per-hunk outcomes; the TUI rebinds `ctx.input.edits` to the\n * approved subset and the renderer reconstructs the full per-hunk view\n * from the `<edit-outcomes>` annotation appended to the tool result.\n */\nexport type ApprovalDecision\n = | 'accept-once'\n | 'accept-session'\n | 'accept-safelist'\n | 'deny'\n | { kind: 'partial', mask: readonly boolean[] }\n\n/**\n * Identifies the caller behind an approval prompt — the parent agent or\n * a specific subagent (`child-N`). The modal's right-side title pins the\n * label so the user knows which agent issued the call when subagents\n * bubble their gates up through the parent's hook bus.\n */\nexport type ApprovalOriginator\n = | { kind: 'parent' }\n | { kind: 'child', label: string }\n\nexport interface ApprovalRequest {\n id: string\n tool: string\n input: Record<string, unknown>\n resolve: (decision: ApprovalDecision) => void\n /** Caller attribution. Absent ≡ `{ kind: 'parent' }`. */\n originator?: ApprovalOriginator\n /**\n * Cross-window correlation id (the daemon's approval request id) for\n * entries surfaced by the daemon runtime. Lets `dropByCorrelation`\n * retract this entry when ANOTHER window resolves the same shared\n * approval, without re-sending a decision. Absent for local-runtime\n * approvals.\n */\n correlationId?: string\n}\n\n/** Function signature consumed by `tool:gate` handlers + the child-tool wrap. */\nexport type RequestApproval = (\n tool: string,\n input: Record<string, unknown>,\n originator?: ApprovalOriginator,\n correlationId?: string,\n) => Promise<ApprovalDecision>\n\nexport interface SafeModeActions {\n /** Request a decision; resolves once the user picks. */\n requestApproval: RequestApproval\n /** Resolve the head and shift the queue forward. */\n resolveHead: (decision: ApprovalDecision) => void\n /** Resolve all pending with `deny`. Used on abort / hard exit. */\n denyAll: () => void\n /**\n * Remove the entry whose `correlationId` matches, WITHOUT resolving it\n * (the daemon already did, in another window). No-op when absent.\n */\n dropByCorrelation: (correlationId: string) => void\n}\n\nconst SafeModeQueueContext = createContext<readonly ApprovalRequest[]>([])\nconst SafeModeActionsContext = createContext<SafeModeActions | null>(null)\n\nlet approvalIdCounter = 0\nfunction nextApprovalId(): string {\n // Monotonic id is enough — uniqueness is scoped to a single TUI session\n // and the value never leaves the React tree. Avoids Date.now/Math.random\n // collisions inside tight parallel-tool batches.\n approvalIdCounter += 1\n return `approval-${approvalIdCounter}`\n}\n\n/**\n * Owns the queue + actions. Splits the value across two contexts so a queue\n * change doesn't invalidate every callback memo that closes over the actions.\n */\nexport function SafeModeProvider({ children }: { children: ReactNode }) {\n const [queue, setQueue] = useState<readonly ApprovalRequest[]>([])\n\n // Mirror the live queue so the unmount cleanup settles pending approvals\n // without re-subscribing on every queue change.\n const queueRef = useRef<readonly ApprovalRequest[]>([])\n queueRef.current = queue\n\n // Provider unmount drops the queue state — a tool body parked on\n // `requestApproval` would then hang forever (its run's `running` gate\n // never clears). Deny every pending request on unmount so no resolver is\n // silently dropped. (#4)\n useEffect(() => () => {\n for (const p of queueRef.current)\n p.resolve('deny')\n }, [])\n\n // `setQueue` is stable, so `useCallback([])` here gives genuine identity\n // stability — `requestApproval` is the same function reference for the\n // lifetime of the provider, which is what hook handlers need.\n const requestApproval = useCallback<RequestApproval>(\n (tool, input, originator, correlationId) => new Promise<ApprovalDecision>((resolve) => {\n setQueue(prev => [\n ...prev,\n {\n id: nextApprovalId(),\n tool,\n input,\n resolve,\n ...(originator ? { originator } : {}),\n ...(correlationId ? { correlationId } : {}),\n },\n ])\n }),\n [],\n )\n\n const resolveHead = useCallback((decision: ApprovalDecision) => {\n setQueue((prev) => {\n const [head, ...rest] = prev\n if (head)\n head.resolve(decision)\n return rest\n })\n }, [])\n\n const denyAll = useCallback(() => {\n setQueue((prev) => {\n for (const p of prev) p.resolve('deny')\n return []\n })\n }, [])\n\n const dropByCorrelation = useCallback((correlationId: string) => {\n // Remove WITHOUT resolving: the daemon already settled this approval\n // in the window that answered it. Resolving here would double-answer\n // (harmless deny) AND fire the RPC guard path unnecessarily.\n setQueue(prev => prev.filter(p => p.correlationId !== correlationId))\n }, [])\n\n // Actions object is stable across renders — its members are all `useCallback`'d\n // with `[]` deps. `useRef` captures the first-render identity and we hand the\n // same object out forever, so consumers calling `useSafeModeActions()` never\n // re-render purely because of safe-mode state.\n const actionsRef = useRef<SafeModeActions | null>(null)\n if (!actionsRef.current)\n actionsRef.current = { requestApproval, resolveHead, denyAll, dropByCorrelation }\n\n return (\n <SafeModeActionsContext.Provider value={actionsRef.current}>\n <SafeModeQueueContext.Provider value={queue}>\n {children}\n </SafeModeQueueContext.Provider>\n </SafeModeActionsContext.Provider>\n )\n}\n\nexport function useSafeModeQueue(): readonly ApprovalRequest[] {\n return useContext(SafeModeQueueContext)\n}\n\nexport function useSafeModeActions(): SafeModeActions {\n const ctx = useContext(SafeModeActionsContext)\n if (!ctx)\n throw new Error('useSafeModeActions must be used inside <SafeModeProvider>')\n return ctx\n}\n","/**\n * Session export — render a `SessionData` as a clean Markdown or JSON\n * document and write it under the project's `.{prefix}/sessions/` directory,\n * or the user's `<dataDir>/sessions/`.\n *\n * Anchor resolution mirrors the read-side `projectUserPaths` convention,\n * but for *writes* we pick a single canonical destination instead of a\n * fallback list: the closest enclosing git repository (walking up from\n * `cwd`), and the user's storage data dir as the final fallback. This keeps\n * exports out of an unrelated project's `.{prefix}/` directory when the\n * user runs the TUI from a non-repo folder.\n *\n * Renderer-agnostic by design: every consumer (TUI, future GUI, SDK\n * scripts) can either call `writeSessionExport` for the canned\n * \"render + write\" combo or compose `renderSession` with a different\n * sink (clipboard, network, S3) without dragging in `node:fs`.\n */\n\nimport type { SessionData, SessionRun } from '../session'\nimport type { SessionContentBlock, SessionTurn, ToolResultContent, TurnUsage } from '../types'\nimport { existsSync, mkdirSync } from 'node:fs'\nimport { writeFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { fmtTokens, shortId } from './format'\nimport { deriveSessionTitle } from './store'\nimport { resolveStorageDirs } from './xdg'\n\n/** File format supported by the exporter. */\nexport type SessionExportFormat = 'markdown' | 'json'\n\n/**\n * Anchor for the resolved destination directory:\n * - `project` — the nearest enclosing git repository (`<repoRoot>/.{prefix}/sessions`)\n * - `home` — fallback when no repo was found (`<dataDir>/sessions`; `~/.{prefix}/sessions`\n * outside an XDG layout)\n */\nexport type SessionExportAnchor = 'project' | 'home'\n\n/** Resolved file destination for a session export. */\nexport interface SessionExportTarget {\n /** Absolute directory holding the file. May not exist yet — `writeSessionExport` creates it on demand. */\n dir: string\n /** Absolute path of the file (`dir/{id}.{ext}`). */\n filepath: string\n /** Where the destination was anchored. */\n anchor: SessionExportAnchor\n}\n\n/** Options shared by every resolve / write entry-point. */\ninterface ResolveOptions {\n /** Discovery cwd. Defaults to `process.cwd()`. */\n cwd?: string\n /** User home directory. Defaults to `os.homedir()`. */\n home?: string\n /**\n * Storage prefix. Leading dot tolerated (`zidane` and `.zidane` are\n * equivalent). Defaults to `'.zidane'`.\n */\n prefix?: string\n /**\n * User storage data dir; home-anchored exports land in `<dataDir>/sessions`.\n * Defaults to `resolveStorageDirs({ prefix, home }).dataDir`. Never a literal\n * `~/.{prefix}`: writing there would flip an XDG install to legacy storage.\n */\n dataDir?: string\n}\n\nconst DEFAULT_PREFIX = '.zidane'\n\n/**\n * Resolve the export target for a session id + format. Pure: no fs\n * write happens here, the caller decides whether to `existsSync` the\n * directory or hand the path to `writeSessionExport`.\n *\n * Anchor selection walks upward from `cwd` looking for a `.git` entry;\n * the first hit anchors to that repo's root (`project`). When the walk\n * exits without finding `.git`, the destination anchors to `home`: the\n * user's storage data dir.\n *\n * @throws RangeError when `sessionId` would resolve to an empty / `..`\n * filename — defensive guard against malicious or buggy callers\n * crossing into a sibling directory via the id.\n */\nexport function resolveSessionExportTarget(opts: {\n sessionId: string\n format: SessionExportFormat\n} & ResolveOptions): SessionExportTarget {\n const cwd = opts.cwd ?? process.cwd()\n const home = opts.home ?? homedir()\n const prefix = normalizePrefix(opts.prefix)\n const filename = exportFilename(opts.sessionId, opts.format)\n\n const repoRoot = findGitRoot(cwd)\n const anchor: SessionExportAnchor = repoRoot ? 'project' : 'home'\n const dir = repoRoot\n ? resolve(repoRoot, `.${prefix}`, 'sessions')\n : resolve(opts.dataDir ?? resolveStorageDirs({ prefix: `.${prefix}`, home }).dataDir, 'sessions')\n return { dir, filepath: join(dir, filename), anchor }\n}\n\n/**\n * Render a session into a string in the requested format.\n *\n * `markdown` produces a human-readable transcript: a YAML-free header\n * block with the title and a one-line `id · created · turns` summary,\n * a stats section (turns / runs / tokens / cost / status), then a\n * `## Conversation` block where each turn renders as `### N. role ·\n * run_X · ISO-date` with text, thinking, tool calls, and tool results\n * formatted as appropriate fenced blocks. Useful for sharing a session\n * with a teammate or pasting into an issue tracker.\n *\n * `json` returns a 2-space-indented, deterministic dump of the full\n * `SessionData` blob. Useful for re-importing into the store or for\n * post-hoc analysis tooling.\n */\nexport function renderSession(session: SessionData, format: SessionExportFormat): string {\n if (format === 'json')\n return `${JSON.stringify(session, null, 2)}\\n`\n return renderMarkdown(session)\n}\n\n/**\n * Render `session` and write the resulting bytes to disk. Returns the\n * resolved target so the caller can show the user where the file\n * landed. The parent directory is created on demand (`recursive: true`)\n * — first-time exports don't need any pre-flight setup.\n */\nexport async function writeSessionExport(\n opts: { session: SessionData, format: SessionExportFormat } & ResolveOptions,\n): Promise<SessionExportTarget> {\n const target = resolveSessionExportTarget({\n sessionId: opts.session.id,\n format: opts.format,\n cwd: opts.cwd,\n home: opts.home,\n prefix: opts.prefix,\n dataDir: opts.dataDir,\n })\n const body = renderSession(opts.session, opts.format)\n // `mkdirSync` is synchronous to avoid two awaits on a hot path that's\n // I/O-bound anyway; `recursive: true` makes it a no-op when the dir\n // already exists, so we don't pay an `existsSync` round-trip.\n mkdirSync(target.dir, { recursive: true })\n await writeFile(target.filepath, body, 'utf8')\n return target\n}\n\n// ---------------------------------------------------------------------------\n// Markdown renderer\n// ---------------------------------------------------------------------------\n\n/**\n * Render a `SessionData` as a clean markdown transcript. Stable across\n * runs (no timestamps or random ids leak into the output beyond what\n * the session itself carries) — diffing two exports of the same\n * session is a no-op.\n */\nfunction renderMarkdown(session: SessionData): string {\n const title = deriveSessionTitle(session.turns, session.metadata)\n const userTurns = session.turns.filter(t => t.role === 'user').length\n const assistantTurns = session.turns.filter(t => t.role === 'assistant').length\n const usage = aggregateUsage(session.runs)\n const lines: string[] = []\n lines.push(`# ${escapeInline(title)}`)\n lines.push('')\n lines.push(`> Session \\`${shortId(session.id)}\\` · ${session.turns.length} turn${session.turns.length === 1 ? '' : 's'} · ${session.runs.length} run${session.runs.length === 1 ? '' : 's'}`)\n lines.push('')\n lines.push('## Metadata')\n lines.push('')\n lines.push(`- **id**: \\`${session.id}\\``)\n lines.push(`- **created**: ${new Date(session.createdAt).toISOString()}`)\n lines.push(`- **updated**: ${new Date(session.updatedAt).toISOString()}`)\n lines.push(`- **status**: ${session.status}`)\n lines.push(`- **turns**: ${session.turns.length} (${userTurns} user · ${assistantTurns} assistant)`)\n lines.push(`- **runs**: ${session.runs.length}`)\n if (usage.total > 0) {\n const tokenBits: string[] = [\n `in ${fmtTokens(usage.input)}`,\n `out ${fmtTokens(usage.output)}`,\n ]\n if (usage.cacheRead > 0)\n tokenBits.push(`cached ${fmtTokens(usage.cacheRead)}`)\n lines.push(`- **tokens**: ${fmtTokens(usage.total)} (${tokenBits.join(' · ')})`)\n if (usage.cost > 0)\n lines.push(`- **cost**: $${usage.cost.toFixed(usage.cost < 0.01 ? 4 : 2)}`)\n }\n lines.push('')\n lines.push('## Conversation')\n lines.push('')\n\n if (session.turns.length === 0) {\n lines.push('_No turns recorded yet._')\n lines.push('')\n return `${lines.join('\\n')}\\n`\n }\n\n session.turns.forEach((turn, idx) => {\n lines.push(renderTurnHeader(turn, idx + 1))\n lines.push('')\n const body = renderTurnBody(turn)\n if (body) {\n lines.push(body)\n lines.push('')\n }\n })\n\n return `${lines.join('\\n').replace(/\\n+$/, '\\n')}\\n`\n}\n\n/** `### 1. user · run_1 · 2026-05-13T01:48:29.895Z` */\nfunction renderTurnHeader(turn: SessionTurn, index: number): string {\n const date = new Date(turn.createdAt).toISOString()\n const runFragment = turn.runId ? ` · \\`${turn.runId}\\`` : ''\n const usageFragment = turn.usage ? ` · ${formatTurnUsage(turn.usage)}` : ''\n return `### ${index}. ${turn.role}${runFragment} · ${date}${usageFragment}`\n}\n\n/** `in 12 · out 48 · cached 1.2k` — only emits non-zero buckets. */\nfunction formatTurnUsage(usage: TurnUsage): string {\n const parts: string[] = []\n if (usage.input > 0)\n parts.push(`in ${fmtTokens(usage.input)}`)\n if (usage.output > 0)\n parts.push(`out ${fmtTokens(usage.output)}`)\n if ((usage.cacheRead ?? 0) > 0)\n parts.push(`cached ${fmtTokens(usage.cacheRead ?? 0)}`)\n return parts.join(' · ')\n}\n\n/**\n * Render all blocks of a single turn into a markdown fragment.\n * Block ordering matches the on-disk turn so resume / replay semantics\n * are preserved: tool_call → tool_result pairs stay adjacent, thinking\n * blocks land right before the assistant text they precede.\n */\nfunction renderTurnBody(turn: SessionTurn): string {\n const parts: string[] = []\n for (const block of turn.content) {\n const chunk = renderBlock(block)\n if (chunk)\n parts.push(chunk)\n }\n return parts.join('\\n\\n')\n}\n\nfunction renderBlock(block: SessionContentBlock): string {\n switch (block.type) {\n case 'text':\n return block.text.trim() ? block.text.trim() : ''\n case 'thinking': {\n const text = block.text.trim()\n if (!text)\n return ''\n // Blockquote prefix on every line so consumers can fold / hide\n // thinking sections without breaking the surrounding markdown.\n const quoted = text.split('\\n').map(l => `> ${l}`).join('\\n')\n return `> **thinking**\\n>\\n${quoted}`\n }\n case 'tool_call': {\n const args = JSON.stringify(block.input, null, 2)\n return [\n `**Tool call** \\`${block.name}\\` · id \\`${block.id}\\``,\n '',\n '```json',\n args,\n '```',\n ].join('\\n')\n }\n case 'tool_result': {\n const header = block.isError\n ? `**Tool result** ✗ error · id \\`${block.callId}\\``\n : `**Tool result** · id \\`${block.callId}\\``\n const output = renderToolOutput(block.output)\n return [header, '', output].join('\\n')\n }\n case 'image':\n // Image data could be megabytes of base64; reference it by media type\n // rather than inline. A future viewer that wants to round-trip can\n // pull the original bytes from the on-disk session.\n return `_[image · ${block.mediaType}]_`\n case 'audio':\n return `_[audio · ${block.name ? `${block.name} · ` : ''}${block.mediaType}]_`\n case 'video':\n return `_[video · ${block.name ? `${block.name} · ` : ''}${block.mediaType}]_`\n case 'document':\n return `_[document · ${block.name ? `${block.name} · ` : ''}${block.mediaType}]_`\n case 'compact-summary': {\n // Boundary card in the markdown export — mirrors the TUI's\n // CompactSummaryBlock so a reader sees what happened at the\n // compaction point. The detailed turn-by-turn history before the\n // marker is still in the export (compaction never deletes from\n // disk), so the reader can compare summary vs source.\n const count = block.replacesTurnIds.length\n return [\n `**Compaction summary** · ${count} turn${count === 1 ? '' : 's'} compacted · model \\`${block.model}\\``,\n '',\n block.summary.trim(),\n ].join('\\n')\n }\n default:\n return ''\n }\n}\n\n/**\n * Tool output is either a flat string (the common case) or a structured\n * array of `ToolResultContent` (multimodal tools — screenshots, charts).\n * Strings render as a fenced code block; structured arrays render\n * their text blocks inline with `[image · …]` placeholders for the rest.\n */\nfunction renderToolOutput(output: string | ToolResultContent[]): string {\n if (typeof output === 'string') {\n const fence = pickFence(output)\n return `${fence}\\n${output}\\n${fence}`\n }\n const segments: string[] = []\n for (const piece of output) {\n if (piece.type === 'text') {\n const fence = pickFence(piece.text)\n segments.push(`${fence}\\n${piece.text}\\n${fence}`)\n }\n else if (piece.type === 'image') {\n segments.push(`_[image · ${piece.mediaType}]_`)\n }\n else if (piece.type === 'audio') {\n segments.push(`_[audio · ${piece.mediaType}]_`)\n }\n else if (piece.type === 'video') {\n segments.push(`_[video · ${piece.mediaType}]_`)\n }\n else {\n segments.push(`_[document · ${piece.name ? `${piece.name} · ` : ''}${piece.mediaType}]_`)\n }\n }\n return segments.join('\\n\\n')\n}\n\n/**\n * Pick a fence (`\\`\\`\\`` or longer) that doesn't collide with any\n * backtick run inside `content`. The CommonMark rule is \"a fenced\n * block ends at a fence of the same length or longer made of the same\n * char\" — choosing a fence strictly longer than the longest run inside\n * the body avoids accidental termination.\n */\nfunction pickFence(content: string): string {\n let longestRun = 0\n let current = 0\n for (const ch of content) {\n if (ch === '`') {\n current++\n if (current > longestRun)\n longestRun = current\n }\n else {\n current = 0\n }\n }\n const len = Math.max(3, longestRun + 1)\n return '`'.repeat(len)\n}\n\n/** Strip control characters from a single-line inline (e.g. the title). */\nfunction escapeInline(s: string): string {\n return s.replace(/[\\r\\n]+/g, ' ').trim()\n}\n\n// ---------------------------------------------------------------------------\n// Path resolution helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Walk parents of `start` looking for a `.git` entry (file or\n * directory — `.git` is a file inside git worktrees). Returns the\n * directory holding `.git`, or `null` at the filesystem root.\n */\nfunction findGitRoot(start: string): string | null {\n let dir = resolve(start)\n // Hard cap as an escape hatch on pathological cwd values\n // (`mount --bind` cycles, etc.); 64 levels is well above what any\n // real-world checkout produces.\n for (let i = 0; i < 64; i++) {\n if (existsSync(join(dir, '.git')))\n return dir\n const parent = dirname(dir)\n if (parent === dir)\n return null\n dir = parent\n }\n return null\n}\n\n/** Trim a leading dot from `prefix`. */\nfunction normalizePrefix(prefix: string | undefined): string {\n return (prefix ?? DEFAULT_PREFIX).replace(/^\\./, '')\n}\n\n/**\n * Compose the on-disk filename for `(sessionId, format)`. Rejects\n * empty ids and path-traversal-ish values so the caller can't escape\n * `.{prefix}/sessions/`.\n */\nfunction exportFilename(sessionId: string, format: SessionExportFormat): string {\n const ext = format === 'json' ? 'json' : 'md'\n const cleaned = sessionId.trim()\n if (!cleaned || cleaned.includes('/') || cleaned.includes('\\\\') || cleaned === '.' || cleaned === '..')\n throw new RangeError(`Cannot export session: invalid id \"${sessionId}\"`)\n return `${cleaned}.${ext}`\n}\n\n// ---------------------------------------------------------------------------\n// Usage aggregation (also read by the TUI session details modal)\n// ---------------------------------------------------------------------------\n\nexport interface AggregatedUsage {\n input: number\n output: number\n cacheRead: number\n total: number\n cost: number\n}\n\n/**\n * Sum token + cost figures across every {@link SessionRun}. Preference\n * order for a run's tally is `totalUsage` → per-`turnUsage[]` sum.\n * `turnUsage` exists on every completed run; `totalUsage` is provider-\n * specific (set by some pi-ai adapters when the API surfaces it).\n *\n * Returns an aggregate of zeroes when no usage data is available; the\n * caller decides whether to render the tokens row at all.\n */\nexport function aggregateUsage(runs: readonly SessionRun[]): AggregatedUsage {\n const acc = { input: 0, output: 0, cacheRead: 0, cost: 0 }\n for (const run of runs) {\n if (run.totalUsage) {\n acc.input += run.totalUsage.input ?? 0\n acc.output += run.totalUsage.output ?? 0\n acc.cacheRead += run.totalUsage.cacheRead ?? 0\n }\n else if (run.turnUsage) {\n for (const u of run.turnUsage) {\n acc.input += u.input ?? 0\n acc.output += u.output ?? 0\n acc.cacheRead += u.cacheRead ?? 0\n }\n }\n if (run.cost)\n acc.cost += run.cost\n }\n return { ...acc, total: acc.input + acc.output }\n}\n","import type { Dispatch, MutableRefObject, SetStateAction } from 'react'\nimport type { Owner, StreamEvent } from './types'\nimport { useCallback, useEffect, useMemo, useRef } from 'react'\nimport { appendMarkdownDelta, appendThinkingLines, capTranscriptEvents } from './streaming-pure'\n\n// Pure delta-merge / finalize reducers + context-window math live in the\n// node-free `./streaming-pure` leaf (importable from `zidane/chat/pure`, and\n// shared with the GUI renderer). Re-exported here so existing `zidane/chat`\n// consumers keep their import paths.\nexport { appendMarkdownDelta, appendThinkingLines, capTranscriptEvents, finalizeStreamingMarkdown, finalizeStreamingMarkdownForOwner, hiddenEarlierTranscriptCount, MAX_TRANSCRIPT_EVENTS, mergeTargetIndex, replaceTranscriptTurnEvents, revealEarlierTranscriptEvents, TRANSCRIPT_TRIM_TO_EVENTS, turnContextSize } from './streaming-pure'\n\n/**\n * Tick interval for the continuous drain loop. ~16ms aligns with the\n * 60fps renderer target so the typewriter cadence reveals 1 portion of\n * content per paint frame. The bucket-derived `chars-per-tick` decides\n * how much actually lands per tick — see {@link smoothCharsForTick}.\n */\nconst TICK_INTERVAL_MS = 16\n\n/**\n * Smooth-streaming display rate, in characters per second.\n *\n * Three-segment continuous ramp (no step functions, no cliff) so the\n * typewriter cadence never visibly \"jumps\" mid-stream:\n *\n * - {@link SMOOTH_BASE_CPS} — calm-state floor. ~200 CPS is a fast\n * typist's pace; comfortably readable without feeling like a\n * deliberate performance.\n * - {@link SMOOTH_BURST_CPS} at {@link SMOOTH_BURST_BACKLOG_CHARS} —\n * moderate catch-up speed once the buffer is one paragraph behind\n * the provider.\n * - {@link SMOOTH_MAX_CPS} at {@link SMOOTH_MAX_BACKLOG_CHARS} —\n * bounded ceiling. Past this we plateau at max-cps rather than\n * instant-draining; max-cps is already well above any human reading\n * rate so even a 10K-char dump completes in ~2.5s of fast typewriter\n * instead of a single-frame teleport.\n *\n * The previous failsafe (instant drain at 2K chars) was a literal\n * step from ~10 chars/frame to \"everything in one frame\" — the worst\n * jump in the smooth pipeline. The continued ramp eliminates it\n * without losing bounded latency, since CPS keeps growing with\n * backlog up to the cap.\n */\nconst SMOOTH_BASE_CPS = 200\nconst SMOOTH_BURST_CPS = 600\nconst SMOOTH_BURST_BACKLOG_CHARS = 400\nconst SMOOTH_MAX_CPS = 4000\nconst SMOOTH_MAX_BACKLOG_CHARS = 4000\n\n/**\n * Safety bound for {@link StreamBuffer.whenDrained} — per window of NO\n * drain progress. A long response legitimately types out for longer\n * than any fixed deadline (the ramp bottoms out at\n * {@link SMOOTH_BASE_CPS}), so each committed tick re-arms the window;\n * only a genuinely wedged ticker — this long with nothing committed —\n * fires the escape hatch, and convergence (transcript resync) is never\n * blocked forever.\n */\nexport const WHEN_DRAINED_TIMEOUT_MS = 3000\n\nconst PARENT_OWNER: Owner = 'parent'\n\n/** One owner's (parent or a subagent) not-yet-committed deltas. */\ninterface DeltaBucket {\n markdown: string\n thinking: string\n owner: Owner\n depth: number\n /** Last turnId seen for this bucket. Tagged onto new events when the bucket flushes. */\n turnId?: string\n /**\n * Fractional chars carried over from the previous smooth tick. The\n * tick computes an exact float (`cps * dt`), takes the integer part,\n * and stashes the leftover here so the next tick adds it back in.\n * This makes the long-run rate match the target CPS exactly instead\n * of being inflated by `Math.ceil` rounding on every tick.\n */\n smoothCarry: number\n}\n\nfunction emptyBucket(owner: Owner, depth: number): DeltaBucket {\n return { markdown: '', thinking: '', owner, depth, smoothCarry: 0 }\n}\n\nfunction applyBucket(prev: StreamEvent[], bucket: DeltaBucket): StreamEvent[] {\n let result = prev\n if (bucket.thinking)\n result = appendThinkingLines(result, bucket.thinking, bucket.owner, bucket.depth, bucket.turnId)\n if (bucket.markdown)\n result = appendMarkdownDelta(result, bucket.markdown, bucket.owner, bucket.depth, bucket.turnId)\n return result\n}\n\n// ---------------------------------------------------------------------------\n// useStreamBuffer — per-owner stream-event accumulator with two drain modes.\n//\n// Provider deltas arrive at ~50Hz; flushing each one through React causes the\n// ScrollBox to recompute layout faster than the terminal can clear and\n// repaint, producing overdraw artifacts during scroll. We buffer per owner\n// (parent + each active subagent) and drain via a continuous ticker:\n//\n// - **smooth mode** (default — gated on {@link Settings.smoothStreaming}):\n// drip-feed text character-by-character at {@link SMOOTH_BASE_CPS}, with\n// an adaptive burst when the buffer falls behind. Reads as a typewriter\n// effect, masks bursty provider chunks behind a steady cadence, and\n// always finishes within one tick of the LLM completing because turn\n// boundaries (`flush` / `appendImmediate` / `flushAndUpdate`) drain\n// remaining content unconditionally.\n// - **batched mode** (off): drain everything per tick — equivalent to the\n// legacy \"one 32ms timeout per burst of deltas\" cadence, just expressed\n// against the same ticker.\n//\n// `getSmooth` is called on every tick so toggling the user setting at\n// runtime takes effect on the next drain without rebuilding the buffer.\n// ---------------------------------------------------------------------------\n\nexport interface StreamSource {\n /** Pass `undefined` / omit for parent-agent events. */\n childId?: string\n /** Nesting depth — 0 for parent, ≥ 1 for subagents. */\n depth?: number\n /**\n * `SessionTurn.id` this delta belongs to. Tagged onto new events so the\n * TUI's select-turn mode can group every event from one turn. Stored on\n * the active bucket and refreshed on every delta so a turn boundary\n * (`turn:after` flushes the bucket) doesn't carry stale ids forward.\n */\n turnId?: string\n}\n\nexport interface StreamBuffer {\n /** Queue a streaming delta for the next flush tick. */\n queueStreamDelta: (kind: 'markdown' | 'thinking', delta: string, source?: StreamSource) => void\n /** Drain pending deltas immediately, then append a non-streaming event. */\n appendImmediate: (evt: StreamEvent) => void\n /** Drain pending deltas immediately, then transform the event list. */\n flushAndUpdate: (update: (events: StreamEvent[]) => StreamEvent[]) => void\n /** Drain pending deltas without further transformation. */\n flush: () => void\n /** Cancel any pending flush and drop buffered deltas (on session teardown). */\n reset: () => void\n /**\n * Resolves once the pacer is idle — no bucket holds queued content and\n * no post-drain updater is pending. Resolves immediately when already\n * idle (the batched / `smoothStreaming: false` path never queues, so\n * this is zero-cost there). A safety timeout (default\n * {@link WHEN_DRAINED_TIMEOUT_MS}) resolves anyway if the ticker\n * wedges — measured as a full window with NO drain progress, so a\n * long response that keeps typing re-arms it and never snaps — and\n * callers gating a transcript convergence on the drain can never\n * dead-lock. `reset()` also releases every waiter — the backlog it\n * drops would otherwise never drain.\n */\n whenDrained: (timeoutMs?: number) => Promise<void>\n}\n\nexport interface StreamBufferOptions {\n /**\n * Returns `true` to drip-feed buffered text at the smooth typewriter\n * cadence, `false` to drain everything per tick (batched mode — the\n * legacy behaviour). Called on every tick, so flipping the user setting\n * takes effect on the next drain.\n */\n getSmooth?: () => boolean\n /**\n * Display-memory bound applied on every drain commit (see\n * {@link capTranscriptEvents}): above this many events the oldest are\n * trimmed at a turn boundary and replaced with a cumulative\n * \"… N earlier items hidden\" marker event. Rendered events hold live\n * renderables/native buffers, so an unbounded buffer OOMs long\n * sessions (~0.13MB RSS per event measured in the TUI).\n *\n * Default {@link MAX_TRANSCRIPT_EVENTS}. Pass `null` to disable and\n * receive the full, unbounded event array (pre-5.13 behavior) — e.g.\n * a host that renders a virtualized list or exports events verbatim.\n */\n maxTranscriptEvents?: number | null\n /**\n * Live override of {@link maxTranscriptEvents}, read inside each drain\n * commit. Use it when the cap changes between renders: a pending drain\n * updater runs during the host's next `useState` evaluation, BEFORE this\n * hook re-mirrors the option, so a render-mirrored value is one commit\n * stale (a history reveal would be re-trimmed by that commit).\n */\n getMaxTranscriptEvents?: () => number | null | undefined\n}\n\n/**\n * Target chars-per-second for the next smooth-mode tick given the\n * current bucket backlog. Two linear segments — base→burst over the\n * first {@link SMOOTH_BURST_BACKLOG_CHARS}, burst→max over the rest of\n * the ramp — so the function is continuous everywhere and plateaus\n * (rather than cliffs) once backlog passes {@link SMOOTH_MAX_BACKLOG_CHARS}.\n *\n * Exported for tests; the runtime path goes through\n * {@link smoothCharsForTick} which folds in the per-bucket fractional\n * remainder.\n */\nexport function smoothCpsForBacklog(backlog: number): number {\n if (backlog <= 0)\n return 0\n if (backlog >= SMOOTH_MAX_BACKLOG_CHARS)\n return SMOOTH_MAX_CPS\n if (backlog <= SMOOTH_BURST_BACKLOG_CHARS) {\n const t = backlog / SMOOTH_BURST_BACKLOG_CHARS\n return SMOOTH_BASE_CPS + t * (SMOOTH_BURST_CPS - SMOOTH_BASE_CPS)\n }\n const t = (backlog - SMOOTH_BURST_BACKLOG_CHARS)\n / (SMOOTH_MAX_BACKLOG_CHARS - SMOOTH_BURST_BACKLOG_CHARS)\n return SMOOTH_BURST_CPS + t * (SMOOTH_MAX_CPS - SMOOTH_BURST_CPS)\n}\n\n/**\n * Number of characters to drain on the next smooth-mode tick + the\n * fractional remainder to carry into the next tick.\n *\n * Combining the CPS curve with a fractional accumulator means the\n * effective draining rate matches the target CPS exactly. The legacy\n * `Math.ceil(cps * dt)` rounded UP on every tick — at 200 CPS / 16ms,\n * that's 4 chars/tick (= 250 CPS effective), a 25 % speed-up. Worse,\n * `ceil` produced visible step transitions (4 → 5 → 7 → 8 → 10 as\n * backlog grew) that read as the typewriter cadence jumping.\n */\nfunction smoothCharsForTick(\n backlog: number,\n carry: number,\n dtMs: number,\n): { take: number, carry: number } {\n if (backlog <= 0)\n return { take: 0, carry: 0 }\n const cps = smoothCpsForBacklog(backlog)\n const want = cps * dtMs / 1000 + carry\n const take = Math.floor(want)\n if (take <= 0)\n return { take: 0, carry: want }\n if (take >= backlog) {\n // Drained the bucket — drop the leftover. Holding it across a\n // bucket boundary would invent a head-start for the next stream.\n return { take: backlog, carry: 0 }\n }\n // Don't clamp `take` to 1: with `dtMs * cps / 1000 < 1`, the carry\n // accumulates over the next tick(s) and the char lands when math\n // says it should. The ticker stays alive because the bucket still\n // has content, so the next tick fires regardless.\n return { take, carry: want - take }\n}\n\n/**\n * Slice `n` chars off the front of `buf` without splitting a UTF-16\n * surrogate pair. Most LLM text is ASCII and never trips this; the guard\n * matters for emoji / extended planes where halving the pair would emit\n * an isolated half-character.\n */\nfunction takeChars(buf: string, n: number): { taken: string, rest: string } {\n if (buf.length <= n)\n return { taken: buf, rest: '' }\n let end = n\n const last = buf.charCodeAt(end - 1)\n // High surrogate at the slice boundary → pull the following low\n // surrogate in too. Going one char over budget on a single tick is\n // strictly better than emitting half a code point.\n if (last >= 0xD800 && last <= 0xDBFF && end < buf.length)\n end++\n return { taken: buf.slice(0, end), rest: buf.slice(end) }\n}\n\n/**\n * Take this tick's portion off every live bucket (mutating the buckets):\n * all of its thinking, and its markdown at the smooth cadence or in full.\n * `stillHasContent` = some bucket kept markdown for a later tick.\n */\nfunction takeTickPortions(\n buckets: Map<Owner, DeltaBucket>,\n smooth: boolean,\n dtMs: number,\n): { portions: DeltaBucket[], stillHasContent: boolean } {\n const portions: DeltaBucket[] = []\n let stillHasContent = false\n for (const bucket of buckets.values()) {\n const thinking = bucket.thinking\n bucket.thinking = ''\n\n let taken = ''\n if (bucket.markdown.length > 0) {\n if (smooth) {\n const { take, carry } = smoothCharsForTick(\n bucket.markdown.length,\n bucket.smoothCarry,\n dtMs,\n )\n bucket.smoothCarry = carry\n if (take > 0) {\n const result = takeChars(bucket.markdown, take)\n taken = result.taken\n bucket.markdown = result.rest\n if (bucket.markdown.length === 0)\n bucket.smoothCarry = 0\n }\n }\n else {\n taken = bucket.markdown\n bucket.markdown = ''\n bucket.smoothCarry = 0\n }\n }\n\n if (taken || thinking) {\n portions.push({\n markdown: taken,\n thinking,\n owner: bucket.owner,\n depth: bucket.depth,\n turnId: bucket.turnId,\n smoothCarry: 0,\n })\n }\n if (bucket.markdown.length > 0)\n stillHasContent = true\n }\n return { portions, stillHasContent }\n}\n\n/** No queued post-drain updater and no bucket holding content. */\nfunction bufferIdle(buckets: Map<Owner, DeltaBucket>, pendingUpdaters: number): boolean {\n let idle = pendingUpdaters === 0\n if (idle) {\n for (const bucket of buckets.values()) {\n if (bucket.markdown.length > 0 || bucket.thinking.length > 0) {\n idle = false\n break\n }\n }\n }\n return idle\n}\n\ninterface DrainWaiter { resolve: () => void, timer: ReturnType<typeof setTimeout> }\n\n/** Register a `whenDrained` waiter, with its no-progress safety timer armed. */\nfunction addDrainWaiter(\n resolve: () => void,\n drainProgressRef: MutableRefObject<number>,\n drainWaitersRef: MutableRefObject<DrainWaiter[]>,\n timeoutMs: number,\n): void {\n // Safety valve: a wedged ticker (cleared interval, starved event\n // loop) must not block the caller forever — resolve anyway and\n // drop the waiter so a late drain doesn't double-resolve. Armed\n // per window of NO progress: a tick that committed content since\n // the last check proves the drain is alive (a long response types\n // for longer than any fixed deadline), so re-arm instead of\n // snapping the tail into the caller's convergence.\n let seenProgress = drainProgressRef.current\n const waiter = {\n resolve,\n timer: undefined as unknown as ReturnType<typeof setTimeout>,\n }\n const arm = (): ReturnType<typeof setTimeout> => setTimeout(() => {\n if (drainProgressRef.current !== seenProgress) {\n seenProgress = drainProgressRef.current\n waiter.timer = arm()\n return\n }\n drainWaitersRef.current = drainWaitersRef.current.filter(w => w !== waiter)\n resolve()\n }, timeoutMs)\n waiter.timer = arm()\n drainWaitersRef.current.push(waiter)\n}\n\nexport function useStreamBuffer(\n setEvents: Dispatch<SetStateAction<StreamEvent[]>>,\n options?: StreamBufferOptions,\n): StreamBuffer {\n const bucketsRef = useRef<Map<Owner, DeltaBucket>>(new Map())\n const tickerRef = useRef<ReturnType<typeof setInterval> | null>(null)\n // Real wall-clock timestamp of the last tick. Feeds the dt argument\n // to `smoothCharsForTick` so the drain rate stays accurate even when\n // `setInterval` is late (event-loop congestion, GC pauses); without\n // this a 50ms-late tick would only commit ~16ms-worth of chars and\n // the visible cadence would stall.\n const lastTickMsRef = useRef<number>(0)\n // Pin the latest `getSmooth` callback inside a ref so the ticker closure\n // always sees the current setting without recreating the timer.\n const getSmoothRef = useRef<(() => boolean) | undefined>(options?.getSmooth)\n getSmoothRef.current = options?.getSmooth\n /** Live mirror so drains read the current cap without re-memoizing. */\n const maxEventsRef = useRef<number | null | undefined>(options?.maxTranscriptEvents)\n maxEventsRef.current = options?.maxTranscriptEvents\n const getMaxEventsRef = useRef(options?.getMaxTranscriptEvents)\n getMaxEventsRef.current = options?.getMaxTranscriptEvents\n const capForCommit = useCallback((events: StreamEvent[]): StreamEvent[] => {\n const cap = getMaxEventsRef.current ? getMaxEventsRef.current() : maxEventsRef.current\n return cap === null ? events : capTranscriptEvents(events, cap ?? undefined)\n }, [])\n\n /**\n * Updaters queued while smooth-streaming was still draining backlog —\n * tool-call appends, finalize-markdown transforms, error events.\n * Applied in FIFO order at the END of `tick()` once every bucket is\n * empty, so the trailing typewriter characters land BEFORE the\n * follow-up event instead of being clobbered by an immediate drain.\n *\n * The buffer treats markdown deltas as the authoritative ordering\n * source: a tool call queued behind 100 buffered chars surfaces after\n * those 100 chars have typed out, preserving the visual stream order\n * the user is reading.\n */\n const pendingUpdatersRef = useRef<((events: StreamEvent[]) => StreamEvent[])[]>([])\n\n /**\n * Pending `whenDrained` promises. Released (with their safety timers\n * cleared) whenever the buffer reaches the idle state: the tick that\n * empties the last bucket, a synchronous `drainNow`, or a `reset`.\n */\n const drainWaitersRef = useRef<DrainWaiter[]>([])\n\n /**\n * Monotonic count of commits (ticks that landed content or updaters).\n * `whenDrained` waiters compare it across their safety window: movement\n * means the ticker is alive — re-arm instead of firing the escape hatch.\n */\n const drainProgressRef = useRef(0)\n\n const releaseDrainWaiters = useCallback(() => {\n if (drainWaitersRef.current.length === 0)\n return\n const waiters = drainWaitersRef.current\n drainWaitersRef.current = []\n for (const waiter of waiters) {\n clearTimeout(waiter.timer)\n waiter.resolve()\n }\n }, [])\n\n const stopTicker = useCallback(() => {\n if (tickerRef.current) {\n clearInterval(tickerRef.current)\n tickerRef.current = null\n }\n // Forget the last-tick stamp so the next ticker run starts from\n // the nominal interval instead of a stale (potentially seconds-old)\n // delta that would burst-drain the first frame.\n lastTickMsRef.current = 0\n }, [])\n\n /**\n * Has at least one bucket got unflushed *markdown* content?\n *\n * Thinking content is excluded: it always flushes in full on every\n * tick (see `tick()`), so its presence in a bucket only matters until\n * the next 16 ms cycle — never long enough to justify deferring an\n * end-of-turn updater.\n */\n const hasMarkdownBacklog = useCallback((): boolean => {\n for (const bucket of bucketsRef.current.values()) {\n if (bucket.markdown.length > 0)\n return true\n }\n return false\n }, [])\n\n /**\n * Drain every bucket in full and synchronously run any queued\n * post-drain updaters plus the caller-provided one. Used by the\n * fast paths below — `reset`, batched-mode `appendImmediate` /\n * `flushAndUpdate`, and smooth-mode calls where no markdown\n * backlog remains.\n */\n const drainNow = useCallback((updater?: (events: StreamEvent[]) => StreamEvent[]) => {\n stopTicker()\n const buckets = Array.from(bucketsRef.current.values())\n bucketsRef.current.clear()\n const queued = pendingUpdatersRef.current\n pendingUpdatersRef.current = []\n const hasDeltas = buckets.some(b => b.markdown.length > 0 || b.thinking.length > 0)\n if (!hasDeltas && !updater && queued.length === 0) {\n releaseDrainWaiters()\n return\n }\n setEvents((prev) => {\n let merged = prev\n for (const bucket of buckets)\n merged = applyBucket(merged, bucket)\n for (const u of queued)\n merged = u(merged)\n if (updater)\n merged = updater(merged)\n // Memory bound: identity under the cap, turn-boundary head trim\n // above it (see capTranscriptEvents). Session turns stay complete.\n return capForCommit(merged)\n })\n releaseDrainWaiters()\n }, [capForCommit, releaseDrainWaiters, setEvents, stopTicker])\n\n /**\n * One tick of the continuous drain loop. Walks every live bucket and\n * commits a portion of its content based on the current mode. Once\n * every bucket empties out, fires any post-drain updaters that were\n * queued while smooth streaming was still in progress (turn\n * finalize, tool calls, errors) and stops the ticker.\n *\n * `thinking` content always flushes immediately even in smooth mode —\n * it's an internal-reasoning surface, surfaced for transparency rather\n * than for reading flow, and users expect it to keep up with the model.\n */\n const tick = useCallback(() => {\n const smooth = getSmoothRef.current?.() ?? true\n const buckets = bucketsRef.current\n\n // Real elapsed time since the last tick. Falls back to the nominal\n // interval on the first tick (when there's nothing to measure\n // against) and clamps to a sane upper bound so a one-off 500ms\n // event-loop stall doesn't burst-drain the entire backlog.\n const now = Date.now()\n const dtMs = lastTickMsRef.current === 0\n ? TICK_INTERVAL_MS\n : Math.min(TICK_INTERVAL_MS * 4, Math.max(1, now - lastTickMsRef.current))\n lastTickMsRef.current = now\n\n const { portions, stillHasContent } = takeTickPortions(buckets, smooth, dtMs)\n\n // Fold post-drain updaters into the same commit as the trailing\n // portions so the resulting transcript has at most one paint per\n // tick — and so the LAST portion of a smooth stream and its\n // companion finalize-markdown / tool-call event land atomically.\n const drainQueued = !stillHasContent && pendingUpdatersRef.current.length > 0\n const queued = drainQueued\n ? pendingUpdatersRef.current.splice(0, pendingUpdatersRef.current.length)\n : []\n\n if (portions.length > 0 || queued.length > 0) {\n drainProgressRef.current += 1\n setEvents((prev) => {\n let next = prev\n for (const portion of portions)\n next = applyBucket(next, portion)\n for (const u of queued)\n next = u(next)\n // Same memory bound as `drainNow`: deferred updaters append\n // tool-call / error events too, so this commit path must not\n // become a cap-bypass window. Identity under the cap.\n return capForCommit(next)\n })\n }\n\n if (!stillHasContent) {\n stopTicker()\n // Buckets and queued updaters both landed in this commit — the\n // buffer is idle, so end-of-stream convergence can proceed.\n releaseDrainWaiters()\n }\n }, [capForCommit, releaseDrainWaiters, setEvents, stopTicker])\n\n const ensureTicker = useCallback(() => {\n if (tickerRef.current)\n return\n tickerRef.current = setInterval(tick, TICK_INTERVAL_MS)\n }, [tick])\n\n /**\n * Decide between fast-drain and deferred-drain for an\n * updater-bearing call (`appendImmediate`, `flushAndUpdate`).\n *\n * Smooth mode + markdown backlog → ENQUEUE the updater behind the\n * trailing characters; the ticker picks it up once buckets empty.\n * Anything else → fall through to `drainNow` so the call retains\n * its synchronous semantics.\n */\n const drainOrDefer = useCallback((updater: (events: StreamEvent[]) => StreamEvent[]) => {\n const smooth = getSmoothRef.current?.() ?? true\n if (smooth && hasMarkdownBacklog()) {\n pendingUpdatersRef.current.push(updater)\n ensureTicker()\n return\n }\n drainNow(updater)\n }, [drainNow, ensureTicker, hasMarkdownBacklog])\n\n const flush = useCallback(() => {\n // In smooth mode with backlog, the ticker is already draining at\n // the typewriter cadence — explicit `flush()` shouldn't yank the\n // remaining characters into a single frame. The ticker is\n // self-stopping once empty, so this becomes a no-op there.\n const smooth = getSmoothRef.current?.() ?? true\n if (smooth && hasMarkdownBacklog()) {\n ensureTicker()\n return\n }\n drainNow()\n }, [drainNow, ensureTicker, hasMarkdownBacklog])\n\n const flushAndUpdate = useCallback(\n (update: (events: StreamEvent[]) => StreamEvent[]) => drainOrDefer(update),\n [drainOrDefer],\n )\n\n const appendImmediate = useCallback(\n (evt: StreamEvent) => drainOrDefer(events => [...events, evt]),\n [drainOrDefer],\n )\n\n const queueStreamDelta = useCallback((\n kind: 'markdown' | 'thinking',\n delta: string,\n source?: StreamSource,\n ) => {\n if (!delta)\n return\n const owner: Owner = source?.childId ?? PARENT_OWNER\n const depth = source?.depth ?? 0\n let bucket = bucketsRef.current.get(owner)\n if (!bucket) {\n bucket = emptyBucket(owner, depth)\n bucketsRef.current.set(owner, bucket)\n }\n bucket[kind] += delta\n // Refresh on every delta — `turn:after` drains the bucket between turns,\n // so a turnId only ever applies to the deltas of one turn. Keeping the\n // latest also lets a turn that starts mid-bucket (rare but theoretically\n // possible if two hooks race the flush ticker) tag the new event.\n if (source?.turnId)\n bucket.turnId = source.turnId\n ensureTicker()\n }, [ensureTicker])\n\n const reset = useCallback(() => {\n stopTicker()\n bucketsRef.current.clear()\n pendingUpdatersRef.current = []\n // The dropped backlog will never drain — release waiters instead of\n // stranding them until the safety timeout.\n releaseDrainWaiters()\n }, [releaseDrainWaiters, stopTicker])\n\n const whenDrained = useCallback((timeoutMs: number = WHEN_DRAINED_TIMEOUT_MS): Promise<void> => {\n if (bufferIdle(bucketsRef.current, pendingUpdatersRef.current.length))\n return Promise.resolve()\n return new Promise(resolve => addDrainWaiter(resolve, drainProgressRef, drainWaitersRef, timeoutMs))\n }, [])\n\n // Unmount hygiene: the interval ticker outlives the render otherwise and\n // fires `setEvents` against an unmounted host. `reset` is stable (all\n // deps are useCallback'd), so this registers exactly once and never\n // perturbs the memoized return below.\n useEffect(() => reset, [reset])\n\n // CRITICAL: stabilize the returned object. All six callbacks are useCallback'd\n // (stable across renders), but a bare object-literal return would be a fresh\n // reference every call, which cascades through every `useCallback`/`useEffect`\n // that depends on `stream` and turns the resume effect into an unbounded\n // destroy/rebuild loop — the exact source of the terminal-host memory leak.\n return useMemo(\n () => ({ queueStreamDelta, appendImmediate, flushAndUpdate, flush, reset, whenDrained }),\n [queueStreamDelta, appendImmediate, flushAndUpdate, flush, reset, whenDrained],\n )\n}\n","import type { ReactNode } from 'react'\nimport type { SyntaxStyles, Theme, ThemeColors, ThemeSelect, ThemeSurfaces } from './theme'\nimport { createContext, useContext } from 'react'\nimport { DEFAULT_THEME } from './theme'\n\n// ---------------------------------------------------------------------------\n// ThemeContext\n//\n// The TUI / GUI mounts `<ThemeProvider theme={…}>` near the root of its tree,\n// resolving the active theme from `Settings.theme`. Every component reads\n// theme values through a hook so a runtime theme switch (Settings → Theme)\n// triggers an immediate re-paint of the whole tree.\n//\n// Sub-hooks (`useColors`, `useSelectStyle`, …) exist so consumers can grab\n// just the slice they need — the rename-friendly shape lets a component\n// keep its body unchanged when migrating from the static `COLOR.brand`\n// pattern to `const COLOR = useColors(); COLOR.brand`.\n// ---------------------------------------------------------------------------\n\nconst ThemeContext = createContext<Theme>(DEFAULT_THEME)\n\nexport function ThemeProvider({ theme, children }: { theme: Theme, children: ReactNode }) {\n return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>\n}\n\nexport function useTheme(): Theme {\n return useContext(ThemeContext)\n}\n\n/** Color palette only — equivalent to `useTheme().colors`. */\nexport function useColors(): ThemeColors {\n return useContext(ThemeContext).colors\n}\n\n/** Select-row styling — equivalent to `useTheme().select`: the `▶` marker and accent text carry the cursor. */\nexport function useSelectStyle(): ThemeSelect {\n return useContext(ThemeContext).select\n}\n\n/** Panel / surface backgrounds — equivalent to `useTheme().surfaces`. */\nexport function useSurfaces(): ThemeSurfaces {\n return useContext(ThemeContext).surfaces\n}\n\n/** Raw syntax style table — `useTheme().syntax`. Renderer converts to its native style type. */\nexport function useSyntaxStyles(): SyntaxStyles {\n return useContext(ThemeContext).syntax\n}\n","import type { AgentHookMap } from '../agent'\nimport type { TodoItem } from './todos'\nimport { appendDynamicSection } from '../system-prompt'\nimport { selectActiveTodos } from './todos'\n\nexport interface ActiveTodoAnchorOptions {\n enabled?: boolean\n maxItems?: number\n heading?: string\n}\n\nexport function renderActiveTodoAnchor(\n todos: readonly TodoItem[],\n options: ActiveTodoAnchorOptions = {},\n): string {\n if (options.enabled === false || todos.length === 0)\n return ''\n const maxItems = Math.max(1, Math.floor(options.maxItems ?? 6))\n const heading = options.heading ?? 'Active Todo Anchor'\n const visible = todos.slice(0, maxItems)\n const lines = [`# ${heading}`, '<active_todos>']\n for (const item of visible)\n lines.push(`- [${item.status}] ${item.content}`)\n if (todos.length > visible.length)\n lines.push(`- ... ${todos.length - visible.length} more`)\n lines.push('</active_todos>')\n return lines.join('\\n')\n}\n\n/**\n * Optional chat-layer hook that keeps the live `todowrite` list visible in the\n * dynamic system prompt. It reads only live todos, never the archive, so an\n * auto-cleared completed plan is not reintroduced on later turns.\n *\n * ## Prompt-cache cost — read before enabling\n *\n * This writes per-turn state into the system prompt, and the system prompt sits\n * ABOVE the entire conversation in the provider's cache prefix (Anthropic hashes\n * tools → system → messages, cumulatively). So every time the rendered anchor\n * changes by a single byte, the whole transcript stops matching the cache and\n * re-bills at the cache-write rate; only `tools` and the static system block\n * survive.\n *\n * That is an acceptable trade only because the anchor changes *rarely* — once\n * per `todowrite`, which in practice is a small fraction of turns. Two rules\n * follow, and breaking either one turns that occasional cost into a per-turn\n * one:\n *\n * 1. Never add anything to the anchor that ticks on its own — no counters, no\n * timestamps, no elapsed times, no per-turn indices.\n * 2. The render must stay a pure function of the todo list.\n * `renderActiveTodoAnchor` is deterministic today, so identical todos emit\n * identical bytes; keep it that way. Note this does NOT cover reordering —\n * todo order is semantically meaningful (it is the plan), so a reorder is\n * a real state change and costs one re-bill like any other `todowrite`.\n *\n * Moving the anchor onto the newest message instead does NOT avoid this: it is\n * wire-only, so the message that carried last turn's anchor re-renders without\n * it, and the prefix diverges at that point just the same. The only injection\n * that is genuinely free is one persisted into the transcript as immutable\n * history.\n */\nexport function createActiveTodoAnchorHooks(options: ActiveTodoAnchorOptions = {}): AgentHookMap {\n return {\n 'system:transform': (ctx) => {\n const state = selectActiveTodos(ctx.session)\n const anchor = renderActiveTodoAnchor(state.todos, options)\n\n if (anchor)\n ctx.system = appendDynamicSection(ctx.system, anchor)\n },\n }\n}\n","// ---------------------------------------------------------------------------\n// Transcript scroll-anchor computation.\n//\n// Walks a list of partitioned transcript items (one entry per row that\n// will be rendered) and assigns a stable scroll-anchor id to the FIRST\n// event of each turn — `turn-anchor-<turnId>`. The renderer applies\n// these ids to whichever container hosts the first event of the turn;\n// scroll-into-view (TUI scrollbox or GUI element.scrollIntoView) then\n// resolves the id to a known target.\n//\n// Pure data-in / data-out so the same logic powers the TUI today and\n// any future GUI without dragging OpenTUI specifics into the chat\n// layer.\n// ---------------------------------------------------------------------------\n\nimport type { StreamEvent } from './types'\n\n/**\n * One entry in the partitioned transcript-row list. Single events\n * render as a normal row; a `child-run` groups ONE subagent's events\n * from a consecutive run of subagent output into one bordered box\n * (concurrent siblings get a `child-run` each, so their rows never\n * braid together inside a shared frame); `tool-group`s\n * collect ALL parent-owned tool/tool-result events of one exchange\n * into a single collapsible summary row (`Settings.groupToolCalls`);\n * an `exchange-fold` goes further (`Settings.transcriptDensity:\n * 'compact'`) and takes every thinking, tool and worker event of the\n * exchange, leaving only the prompt and the assistant's prose in place.\n * `key` is stable across re-partitions of the same stream (derived\n * from the first grouped event) so expand state survives appends.\n *\n * Currently produced by the TUI's `partitionTranscript`; a GUI shell\n * grouping subagent runs the same way can produce the same shape.\n */\nexport type TranscriptItem\n = | { kind: 'event', event: StreamEvent, previous?: StreamEvent }\n | { kind: 'child-run', events: StreamEvent[], previous?: StreamEvent }\n | { kind: 'tool-group', key: string, events: StreamEvent[], previous?: StreamEvent }\n | { kind: 'exchange-fold', key: string, events: StreamEvent[], previous?: StreamEvent }\n /** Compact density: an exchange's earlier messages, ahead of its last one. */\n | { kind: 'message-group', key: string, events: StreamEvent[], previous?: StreamEvent }\n\n/**\n * Per-item anchor ids for auto-scroll. Walks `items` in render order\n * and, for each event, returns either:\n * - `'turn-anchor-<turnId>'` — the first event of this turn (the\n * scroll target).\n * - `undefined` — later event of an already-tagged turn (or a\n * synthetic event with no `turnId`).\n *\n * `ids[i]` is a tuple per item: length 1 for plain events, length N\n * for subagent runs (one entry per inner event). `idByTurn` is the\n * inverse lookup used by the scroll effect. `lastTurnId` is the\n * most-recently-rendered turn — the scroll effect special-cases it to\n * snap to bottom rather than scroll the anchor into view (which would\n * stop short of the actual tail).\n *\n * Exported so the anchor-tagging matrix can be unit-tested without\n * rendering anything.\n */\nexport function computeTurnAnchors(items: readonly TranscriptItem[]): {\n idByTurn: ReadonlyMap<string, string>\n ids: readonly (readonly (string | undefined)[])[]\n lastTurnId: string | undefined\n} {\n const idByTurn = new Map<string, string>()\n let lastTurnId: string | undefined\n const tag = (turnId: string | undefined): string | undefined => {\n if (!turnId)\n return undefined\n lastTurnId = turnId\n if (idByTurn.has(turnId))\n return undefined\n const id = `turn-anchor-${turnId}`\n idByTurn.set(turnId, id)\n return id\n }\n const ids: (string | undefined)[][] = []\n for (const item of items) {\n if (item.kind === 'event')\n ids.push([tag(item.event.turnId)])\n else\n ids.push(item.events.map(e => tag(e.turnId)))\n }\n return { idByTurn, ids, lastTurnId }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,6BAAoD;CAClE,MAAM,uBAAO,IAAI,IAAiC;CAClD,OAAO;EACL,SAAQ,YAAW,KAAK,KAAK,IAAI,QAAQ,IAAI,OAAO;EACpD,SAAQ,OAAM,KAAK,KAAK,OAAO,EAAE;EACjC,aAAa,KAAK,MAAM;EACxB,YAAY,CAAC,GAAG,KAAK,OAAO,CAAC;CAC/B;AACF;AAEA,SAAgB,kBAAkB,SAKlB;CACd,MAAM,EAAE,WAAW,gBAAgB;CACnC,MAAM,cAAc,QAAQ,eAAe,2BAA2B;CACtE,MAAM,0BAAU,IAAI,IAA4B;CAEhD,OAAO;EACL,MAAM,QAAQ,OAAO;GACnB,IAAI,CAAC,MAAM,aAAa,aAAa,kBAAkB,YAAY,GAAG,MAAM,GAAG,GAAG,MAAM,MAAM,MAAM,KAAK,GACvG,OAAO;GAET,MAAM,KAAK,WAAW;GACtB,MAAM,OAA4B;IAChC;IACA,WAAW,MAAM;IACjB,KAAK,MAAM;IACX,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,0BAA0B,MAAM,YAAY,CAAC,IAAI,uBAAuB,MAAM,MAAM,MAAM,KAAK;IAC/F,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;IACzC,GAAI,MAAM,iBAAiB,KAAA,IAAY,EAAE,cAAc,MAAM,aAAa,IAAI,CAAC;IAC/E,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;IAElD,GAAI,MAAM,cAAc,MAAM,WAAW,SAAS,UAAU,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;GAClG;GAOA,YAAY,OAAO,IAAI;GAEvB,OAAO,IAAI,SAA2B,YAAY;IAChD,QAAQ,IAAI,IAAI;KAAE,SAAS;KAAM;IAAQ,CAAC;IAC1C,UAAU;KAAE,MAAM;KAAoB,SAAS;IAAK,CAAC;GACvD,CAAC;EACH;EAEA,QAAQ,IAAI,UAAU;GACpB,MAAM,QAAQ,QAAQ,IAAI,EAAE;GAO5B,IAAI,SAAS,aAAa,mBACxB,IAAI;IACF,MAAM,UACF,MAAM,QAAQ,4BACX,uBAAuB,MAAM,QAAQ,MAAM,MAAM,QAAQ,KAAK;IACrE,oBAAoB,YAAY,GAAG,MAAM,QAAQ,KAAK,OAAO;GAC/D,QACM,CAEN;GAGF,YAAY,OAAO,EAAE;GAErB,IAAI,CAAC,OACH;GAEF,QAAQ,OAAO,EAAE;GACjB,MAAM,QAAQ,QAAQ;GACtB,UAAU;IAAE,MAAM;IAAqB,WAAW,MAAM,QAAQ;IAAW,WAAW;IAAI;GAAS,CAAC;EACtG;EAEA,QAAQ,WAAW;GACjB,IAAI,cAAc,KAAA,GAAW;IAC3B,KAAK,MAAM,CAAC,IAAI,UAAU,SAAS;KACjC,MAAM,QAAQ,MAAM;KACpB,UAAU;MAAE,MAAM;MAAqB,WAAW,MAAM,QAAQ;MAAW,WAAW;MAAI,UAAU;KAAO,CAAC;IAC9G;IACA,QAAQ,MAAM;IACd,YAAY,MAAM;IAClB;GACF;GAEA,KAAK,MAAM,CAAC,IAAI,UAAU,SAAS;IACjC,IAAI,MAAM,QAAQ,cAAc,WAC9B;IACF,MAAM,QAAQ,MAAM;IACpB,QAAQ,OAAO,EAAE;IACjB,YAAY,OAAO,EAAE;IACrB,UAAU;KAAE,MAAM;KAAqB;KAAW,WAAW;KAAI,UAAU;IAAO,CAAC;GACrF;EACF;EAEA,cAAc;GACZ,OAAO,YAAY,KAAK;EAC1B;EAEA,YAAY;GACV,KAAK,MAAM,OAAO,YAAY,KAAK,GAAG;IACpC,IAAI,QAAQ,IAAI,IAAI,EAAE,GACpB;IAOF,QAAQ,IAAI,IAAI,IAAI;KAAE,SAAS;KAAK,eAAe,KAAA;IAAU,CAAC;GAChE;EACF;CACF;AACF;;;;;;;;;;AChHA,eAAsB,cACpB,OACA,WACA,OACkC;CAClC,UAAU;EAAE,MAAM;EAAoB,WAAW,MAAM;CAAU,CAAC;CAElE,IAAI,KAAK;CACT,IAAI,SAAkC;CACtC,MAAM,uBAAuB,IAAI,gBAAgB;CACjD,MAAM,EAAE,WAAW,MAAM;CAEzB,IAAI;EACF,MAAM,OAAO,MAAM,MAAM,KAAK,MAAM,SAAS;EAC7C,IAAI,CAAC,MACH,OAAO;EAET,MAAM,QAAuB,KAAK;EAOlC,MAAM,qBACF,MAAM,oBAAoB,QAAQ,KAC/B,kBAAkB,MAAM,YAAY,EAAE,QAAQ,KAC9C,kBAAkB,UAAU,QAAQ;EAE3C,MAAM,SAAS,MAAM,oBAAoB;GACvC,UAAU;GACV,OAAO,MAAM;GAKb,OAAO,0BAA0B,KAAK;GACtC,OAAO;GACP;EACF,CAAC;EACD,MAAM,cAAc,cAAc;GAChC,SAAS,OAAO;GAChB,iBAAiB,OAAO;GACxB,OAAO,OAAO;GACd,OAAO,MAAM;EACf,CAAC;EASD,MAAM,UAAU,MAAM,MAAM;EAC5B,MAAM,SAAS,MAAM,MAAM,UAAU,KAAA;EACrC,MAAM,cAAc,UAChB,MAAM,4BAA4B;GAChC,aAAa,uBAAuB,SAAS,QAAQ,OAAO,MAAM,GAAG;GACrE,cAAc,MAAM,MAAM;GAC1B,WAAW,MAAM,MAAM;GACvB;GAGA;EACF,CAAC,IACD;GAAE,OAAO,CAAC;GAAG,eAAe;GAAG,gBAAgB;GAAG,iBAAiB;EAAE;EAEzE,MAAM,iBAAiB,CAAC,aAAa,GAAG,YAAY,KAAK;EACzD,IAAI,SACF,MAAM,QAAQ,YAAY,cAAc;OAExC,MAAM,MAAM,YAAY,MAAM,WAAW,cAAc;EACzD,SAAS;GACP,eAAe,OAAO,kBAAkB;GACxC,cAAc,OAAO,gBAAgB;GACrC,eAAe,YAAY;GAC3B,gBAAgB,YAAY;GAC5B,OAAO,MAAM;GACb,aAAa,uBAAuB,OAAO,KAAK;GAChD,cAAc,OAAO,MAAM,UAAU;GACrC,kBAAkB,OAAO,MAAM,UAAU,KAAK,YAAY;EAC5D;EAIA,MAAM,eAAe,YAAY,QAAQ,MAAK,MAAK,EAAE,SAAS,iBAAiB;EAC/E,IAAI,gBAAgB,aAAa,SAAS,mBACxC,UAAU;GACR,MAAM;GACN,WAAW,MAAM;GACjB,OAAO,oBAAoB,cAAc,YAAY,EAAE;EACzD,CAAC;EAEH,KAAK;CACP,SACO,KAAK;EACV,IAAI,OAAO,SACT,UAAU;GACR,MAAM;GACN,WAAW,MAAM;GACjB,OAAO;IAAE,MAAM;IAAQ,MAAM;GAA6B;EAC5D,CAAC;OAGD,UAAU;GACR,MAAM;GACN,WAAW,MAAM;GACjB,OAAO;IAAE,MAAM;IAAS,MAAM,2BAA4B,IAAc;GAAU;EACpF,CAAC;CAEL,UACQ;EACN,MAAM,uBAAuB,KAAA;EAC7B,UAAU;GAAE,MAAM;GAAkB,WAAW,MAAM;GAAW;EAAG,CAAC;CACtE;CACA,OAAO;AACT;;;AC3KA,SAAgB,wBAAwB,EAAE,QAAQ,WAAW,OAAO,eAKlC;;;;;;CAMhC,OAAO,eAAe,kBAAkB,WAAW;EAGjD,MAAM,QAAQ,OAAO,IAAI,SAAS,KAAK,MAAM,YAAY,SAAS;EAGlE,IAAI,MAAM,YACR,OAAO,MAAM;EAEf,MAAM,aAAa,cAAc,OAAO,WAAW,KAAK,CAAC,CAAC,cAAc;GACtE,MAAM,OAAO,OAAO,IAAI,SAAS;GACjC,IAAI,QAAQ,KAAK,eAAe,MAAM,YACpC,KAAK,aAAa,KAAA;EACtB,CAAC;EACD,OAAO,MAAM;CACf;AACF;;;ACrBA,SAAgB,2BAA2B,EAAE,WAAW,OAAO,aAA+B,YAA8B;CAM1H,MAAM,MAAM,KAAK,kBAAkB,EAAE,mBAAmB;EACtD,UAAU;GAAE,MAAM;GAAoB;EAAU,CAAC;EACjD,UAAU;GACR,MAAM;GACN;GACA,OAAO;IAAE,MAAM;IAAQ,MAAM,yCAAyC,KAAK,MAAM,eAAe,GAAG,EAAE;GAA0B;EACjI,CAAC;CACH,CAAC;CAED,MAAM,MAAM,KAAK,qBAAqB,EAAE,sBAAsB;EAC5D,UAAU;GAAE,MAAM;GAAuB;GAAW;EAAgB,CAAC;CACvE,CAAC;CACD,MAAM,MAAM,KAAK,gBAAgB,QAAQ;EACvC,IAAI,IAAI,WAAW,WAAW;GAI5B,MAAM,aAAa,CAAC,GAAI,MAAM,SAAS,SAAS,CAAC,CAAE,CAAC,CACjD,QAAQ,CAAC,CACT,MAAK,MAAK,EAAE,QAAQ,MAAK,MAAK,EAAE,SAAS,iBAAiB,CAAC;GAC9D,MAAM,SAAS,YAAY,QAAQ,MAAK,MAAK,EAAE,SAAS,iBAAiB;GACzE,IAAI,cAAc,UAAU,OAAO,SAAS,mBAC1C,UAAU;IAAE,MAAM;IAAS;IAAW,OAAO,oBAAoB,QAAQ,WAAW,EAAE;GAAE,CAAC;EAC7F,OACK;GAEH,MAAM,MAAO,IAAI,OAAiB,WAAW,OAAO,IAAI,KAAK;GAC7D,IAAI,CAAC,SAAS,KAAK,GAAG,GACpB,WAAW;IAAE,UAAU;IAAS,OAAO;GAAkB,GAAG,GAAG;EACnE;EACA,UAAU;GACR,MAAM;GACN;GACA,IAAI,IAAI,WAAW;GAEnB,GAAI,IAAI,WAAW,aAAa,OAAO,IAAI,oBAAoB,WAC3D,EAAE,iBAAiB,IAAI,gBAAgB,IACvC,CAAC;EACP,CAAC;CACH,CAAC;AACH;;;AChCA,IAAa,oBAAb,MAA+B;CAC7B,2BAAmB,IAAI,IAA+B;CAEtD,MAAM,QAAgB,SAAkC;EACtD,KAAK,SAAS,IAAI,QAAQ,OAAO;CACnC;;CAGA,MAAM,QAA0C;EAC9C,MAAM,QAAQ,KAAK,SAAS,IAAI,MAAM;EACtC,IAAI,CAAC,OACH,OAAO;EACT,KAAK,SAAS,OAAO,MAAM;EAC3B,OAAO;CACT;;CAGA,KAAK,QAA0C;EAC7C,OAAO,KAAK,SAAS,IAAI,MAAM,KAAK;CACtC;;CAGA,QAAQ,QAAsB;EAC5B,KAAK,SAAS,OAAO,MAAM;CAC7B;;CAGA,QAAc;EACZ,KAAK,SAAS,MAAM;CACtB;AACF;;;;;;;ACfA,MAAM,iBAAiB;;;;;;AAkCvB,SAAgB,kBAAkB,SAAyB;CACzD,OAAO,QAAQ,SAAS,cAAc;AACxC;;;;;;;;;;;;AAaA,SAAgB,kBAAkB,MAA0C;CAC1E,MAAM,OAAO,kBAAkB,KAAK,OAAO;CAC3C,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,IAAI;EACF,MAAM,MAAM,aAAa,MAAM,OAAO;EACtC,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,OAAO,CAAC;EACV,MAAM,MAAqB,CAAC;EAC5B,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAiC,GAC1E,IAAI,cAAc,KAAK,GACrB,IAAI,QAAQ;EAEhB,OAAO;CACT,QACM;EACJ,OAAO,CAAC;CACV;AACF;;;;;;AAOA,SAAgB,kBAAkB,MAAuD;CACvF,gBACE,kBAAkB,KAAK,OAAO,GAC9B,GAAG,KAAK,UAAU,KAAK,OAAO,MAAM,CAAC,EAAE,KACvC,EAAE,WAAW,KAAK,CACpB;AACF;;;;;;;;;;;AAYA,SAAgB,mBAAmB,MAA2E;CAC5G,MAAM,UAAU,kBAAkB,IAAI;CACtC,IAAI,CAAC,KAAK,aAAa;EACrB,kBAAkB;GAAE,SAAS,KAAK;GAAS,OAAO,CAAC;EAAE,CAAC;EACtD,OAAO,CAAC;CACV;CACA,MAAM,OAAsB,EAAE,GAAG,QAAQ;CACzC,KAAK,MAAM,QAAQ,KAAK,aACtB,OAAO,KAAK;CACd,kBAAkB;EAAE,SAAS,KAAK;EAAS,OAAO;CAAK,CAAC;CACxD,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,uBACd,OACA,MAIY;CAkBZ,OAjBoB,MAAM,KAAK,mBAAmB,QAAQ;EACxD,MAAM,QAA2B;GAC/B,OAAO,CAAC,GAAG,IAAI,KAAK;GACpB,WAAW,KAAK,IAAI;GACpB,WAAW,IAAI;EACjB;EACA,IAAI;GAEF,MAAM,OAAsB;IAAE,GADd,kBAAkB,EAAE,SAAS,KAAK,QAAQ,CACnB;KAAI,IAAI,OAAO;GAAM;GAC5D,kBAAkB;IAAE,SAAS,KAAK;IAAS,OAAO;GAAK,CAAC;GACxD,KAAK,WAAW;IAAE,MAAM,IAAI;IAAM,GAAG;GAAM,CAAC;EAC9C,SACO,KAAK;GACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,mDAAmD,IAAI,KAAK,KAAKA,eAAa,GAAG,EAAE,GAAG;EAC/G;CACF,CACiB;AACnB;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,eAAsB,uBAAuB,MAS3B;CAChB,IAAI,KAAK,QAAQ,WAAW,GAC1B;CAWF,OAAM,MAVmB,kBACvB,KAAK,SACL,KAAA,GACA,KAAK,OACL,KAAK,oBAAoB,EAAE,mBAAmB,KAAK,kBAAkB,IAAI,KAAA,CAC3E,EAAA,CAKiB,MAAM,CAAC,CAAC,OAAO,QAAQ;EACtC,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,yDAAyDA,eAAa,GAAG,EAAE,GAAG;CACvG,CAAC;AACH;;;;;;AAOA,SAAS,cAAc,OAA4C;CACjE,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO;CACT,MAAM,QAAQ;CACd,IAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,GAC5B,OAAO;CACT,IAAI,OAAO,MAAM,cAAc,YAAY,CAAC,OAAO,SAAS,MAAM,SAAS,GACzE,OAAO;CACT,IAAI,MAAM,cAAc,WAAW,MAAM,cAAc,SAAS,MAAM,cAAc,mBAClF,OAAO;CAKT,OAAO;AACT;;;;AC3OA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;AAmCxB,SAAgB,uBAAuB,OAInC,CAAC,GAAsB;CACzB,OAAO,iBAAiB;EAAE,SAAS;EAAiB,GAAG;CAAK,CAAC;AAC/D;;;;;;;;;;;;;;;AAgBA,SAAgB,uBACd,QAA4B,QAAQ,IAAI,oBAC9B;CACV,IAAI,CAAC,OACH,OAAO,CAAC;CACV,OAAO,MAAM,MAAM,SAAS,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO;AACjE;;;;;;;;;;;;;AAcA,eAAsB,uBAAuB,OAczC,CAAC,GAAuE;CAC1E,MAAM,QAAQ,CACZ,GAAG,uBAAuB,IAAI,GAC9B,IAAI,KAAK,cAAc,CAAC,EAAA,CAAG,KAAI,UAAS;EAAE;EAAM,QAAQ;CAAmB,EAAE,CAC/E,CAAC,CAAC,QAAO,MAAK,WAAW,EAAE,IAAI,CAAC;CAChC,MAAM,WAAW,sBAAsB;EACrC,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;CACvD,CAAC;CACD,MAAM,UAA8B,CAAC;CACrC,MAAM,SAA2B,CAAC;CAClC,MAAM,uBAAO,IAAI,IAAY;CAE7B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,QAAQ,SACf;EAEF,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,QAAQ,KAAK,IAAI;EACnC,SACO,KAAK;GACV,OAAO,KAAK;IACV,MAAM,KAAK;IACX,QAAQ,KAAK;IACb,SAAS,oCAAoC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC9F,CAAC;GACD;EACF;EAGA,KAAK,MAAM,SAAS,QAAQ,KAAK,GAAG;GAClC,IAAI,KAAK,QAAQ,SACf;GACF,MAAM,MAAM,KAAK,KAAK,MAAM,KAAK;GACjC,IAAI;IAgBF,IAAI,EAAE,MAAM,KAAK,GAAG,EAAA,CAAG,YAAY,GACjC;GACJ,QACM;IACJ;GACF;GAOA,MAAM,SAAS,MAAM,gBAAgB,KAAK;IACxC,QAAQ,KAAK;IACb;GACF,CAAC;GAID,IAAI,CAAC,OAAO,MAAM,OAAO,YAAY,MAAK,MAAK,EAAE,SAAS,kBAAkB,GAC1E;GAEF,MAAM,OAAO,OAAO,UAAU,QAAQ,SAAS,GAAG;GAClD,IAAI,KAAK,IAAI,IAAI,GACf;GACF,KAAK,IAAI,IAAI;GACb,QAAQ,KAAK;IAAE;IAAM,QAAQ;IAAQ,QAAQ,KAAK;IAAQ,MAAM;GAAI,CAAC;EACvE;CACF;CAEA,OAAO;EAAE;EAAS;CAAO;AAC3B;;;;;;;;;;;;;AAcA,SAAgB,yBAAyB,MAGoB;CAC3D,MAAM,QAAQ,KAAK,YAAY,KAAA,IAAY,OAAO,IAAI,IAAI,KAAK,OAAO;CACtE,MAAM,SAAwB,CAAC;CAC/B,MAAM,aAAgC,CAAC;CAEvC,KAAK,MAAM,SAAS,KAAK,YAAY;EACnC,IAAI,CAAC,MAAM,OAAO,IAChB;EACF,IAAI,UAAU,QAAQ,CAAC,MAAM,IAAI,MAAM,IAAI,GACzC;EACF,OAAO,KAAK,GAAG,MAAM,OAAO,MAAM;EAClC,WAAW,KAAK,GAAG,MAAM,OAAO,UAAU;CAC5C;CAEA,OAAO;EAAE;EAAQ;CAAW;AAC9B;;;;;;;;;;;;;;;;;;AC5NA,SAAgB,gBAAwB;CACtC,OAAO,QAAQ;AACjB;;;;;;;;AASA,SAAgB,kBAAkB,KAGvB;CAGT,QAFiB,OAAO,IAAI,UAAU,QAAQ,WAAW,IAAI,SAAS,MAAM,KAAA,MAEzD,IAAI,eAAe,cAAc;AACtD;;;;;;;;AASA,SAAgB,SAAS,KAAqB;CAC5C,OAAO,OAAO,cAAc;AAC9B;;;;;;;;;;;ACvBA,MAAa,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;AAwBhC,SAAgB,kBAAkB,MAkBhC;CACA,MAAM,UAAU,KAAK,IAAI,iBAAiB,QAAQ,KAAK,IAAI,aAAa,CAAC,CAAC,cAAc;CACxF,IAAI,WAA6B,QAAQ,QAAQ;CACjD,IAAI,eAAe;CACnB,IAAI;CACJ,MAAM,aAAmB;EACvB,MAAM,cAAgC,KAAK,IAAI,MAAM,aAAa,KAAK,WAAW,SAAS;EAM3F,MAAM,UAAU,eAAe,SAAS,KAAK,KAAK,IAAI,IAAI,SAAQ,YAAW,QAAQ,MAAM,CAAC,CAAC;EAC7F,eAAe;EACf,MAAM,UAAU,QACb,YAAY,KAAA,CAAS,CAAC,CACtB,cAAc;GACb,IAAI,aAAa,SACf,eAAe;EACnB,CAAC;EACH,WAAW;CACb;CACA,IAAI,WAAW,KAAK,WAClB,KAAK;CACP,MAAM,QAAQ,UACV,kBAAkB;EAChB,IAAI,CAAC,UAAU,CAAC,gBAAgB,KAAK,UAAU,GAC7C,KAAK;CACT,GAAG,gBAAgB,IACnB,KAAA;CACJ,OAAO;EACL,OAAO;GACL,IAAI,WAAW,CAAC,QACd,KAAK;EACT;EACA,IAAI,eAAe;GACjB,IAAI,QACF,OAAO;GACT,IAAI,UAAU,KAAA,GACZ,cAAc,KAAK;GACrB,SAAS,SACN,KAAK,YAAY;IAChB,IAAI,WAAW,iBAAiB,kBAAkB,WAChD,MAAM,KAAK,IAAI,MAAM,aAAa,KAAK,WAAW,aAAa;GACnE,CAAC,CAAC,CACD,YAAY,KAAA,CAAS;GACxB,OAAO;EACT;CACF;AACF;;;;;;;;;;AAWA,SAAgB,4BACd,KACA,eACA,MACmD;CACnD,IAAI,CAAC,KACH,OAAO,KAAA;CACT,MAAM,QAAQ,IAAI,QAAQ,GAAG;CAC7B,IAAI,SAAS,KAAK,UAAU,IAAI,SAAS,GACvC,OAAO,KAAA;CACT,MAAM,cAAc,IAAI,MAAM,GAAG,KAAK;CACtC,MAAM,QAAQ,IAAI,MAAM,QAAQ,CAAC;CACjC,IAAI,gBAAgB,KAAK,eAAe,UAAU,KAAK,OACrD,OAAO,KAAA;CACT,IAAI;EACF,OAAO;GAAE,UAAU,cAAc,WAAW;GAAG;EAAM;CACvD,QACM;EACJ;CACF;AACF;AAEA,eAAsB,aAAa,MAA+B;CAChE,IAAI;EACF,OAAO,MAAM,SAAS,MAAM,MAAM;CACpC,QACM;EACJ,OAAO;CACT;AACF;;AAGA,SAAgB,eAAe,KAAa,GAAmB;CAC7D,IAAI,EAAE,WAAW,GAAG,GAClB,OAAO;CACT,OAAO,GAAG,IAAI,QAAQ,OAAO,EAAE,EAAE,GAAG,EAAE,QAAQ,OAAO,EAAE;AACzD;;;;;;;;AASA,SAAgB,0BAA0B,MAAc,OAAyD;CAC/G,IAAI,SAAS,UAAU,SAAS,cAC9B,OAAO,mBAAmB,MAAM,KAAK;CACvC,IAAI,SAAS,cACX,OAAO,mBAAmB,MAAM,OAAO,EAAE;AAE7C;;;;;;AAOA,SAAgB,iBAAiB,SAA2C;CAC1E,OAAO;EACL,UAAU,QAAQ;EAClB,aAAa,CAAC,GAAG,QAAQ,WAAW;EACpC,YAAY,QAAQ,WAAW,KAAI,OAAM,EAAE,GAAG,EAAE,EAAE;EAClD,iBAAiB;GACf,GAAG,QAAQ;GACX,OAAO,QAAQ,gBAAgB,MAAM,KAAI,OAAM,EAAE,GAAG,EAAE,EAAE;GACxD,GAAI,QAAQ,gBAAgB,WACxB,EAAE,UAAU,QAAQ,gBAAgB,SAAS,KAAI,OAAM,EAAE,GAAG,EAAE,EAAE,EAAE,IAClE,CAAC;EACP;CACF;AACF;;;AC9KA,SAAgB,yBAAiI;;;;;;;CAO/I,MAAM,mCAAmB,IAAI,IAAyB;CACtD,SAAS,mBAAmB,WAAgC;EAC1D,IAAI,WAAW,iBAAiB,IAAI,SAAS;EAC7C,IAAI,CAAC,UAAU;GACb,2BAAW,IAAI,IAAI;GACnB,iBAAiB,IAAI,WAAW,QAAQ;EAC1C;EACA,OAAO;CACT;CACA,OAAO;EAAE;EAAkB;CAAmB;AAChD;AAEA,SAAgB,wBAAwB,EAAE,KAAK,WAAW,0BAIpB;CAMpC,MAAM,kBAAkB,OAAO,SAAkC;EAC/D,IAAI,CAAC,WACH,OAAO,aAAa,eAAe,KAAK,IAAI,CAAC;EAC/C,IAAI;GACF,OAAO,MAAM,uBAAuB,QAAQ,SAAS,MAAM,uBAAuB,OAAO,GAAG,MAAM,WAAW,IAAI,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC;EACzJ,QACM;GACJ,OAAO;EACT;CACF;CACA,OAAO;AACT;AAEA,SAAgB,oBACd,EAAE,WAAW,OAAO,aACpB,OAUM;CACN,MAAM,EAAE,KAAK,WAAW,WAAW,KAAK,iBAAiB,iBAAiB,QAAQ,8BAA8B;;;;;;;;;;;;;CAahH,MAAM,YAAY,OAChB,KAUA,eACkB;EAClB,IAAI,IAAI,OAEN;EAGF,MAAM,QAAQ,IAAI;EAOlB,MAAM,YAAY,IAAI,SAAS,oBAAoB,UAAU,QAAQ,OAAO,MAAM,EAAE,CAAC,MAAM;EAC3F,IAAI,IAAI,aAAa,CAAC,CAAC,aAAa,SAAU,CAAC,aAAa,aAAa,CAAC,GAAG,eAAe,GAAG,IAAI,MAAM,KAAK,GAC5G;EAEF,MAAM,UAAU,0BAA0B,IAAI,MAAM,KAAK;EAEzD,IAAI,eAA8B;EAClC,IAAI;EAEJ,IAAI,SAAS;GACX,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,KAAA;GAC3D,eAAe,OAAO,MAAM,gBAAgB,IAAI,IAAI;GAEpD,IAAI;IAOF,UAAU,iBADK,mBAAmB,SAAS,cAAc,CAC9B,CAAM;GACnC,QACM,CAEN;EACF;EAEA,MAAM,WAAW,MAAM,UAAU,QAAQ;GACvC;GACA;GACA,MAAM,IAAI;GACV;GACA,GAAI,UAAU;IAAE,MAAM;IAAS;GAAa,IAAI,CAAC;GACjD,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;GAC7B,GAAI,WAAW,SAAS,UAAU,EAAE,WAAW,IAAI,CAAC;GACpD,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACnC,CAAC;EAED,IAAI,aAAa,oBAAoB,CAAC,WACpC,KAAK,MAAM,SAAS,uBAAuB,IAAI,MAAM,KAAK,GACxD,gBAAgB,IAAI,KAAK;EAG7B,IAAI,SAAS;GACX,MAAM,WAAW,0BAA0B,UAAU,OAAO;GAE5D,IAAI,SAAS,aAAa;IACxB,IAAI,QAAQ;IACZ,IAAI,SAAS,aAAa,SAAS,+BAA+B;IAOlE,MAAM,YACF,IAAI,YAAY,KAAA,KAAa,IAAI,UAAU,KAAA,IAAY;KAAE,SAAS,IAAI;KAAS,OAAO,IAAI;IAAM,IAAI,KAAA;IAExG,MAAM,gBAAgB,SAAS,kBAAkB;KAAE,GAAG;KAAS,UAAU,SAAS;IAAS;IAY3F,UAAU;KAAE,MAAM;KAAS;KAAW,OAAO;MAT3C,MAAM;MACN,MAAM,gBAAgB,IAAI,MAAM,KAAK;MACrC,MAAM,IAAI;MACV,QAAQ,IAAI;MACZ;MACA,MAAM;MACN,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;MAC3C,GAAI,aAAa,CAAC;KAEiC;IAAE,CAAC;IAExD,MAAM,aAAa,4BAA4B,SAAS,QAAQ;IAUhE,UAAU;KAAE,MAAM;KAAS;KAAW,OAAO;MAP3C,MAAM;MACN,MAAM,YAAY,IAAI,OAAO,MAAM;MACnC,MAAM,IAAI;MACV,QAAQ,IAAI;MACZ,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;MAC3C,GAAI,aAAa,CAAC;KAEmC;IAAE,CAAC;IAC1D,0BAA0B,IAAI,IAAI,MAAM;IAExC;GACF;GAQA,IAAI,OAAO,aAAa,YAAY,SAAS,SAAS,aAAa,MAAM,QAAQ,MAAM,KAAK,GAAG;IAC7F,MAAM,eAAgB,MAAM,MAAoB,QAAQ,GAAG,MAAM,SAAS,KAAK,OAAO,IAAI;IAC1F,IAAI,QAAQ;KAAE,GAAG;KAAO,OAAO;IAAa;IAC5C,OAAO,MAAM,IAAI,QAAQ;KACvB,UAAU,SAAS;KACnB,eAAe;KACf,iBAAiB;IACnB,CAAC;GACH;GAEA;EACF;EAMA,IAAI,aAAa,UAAW,OAAO,aAAa,YAAY,SAAS,SAAS,WAAY;GACxF,IAAI,QAAQ;GACZ,IAAI,SAAS;EACf;CACF;CAEA,MAAM,MAAM,KAAK,cAAa,QAAO,UAAU,KAAK,EAAE,MAAM,SAAS,CAAC,CAAC;CACvE,MAAM,MAAM,KAAK,oBAAmB,QAAO,UAAU,KAAK;EAAE,MAAM;EAAS,OAAO,IAAI;CAAQ,CAAC,CAAC;CAChG,MAAM,MAAM,KAAK,iBAAiB,OAAO,QAAQ;EAC/C,MAAM,OAAO;GACX,OAAO,IAAI;GACX,QAAQ,IAAI;GACZ,MAAM,IAAI;GACV,OAAO,IAAI;GACX,QAAQ,IAAI;GACZ,QAAQ,IAAI;EACd;EACA,MAAM,UAAU,MAAM,EAAE,MAAM,SAAS,CAAC;EACxC,IAAI,QAAQ,KAAK;EACjB,IAAI,SAAS,KAAK;EAClB,IAAI,QAAQ,KAAK;CACnB,CAAC;CACD,MAAM,MAAM,KAAK,uBAAuB,OAAO,QAAQ;EACrD,MAAM,OAAO;GACX,OAAO,IAAI;GACX,QAAQ,IAAI;GACZ,MAAM,IAAI;GACV,OAAO,IAAI;GACX,QAAQ,IAAI;GACZ,QAAQ,IAAI;GACZ,SAAS,IAAI;GACb,OAAO,IAAI;EACb;EACA,MAAM,UAAU,MAAM;GAAE,MAAM;GAAS,OAAO,IAAI;EAAQ,CAAC;EAC3D,IAAI,QAAQ,KAAK;EACjB,IAAI,SAAS,KAAK;EAClB,IAAI,QAAQ,KAAK;CACnB,CAAC;AACH;;;;;;;;AChQA,SAAgB,kBACd,EAAE,MAAM,OAAO,UAC+C;CAC9D,MAAM,UAAU,WAAW;CAC3B,OAAO;EACL,QAAQ;GAAE,UAAU,UAAU,UAAU;GAAQ,OAAO;EAAe;EACtE,MAAM,UACF,GAAG,KAAK,YAAY,MAAM,2CAC1B,GAAG,KAAK,YAAY,MAAM;CAChC;AACF;;;;;;;;;;;;;AC4BA,SAAgB,aAAa,QAAgE;CAC3F,QAAQ,QAAR;EACE,KAAK,UACH,OAAO;GACL,QAAQ;IAAE,UAAU;IAAQ,OAAO;GAAe;GAClD,MAAM;EACR;EACF,KAAK,SACH,OAAO;GACL,QAAQ;IAAE,UAAU;IAAQ,OAAO;GAAY;GAC/C,MAAM;EACR;EACF,KAAK,kBAQH,OAAO;GACL,QAAQ;IAAE,UAAU;IAAQ,OAAO;GAAU;GAC7C,MAAM;EACR;EACF,SACE;CACJ;AACF;;;;;;;;AClEA,MAAa,YAAY,eAAe,WAAW;;;;;;;;ACuBnD,SAAgB,kBACd,EAAE,WAAW,OAAO,aACpB,QACA,MACA,OACM;CACN,MAAM,SAAS,WAAW;CAC1B,UAAU;EAAE,MAAM;EAAS;EAAW,OAAO;GAAE,MAAM,OAAO,aAAa,UAAU,UAAU;GAAQ;GAAM;GAAQ;GAAQ,GAAI,SAAS,CAAC;EAAG;CAAE,CAAC;CAC/I,OAAY,SACR,YAAY,CAAC;EAAE,IAAI;EAAQ,MAAM;EAAW,WAAW,KAAK,IAAI;EAAG,SAAS,kBAAkB,QAAQ,MAAM,KAAK;CAAE,CAAC,CAAC,CAAC,CACvH,OAAM,QAAO,UAAU,UAAU,GAAG,OAAO,MAAM,mBAAmB,OAAO,GAAG,GAAG,CAAC;AACvF;;;;;AAMA,SAAgB,eAAe,EAAE,WAAW,OAAO,aAA2C;CAQ5F,wBAAwB,MAAM,OAAO,EAAE,MAAK,SAAQ,UAAU,eAAe,IAAI,EAAE,CAAC;CAOpF,MAAM,cAA0B,QAAQ,MAAM,UAAU,kBAAkB;EAAE;EAAW;EAAO;CAAU,GAAG,QAAQ,MAAM,KAAK;CAM9H,MAAM,+BAAe,IAAI,IAAY;CAErC,MAAM,qBACJ,MACA,UACS;EACT,MAAM,MAAM,GAAG,OAAO,WAAW,GAAG,QAAQ,KAAK,KAAK,QAAQ,KAAK;EACnE,IAAI,aAAa,IAAI,GAAG,GACtB;EACF,aAAa,IAAI,GAAG;EACpB,MAAM,EAAE,QAAQ,SAAS,kBAAkB,IAAI;EAC/C,WAAW,QAAQ,MAAM,KAAK;CAChC;CACA,MAAM,MAAM,KAAK,0BAAyB,SAAQ,kBAAkB,IAAI,CAAC;CACzE,MAAM,MAAM,KAAK,gCAAgC,EAAE,SAAS,OAAO,GAAG,WAAW,kBAAkB,MAAM;EAAE;EAAS;CAAM,CAAC,CAAC;CAC5H,MAAM,MAAM,KAAK,oBAAoB,aAAa,MAAM,CAAC;CAazD,IAAI,qBAA4C;CAChD,MAAM,MAAM,KAAK,gBAAgB,SAAS;EACxC,UAAU;GAAE,MAAM;GAAe;GAAW;EAAK,CAAC;EAClD,qBAAqB;CACvB,CAAC;CACD,MAAM,MAAM,KAAK,uBAAuB;EACtC,MAAM,OAAO;EACb,IAAI,CAAC,MACH;EACF,qBAAqB;EACrB,MAAM,UAAU,MAAM;EACtB,IAAI,CAAC,SACH;EACF,MAAM,OAAO,eAAe,IAAI;EAIhC,MAAM,OAAO,qBAAqB,IAAI;EACtC,MAAM,SAAS;GAAE,UAAU,KAAK,SAAS,SAAS,SAAkB;GAAiB,OAAO;EAAmB;EAC/G,MAAM,SAAS,WAAW;EAC1B,QACG,YAAY,CAAC;GAAE,IAAI;GAAQ,MAAM;GAAW,WAAW,KAAK,IAAI;GAAG,SAAS,kBAAkB,QAAQ,IAAI;EAAE,CAAC,CAAC,CAAC,CAC/G,WAAW,UAAU;GAAE,MAAM;GAAS;GAAW,OAAO;IAAE,MAAM;IAAQ;IAAM;IAAQ;GAAO;EAAE,CAAC,CAAC,CAAC,CAClG,OAAM,QAAO,UAAU,eAAe,0BAA0B,OAAO,GAAG,GAAG,CAAC;CACnF,CAAC;CACD,OAAO;AACT;;AAGA,SAAgB,wBAAwB,EAAE,WAAW,aAAgE,SAAqC;CAIxJ,IAAI,QAAQ,SACV,UAAU;EACR,MAAM;EACN;EACA,OAAO;GAAE,MAAM;GAAQ,MAAM,QAAQ;GAAS,QAAQ;IAAE,UAAU;IAAQ,OAAO;GAAU;EAAE;CAC/F,CAAC;AAEL;AAEA,SAAgB,oBAAoB,OAAc,YAA8B;;;;;;;;;;;CAW9E,MAAM,MAAM,KAAK,eAAe,UAAU;EACxC,MAAM,OAAO,aAAa,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE,YAAY;EAC/D,IAAI,MACF,WAAW,KAAK,QAAQ,KAAK,IAAI;CACrC,CAAC;AACH;AAEA,SAAgB,uBAAuB,EAAE,WAAW,OAAO,aAA+B,YAA8B;CAMtH,MAAM,MAAM,KAAK,mBAAmB,QAAQ;EAE1C,WAAW;GAAE,UAAU;GAAQ,OAAO;EAAiB,GAAG,WAAW,GADnD,IAAI,cAAc,wBAAwB,IAAI,kBAAkB,IAAI,KAAK,MACf,wBAAwB,IAAI,YAAY,KAAK,gCAAgC;CAC3J,CAAC;CAMD,MAAM,MAAM,KAAK,mBAAmB,QAAQ;EAC1C,UAAU;GAAE,MAAM;GAAkB;GAAW,MAAM,IAAI;GAAM,IAAI,IAAI;EAAG,CAAC;EAC3E,MAAM,SAAU,IAAI,KAAe,WAAW,OAAO,IAAI,GAAG;EAC5D,WAAW;GAAE,UAAU;GAAQ,OAAO;EAAiB,GAAG,GAAG,IAAI,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,WAAW,OAAO,mBAAmB,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO;CACzK,CAAC;AACH;;;ACvJA,MAAM,eAAoC;CACxC,OAAO;CACP,YAAY;CACZ,MAAM;CACN,SAAS;CACT,KAAK;CACL,QAAQ;CACR,UAAU;CACV,eAAe;AACjB;;AAGA,SAAS,cAAc,MAAmB,MAA8B,OAAmG;CACzK,OAAO,OAAO,QAAQ,SAAS,UAAU,CAAC,MAAM;EAC9C,MAAM,SAAS,WAAW;EAC1B,MAAM,SAAS,IAAI,YAAY;EAC/B,MAAM,SAAS,IAAI,YAAY;EAC/B,IAAI;EACJ,MAAM,SAAS,IAAI,SAAiB,YAAY;GAC9C,cAAc;EAChB,CAAC;EACD,KAAK,QAAQ,IAAI,QAAQ;GACvB,OAAO,QAAQ,WAAW,WAAW,WAAW,SAAS,OAAA,CAAQ,KAAK,KAAK;GAC3E,OAAO,SAAS;IACd,OAAO,MAAM;IACb,OAAO,MAAM;IACb,YAAY,IAAI;GAClB;EACF,CAAC;EACD,MAAM,eAAqB,KAAK,OAAO,eAAe,EAAE,OAAO,CAAC;EAChE,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,KAAK,KAAK,eAAe;IACvC,QAAQ,MAAM,MAAM;IACpB;IACA;IACA,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;IAC1C,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;GAC5C,GAAG;IAAE,GAAG;IAAM,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;IAAI,SAAS;GAAO,CAAC;EACxF,SACO,KAAK;GACV,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,KAAK,EAAE;GACjC,KAAK,QAAQ,OAAO,MAAM;GAC1B,MAAM;EACR;EACA,QAAQ,QAAQ,iBAAiB,SAAS,QAAQ,EAAE,MAAM,KAAK,CAAC;EAChE,OAAY,WAAW,QAAQ,QAAQ,oBAAoB,SAAS,MAAM,CAAC;EAe3E,OAAO;GAbL,KAAK,QAAQ;GACb;GACA;GACA,MAAM,MAAM,MAAM;IAChB,KAAK,IAAI,KAAK,GAAG,KAAK,KAAK,YAAY,MAAM,4BAC3C,MAAM,KAAK,KAAK,qBAAqB;KAAE;KAAQ,MAAM,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,0BAA0B,CAAC,CAAC,CAAC,SAAS,QAAQ;IAAE,GAAG;KAAE,GAAG;KAAM,MAAM;IAAM,CAAC;GACvK;GACA,MAAM,OAAO;IACX,IAAI,KAAK,QAAQ,IAAI,MAAM,GACzB,MAAM,KAAK,KAAK,eAAe,EAAE,OAAO,GAAG;KAAE,GAAG;KAAM,MAAM;IAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;GAC9F;GACA;EAEU;CACd;AACF;AAEA,SAAgB,qBAAqB,OAA8C;CACjF,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,UAAU,MAAM,cAAc,WAAW;CAC/C,MAAM,OAAO,cAAc,KAAA,IAAY,EAAE,UAAU,IAAI,CAAC;CACxD,MAAM,SAAS,YAA+C;EAAE,IAAI,OAAO;EAAI,KAAK,OAAO;CAAI;;CAE/F,MAAM,yBAAS,IAAI,IAAyE;CAE5F,MAAM,aAAa,QAAgB,UAAkB,WAAgD;EACnG,OAAO,IAAI,QAAQ;GAAE;GAAU,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAG,CAAC;EAC9D,KAAK,MAAM,IAAI,SAAS,SAAS;GAE/B,OADqB,IAAI,MACrB,CAAC,EAAE,SAAS,IAAoB;EACtC,CAAC;CACH;CAEA,SAAS,gBAAgB,YAAoB,SAA2C;EACtF,IAAI;EACJ,MAAM,SAAS,IAAI,SAAiB,YAAY;GAC9C,cAAc;EAChB,CAAC;EACD,MAAM,WAA6B;GAAE,QAAQ,QAAQ;GAAQ,MAAM;GAAa,MAAM;EAAE;EACxF,KAAK,UAAU,IAAI,YAAY,QAAQ;EACvC,MAAM,WAAW,YAAoC,KAAK,QAAQ,YAAY,KAAA,CAAS;EACvF,OAAO;GACL,IAAI;GACJ,eAAe;GACf,QAAO,SAAQ,QAAQ,KAAK,KAAK,kBAAkB;IAAE;IAAY,MAAM,OAAO,KAAK,OAAO,SAAS,WAAW,OAAO,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC,SAAS,QAAQ;GAAE,GAAG;IAAE,GAAG;IAAM,MAAM;GAAM,CAAC,CAAC;GACvL,SAAS,MAAM,SAAS,QAAQ,KAAK,KAAK,mBAAmB;IAAE;IAAY;IAAM;GAAK,GAAG;IAAE,GAAG;IAAM,MAAM;GAAM,CAAC,CAAC;GAClH,MAAM,YAAY;IAChB,KAAK,UAAU,OAAO,UAAU;IAChC,MAAM,KAAK,KAAK,iBAAiB,EAAE,WAAW,GAAG;KAAE,GAAG;KAAM,MAAM;IAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;IAChG,YAAY,EAAE;GAChB;GACA,QAAQ,YAAY;IAClB,KAAK,UAAU,OAAO,UAAU;IAChC,MAAM,KAAK,KAAK,mBAAmB,EAAE,WAAW,GAAG;KAAE,GAAG;KAAM,MAAM;IAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;GACpG;GACA;EACF;CACF;CAEA,OAAO;EACL,MAAM;EAEN,cAAc;GAAE,GAAG;GAAc,QAAQ;GAAS,UAAU,MAAM,cAAc,cAAc;EAAK;EACnG,GAAI,UAAU,EAAE,YAAY,cAAc,MAAM,MAAM,KAAK,EAAE,IAAI,CAAC;EAElE,MAAM,MAAM,QAAQ;GAClB,MAAM,MAAM;IAAE,IAAI,KAAK,WAAW;IAAK,KAAK,QAAQ,OAAO,MAAM;GAAI;GACrE,MAAM,UAAU,MAAM,KAAK,KAAK,cAAc,EAAE,QAAQ,IAAI,GAAG,IAAI;GACnE,OAAO;IAAE,IAAI,QAAQ;IAAI,MAAM;IAAW,KAAK,QAAQ;GAAI;EAC7D;EAEA,MAAM,KAAK,QAAQ,SAAS,UAAU,CAAC,GAAG;GACxC,MAAM,SAAS,WAAW;GAC1B,OAAO,KAAK,KAAK,YAAY;IAC3B,QAAQ,MAAM,MAAM;IACpB;IACA;IACA,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;IAC1C,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;IAC1C,GAAI,QAAQ,YAAY,KAAA,IAAY,EAAE,SAAS,QAAQ,QAAQ,IAAI,CAAC;GACtE,GAAG;IAAE,GAAG;IAAM,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;IAAI,eAAe,KAAK,OAAO,eAAe,EAAE,OAAO,CAAC;GAAE,CAAC;EAC9H;EAEA,MAAM,SAAS,QAAQ,MAAM;GAC3B,QAAQ,MAAM,KAAK,KAAK,WAAW;IAAE,QAAQ,MAAM,MAAM;IAAG;GAAK,GAAG,IAAI,EAAA,CAAG;EAC7E;EAEA,MAAM,eAAe,QAAQ,MAAM;GACjC,OAAO,IAAI,WAAW,OAAO,MAAM,MAAM,KAAK,KAAK,WAAW;IAAE,QAAQ,MAAM,MAAM;IAAG;IAAM,QAAQ;GAAK,GAAG,IAAI,EAAA,CAAG,SAAS,QAAQ,CAAC;EACxI;EAEA,MAAM,SAAS,QAAQ,MAAM;GAC3B,QAAQ,MAAM,KAAK,KAAK,WAAW;IAAE,QAAQ,MAAM,MAAM;IAAG;GAAK,GAAG,IAAI,EAAA,CAAG;EAC7E;EAEA,MAAM,UAAU,QAAQ,MAAM,SAAS,UAAU;GAC/C,MAAM,QAAQ,OAAO,YAAY,WAAW,OAAO,KAAK,SAAS,YAAY,MAAM,IAAI;GACvF,MAAM,KAAK,KAAK,YAAY;IAAE,QAAQ,MAAM,MAAM;IAAG;IAAM,SAAS,MAAM,SAAS,QAAQ;GAAE,GAAG,IAAI;EACtG;EAEA,MAAM,UAAU,QAAQ,MAAM,UAAU,CAAC,GAAG;GAC1C,MAAM,EAAE,QAAQ,SAAS,GAAG,SAAS;GACrC,QAAQ,MAAM,KAAK,KAAK,WAAW;IAAE,QAAQ,MAAM,MAAM;IAAG;IAAM,SAAS;GAAK,GAAG,IAAI,EAAA,CAAG;EAC5F;EAEA,MAAM,eAAe,QAAQ,SAAS,SAA8B;GAElE,MAAM,OAAO,MAAM,KAAK,KAAK,YAAY;IACvC,QAAQ,MAAM,MAAM;IACpB;IACA,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;IAC1C,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;IAC1C,GAAI,QAAQ,iBAAiB,EAAE,gBAAgB,QAAQ,eAAe,IAAI,CAAC;GAC7E,GAAG,IAAI;GACP,UAAU,KAAK,QAAQ,OAAO,IAAI,QAAQ,MAAM;GAChD,OAAO;IAAE,QAAQ,KAAK;IAAQ,KAAK,KAAK;IAAK,YAAY,KAAK;GAAW;EAC3E;EAEA,MAAM,eAAe,QAAQ;GAC3B,QAAQ,MAAM,KAAK,KAAK,WAAW,EAAE,QAAQ,MAAM,MAAM,EAAE,GAAG,IAAI,EAAA,CAAG;EACvE;EAEA,MAAM,eAAe,QAAQ,QAAQ;GACnC,QAAQ,MAAM,KAAK,KAAK,WAAW;IAAE,QAAQ,MAAM,MAAM;IAAG;GAAO,GAAG,IAAI,EAAA,CAAG;EAC/E;EAEA,MAAM,eAAe,QAAQ,QAAQ,UAAU,CAAC,GAAG;GACjD,QAAQ,MAAM,KAAK,KAAK,WAAW;IAAE,QAAQ,MAAM,MAAM;IAAG;IAAQ,GAAI,QAAQ,cAAc,KAAA,IAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;GAAG,GAAG;IAAE,GAAG;IAAM,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;GAAG,CAAC,EAAA,CAAG;EAC3N;EAEA,MAAM,wBAAwB,MAAM,IAAI,WAAW;GACjD,MAAM,WAAY,MAAM,KAAK,KAAK,WAAW,EAAE,QAAQ,MAAM,IAAI,EAAE,GAAG,IAAI,EAAA,CAAG,MAAiC,QAAO,SAAQ,KAAK,WAAW,SAAS;GACtJ,KAAK,MAAM,QAAQ,SACjB,IAAI,KAAK,OAAO,GAAG,MAAM,OAAO,IAAI,KAAK,MAAM,CAAC,EAAE,aAAa,KAAK,IAClE,UAAU,KAAK,QAAQ,GAAG,IAAI,aAAa,OAAO,IAAI,KAAK,MAAM,CAAC,EAAE,MAAM;GAE9E,OAAO;EACT;EAEA,MAAM,aAAa,QAAQ,SAAS;GAClC,MAAM,EAAE,eAAe,MAAM,KAAK,KAAK,iBAAiB;IAAE,QAAQ,MAAM,MAAM;IAAG,MAAM,QAAQ;IAAM,MAAM,QAAQ;IAAM,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;GAAG,GAAG,IAAI;GAC7K,OAAO,gBAAgB,YAAY,OAAO;EAC5C;EAEA,MAAM,kBAAkB,SAAS,YAAY,SAAS;GACpD,MAAM,EAAE,UAAU,YAAY,MAAM,KAAK,KAAK,mBAAmB,EAAE,WAAW,GAAG,IAAI;GACrF,IAAI,CAAC,UACH,OAAO;GACT,MAAM,UAAU,gBAAgB,YAAY,OAAO;GACnD,MAAM,QAAQ,OAAO,KAAK,SAAS,QAAQ;GAC3C,IAAI,MAAM,aAAa,GAAG;IACxB,KAAK,UAAU,IAAI,UAAU,CAAC,CAAE,QAAQ,MAAM;IAC9C,QAAQ,OAAO,KAAK;GACtB;GACA,OAAO;EACT;EAEA,MAAM,QAAQ,QAAQ;GAEpB,MAAM,KAAK,KAAK,gBAAgB,EAAE,QAAQ,MAAM,MAAM,EAAE,GAAG;IAAE,GAAG;IAAM,MAAM;GAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAC5G;CACF;AACF;;;;;ACvOA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,cAAc;EACZ,MAAM,gCAAgC;EACtC,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,MAAc;EACxB,MAAM,gBAAgB,KAAK,kFAAkF;EAC7G,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,0BAAb,cAA6C,MAAM;CACjD,YAAY,MAAc,SAAkB;EAC1C,MAAM,YAAY,KAAA,IACd,GAAG,KAAK,4CACR,GAAG,KAAK,kDAAkD,QAAQ,MAAM;EAC5E,KAAK,OAAO;CACd;AACF;;AAGA,IAAa,uBAAb,cAA0C,MAAM;CACzB;CAArB,YAAY,MAAuB,SAAiB;EAClD,MAAM,OAAO;EADM,KAAA,OAAA;EAEnB,KAAK,OAAO;CACd;AACF;AAEA,MAAa,iBAAiB;AAE9B,SAAgB,YAAY,QAAgB,MAAoC;CAC9E,OAAO,IAAI,qBAAqB,iBAAiB,aAAa,oBAAoB,OAAO,4CAA4C,KAAK,0BAA0B;AACtK;;;ACrBA,SAAgB,qBAAqB,OAAoH;CACvJ,MAAM,EAAE,cAAc,cAAc;CAEpC,MAAM,aAAa,MAAc,QAA4C;EAC3E,MAAM,SAAS,iBAAiB,IAAI;EACpC,MAAM,WAAW,SAAS,aAAa,IAAI,IAAI,IAAI,KAAA;EACnD,IAAI,CAAC,UAAU,CAAC,UAAU,aACxB,OAAO,KAAA;EACT,OAAO;GAAE,KAAK,SAAS,YAAY,GAAG;GAAG,SAAS;IAAE,MAAM,OAAO;IAAM,MAAM,SAAS,OAAO;GAAO;EAAE;CACxG;CAEA,QAAQ,KAAK,SAAS;EAEpB,MAAM,QAAQ,OAAO,UAAU,MAAM,GAAG,IAAI,KAAA;EAC5C,IAAI,OACF,OAAO;EACT,IAAI;GACF,OAAO,EAAE,KAAK,UAAU,YAAY,GAAG,EAAE;EAC3C,SACO,KAAK;GAEV,KAAK,MAAM,YAAY,aAAa,KAAK,GAAG;IAC1C,IAAI,CAAC,SAAS,UAAU,KAAK,iBAAiB,SAAS,IAAI,CAAC,EAAE,SAAS,SACrE;IACF,IAAI;KACF,MAAM,QAAQ,UAAU,SAAS,MAAM,GAAG;KAC1C,IAAI,OACF,OAAO;IACX,QACM,CAEN;GACF;GACA,MAAM;EACR;CACF;AACF;;;;;;;;;AC3CA,IAAa,WAAb,cAA8B,MAAM;CAClC;CACA;CACA,YAAY,MAAyB,QAAgB,MAAmC;EACtF,MAAM,OAAO,KAAK,KAAK,OAAO,KAAK,KAAK,GAAG,EAAE,SAAS,SAAS,KAAA,IAAY,KAAK,KAAK,KAAK,IAAI;EAC9F,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,KAAK,OAAO;CACd;AACF;AAEA,SAAgB,IAAI,KAAa,MAAyB,UAAwD,CAAC,GAAuB;CACxI,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,SAAS,OAAO,MAAM;GACpB;GACA,SAAS,QAAQ,aAAa;GAC9B,WAAW;GACX,UAAU;GACV,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;GAEnD,KAAK;IAAE,GAAG,QAAQ;IAAK,qBAAqB;IAAK,YAAY;GAAO;EACtE,IAAI,KAAK,QAAQ,WAAW;GAC1B,IAAI,KACF,OAAO,IAAI,SAAS,MAAM,UAAU,IAAI,SAAU,IAAmC,IAAI,CAAC;QAE1F,QAAQ;IAAE;IAAQ;GAAO,CAAC;EAC9B,CAAC;CACH,CAAC;AACH;;AAGA,eAAsB,YAAY,KAAa,MAAyB,UAAoC,CAAC,GAAqB;CAChI,IAAI;EACF,MAAM,IAAI,KAAK,MAAM,OAAO;EAC5B,OAAO;CACT,QACM;EACJ,OAAO;CACT;AACF;AAEA,IAAI;;AAEJ,SAAgB,iBAAmC;CACjD,iBAAiB,YAAY,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC;CACzD,OAAO;AACT;;;;;;;;AC5BA,SAAgB,eAAe,KAAoC;CACjE,MAAM,UAAU,IAAI,KAAK;CACzB,IAAI;CACJ,IAAI;CACJ,MAAM,MAAM,iCAAiC,KAAK,OAAO;CACzD,IAAI,KAAK;EACP,OAAO,IAAI;EACX,OAAO,IAAI;CACb,OAEE,IAAI;EACF,MAAM,SAAS,IAAI,IAAI,OAAO;EAC9B,IAAI,CAAC;GAAC;GAAU;GAAS;GAAQ;EAAM,CAAC,CAAC,SAAS,OAAO,QAAQ,GAC/D,OAAO,KAAA;EACT,OAAO,OAAO;EACd,OAAO,OAAO;CAChB,QACM;EACJ;CACF;CAEF,MAAM,YAAY,QAAQ,GAAA,CAAI,QAAQ,cAAc,EAAE,CAAC,CAAC,QAAQ,UAAU,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;CACvG,IAAI,CAAC,QAAQ,SAAS,SAAS,GAC7B,OAAO,KAAA;CACT,MAAM,OAAO,SAAS,GAAG,EAAE;CAC3B,MAAM,QAAQ,SAAS,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,GAAG;CAC5C,OAAO;EAAE;EAAM;EAAO;EAAM,UAAU,WAAW,KAAK,GAAG,MAAM,GAAG,KAAK;CAAM;AAC/E;;AAGA,eAAsB,cAAc,KAAiC;CACnE,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,IAAI,KAAK;GAAC;GAAU;GAAW;EAAQ,CAAC,EAAA,CAAG,OAAO,KAAK;CACtE,QACM;EACJ,MAAM,IAAI,MAAM,wDAAsD;CACxE;CACA,MAAM,SAAS,eAAe,GAAG;CACjC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,gBAAgB,IAAI,iDAAiD;CACvF,OAAO;AACT;AAEA,SAAgB,SAAS,QAA0C;CACjE,OAAO,OAAO,SAAS;AACzB;;;;;;AAOA,eAAsB,gBAAgB,QAA2B,QAAiC,MAA0C,QAAQ,KAAkC;CACpL,MAAM,aAAa,OAAO,OAAO,aAAa,WAAW,OAAO,SAAS,KAAK,IAAI;CAClF,IAAI,YACF,OAAO;CACT,IAAI,SAAS,MAAM,GAAG;EACpB,MAAM,UAAU,IAAI,UAAU,KAAK,KAAK,IAAI,cAAc,KAAK;EAC/D,IAAI,SACF,OAAO;CACX;CACA,OAAO,YAAY,OAAO,IAAI;AAChC;AAEA,SAAS,YAAY,MAA2C;CAC9D,OAAO,IAAI,SAAS,YAAY;EAC9B,SAAS,MAAM;GAAC;GAAQ;GAAS;GAAc;EAAI,GAAG;GAAE,SAAS;GAAM,UAAU;EAAO,IAAI,KAAK,WAAW;GAC1G,QAAQ,MAAM,KAAA,IAAY,OAAO,KAAK,KAAK,KAAA,CAAS;EACtD,CAAC;CACH,CAAC;AACH;;;;;;AAcA,eAAsB,kBAAkB,KAAa,UAAoC,CAAC,GAAwB;CAChH,MAAM,WAAW,MAAM,IAAI,KAAK;EAAC;EAAa;EAAgB;CAAM,GAAG,OAAO,CAAC,CAAC,aAAa,EAAE,QAAQ,GAAG,EAAE,EAAA,CAAG,OAAO,KAAK;CAC3H,IAAI,WAAW,YAAY,UAAU,MAAM,YAAY,KAAK;EAAC;EAAa;EAAe;EAAW;EAAU;CAAO,GAAG,OAAO,GAAG;EAChI,MAAM,QAAQ,MAAM,IAAI,KAAK;GAAC;GAAY;GAAW,UAAU,QAAQ;EAAO,GAAG,OAAO,CAAC,CAAC,aAAa,EAAE,QAAQ,IAAI,EAAE;EACvH,OAAO;GAAE,MAAM;GAAS,UAAU,OAAO,SAAS,MAAM,OAAO,KAAK,GAAG,EAAE,KAAK;EAAE;CAClF;CACA,IAAI;EACF,MAAM,EAAE,WAAW,MAAM,IAAI,KAAK;GAAC;GAAa;GAAY;GAAU;EAAM,GAAG;GAAE,GAAG;GAAS,WAAW;EAAO,CAAC;EAChH,MAAM,QAAQ,mCAAmC,KAAK,MAAM;EAC5D,IAAI,OACF,OAAO;GAAE,MAAM,MAAM;GAAK,UAAU;EAAE;CAC1C,SACO,KAAK;EACV,MAAM,IAAI,MAAM,uCAAuC,eAAe,WAAW,IAAI,UAAU,OAAO,GAAG,GAAG;CAC9G;CACA,OAAO;EAAE,MAAM;EAAQ,UAAU;CAAE;AACrC;;AAGA,eAAsB,gBAAgB,KAAyD;CAC7F,MAAM,OAAO,OAAO,SAAiB,MAAM,IAAI,KAAK;EAAC;EAAU;EAAS;CAAG,CAAC,CAAC,CAAC,aAAa,EAAE,QAAQ,GAAG,EAAE,EAAA,CAAG,OAAO,KAAK,KAAK,KAAA;CAC9H,MAAM,CAAC,MAAM,SAAS,MAAM,QAAQ,IAAI,CAAC,KAAK,WAAW,GAAG,KAAK,YAAY,CAAC,CAAC;CAC/E,OAAO;EAAE,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;EAAI,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;CAAG;AAClE;;AAGA,SAAgB,WAAW,OAAuB;CAChD,OAAO,IAAI,MAAM,QAAQ,MAAM,OAAO,EAAE;AAC1C;;AAGA,MAAa,gBAAgB;;AAG7B,SAAS,gBAAgB,MAAwB;CAC/C,OAAO;EACL,aAAa,cAAc;EAC3B;EACA;EACA,gDAAgD,cAAc,IAAI,WAAW,IAAI,EAAE;EACnF;CACF;AACF;;;;;;AAOA,SAAgB,YAAY,OAA8H;CACxJ,MAAM,EAAE,QAAQ,KAAK,QAAQ,MAAM,aAAa;CAChD,MAAM,IAAI,WAAW,GAAG;CACxB,MAAM,IAAI,WAAW,MAAM;CAC3B,OAAO;EACL;EACA;EACA;EACA,GAAG,gBAAgB,OAAO,IAAI;EAC9B,GAAI,SAAS,OAAO,CAAC,iCAAiC,WAAW,SAAS,IAAI,GAAG,IAAI,CAAC;EACtF,GAAI,SAAS,QAAQ,CAAC,kCAAkC,WAAW,SAAS,KAAK,GAAG,IAAI,CAAC;EACzF,WAAW,EAAE,mBAAmB,EAAE,uDAAuD,WAAW,OAAO,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE;EACrI,qCAAqC,WAAW,cAAc,QAAQ,EAAE,yCAAyC,EAAE;EACnH,iDAAiD,EAAE,iDAAiD,EAAE,WAAW,WAAW,UAAU,QAAQ,EAAE;EAChJ,gCAAgC,EAAE,GAAG,WAAW,UAAU,MAAM,EAAE;CACpE,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAgB,WAAW,OAAsD;CAC/E,OAAO;EACL;EACA;EACA,GAAG,gBAAgB,MAAM,OAAO,IAAI;EACpC,8BAA8B,WAAW,mBAAmB,MAAM,QAAQ;CAC5E,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAS,UAAU,MAAsB;CACvC,OAAO,SAAS,eAAe,2BAA2B,WAAW,KAAK;AAC5E;;;;;AAMA,eAAsB,gBAAgB,OAQS;CAC7C,MAAM,EAAE,QAAQ,OAAO,MAAM,SAAS;CACtC,MAAM,UAAU,MAAM,aAAa;CACnC,MAAM,MAAM,GAAG,UAAU,OAAO,IAAI,EAAE,SAAS,OAAO,MAAM,GAAG,OAAO,KAAK;CAC3E,MAAM,UAAU;EACd,UAAU;EACV,iBAAiB,UAAU;EAC3B,wBAAwB;EACxB,gBAAgB;CAClB;CACA,MAAM,WAAW,MAAM,QAAQ,KAAK;EAAE,QAAQ;EAAQ;EAAS,MAAM,KAAK,UAAU;GAAE,OAAO,MAAM;GAAO,MAAM,MAAM;GAAM;GAAM;EAAK,CAAC;CAAE,CAAC;CAC3I,IAAI,SAAS,IACX,OAAO;EAAE,MAAO,MAAM,SAAS,KAAK,EAAA,CAA4B;EAAU,SAAS;CAAK;CAC1F,MAAM,UAAU,MAAM,SAAS,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE;CACtD,IAAI,SAAS,WAAW,KAAK;EAC3B,MAAM,QAAQ,OAAO,MAAM,MAAM,GAAG,CAAC,CAAC;EACtC,MAAM,WAAW,MAAM,QAAQ,GAAG,IAAI,mBAAmB,mBAAmB,GAAG,MAAM,GAAG,MAAM,KAAK,EAAE,QAAQ,CAAC;EAC9G,IAAI,SAAS,IAAI;GACf,MAAM,CAAC,QAAQ,MAAM,SAAS,KAAK;GACnC,IAAI,MACF,OAAO;IAAE,KAAK,KAAK;IAAU,SAAS;GAAM;EAChD;CACF;CACA,MAAM,SAAS,QAAQ,QAAQ,KAAI,UAAS,MAAM,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,IAAI;CACpF,MAAM,IAAI,MAAM,oCAAoC,SAAS,OAAO,KAAK,QAAQ,WAAW,kBAAkB,SAAS,KAAK,WAAW,IAAI;AAC7I;;;AChKA,SAAgB,qBAAqB,aAA+D;CAClG,MAAM,MAAM,YAAY;CACxB,MAAM,SAAS,KAAK;CACpB,OAAO,OAAO,KAAK,cAAc,YAAY,UAAU,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,UAAU,YAC7G,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,aAAa,WAC/D;EAAE,WAAW,IAAI;EAAmB;CAAoB,IACxD,KAAA;AACN;AAEA,MAAM,wBAAwB;AAC9B,MAAMC,0BAAwB;AAC9B,MAAM,uBAAuB;AAC7B,MAAM,cAAc;;AAGpB,MAAa,uBAA0D;CACrE;EACE,KAAK;EACL,MAAM;EACN,OAAO;EAGP,aAAa;EACb,aAAa;CACf;CACA;EAAE,KAAK;EAAgB,MAAM;EAAU,OAAO;EAAiB,aAAa;EAAwC,SAAS;EAAW,aAAa;CAAU;CAC/J;EAAE,KAAK;EAAgB,MAAM;EAAU,OAAO;EAAiB,aAAa;EAA4E,aAAa;EAAU,SAAS;CAAG;CAC3L;EAAE,KAAK;EAAe,MAAM;EAAU,OAAO;EAA8B,aAAa;EAA2G,SAAS;CAAG;AACjN;AAEA,SAAS,KAAK,MAAsB;CAClC,MAAM,UAAU,KAAK,KAAK;CAC1B,OAAO,QAAQ,SAAS,cAAc,IAAI,QAAQ,MAAM,IAAY,MAAM;AAC5E;AAEA,SAAS,aAAa,QAA2B,KAAa,UAA0B;CACtF,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAgB,uCAAuC,QAAkD;CACvG,MAAM,aAAgC;EACpC,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAW,gBAAe,QAAQ,YAAY,UAAU,qBAAqB,WAAW,CAAC;EACzF,MAAM,IAAI,EAAE,aAAa,QAAQ,QAAQ;GACvC,MAAM,MAAM,qBAAqB,WAAW;GAC5C,MAAM,QAAQ,MAAM,gBAAgB,QAAQ,IAAI,MAAM;GACtD,MAAM,SAAS,MAAM,KAAK,WAAW;IAAE,QAAQ,IAAI;IAAQ,QAAQ,YAAY;GAAQ,CAAC,GAAG;IAAE,KAAK,SAAS,KAAK;IAAG,gBAAgB;GAAqB,CAAC;GACzJ,IAAI,OAAO,aAAa,GACtB,MAAM,IAAI,MAAM,oBAAoB,KAAK,OAAO,UAAU,OAAO,MAAM,KAAK,QAAQ,OAAO,aAAa,QAAQ,KAAK,8BAA8B;GACrJ,OAAO,EAAE,SAAS,UAAU,YAAY,OAAO,MAAM,IAAI,OAAO,MAAM,GAAG,IAAI,OAAO,KAAK,GAAG;EAC9F;CACF;CAEA,MAAM,oBAAuC;EAC3C,IAAI;EACJ,OAAO;EACP,aAAa;EACb,YAAY,gBAAgB;GAC1B,MAAM,MAAM,qBAAqB,WAAW;GAC5C,OAAO,QAAQ,YAAY,UAAU,YAAY,QAAQ,OAAO,SAAS,IAAI,MAAM,CAAC;EACtF;EACA,MAAM,IAAI,OAAO;GACf,MAAM,EAAE,aAAa,QAAQ,SAAS;GACtC,MAAM,MAAM,qBAAqB,WAAW;GAC5C,MAAM,QAAQ,MAAM,gBAAgB,QAAQ,IAAI,MAAM;GACtD,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,kFAAkF;GACpG,MAAM,WAAW,IAAI,KAAK;GAE1B,MAAM,MAAM,MAAM,KAAK,uBAAuB,WAAW,UAAU,YAAY,KAAK,OAAO,KAAK,EAAE,gBAAgB,GAAG,CAAC;GACtH,MAAM,WAAW,IAAI,aAAa,IAAI,IAAI,OAAO,MAAM,IAAI,CAAC,CAAC,KAAI,SAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO,IAAI,CAAC;GACzG,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,GAAG,YAAY,OAAO,4BAA4B,YAAY,KAAK,MAAM;GAC3F,MAAM,QAAQ,SAAS,GAAG,EAAE;GAC5B,MAAM,OAAO,SAAS,SAAS,IAAI,SAAS,QAAQ,CAAC,CAAC,KAAI,YAAW,KAAK,SAAS,CAAC,CAAC,KAAK,IAAI,IAAI;GAClG,MAAM,OAAO,MAAM,gBAAgB;IAAE,QAAQ,IAAI;IAAQ;IAAO,MAAM,YAAY;IAAS,MAAM,YAAY;IAAO;IAAO;GAAK,CAAC;GACjI,OAAO;IAAE,SAAS,KAAK,UAAU,6BAA6B,YAAY,OAAO,KAAK,sBAAsB,YAAY,OAAO;IAAoB,KAAK,KAAK;GAAI;EACnK;CACF;CAEA,OAAO;EACL,MAAM,OAAO;EACb,OAAO,OAAO;EACd,aAAa,OAAO;EACpB,cAAc;EACd,cAAc,CAAC,GAAG,OAAO,QAAQ,GAAG,oBAAoB;EACxD,aAAa;EACb,gBAAe,WAAU,cAAc,MAAM;EAC7C,qBAAoB,WAAU,aAAa,QAAQ,eAAe,EAAE;EACpE,SAAS,CAAC,YAAY,iBAAiB;EAEvC,MAAM,UAAU,EAAE,KAAK,UAAU;GAC/B,MAAM,SAAS,MAAM,OAAO,kBAAkB,MAAM;GACpD,IAAI,QACF,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAO;GACrC,IAAI,CAAC,KACH,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAyC;GACvE,IAAI,CAAC,MAAM,eAAe,GACxB,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAwB;GACtD,MAAM,OAAOC,cAAY,GAAG;GAC5B,IAAI,CAAC,MACH,OAAO;IAAE,IAAI;IAAO,QAAQ;GAA6C;GAC3E,IAAI;IACF,MAAM,cAAc,IAAI;GAC1B,SACO,KAAK;IACV,OAAO;KAAE,IAAI;KAAO,QAAS,IAAc;IAAQ;GACrD;GACA,OAAO,EAAE,IAAI,KAAK;EACpB;EAEA,SAAS,EAAE,aAAa,OAAO,OAAO,MAAM;EAG5C,MAAM,KAAK,EAAE,OAAO;GAClB,MAAM,OAAOA,cAAY,GAAG;GAC5B,IAAI,CAAC,MACH,OAAO,KAAA;GACT,MAAM,SAAS,MAAM,cAAc,IAAI;GACvC,MAAM,UAAU,MAAM,IAAI,MAAM;IAAC;IAAa;IAAgB;GAAM,CAAC,CAAC,CAAC,aAAa,EAAE,QAAQ,GAAG,EAAE,EAAA,CAAG,OAAO,KAAK;GAClH,MAAM,QAAQ,OAAO,UAAU,MAAM,IAAI,MAAM;IAAC;IAAY;IAAW;GAAmB,CAAC,CAAC,CAAC,aAAa,EAAE,QAAQ,IAAI,EAAE,EAAA,CAAG,OAAO,KAAK,GAAG,EAAE,KAAK;GACnJ,MAAM,OAAO,UAAU,WAAW,SAAS,mBAAmB,WAAW;GACzE,MAAM,UAAU,QAAQ,IAAI,IAAI,MAAM,eAAe,UAAU,IAAI,WAAY,WAAY,kCAAkC;GAC7H,OAAO,UAAU,OAAO,MAAM,GAAG,OAAO,KAAK,cAAc,KAAK,GAAG;EACrE;EAEA,MAAM,QAAQ,EAAE,KAAK,aAAa,QAAQ,UAA6C;GACrF,MAAM,OAAOA,cAAY,GAAG,KAAK;GACjC,MAAM,SAAS,MAAM,cAAc,IAAI;GACvC,MAAM,OAAO,YAAY,OAAO;IAAE,MAAM,YAAY;IAAM,UAAU;GAAE,IAAI,MAAM,kBAAkB,MAAM,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC;GAChI,MAAM,SAAS,YAAY,QAAQ,KAAK,KAAK,cAAc,MAAM;GAEjE,IAAI,OAAO,WAAW,GAAG,KAAK,CAAC,MAAM,YAAY,MAAM;IAAC;IAAoB;IAAY;GAAM,GAAG,SAAS,EAAE,OAAO,IAAI,CAAC,CAAC,GACvH,MAAM,IAAI,MAAM,IAAI,OAAO,8BAA8B;GAC3D,MAAM,CAAC,OAAO,YAAY,MAAM,QAAQ,IAAI,CAAC,gBAAgB,QAAQ,MAAM,GAAG,gBAAgB,IAAI,CAAC,CAAC;GAEpG,MAAM,UAAU,qBAAqB,OAAO,SAAS,QAAQ,CAAC,CAAC,CAAC;GAChE,IAAI;GACJ,MAAM,UAAU,YAAY;IAC1B,IAAI,QACF,MAAM,OAAO,OAAO,QAAQ,OAAO,EAAE,CAAC,CAAC,YAAY,KAAA,CAAS;GAChE;GACA,IAAI;IACF,SAAS,MAAM,QAAQ,MAAM,OAAO,cAAc,MAAM,KAAK,CAAC,CAAC;IAC/D,QAAQ,eAAe;IACvB,MAAM,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI;IAC9C,MAAM,QAAQ,MAAM,QAAQ,KAAK,QAAQ,YAAY;KAAE;KAAQ;KAAK;KAAQ,MAAM,KAAK;KAAM;IAAS,CAAC,GAAG;KAAE,KAAK,SAAS,KAAK;KAAG,SAAS;IAAsB,CAAC;IAClK,IAAI,MAAM,aAAa,GACrB,MAAM,IAAI,MAAM,WAAW,OAAO,MAAM,GAAG,OAAO,KAAK,WAAW,KAAK,MAAM,UAAU,MAAM,MAAM,KAAK,QAAQ,MAAM,aAAa,QAAQ,KAAK,mDAAmD;IACrM,QAAQ,eAAe;IACvB,MAAM,QAAQ,OAAO,OAAO,iBAAiB,WAAW,OAAO,aAAa,KAAK,IAAI;IACrF,IAAI,OAAO;KACT,MAAM,SAAS,MAAM,QAAQ,KAAK,QAAQ,OAAO;MAAE,KAAK;MAAK,SAASD;KAAsB,CAAC;KAC7F,IAAI,OAAO,aAAa,GACtB,MAAM,IAAI,MAAM,8BAA8B,OAAO,SAAS,KAAK,KAAK,OAAO,UAAU,OAAO,MAAM,GAAG;IAC7G;IACA,QAAQ,eAAe;IAEvB,OAAO,EAAE,aAAa;KAAE,KAAK;MADG,WAAW,OAAO;MAAI;KACvB;KAAwD,SAAS;KAAK;KAAQ,MAAM,KAAK;IAAK,EAAE;GACjI,SACO,KAAK;IACV,MAAM,QAAQ;IACd,MAAM;GACR,UACQ;IAGN,IAAI,QACF,MAAM,QAAQ,QAAQ,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;GACvD;EACF;EAEA,UAAU,EAAE,aAAa,UAAU;GACjC,MAAM,MAAM,qBAAqB,WAAW;GAC5C,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,QAAQ,OAAO,MAAM,6DAA6D;GACpG,MAAM,MAAM,YAAY;GACxB,OAAO;IACL,KAAK,KAAK,UAAU;KAAE,WAAW,IAAI;KAAW,KAAK,OAAO;KAAM,QAAQ,OAAO,OAAO,KAAI,UAAS,MAAM,SAAS,WAAW,MAAM,MAAM,GAAG,MAAM,IAAI,GAAG,OAAO,OAAO,MAAM,QAAQ,EAAE,GAAG;IAAE,CAAC;IAE/L,cAAgC,qBAAqB,OAAO,SAAS,QAAQ;KAAE,WAAW,IAAI;KAAW,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;IAAG,CAAC,CAAC;IACnI,GAAI,MAAM,EAAE,WAAW,IAAI,IAAI,CAAC;GAClC;EACF;EAEA,MAAM,QAAQ,aAAa,EAAE,UAAU;GACrC,MAAM,MAAM,qBAAqB,WAAW;GAC5C,IAAI,KACF,MAAM,OAAO,MAAM,QAAQ,IAAI,SAAS;EAC5C;EAEA,MAAM,SAAS,aAAa,EAAE,UAAU;GACtC,MAAM,MAAM,qBAAqB,WAAW;GAC5C,IAAI,CAAC,KACH,OAAO,EAAE,SAAS,KAAK;GACzB,IAAI;IACF,MAAM,OAAO,OAAO,QAAQ,IAAI,SAAS;IACzC,OAAO,EAAE,SAAS,KAAK;GACzB,SACO,KAAK;IACV,OAAO;KAAE,SAAS;KAAO,QAAQ,mBAAmB,OAAO,MAAM,WAAW,IAAI,UAAU,IAAK,IAAc;IAAU;GACzH;EACF;CACF;AACF;AAEA,SAAS,cAAc,QAAmC;CACxD,OAAO,GAAG,OAAO,OAAO,iBAAiB,YAAY,OAAO,eAAe,OAAO,eAAe,YAAY,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK;AAC5I;;AAGA,SAAS,SAAS,OAAmD;CACnE,OAAO,QAAQ,GAAG,gBAAgB,MAAM,IAAI,CAAC;AAC/C;;;ACnRA,MAAa,2BAA2B;AAExC,MAAME,aAAW,eAAe,qBAAqB;AACrD,MAAMC,WAAS,aAAa,EAAE,OAAM,WAAUD,WAAS,OAAO,SAAS,OAAO,KAAK,EAAE,CAAC;AAgBtF,SAASE,OAAK,QAA2B,KAAiC;CACxE,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,KAAA;AACpE;AAEA,SAAS,SAAS,QAA2B,KAAiC;CAC5E,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,UAAU,YAAY,QAAQ,IAAI,QAAQ,KAAA;AAC1D;AAEA,SAAS,cAAc,QAAkF;CACvG,MAAM,SAASA,OAAK,QAAQ,QAAQ;CACpC,MAAM,SAASA,OAAK,QAAQ,QAAQ;CACpC,MAAM,SAASA,OAAK,QAAQ,QAAQ;CACpC,OAAO;EAAE,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAI,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAI,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAAG;AACvG;AAEA,eAAe,WAAW,QAAuD;CAC/E,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,OAAO,gBAAA,CAAwD;CAClF,QACM;EACJ,MAAM,IAAI,MAAM,kFAAkF;CACpG;CACA,OAAO,IAAI,QAAQ,cAAc,MAAM,CAAC;AAC1C;AAEA,MAAa,gBAAqC;CAChD,MAAM;CACN,OAAO;CACP,aAAa;CACb,QAAQ;EACN;GAAE,KAAK;GAAU,MAAM;GAAU,OAAO;GAAW,aAAa;GAA+B,KAAK;GAAmB,aAAa;EAAQ;EAC5I;GAAE,KAAK;GAAU,MAAM;GAAU,OAAO;GAAW,aAAa;GAA6C,KAAK;GAAmB,aAAa;GAA8B,SAAS;EAAG;EAC5L;GAAE,KAAK;GAAU,MAAM;GAAU,OAAO;GAAU,aAAa;GAAoD,KAAK;GAAkB,aAAa;GAAM,SAAS;EAAG;EACzK;GAAE,KAAK;GAAY,MAAM;GAAU,OAAO;GAAY,aAAa;GAA8E,SAAS;EAAG;EAC7J;GAAE,KAAK;GAAO,MAAM;GAAU,OAAO;GAAQ,aAAa;EAAgC;EAC1F;GAAE,KAAK;GAAU,MAAM;GAAU,OAAO;GAAgB,aAAa;EAAgC;CACvG;CAEA,MAAM,kBAAkB,QAAQ;EAC9B,IAAI;GACF,MAAM,OAAO;EACf,QACM;GACJ,OAAO;EACT;EACA,OAAOA,OAAK,QAAQ,QAAQ,IAAI,KAAA,IAAY;CAC9C;CAEA,SAAS,QAAQ,EAAE,WAAW,OAAO;EACnC,MAAM,WAAWA,OAAK,QAAQ,UAAU;EACxC,MAAM,MAAM,SAAS,QAAQ,KAAK;EAClC,MAAM,SAAS,SAAS,QAAQ,QAAQ;EACxC,OAAO,sBAAsB;GAC3B,GAAG,cAAc,MAAM;GACvB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;GAC/B,GAAI,OAAO,SAAS,EAAE,WAAW;IAAE,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;IAAI,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAAG,EAAE,IAAI,CAAC;GACjG,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;GACjC,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;GACrB,WAAW;GACX,QAAA;EACF,CAAC;CACH;CAEA,YAAY,QAAQ;EAClB,MAAM,OAAO,OAAO,OAAO,gBAAgB,YAAY,OAAO,cAAc,IAAI,OAAO,cAAc;EACrG,OAAO,EAAE,SAAS;GAAE,UAAU;GAAW,kBAAkB,KAAK,IAAI,IAAI,OAAO,CAAC;EAAE,EAAE;CACtF;CAEA,MAAM,MAAM,QAAQ,WAAW;EAE7B,OAAM,OADiB,MAAM,WAAW,MAAM,EAAA,CAAG,IAAI,SAAS,EAAA,CAChD,OAAO;CACvB;CAEA,MAAM,OAAO,QAAQ,WAAW;EAE9B,OAAM,OADiB,MAAM,WAAW,MAAM,EAAA,CAAG,IAAI,SAAS,EAAA,CAChD,OAAO;CACvB;CAEA,MAAM,OAAO,QAAQ;EACnB,IAAI,CAACA,OAAK,QAAQ,QAAQ,GACxB,OAAO;GAAE,IAAI;GAAO,QAAQ;EAAyB;EAEvD,MAAM,SAAS,OAAM,MADA,WAAW,MAAM,EAAA,CACV,KAAK;EACjC,IAAI,QAAQ;EACZ,IAAI,UAAU,OAAQ,OAAkC,OAAO,mBAAmB,YACrE;cAAA,MAAM,KAAK,QACpB,IAAI,EAAE,SAAS,KACb;EAAA,OAGD,IAAI,MAAM,QAAS,QAAkC,KAAK,GAC7D,QAAS,OAAgC,MAAM;EAGjD,OAAO;GAAE,IAAI;GAAM,QAAQ,gBADbA,OAAK,QAAQ,QAAQ,KAAK,iBACS,IAAI,MAAM,UAAU,UAAU,IAAI,KAAK,KAAK;EAAwB;CACvH;AACF;AAEA,SAAgB,mCAAwD;CACtE,OAAO,uCAAuC,aAAa;AAC7D;;;AClHA,MAAa,4BAA4B;AAUzC,MAAM,mBAAmB;AAGzB,SAAS,gBAAgB,aAA0D;CACjF,MAAM,MAAM,YAAY;CACxB,OAAO,OAAO,OAAO,IAAI,SAAS,YAAY,OAAO,IAAI,aAAa,WAAW;EAAE,MAAM,IAAI;EAAM,UAAU,IAAI;CAAS,IAAI,KAAA;AAChI;;AAGA,SAAS,WAAW,QAAwB;CAC1C,OAAO,OAAO,QAAQ,aAAa,GAAG,CAAC,CAAC,QAAQ,YAAY,EAAE,KAAK;AACrE;AAEA,SAAS,MAAM,OAAuB;CACpC,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;AACpE;;AAGA,SAAgB,aAAa,OAAyF;CACpH,MAAM,OAAO,WAAW,MAAM,MAAM;CACpC,MAAM,OAAO,SAAS,MAAM,QAAQ;CACpC,QAAQ,MAAM,UAAd;EACE,KAAK,WACH,OAAO,KAAK,QAAQ,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,MAAM;EACzD,KAAK,WACH,OAAO,KAAK,MAAM,UAAU,WAAW,aAAa,IAAI;EAC1D,SAEE,OAAO,KAAK,MAAM,SAAS,aAAa,GAAG,KAAK,GAAG,MAAM,MAAM,QAAQ,KAAK,IAAI;CACpF;AACF;;AAGA,eAAe,cAAc,UAAkB,QAAuC;CACpF,IAAI;EACF,MAAM,EAAE,WAAW,MAAM,IAAI,UAAU;GAAC;GAAgB;GAAW;EAA0B,GAAG,EAAE,OAAO,CAAC;EAC1G,IAAI,OAAO,KAAK,GACd,OAAO,OAAO,KAAK;CACvB,QACM,CAAC;CACP,KAAK,MAAM,aAAa,CAAC,QAAQ,QAAQ,GACvC,IAAI,MAAM,YAAY,UAAU;EAAC;EAAY;EAAY;EAAW,cAAc;CAAW,GAAG,EAAE,OAAO,CAAC,GACxG,OAAO;CAEX,OAAO;AACT;;AAGA,SAAS,uBAAuB,UAAwB;CACtD,MAAM,UAAU,KAAK,UAAU,QAAQ,QAAQ,SAAS;CACxD,MAAM,OAAO;CACb,IAAI;EACF,MAAM,UAAU,WAAW,OAAO,IAAI,aAAa,SAAS,MAAM,IAAI;EACtE,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC,SAAS,IAAI,GACnC;EACF,UAAU,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;EAC/C,eAAe,SAAS,GAAG,WAAW,CAAC,QAAQ,SAAS,IAAI,IAAI,OAAO,KAAK,KAAK,GAAG;CACtF,QACM,CAAC;AACT;;AAGA,eAAe,iBAAiB,UAAkB,MAAc,QAAgE;CAC9H,MAAM,EAAE,WAAW,MAAM,IAAI,UAAU;EAAC;EAAY;EAAQ;CAAa,GAAG,EAAE,OAAO,CAAC;CACtF,MAAM,SAAS,QAAQ,IAAI;CAC3B,KAAK,MAAM,SAAS,OAAO,MAAM,MAAM,GAAG;EACxC,MAAM,QAAQ,MAAM,MAAM,IAAI;EAC9B,MAAM,WAAW,MAAM,MAAK,MAAK,EAAE,WAAW,WAAW,CAAC,CAAC,EAAE,MAAM,CAAkB;EACrF,IAAI,CAAC,YAAY,QAAQ,QAAQ,MAAM,QACrC;EACF,MAAM,SAAS,MAAM,MAAK,MAAK,EAAE,WAAW,SAAS,CAAC,CAAC,EAAE,MAAM,EAA2B;EAC1F,OAAO,SAAS,EAAE,OAAO,IAAI,CAAC;CAChC;AAEF;AAEA,SAAS,SAAS,SAAiB,KAAa,QAAqC;CACnF,OAAO,IAAI,SAAS,gBAAgB,WAAW;EAC7C,SAAS,MAAM,CAAC,MAAM,OAAO,GAAG;GAC9B;GACA,SAAS;GACT,WAAW;GACX,UAAU;GACV,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC7B,IAAI,KAAK,QAAQ,WAAW;GAC1B,IAAI,CAAC,KACH,OAAO,eAAe;GACxB,MAAM,OAAO,GAAG,SAAS,SAAS,KAAK,CAAC,CAAC,MAAM,IAAkB;GACjE,MAAM,OAAQ,IAAmC;GACjD,uBAAO,IAAI,MAAM,uBAAuB,SAAS,KAAA,IAAY,UAAU,KAAK,KAAK,KAAK,OAAO,MAAM,SAAS,KAAK,CAAC;EACpH,CAAC;CACH,CAAC;AACH;AAEA,SAAS,YAAY,MAAuB;CAC1C,IAAI;EACF,OAAO,SAAS,IAAI,CAAC,CAAC,YAAY;CACpC,QACM;EACJ,OAAO;CACT;AACF;;AAGA,SAAS,gBAAgB,KAAa,cAAsB,UAA0B;CACpF,MAAM,QAAQ,SAAS,cAAc,GAAG;CACxC,IAAI,CAAC,SAAS,MAAM,WAAW,IAAI,GACjC,OAAO;CACT,MAAM,YAAY,KAAK,UAAU,KAAK;CACtC,OAAO,YAAY,SAAS,IAAI,YAAY;AAC9C;;AAGA,eAAsB,gBACpB,OACA,SACmC;CACnC,MAAM,EAAE,KAAK,aAAa,QAAQ,WAAW;CAC7C,MAAM,eAAeC,cAAY,GAAG;CACpC,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,GAAG,IAAI,iCAAiC;CAC1D,MAAM,WAAW,iBAAiB,YAAY,KAAK;CACnD,MAAM,SAAS,YAAY,QAAQ,KAAK;CACxC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,yCAAyC;CAC3D,IAAI,CAAC,MAAM,YAAY,UAAU;EAAC;EAAoB;EAAY;CAAM,GAAG,EAAE,OAAO,CAAC,GACnF,MAAM,IAAI,MAAM,IAAI,OAAO,8BAA8B;CAE3D,MAAM,OAAO,aAAa;EAAE;EAAS;EAAU;EAAQ,UAAU,OAAO;CAAS,CAAC;CAClF,MAAM,OAAO,YAAY,SAAS,OAAO,SAAS,YAAY,MAAM,cAAc,UAAU,MAAM,IAAI;CAEtG,MAAM,WAAW,MAAM,iBAAiB,UAAU,MAAM,MAAM;CAC9D,IAAI,UAGE;MAAA,SAAS,WAAW,QACtB,MAAM,IAAI,MAAM,GAAG,KAAK,6BAA6B,SAAS,SAAS,WAAW,SAAS,OAAO,KAAK,kBAAkB,EAAE;CAAA,OAE1H;EACH,IAAI,WAAW,IAAI,GACjB,MAAM,IAAI,MAAM,GAAG,KAAK,0DAA0D;EACpF,IAAI,MAAM,YAAY,UAAU;GAAC;GAAY;GAAY;GAAW,cAAc;EAAQ,GAAG,EAAE,OAAO,CAAC,GACrG,MAAM,IAAI,MAAM,WAAW,OAAO,qCAAqC;EACzE,IAAI;EACJ,IAAI;GACF,cAAc,MAAM,IAAI,UAAU;IAAC;IAAa;IAAY,GAAG,KAAK;GAAU,GAAG,EAAE,OAAO,CAAC,EAAA,CAAG,OAAO,KAAK;EAC5G,QACM;GACJ,MAAM,IAAI,MAAM,SAAS,KAAK,+BAA+B,SAAS,SAAS,4CAA4C,KAAK;EAClI;EACA,IAAI,OAAO,aAAa,WACtB,uBAAuB,QAAQ;EACjC,UAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EAC5C,IAAI;GACF,MAAM,IAAI,UAAU;IAAC;IAAY;IAAO;IAAM;IAAQ;IAAM;GAAU,GAAG,EAAE,OAAO,CAAC;EACrF,SACO,KAAK;GACV,MAAM,IAAI,MAAM,eAAe,WAAW,IAAI,UAAU,OAAO,GAAG,CAAC;EACrE;CACF;CAEA,MAAM,QAAQ,OAAO,OAAO,iBAAiB,WAAW,OAAO,aAAa,KAAK,IAAI;CACrF,IAAI,OACF,MAAM,SAAS,OAAO,MAAM,MAAM;CAEpC,OAAO;EACL,KAAK,gBAAgB,KAAK,cAAc,IAAI;EAE5C,aAAa;GAAE;GAAQ;GAAM,KAAK;IAAE;IAAM;GAAS;EAAE;CACvD;AACF;AAEA,SAAgB,kCAAkC,SAAmD;CACnG,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa;EACb,aAAa;EACb,gBAAe,WAAU,GAAG,OAAO,OAAO,iBAAiB,WAAW,OAAO,eAAe,YAAY,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK;EACrI,cAAc;GACZ;IACE,KAAK;IACL,MAAM;IACN,OAAO;IACP,aAAa;IACb,SAAS;KACP;MAAE,OAAO;MAAQ,OAAO;MAAsB,aAAa;KAA0D;KACrH;MAAE,OAAO;MAAW,OAAO;MAA0B,aAAa;KAAyC;KAC3G;MAAE,OAAO;MAAW,OAAO;MAAyB,aAAa;KAAyC;IAC5G;IACA,SAAS;GACX;GACA;IAAE,KAAK;IAAgB,MAAM;IAAU,OAAO;IAAiB,aAAa;IAAwC,SAAS;IAAW,aAAa;GAAU;GAC/J;IACE,KAAK;IACL,MAAM;IACN,OAAO;IACP,aAAa;IACb,SAAS,CACP;KAAE,OAAO;KAAQ,OAAO;KAAgB,aAAa;IAAmD,GACxG;KAAE,OAAO;KAAW,OAAO;KAAkB,aAAa;IAAoC,CAChG;IACA,SAAS;GACX;GACA;IACE,KAAK;IACL,MAAM;IACN,OAAO;IACP,aAAa;IACb,SAAS,CACP;KAAE,OAAO;KAAY,OAAO;KAAmB,aAAa;IAA6C,GACzG;KAAE,OAAO;KAAS,OAAO;KAAQ,aAAa;IAA6D,CAC7G;IACA,SAAS;GACX;GACA;IAAE,KAAK;IAAgB,MAAM;IAAU,OAAO;IAAiB,aAAa;IAAmF,aAAa;IAAe,SAAS;GAAG;EACzM;EAEA,MAAM,UAAU,EAAE,OAAO;GACvB,IAAI,CAAC,KACH,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAyC;GACvE,IAAI,CAAC,MAAM,eAAe,GACxB,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAwB;GACtD,OAAOA,cAAY,GAAG,IAAI,EAAE,IAAI,KAAK,IAAI;IAAE,IAAI;IAAO,QAAQ;GAA6C;EAC7G;EAEA,UAAS,UAAS,gBAAgB,OAAO,QAAQ,OAAO;EAExD,YAAY,EAAE,KAAK,iBAAiB;GAClC,KAAK,KAAK,UAAU;IAAE;IAAK,WAAW,aAAa;GAAK,CAAC;GACzD,cAAc,qBAAqB;IAAE;IAAK,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;GAAG,CAAC;EACjF;EAEA,WAAW,aAAa,EAAE,aAAa,iBAAiB,gBAAgB,WAAW,GAAG,YAAY,QAAQ,MAAM;CAClH;AACF;;AAGA,eAAsB,iBAAiB,KAA8B,QAA4B,QAA+D;CAC9J,IAAI,CAAC,KACH,OAAO,EAAE,SAAS,KAAK;CACzB,IAAI,OAAO,aAAa,SACtB,OAAO;EAAE,SAAS;EAAO,QAAQ,wBAAwB,IAAI,KAAK;CAAwC;CAC5G,IAAI,CAAC,WAAW,IAAI,IAAI,GAAG;EACzB,MAAM,YAAY,IAAI,UAAU,CAAC,YAAY,OAAO,CAAC;EACrD,OAAO,EAAE,SAAS,KAAK;CACzB;CACA,MAAM,EAAE,WAAW,MAAM,IAAI,IAAI,MAAM,CAAC,UAAU,aAAa,CAAC;CAChE,IAAI,OAAO,KAAK,GACd,OAAO;EAAE,SAAS;EAAO,QAAQ,wBAAwB,IAAI,KAAK,0CAA0C,SAAS,KAAK,OAAO,KAAK,GAAG;CAAe;CAC1J,MAAM,IAAI,IAAI,UAAU;EAAC;EAAY;EAAU,IAAI;CAAI,CAAC;CACxD,OAAO,EAAE,SAAS,KAAK;AACzB;;;AClQA,MAAa,0BAA0B;AAEvC,MAAM,gBAAgB;AACtB,MAAM,wBAAwB;AAC9B,MAAM,gBAAgB;AAWtB,eAAe,aAAqC;CAClD,IAAI;CACJ,IAAI;EACF,aAAa,MAAM,OAAO,aAAA,CAAiE;CAC7F,QACM;EACJ,MAAM,IAAI,MAAM,4EAA4E;CAC9F;CACA,OAAO,IAAI,UAAU;AACvB;AAEA,IAAI;;AAEJ,eAAe,0BAAuD;CACpE,IAAI,YAAY,KAAK,IAAI,IAAI,SAAS,KAAK,eACzC,OAAO,SAAS;CAClB,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,WAAW,EAAA,CAAG,KAAK;CAClC,SACO,KAAK;EACV,MAAM,UAAW,IAAc;EAC/B,SAAS,QAAQ,SAAS,WAAW,IAAI,UAAU,2BAA2B,QAAQ;CACxF;CACA,WAAW;EAAE,IAAI,KAAK,IAAI;EAAG;CAAO;CACpC,OAAO;AACT;AAEA,SAASC,OAAK,QAA2B,KAAa,WAAW,IAAY;CAC3E,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI;AACpE;AAEA,SAAS,aAAa,QAAoC;CACxD,OAAO,OAAO,cAAc;AAC9B;AAEA,eAAe,YAAY,OAAe,QAAqC;CAC7E,MAAM,SAAS,MAAM,WAAW;CAEhC,IAAI,MADkB,OAAO,SAAS,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,YAAY,KAAK,GAEjF;CACF,QAAQ,eAAe;CACvB,MAAM,SAAS,MAAM,OAAO,KAAK,KAAK;CACtC,MAAM,IAAI,SAAe,SAAS,WAAW,OAAO,MAAM,eAAe,SAAQ,QAAO,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,CAAC;AACxH;;AAGA,SAAS,WAA+B;CACtC,MAAM,MAAM,QAAQ,SAAS;CAC7B,MAAM,MAAM,QAAQ,SAAS;CAC7B,OAAO,QAAQ,KAAA,KAAa,QAAQ,KAAA,IAAY,KAAA,IAAY,GAAG,IAAI,GAAG;AACxE;;AAGA,SAAS,iBAAiB,SAA2B,SAAiB,KAA+B;CACnG,IAAI,CAAC,SACH,OAAO;CACT,OAAO;EACL,GAAG;EACH,MAAM,MAAM,QAAQ;GAClB,MAAM,SAA0B,MAAM,QAAQ,MAAM,MAAM;GAC1D,MAAM,SAAS,MAAM,QAAQ,KAAK,QAAQ,SAAS;IAAE;IAAK,SAAS;GAAsB,CAAC;GAC1F,IAAI,OAAO,aAAa,GAAG;IACzB,MAAM,QAAQ,QAAQ,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;IACnD,MAAM,IAAI,MAAM,qCAAqC,OAAO,SAAS,MAAM,OAAO,UAAU,OAAO,OAAA,CAAQ,KAAK,CAAC,CAAC,MAAM,IAAK,GAAG;GAClI;GACA,OAAO;EACT;CACF;AACF;AAEA,SAAgB,gCAAgC,SAAmD;CAEjG,MAAM,WAAW,kCAAkC,OAAO;CAC1D,MAAM,kBAAkB,YAAkD;EACxE,UAAU;EACV,MAAM;EACN,UAAU;EACV,cAAcA,OAAK,QAAQ,gBAAgB,SAAS;CACtD;CAEA,OAAO;EACL,MAAM;EACN,OAAO;EACP,aAAa;EACb,cAAc;EACd,cAAc;GACZ;IAAE,KAAK;IAAS,MAAM;IAAU,OAAO;IAAS,aAAa;IAA+E,SAAS;IAAe,aAAa;GAAc;GAC/L;IACE,KAAK;IACL,MAAM;IACN,OAAO;IACP,SAAS,CACP;KAAE,OAAO;KAAY,OAAO;KAAiB,aAAa;IAA8E,GACxI;KAAE,OAAO;KAAY,OAAO;KAAgB,aAAa;IAAmE,CAC9H;IACA,SAAS;GACX;GACA;IAAE,KAAK;IAAgB,MAAM;IAAU,OAAO;IAAiB,aAAa;IAAwC,SAAS;IAAW,aAAa;IAAW,MAAM;KAAE,KAAK;KAAa,QAAQ;IAAW;GAAE;GAC/M;IACE,KAAK;IACL,MAAM;IACN,OAAO;IACP,SAAS,CAAC;KAAE,OAAO;KAAU,OAAO;IAAK,GAAG;KAAE,OAAO;KAAQ,OAAO;IAAM,CAAC;IAC3E,SAAS;GACX;GACA;IAAE,KAAK;IAAgB,MAAM;IAAU,OAAO;IAAiB,aAAa;IAA2J,aAAa;IAAU,SAAS;GAAG;GAC1Q;IAAE,KAAK;IAAe,MAAM;IAAU,OAAO;IAAyC,aAAa;IAAqF,SAAS;GAAG;EACtM;EACA,aAAa;EACb,gBAAe,WAAU,SAAS,cAAe,eAAe,MAAM,CAAC;EACvE,qBAAoB,WAAU,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAc;EAE5F,MAAM,UAAU,EAAE,KAAK,UAAU;GAC/B,MAAM,SAAS,MAAM,wBAAwB;GAC7C,IAAI,QACF,OAAO;IAAE,IAAI;IAAO;GAAO;GAC7B,IAAI,CAAC,KACH,OAAO;IAAE,IAAI;IAAO,QAAQ;GAA6C;GAC3E,IAAI,aAAa,MAAM,GAAG;IACxB,IAAI,CAAC,MAAM,eAAe,GACxB,OAAO;KAAE,IAAI;KAAO,QAAQ;IAAwB;IACtD,IAAI,CAACC,cAAY,GAAG,GAClB,OAAO;KAAE,IAAI;KAAO,QAAQ;IAAyD;GACzF;GACA,OAAO,EAAE,IAAI,KAAK;EACpB;EAEA,MAAM,SAA2C;GAC/C,MAAM,SAAS,MAAM,WAAW;GAChC,MAAM,OAAO,KAAK;GAClB,MAAM,UAAU,MAAM,OAAO,QAAQ;GACrC,WAAW;IAAE,IAAI,KAAK,IAAI;IAAG,QAAQ,KAAA;GAAU;GAC/C,OAAO;IAAE,IAAI;IAAM,QAAQ,UAAU,QAAQ,WAAW,MAAM,QAAQ,KAAK,KAAK,QAAQ,GAAG,GAAG,QAAQ,QAAQ,IAAI,KAAK;GAAK;EAC9H;EAIA,MAAM,QAAQ,OAAO;GACnB,MAAM,YAAYD,OAAK,MAAM,QAAQ,SAAS,aAAa,GAAG,MAAM,MAAM;GAC1E,OAAO,aAAa,MAAM,MAAM,IAC5B,SAAS,QAAS;IAAE,GAAG;IAAO,QAAQ,eAAe,MAAM,MAAM;GAAE,CAAC,IACpE,CAAC;EACP;EAEA,UAAU,EAAE,KAAK,UAAU;GACzB,MAAM,QAAQA,OAAK,QAAQ,SAAS,aAAa;GACjD,MAAM,UAAU,OAAO,YAAY,SAAS,SAAS,KAAA;GACrD,MAAM,QAAQA,OAAK,QAAQ,cAAc;GACzC,MAAM,OAAO,SAAS;GACtB,OAAO;IACL,KAAK,KAAK,UAAU;KAAE;KAAK;KAAO,SAAS,WAAW;KAAM;KAAO,MAAM,QAAQ;IAAK,CAAC;IACvF,cAAc,iBAAiB,oBAAoB;KACjD;KACA;KACA,QAAQ,oBAAoB,GAAG;KAC/B,KAAK,EAAE,MAAM,OAAO;KACpB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;KAC7B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;KACvB,QAAQ,EAAE,sBAAsB,SAAS;IAC3C,CAAC,GAAG,OAAO,GAAG;GAChB;EACF;EAEA,WAAW,aAAa,YAAY,YAAY,MAC5C,SAAS,SAAU,aAAa;GAAE,GAAG;GAAS,QAAQ,eAAe,QAAQ,MAAM;EAAE,CAAC,IACtF,QAAQ,QAAQ,EAAE,SAAS,KAAK,CAAC;CACvC;AACF;ACjMA,MAAME,aAAW,eAAe,iBAAiB;AACjD,MAAM,SAAS,aAAa,EAAE,OAAM,WAAUA,WAAS,OAAO,SAAS,OAAO,KAAK,EAAE,CAAC;AAetF,SAAS,KAAK,QAA2B,KAAiC;CACxE,MAAM,QAAQ,OAAO;CACrB,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,KAAA;AACpE;AAEA,SAAS,WAAW,QAA0C;CAC5D,MAAM,SAAS,KAAK,QAAQ,QAAQ;CACpC,MAAM,SAAS,KAAK,QAAQ,QAAQ;CACpC,OAAO;EAAE,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAI,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAAG;AACxE;AAEA,SAAS,gBAAgB,QAAmC;CAC1D,MAAM,UAAU,OAAO,OAAO,oBAAoB,YAAY,OAAO,kBAAkB,IAAI,OAAO,kBAAkB;CACpH,OAAO,KAAK,MAAM,UAAU,EAAE;AAChC;AAEA,eAAe,cAAmC;CAChD,IAAI;EACF,QAAQ,MAAM,OAAO,OAAA,CAA8C;CACrE,QACM;EACJ,MAAM,IAAI,MAAM,gEAAgE;CAClF;AACF;AAEA,MAAa,YAAiC;CAC5C,MAAA;CACA,OAAO;CACP,aAAa;CACb,QAAQ;EACN;GAAE,KAAK;GAAU,MAAM;GAAU,OAAO;GAAW,aAAa;GAAwC,KAAK;GAAe,aAAa;EAAQ;EACjJ;GAAE,KAAK;GAAU,MAAM;GAAU,OAAO;GAAU,aAAa;GAAmD,KAAK;GAAc,aAAa;GAAW,SAAS;EAAG;EACzK;GAAE,KAAK;GAAY,MAAM;GAAU,OAAO;GAAY,aAAa;GAA+D,KAAK;GAAgB,aAAa;GAAQ,SAAS;EAAG;EACxL;GAAE,KAAK;GAAmB,MAAM;GAAU,OAAO;GAA+B,aAAa;GAA6F,SAAS;EAAG;CACxM;CAEA,MAAM,kBAAkB,QAAQ;EAC9B,IAAI;GACF,MAAM,YAAY;EACpB,SACO,KAAK;GACV,OAAQ,IAAc;EACxB;EACA,OAAO,KAAK,QAAQ,QAAQ,IAAI,KAAA,IAAY;CAC9C;CAEA,SAAS,QAAQ,EAAE,WAAW,OAAO;EACnC,MAAM,UAAU,gBAAgB,MAAM;EACtC,MAAM,WAAW,KAAK,QAAQ,UAAU;EACxC,OAAO,kBAAkB;GACvB,GAAG,WAAW,MAAM;GACpB,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;GAC/B,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;GACjC,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;GACrB,gBAAgB;GAChB,kBAAkB;GAClB,WAAW;IAAE,WAAW;IAAS,YAAY;GAAK;GAClD,WAAW;GACX;EACF,CAAC;CACH;CAEA,MAAM,MAAM,QAAQ,WAAW;EAC7B,MAAM,UAAU,MAAM,YAAY;EAClC,MAAM,QAAQ,QAAQ,SAAS,QAAQ;EACvC,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,oDAAqD;EACvE,MAAM,MAAM,KAAK,SAAS,WAAW,WAAW,MAAM,CAAC;CACzD;CAEA,MAAM,OAAO,QAAQ,WAAW;EAE9B,OAAM,MADgB,YAAY,EAAA,CACpB,KAAK,WAAW,WAAW,MAAM,CAAC;CAClD;CAEA,MAAM,OAAO,QAAQ;EACnB,IAAI,CAAC,KAAK,QAAQ,QAAQ,GACxB,OAAO;GAAE,IAAI;GAAO,QAAQ;EAAyB;EAEvD,MAAM,UAAU,OAAM,MADA,YAAY,EAAA,CACJ,KAAK;GAAE,GAAG,WAAW,MAAM;GAAG,OAAO;EAAI,CAAC,CAAC,CAAC,UAAU;EAEpF,OAAO;GAAE,IAAI;GAAM,QAAQ,gBADb,KAAK,QAAQ,QAAQ,KAAK,UACS,IAAI,QAAQ,OAAO,UAAU,QAAQ,WAAW,IAAI,KAAK,KAAK;EAAmB;CACpI;AACF;AAEA,SAAgB,+BAAoD;CAClE,OAAO,uCAAuC,SAAS;AACzD;;;AChHA,MAAa,2BAAgD;CAC3D,MAAM,kBAAkB;CACxB,OAAO;CACP,aAAa;CACb,cAAc;EACZ;GACE,KAAK;GACL,SAAS;GACT,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS;EACX;EACA;GACE,KAAK;GACL,SAAS;GACT,MAAM;GACN,OAAO;GACP,aAAa;GACb,SAAS,CAAC;IAAE,OAAO;IAAS,OAAO;GAAQ,GAAG;IAAE,OAAO;IAAQ,OAAO;GAAO,CAAC;GAC9E,SAAS;GACT,MAAM;IAAE,KAAK;IAAW,QAAQ;GAAK;EACvC;EACA;GACE,KAAK;GACL,SAAS;GACT,MAAM;GACN,OAAO;GACP,aAAa;GACb,aAAa;GACb,SAAS;GACT,MAAM;IAAE,KAAK;IAAW,QAAQ;GAAK;EACvC;CACF;CACA,YAAY,EAAE,KAAK,iBAAiB;EAClC,KAAK,KAAK,UAAU;GAAE;GAAK,WAAW,aAAa;EAAK,CAAC;EACzD,cAAc,qBAAqB;GAAE;GAAK,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EAAG,CAAC;CACjF;AACF;;;AChCA,SAAgB,4BAA4B,SAA2D;CACrG,OAAO;EACL;EACA,kCAAkC,OAAO;EACzC,gCAAgC,OAAO;EACvC,6BAA6B;EAC7B,iCAAiC;CACnC;AACF;;;ACOA,SAAS,eAAe,aAAyD;CAC/E,MAAM,MAAM,YAAY;CACxB,OAAO,OAAO,OAAO,IAAI,cAAc,WAAW,MAAoB,KAAA;AACxE;;AAGA,SAAgB,oBAAoB,OAA+B,KAAsB;CACvF,IAAI,CAAC,IAAI,WAAW,GAAG,GACrB,OAAO;CACT,MAAM,aAAa,MAAM,UAAU,GAAG;CACtC,OAAO,MAAM,MAAM,SAAS;EAC1B,MAAM,IAAI,MAAM,UAAU,KAAK,IAAI,CAAC,CAAC,QAAQ,QAAQ,EAAE,KAAK;EAC5D,OAAO,eAAe,KAAK,WAAW,WAAW,MAAM,MAAM,MAAM,GAAG,EAAE,EAAE;CAC5E,CAAC;AACH;AAEA,SAAgB,uBAAuB,MAAc,UAAgD;CACnG,MAAM,gCAAuB,IAAI,MAAM,oBAAoB,KAAK,uDAAuD;CACvH,MAAM,gBAAgB,SAAS,OAAO,IAAI;;CAG1C,MAAM,WAAW,gBAAiD;EAChE,MAAM,UAAU,QAAQ;EACxB,MAAM,MAAM,eAAe,WAAW;EACtC,IAAI,CAAC,WAAY,OAAO,IAAI,cAAc,QAAQ,IAChD,MAAM,QAAQ;EAChB,MAAM,OAAO,SAAS,KAAK,QAAQ,EAAE;EACrC,IAAI,CAAC,MACH,MAAM,QAAQ;EAChB,OAAO;CACT;CAEA,MAAM,eAAe,QAAwB;EAC3C,MAAM,UAAU,QAAQ;EACxB,IAAI,CAAC,SACH,MAAM,QAAQ;EAChB,IAAI,CAAC,oBAAoB,QAAQ,OAAO,GAAG,GACzC,MAAM,IAAI,MAAM,GAAG,OAAO,cAAc,cAAc,KAAK,YAAY,QAAQ,MAAM,KAAI,MAAK,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,GAAG;EACtH,OAAO,MAAM,UAAU,GAAG;CAC5B;CAEA,MAAM,iBAAyF;EAC7F,MAAM,UAAU,QAAQ;EACxB,OAAO,UAAU;GAAE,IAAI,QAAQ;GAAI;GAAM,QAAQ,SAAS,OAAO,QAAQ,EAAE;EAAE,IAAI,KAAA;CACnF;CAGA,MAAM,kBAAqD,QAAQ,IAAI,EAAE,IAAI,KAAK,IAAI;EAAE,IAAI;EAAO,QAAQ,GAAG,KAAK;CAAiC;CAEpJ,MAAM,aAA+C,EAAE,WAAW,KAAK,kBAAkB;EACvF,MAAM,OAAO,QAAQ,WAAW;EAChC,OAAO;GACL,KAAK,KAAK,UAAU;IAAE,WAAW,KAAK;IAAW;GAAI,CAAC;GACtD,cAAc,qBAAqB;IAAE;IAAM;IAAW;IAAK,cAAc,QAAQ,CAAC,EAAE;GAAa,CAAC;GAClG,WAAW;EACb;CACF;CAEA,MAAM,kBAAkB,kCAAkC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAA,CAAG,QAAO,UAAS,MAAM,QAAQ,UAAU;CAEvI,MAAM,QAA6B;EACjC,MAAM,YAAY,SAAS,IAAI;EAC/B,OAAO,WAAW;EAClB,aAAa,eAAe,KAAK;EACjC;EACA,SAAS;EACT;EACA,MAAM,QAAQ,EAAE,WAAW,KAAK,UAAU;GACxC,MAAM,OAAO,QAAQ;IAAE,MAAM,MAAM;IAAM,OAAO;GAAe,CAAC;GAEhE,OAAO;IAAE,MAAK,MADQ,KAAK,KAAK,mBAAmB,EAAE,IAAI,GAAG;KAAE;KAAW,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAAG,CAAC,EAAA,CAClF;IAAK,aAAa,EAAE,KAAK,EAAE,WAAW,KAAK,UAAU,EAAE;GAAE;EACjF;EACA;CACF;CAgCA,OAAO,CAAC,OAAO;EA7Bb,MAAM,YAAY,YAAY,IAAI;EAClC,OAAO,cAAc;EACrB,aAAa,2CAA2C,KAAK;EAC7D,aAAa;EACb,gBAAe,WAAU,GAAG,OAAO,OAAO,iBAAiB,WAAW,OAAO,eAAe,YAAY,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK;EACrI,cAAc;EACd;EACA,SAAS;EACT;EACA,MAAM,QAAQ,EAAE,WAAW,KAAK,aAAa,QAAQ,UAAU;GAC7D,MAAM,OAAO,QAAQ,WAAW;GAChC,MAAM,SAAS,YAAY,QAAQ,KAAK;GACxC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,yCAAyC;GAC3D,MAAM,WAAW,MAAM,KAAK,KAAK,uBAAuB;IAAE;IAAK;IAAQ,GAAI,YAAY,OAAO,EAAE,MAAM,YAAY,KAAK,IAAI,CAAC;IAAI;GAAO,GAAG;IAAE;IAAW,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAAG,CAAC;GACtL,OAAO;IAAE,KAAK,SAAS;IAAK,aAAa;KAAE,QAAQ,SAAS;KAAQ,MAAM,SAAS;KAAM,KAAK;MAAE,WAAW,KAAK;MAAW,GAAG,SAAS;KAAI;IAAE;GAAE;EACjJ;EACA;EACA,MAAM,SAAS,aAAa,EAAE,UAAU;GACtC,MAAM,MAAM,eAAe,WAAW;GACtC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,UACrB,OAAO,EAAE,SAAS,KAAK;GACzB,MAAM,OAAO,SAAS,KAAK,IAAI,SAAS;GACxC,IAAI,CAAC,MAAM,OAAO,GAChB,OAAO;IAAE,SAAS;IAAO,QAAQ,wBAAwB,IAAI,KAAK,IAAI,KAAK;GAAc;GAC3F,OAAO,KAAK,KAAK,wBAAwB;IAAE,KAAK;KAAE,MAAM,IAAI;KAAM,UAAU,IAAI;IAAS;IAAG,GAAI,YAAY,SAAS,EAAE,QAAQ,YAAY,OAAO,IAAI,CAAC;IAAI;GAAO,GAAG,EAAE,MAAM,MAAM,CAAC;EACtL;CAGoB,CAAC;AACzB;;;AC5GA,MAAM,wBAAwB;AAC9B,MAAM,kBAAkB;AACxB,MAAM,gBAAgB;AACtB,MAAM,aAAa;AAyBnB,SAASC,WAAS,MAAc,KAAqB;CACnD,OAAO,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,GAAG,GAAG,EAAE,sBAAsB,KAAK,SAAS,IAAI,mCAAmC;AAC9H;;AAGA,SAAgB,iBAAiB,QAAiD;CAChF,IAAI,OAAO,cAAc,SACvB,OAAO;CACT,OAAO;EAAE,GAAG,uBAAuB,MAAM;EAAG,OAAO;CAAU;AAC/D;AAEA,eAAsB,mBAAmB,OAAqD;CAC5F,MAAM,EAAE,SAAS,QAAQ,KAAK,UAAU;CACxC,MAAM,SAAS,MAAM,OAAO,QAAQ,OAAO,EAAE;CAC7C,MAAM,UAAoB,CAAC;CAE3B,MAAM,OAAO,OAAO,MAAc,QAA6C;EAC7E,IAAI;GACF,MAAM,OAAO,QAAQ,WAAW,MAAM,QAAQ,SAAS,QAAQ,IAAI,IAAI;GACvE,IAAI,SAAS,QAAQ,QAAQ,UAC3B,OAAO,KAAA;GACT,IAAI,SAAS,QAAQ,OAAO,MAAM,GAChC,OAAO,KAAA;GACT,OAAO,MAAM,QAAQ,SAAS,QAAQ,IAAI;EAC5C,QACM;GACJ;EACF;CACF;CACA,MAAM,OAAO,OAAO,QAAmC;EACrD,IAAI;GACF,QAAQ,MAAM,QAAQ,UAAU,QAAQ,GAAG,EAAA,CAAG,KAAI,UAAU,OAAO,UAAU,WAAW,QAAQ,MAAM,IAAK;EAC7G,QACM;GACJ,OAAO,CAAC;EACV;CACF;CAEA,MAAM,OAAO,OAAO,YAAY;EAC9B,IAAI;GACF,MAAM,SAAS,MAAM,QAAQ,KAAK,QAAQ,iCAAiC;IAAE;IAAK,SAAS;GAAG,CAAC;GAC/F,MAAM,MAAM,OAAO,aAAa,IAAI,OAAO,OAAO,KAAK,IAAI;GAC3D,OAAO,OAAO,oBAAoB,OAAO,GAAG,IAAI,MAAM,UAAU,GAAG,IAAI;EACzE,QACM;GACJ,OAAO;EACT;CACF,EAAA,CAAG;CAEH,MAAM,WAA2B,CAAC;CAClC,KAAK,MAAM,OAAO;EAAC;EAAa;EAAqB,IAAI,OAAO;EAAa;CAAW,GAAG;EACzF,MAAM,OAAO,MAAM,KAAK,MAAM,GAAG;EACjC,MAAM,OAAO,MAAM,KAAK,MAAM,qBAAqB;EACnD,IAAI,QAAQ,KAAK,KAAK,GACpB,SAAS,KAAK;GAAE;GAAM,QAAQ;GAAW,UAAUA,WAAS,MAAM,qBAAqB;EAAE,CAAC;CAC9F;CAEA,MAAM,aAAa,MAAM,KAAK,MAAM,WAAW;CAC/C,MAAM,aAAa,MAAM,KAAK,YAAY,qBAAqB;CAC/D,MAAM,WAAW,cAAc,WAAW,KAAK,IAAI;EAAE,MAAM;EAAY,QAAQ;EAAoB,UAAUA,WAAS,YAAY,qBAAqB;CAAE,IAAI;CAG7J,MAAM,SAAwB,CAAC;CAC/B,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,OAAO,CAAC,kBAAkB,IAAI,OAAO,QAAQ,GAAG;EACzD,MAAM,MAAM,MAAM,KAAK,MAAM,GAAG;EAChC,KAAK,MAAM,UAAU,MAAM,KAAK,GAAG,EAAA,CAAG,QAAO,MAAK,EAAE,SAAS,GAAG,CAAC,GAAG;GAClE,IAAI,OAAO,UAAU,YACnB;GACF,MAAM,WAAW,MAAM,KAAK,KAAK,OAAO,UAAU;GAClD,MAAM,OAAO,MAAM,KAAK,UAAU,eAAe;GACjD,MAAM,QAAQ,OAAO,kBAAkB,MAAM,UAAU,EAAE,QAAQ,UAAU,CAAC,IAAI;GAChF,IAAI,SAAS,CAAC,MAAM,IAAI,MAAM,IAAI,GAAG;IACnC,MAAM,IAAI,MAAM,IAAI;IACpB,OAAO,KAAK,KAAK;GACnB;EACF;CACF;CAEA,MAAM,OAAwB,CAAC;CAC/B,MAAM,0BAAU,IAAI,IAAY;CAChC,KAAK,MAAM,OAAO;EAAC;EAAqB;EAAoB,IAAI,OAAO;EAAa,IAAI,OAAO;CAAU,GAAG;EAC1G,MAAM,OAAO,MAAM,KAAK,MAAM,GAAG;EACjC,MAAM,OAAO,MAAM,KAAK,MAAM,aAAa;EAC3C,IAAI,CAAC,MACH;EACF,IAAI;EACJ,IAAI;GACF,UAAU,cAAc,IAAI;EAC9B,SACO,KAAK;GACV,QAAQ,KAAK,GAAG,KAAK,IAAK,IAAc,SAAS;GACjD;EACF;EACA,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,QAAQ,IAAI,OAAO,IAAI,GACzB;GACF,QAAQ,IAAI,OAAO,IAAI;GACvB,MAAM,SAAS,iBAAiB,MAAM;GACtC,IAAI,QACF,KAAK,KAAK;IAAE,QAAQ;IAAQ,QAAQ;IAAW;GAAK,CAAC;QAErD,QAAQ,KAAK,eAAe,OAAO,KAAK,KAAK,KAAK,0EAA0E;EAChI;CACF;CAEA,OAAO;EAAE;EAAM;EAAU;EAAU;EAAQ;EAAM;CAAQ;AAC3D;;;AC1IA,MAAa,aAA4B;CACvC,aAAa,IAAI,OAAO;EACtB,MAAM,QAAQ,WAAW,IAAI,EAAE;EAC/B,MAAM,QAAQ;EACd,OAAO;CACT;CACA,eAAc,OAAM,aAAa,EAAmC;AACtE;AA4DA,SAAS,YAAY,QAA8B;CACjD,OAAO,OAAO,UAAU,IAAI,aAAa,8BAA8B,YAAY;AACrF;AAEA,SAAgB,kBAAkB,OAAwI;CACxK,MAAM,EAAE,WAAW,MAAM,QAAQ,WAAW;CAC5C,IAAI,UAAoC;CACxC,MAAM,0BAAU,IAAI,IAAY;;CAEhC,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,wBAAQ,IAAI,IAAqC;CACvD,MAAM,4BAAY,IAAI,IAA8B;CACpD,MAAM,0BAAU,IAAI,IAA4B;CAChD,IAAI,SAAS;CAEb,SAAS,kBAAkB,SAAyD;EAClF,IAAI,QAAQ,SAAS,SAAS,QAC5B,OAAO,QAAQ,OAAO,IAAI,wBAAwB,KAAK,CAAC,CAAC;EAC3D,MAAM,EAAE,WAAW,WAAW;EAC9B,IAAI,QAAQ,SACV,OAAO,QAAQ,OAAO,YAAY,MAAM,CAAC;EAC3C,MAAM,UAAU,MAAM,YAAY;EAClC,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAqD,CAAC;GAC5D,MAAM,SAAiB;IACrB,UAAU,eAAe;KACvB,OAAO;KACP,QAAQ,UAAU;IACpB;IACA,SAAS,QAAQ;KACf,OAAO;KACP,OAAO,GAAG;IACZ;GACF;GACA,SAAS,SAAe;IACtB,QAAQ,OAAO,MAAM;IACrB,OAAO,aAAa,QAAQ,KAAK;IACjC,IAAI,QAAQ,SACV,QAAQ,oBAAoB,SAAS,QAAQ,OAAO;GACxD;GACA,QAAQ,gBAAgB,OAAO,OAAO,YAAY,MAAO,CAAC;GAC1D,QAAQ,QAAQ,OAAO,iBAAiB;IACtC,OAAO,OAAO,IAAI,wBAAwB,KAAK,GAAG,OAAO,CAAC;IAC1D,IAAI,cAAc,KAAA,KAAa,QAAQ,OAAO,SAAS,GACrD,OAAO,SAAS,WAAW,KAAK,GAAG,OAAO;GAC9C,GAAG,UAAU,GAAM;GACnB,QAAQ,iBAAiB,SAAS,QAAQ,SAAS,EAAE,MAAM,KAAK,CAAC;GACjE,QAAQ,IAAI,MAAM;GAClB,IAAI,cAAc,KAAA,KAAa,CAAC,QAAQ,IAAI,SAAS,GAAG;IACtD,QAAQ,IAAI,SAAS;IACrB,OAAO,UAAU,WAAW,KAAK,CAAC;GACpC;EACF,CAAC;CACH;;CAGA,SAAS,MAAS,OAAmB,SAAyC;EAC5E,MAAM,EAAE,WAAW;EACnB,IAAI,CAAC,QACH,OAAO;EACT,OAAO,IAAI,SAAY,SAAS,WAAW;GACzC,MAAM,gBAAsB;IAC1B,QAAQ,UAAU;IAClB,OAAO,YAAY,MAAM,CAAC;GAC5B;GACA,IAAI,OAAO,SACT,OAAO,QAAQ;GACjB,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;GACxD,MAAM,KAAK,SAAS,MAAM,CAAC,CAAC,cAAc,OAAO,oBAAoB,SAAS,OAAO,CAAC;EACxF,CAAC;CACH;CAEA,eAAe,KAAK,QAA2B,QAAiB,UAA8B,CAAC,GAAqB;EAClH,SAAS;GACP,MAAM,aAAa,WAAW,MAAM,kBAAkB,OAAO;GAC7D,IAAI;IACF,OAAO,MAAM,MAAM,WAAW,QAAQ,QAAQ,MAAM,GAAG,OAAO;GAChE,SACO,KAAK;IACV,IAAI,EAAE,eAAe,uBACnB,MAAM;IACR,IAAI,CAAC,2BAA2B,IAAI,MAAM,GACxC,MAAM,IAAI,uBAAuB,KAAK,CAAC;GAC3C;EACF;CACF;CAEA,SAAS,kBAAkB,YAAqC;EAC9D,KAAK,MAAM,CAAC,YAAY,aAAa,WACnC,WAAgB,QAAQ,mBAAmB,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,UAAU;GACzE,MAAM,EAAE,UAAU,SAAS,UAAU;GACrC,IAAI,CAAC,UAAU;IACb,UAAU,OAAO,UAAU;IAC3B,SAAS,KAAK,EAAE;IAChB;GACF;GACA,MAAM,QAAQ,OAAO,KAAK,SAAS,QAAQ;GAC3C,MAAM,SAAS,OAAO,UAAU,WAAW,KAAK,IAAI,KAAK,IAAI,QAAQ,SAAS,MAAM,CAAC,GAAG,MAAM,UAAU,IAAI;GAC5G,IAAI,SAAS,GAAG;IACd,SAAS,QAAQ;IACjB,SAAS,OAAO,MAAM,SAAS,MAAM,aAAa,MAAM,CAAC;GAC3D;EACF,SAAS,KAAA,CAAS;CAEtB;CAEA,OAAO;EACL;EACA;EACA,cAAc,YAAY;EACpB;EACN,OAAO,QAAQ,QAAQ;GACrB,IAAI;IACF,SAAS,OAAO,QAAQ,MAAM;GAChC,QACM,CAEN;EACF;EACA;EACA;EACA;EACA,QAAQ,QAAQ,QAAQ;GACtB,MAAM,IAAK,UAAU,CAAC;GACtB,IAAI,WAAW,eAAe,OAAO,EAAE,WAAW,UAAU;IAC1D,MAAM,IAAI,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI;IAC5B,MAAM,OAAO,EAAE,MAAM;GACvB,OACK,IAAI,WAAW,mBAAmB,OAAO,EAAE,eAAe,YAAY,OAAO,EAAE,SAAS,UAAU;IACrG,MAAM,WAAW,UAAU,IAAI,EAAE,UAAU;IAC3C,IAAI,UAAU;KACZ,MAAM,QAAQ,OAAO,KAAK,EAAE,MAAM,QAAQ;KAC1C,SAAS,QAAQ,MAAM;KACvB,SAAS,OAAO,KAAK;IACvB;GACF,OACK,IAAI,WAAW,mBAAmB,OAAO,EAAE,eAAe,UAAU;IACvE,UAAU,IAAI,EAAE,UAAU,CAAC,EAAE,KAAK,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,EAAE;IAC1E,UAAU,OAAO,EAAE,UAAU;GAC/B,OACK,IAAI,WAAW,sBAAsB,OAAO,EAAE,WAAW,YAAY,OAAO,EAAE,SAAS,UAC1F,QAAQ,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,WAAW,WAAW,UAAU,OAAO,KAAK,EAAE,MAAM,QAAQ,CAAC;QAEnG,IAAI,WAAW,sBAAsB,OAAO,EAAE,WAAW,UAAU;IACtE,MAAM,WAAW,QAAQ,IAAI,EAAE,MAAM;IACrC,QAAQ,OAAO,EAAE,MAAM;IACvB,UAAU,KAAK,OAAO,EAAE,SAAS,WAAW,EAAE,OAAO,EAAE;GACzD;EACF;EACA,cAAc,YAAY;GACxB,MAAM,YAAY,YAAY;GAC9B,UAAU;GACV,IAAI,CAAC,YAAY;IAEf,KAAK,MAAM,CAAC,QAAQ,aAAa,CAAC,GAAG,OAAO,GAAG;KAC7C,QAAQ,OAAO,MAAM;KACrB,SAAS,KAAK,EAAE;IAClB;IACA;GACF;GACA,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAC9B,OAAO,QAAQ,UAAU;GAC3B,KAAK,MAAM,aAAa,SACtB,OAAO,OAAO,WAAW,KAAK,CAAC;GACjC,QAAQ,MAAM;GACd,IAAI,WACF;GACF,kBAAkB,UAAU;EAC9B;EACA,kBAAkB;EAClB,WAAW;GACT,SAAS;GACT,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAC9B,OAAO,OAAO,IAAI,wBAAwB,KAAK,CAAC,CAAC;EACrD;CACF;AACF;;;AC3PA,MAAM,YAAY;AAClB,MAAM,gBAAgB;AAmEtB,SAAS,WAAW,OAA+B;CACjD,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,KAAK,MAAM,SAAS,WAChE,MAAM,IAAI,qBAAqB,gBAAgB,4CAA4C,UAAU,UAAU;CACjH,OAAO,MAAM,KAAK,SAAS;EACzB,MAAM,IAAI;EACV,IAAI,CAAC,KAAK,OAAO,EAAE,SAAS,YAAY,CAAC,EAAE,KAAK,WAAW,GAAG,KAAK,EAAE,KAAK,SAAS,QAAS,EAAE,UAAU,KAAA,KAAa,OAAO,EAAE,UAAU,UACtI,MAAM,IAAI,qBAAqB,gBAAgB,6DAA6D;EAC9G,OAAO;GAAE,MAAM,EAAE;GAAM,GAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC;EAAG;CAC9E,CAAC;AACH;;AAGA,SAAS,eAAe,OAA8C;CACpE,MAAM,MAAO,SAAS,OAAO,UAAU,WAAW,QAAQ,CAAC;CAE3D,OAAO,OAAO,YAAY;EADZ;EAAS;EAAa;EAAc;EAAa;EAAU;CAC5C,CAAC,CAAC,QAAO,QAAO,OAAO,IAAI,SAAS,SAAS,CAAC,CAAC,KAAI,QAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AACzG;AAEA,SAAS,SAAS,MAA4E;CAC5F,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO;EAAE,UAAU,CAAC;EAAG,WAAW,CAAC;CAAE;CACvC,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;EACpD,OAAO;GACL,UAAU,MAAM,QAAQ,OAAO,QAAQ,IACnC,OAAO,SAAS,QAAQ,MAA0B,CAAC,CAAC,KAAK,OAAO,EAAE,OAAO,YAAY,OAAO,EAAE,SAAS,YAAY,MAAM,QAAQ,EAAE,KAAK,CAAC,IACzI,CAAC;GACL,WAAW,MAAM,QAAQ,OAAO,SAAS,IACrC,OAAO,UAAU,QAAQ,MAA6B,CAAC,CAAC,KAAK,OAAO,EAAE,cAAc,YAAY,OAAO,EAAE,cAAc,QAAQ,IAC/H,CAAC;EACP;CACF,QACM;EACJ,OAAO;GAAE,UAAU,CAAC;GAAG,WAAW,CAAC;EAAE;CACvC;AACF;AAEA,MAAM,WAAW,YAA0C,IAAI,qBAAqB,iBAAiB,SAAS,OAAO;AAErH,SAAgB,sBAAsB,SAAkD;CACtF,MAAM,EAAE,cAAc,WAAW;CACjC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,MAAM,QAAQ,OAAO,KAAK;CAChC,MAAM,OAAO,KAAK,QAAQ,SAAS,aAAa;CAChD,MAAM,SAAS,SAAS,IAAI;CAC5B,MAAM,UAAU,IAAI,IAA2B,OAAO,SAAS,KAAI,WAAU,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC;CACjG,IAAI,YAAY,OAAO;CACvB,MAAM,QAAQ,cAA+B,QAAQ,gBAAgB,SAAS,KAAK;CACnF,MAAM,eAAwB,QAAQ,SAAS,KAAK;CACpD,MAAM,wBAAQ,IAAI,IAAyB;CAC3C,MAAM,kCAAkB,IAAI,IAAY;CACxC,MAAM,UAA6B,CAAC;CAEpC,MAAM,aAAmB;EACvB,IAAI;GAEF,YAAY,UAAU,QAAO,MAAK,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,IAAc;GACzE,oBAAoB,MAAM;IAAE,SAAS;IAAG,UAAU,CAAC,GAAG,QAAQ,OAAO,CAAC;IAAG,GAAI,UAAU,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;GAAG,GAAG;IAAE,WAAW;IAAM,MAAM;GAAM,CAAC;EAC7J,QACM,CAEN;CACF;CAEA,MAAM,UAAU,SAA6C,OAAO,IAAI,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAK,WAAU,OAAO,SAAS,IAAI,IAAI,KAAA;;CAGrI,MAAM,gBAAgB,WAAmB,cAAwC;EAC/E,MAAM,QAAQ,QAAQ,IAAI,SAAS,CAAC,EAAE;EACtC,IAAI,SAAS,UAAU,aAAa,KAAK,KAAK,GAC5C,MAAM,QAAQ,WAAW,UAAU,0HAA0H;EAC/J,IAAI,aAAa,UAAU,MAAK,MAAK,EAAE,cAAc,aAAa,EAAE,cAAc,SAAS,GACzF,MAAM,QAAQ,4BAA4B,UAAU,gDAAgD;CACxG;CAEA,MAAM,UAAU,WAAuC;EACrD,IAAI,OAAO,MAAM,IAAI,OAAO,EAAE;EAC9B,IAAI,CAAC,MAAM;GACT,OAAO,kBAAkB;IAAE,WAAW,OAAO;IAAI,YAAY,QAAQ,IAAI,OAAO,EAAE,CAAC,EAAE,QAAQ,OAAO;IAAM,aAAa,QAAQ;IAAa;IAAQ;GAAO,CAAC;GAC5J,MAAM,IAAI,OAAO,IAAI,IAAI;EAC3B;EACA,OAAO;CACT;;CAGA,MAAM,iBAAiB,SAAuB;EAC5C,IAAI,gBAAgB,IAAI,IAAI,GAC1B;EACF,gBAAgB,IAAI,IAAI;EACxB,KAAK,MAAM,YAAY,uBAAuB,MAAM;GAAE;GAAQ,SAAQ,OAAO,MAAM,IAAI,EAAE,CAAC,EAAE,OAAO,IAAI,WAAW;GAAY,OAAM,OAAO,QAAQ,IAAI,EAAE,IAAI,OAAO,QAAQ,IAAI,EAAE,CAAE,IAAI,KAAA;EAAW,CAAC,GAClM,aAAa,SAAS,QAAQ;CAClC;CACA,KAAK,MAAM,UAAU,QAAQ,OAAO,GAClC,cAAc,OAAO,IAAI;CAE3B,MAAM,QAAQ,YAAwC;EACpD,IAAI,OAAO;EACX,MAAM,OAAO;EACb,OAAO,OAAO;EACd,QAAQ,MAAM,IAAI,OAAO,EAAE,CAAC,EAAE,OAAO,IAAI,WAAW;EACpD,GAAI,OAAO,aAAa,KAAA,IAAY,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;EACrE,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EACpD,GAAI,OAAO,eAAe,EAAE,cAAc,OAAO,aAAa,IAAI,CAAC;CACrE;CAEA,SAAS,OAAO,QAA+B,YAA+B,OAA+B,CAAC,GAAoB;EAChI,IAAI,CAAC,OAAO,GACV,MAAM,IAAI,qBAAqB,iBAAiB,kBAAkB,0DAA0D;EAC9H,IAAI,OAAO,oBAAA,GACT,MAAM,YAAY,OAAO,iBAAA,CAAyC;EACpE,IAAI,OAAO,OAAO,cAAc,YAAY,CAAC,gBAAgB,KAAK,OAAO,SAAS,GAChF,MAAM,IAAI,qBAAqB,gBAAgB,kFAA4E;EAC7H,IAAI,OAAO,OAAO,SAAS,YAAY,CAAC,mBAAmB,OAAO,IAAI,GACpE,MAAM,IAAI,qBAAqB,gBAAgB,oFAA4E;EAC7H,MAAM,QAAQ,WAAW,OAAO,KAAK;EACrC,aAAa,OAAO,WAAW,KAAK,SAAS;EAC7C,MAAM,SAAS,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAK,WAAU,OAAO,SAAS,OAAO,IAAI;EAC/E,IAAI,UAAU,OAAO,OAAO,OAAO,WACjC,MAAM,IAAI,qBAAqB,iBAAiB,WAAW,aAAa,OAAO,KAAK,4FAA4F;EAElL,MAAM,SAAwB;GAC5B,IAAI,OAAO;GACX,MAAM,OAAO;GACb;GACA,UAAU,IAAI;GACd,GAAI,OAAO,OAAO,YAAY,WAAW,EAAE,SAAS,OAAO,QAAQ,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC;GACtF,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;GACtD,cAAc,eAAe,OAAO,YAAY;EAClD;EACA,QAAQ,IAAI,OAAO,IAAI,MAAM;EAC7B,IAAI,KAAK,WACP,YAAY,UAAU,QAAO,MAAK,EAAE,cAAc,OAAO,EAAE;EAC7D,KAAK;EACL,cAAc,OAAO,IAAI;EACzB,MAAM,OAAO,OAAO,MAAM;EAE1B,KAAK,WAAW,CAAC,EAAE,MAAM,8BAA8B;EACvD,KAAK,cAAc,UAAU;EAC7B,OAAO,SAAS;GAAE,WAAW,OAAO;GAAI,MAAM,OAAO;GAAM,QAAQ;EAAS,CAAC;EAE7E,IAAI,OAAO;EACX,OAAO;GACL,QAAQ,EAAE,WAAW,OAAO,GAAG;GAC/B,eAAe,QAAQ,MAAM;IAC3B,IAAI,MACF,KAAK,QAAQ,QAAQ,CAAC;GAC1B;GACA,SAAS;IACP,IAAI,CAAC,MACH;IACF,OAAO;IACP,IAAI,KAAK,WAAW,MAAM,YACxB;IACF,KAAK,cAAc,IAAI;IACvB,MAAM,UAAU,QAAQ,IAAI,OAAO,EAAE;IACrC,IAAI,SAAS;KACX,QAAQ,WAAW,IAAI;KACvB,KAAK;IACP;IACA,OAAO,SAAS;KAAE,WAAW,OAAO;KAAI,MAAM,OAAO;KAAM,QAAQ;IAAU,CAAC;GAChF;EACF;CACF;CAEA,OAAO;EACL,YAAa,OAAO,IAAI,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC;EAC3D,MAAM,cAAc;GAClB,MAAM,SAAS,OAAO,IAAI,QAAQ,IAAI,SAAS,IAAI,KAAA;GACnD,OAAO,SAAS,KAAK,MAAM,IAAI,KAAA;EACjC;EACA,OAAM,cAAc,OAAO,KAAK,QAAQ,IAAI,SAAS,IAAI,OAAO,QAAQ,IAAI,SAAS,CAAE,IAAI,KAAA;EAC3F;EACA,OAAO,WAAW;GAChB,MAAM,SAAS,QAAQ,IAAI,SAAS;GACpC,IAAI,CAAC,QACH,OAAO;GACT,QAAQ,OAAO,SAAS;GAExB,IAAI,OAAO,WACT,YAAY,CAAC,GAAG,UAAU,QAAO,MAAK,EAAE,cAAc,aAAa,EAAE,cAAc,OAAO,SAAS,GAAG;IAAE;IAAW,WAAW,OAAO;GAAU,CAAC;GAClJ,KAAK;GACL,MAAM,OAAO,MAAM,IAAI,SAAS;GAChC,MAAM,OAAO,SAAS;GACtB,MAAM,WAAW,CAAC,EAAE,MAAM,uBAAuB;GACjD,MAAM,cAAc,IAAI;GACxB,OAAO;EACT;EACA,UAAU,WAAW,QAAQ,WAAW,MAAM,IAAI,SAAS,CAAC,EAAE,QAAQ,QAAQ,MAAM;EACpF,QAAQ;GACN,KAAK,MAAM,QAAQ,MAAM,OAAO,GAC9B,KAAK,SAAS;GAChB,KAAK,MAAM,MAAM,QAAQ,OAAO,CAAC,GAC/B,IAAI;IACF,GAAG;GACL,QACM,CAEN;EAEJ;EACA,UAAS,OAAM,KAAK,QAAQ,KAAK,EAAE;CACrC;AACF;;;;;;;;ACrPA,SAAgB,oBAAoB,SAAyB;CAC3D,MAAM,MAAM,KAAK,SAAS,kBAAkB;CAC5C,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;CAClC,OAAO;AACT;;AAGA,SAAgB,gBAAgB,MAA0B,KAAa,SAAyB;CAC9F,OAAO,QAAQ,iBAAiB,IAAI,IAAI,oBAAoB,OAAO,IAAI;AACzE;;AAGA,SAAgB,cAAc,UAAyC,MAAuB;CAC5F,MAAM,SAAS,iBAAiB,IAAI;CACpC,OAAO,SAAS,SAAS,KAAK,CAAC,CAAC,MAAK,YAAW,QAAQ,SAAS,OAAO,QAAQ,QAAQ,WAAW,QAAQ,IAAI;AACjH;;AAGA,SAAgB,gBAAgB,UAAyC,MAAkD;CACzH,MAAM,SAAS,iBAAiB,IAAI;CACpC,OAAO,SAAS,SAAS,KAAK,CAAC,CAAC,MAAK,YAAW,QAAQ,SAAS,OAAO,IAAI,CAAC,EAAE,QAAQ,KAAA;AACzF;;;;;AAMA,SAAgB,qBAAqB,OAAiI;CACpK,MAAM,EAAE,aAAa;CACrB,MAAM,UAAU,qBAAqB;EAAE,cAAc,MAAM;EAAc,WAAW,MAAM;CAAU,CAAC;CACrG,MAAM,UAAU,SAAuE;EACrF,MAAM,OAAO,SAAS,KAAK,CAAC,CAAC,MAAK,YAAW,QAAQ,SAAS,IAAI;EAClE,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,EAAE,IAAI,KAAA;EAC7C,IAAI,CAAC,QAAQ,CAAC,MACZ,MAAM,IAAI,MAAM,oBAAoB,KAAK,GAAG;EAC9C,OAAO;GAAE;GAAM,OAAO,KAAK;EAAM;CACnC;CACA,MAAM,UAAU;EACd;;EAEA,eAAe,KAAa,SAA2B,OAAO,QAAQ,KAAK,IAAI,CAAC,CAAC,UAAU,oBAAoB,MAAM,QAAQ,CAAC,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC;EACrJ,MAAM,OAAO,KAAa,MAAwC;GAChE,MAAM,SAAS,QAAQ,KAAK,IAAI;GAChC,IAAI,CAAC,OAAO,WAAW,CAAC,OAAO,KAC7B,OAAO;GAET,MAAM,UAAU,MAAM,OAAO,OAAO,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,mBAAmB,EAAE,KAAK,OAAO,IAAI,GAAG,EAAE,MAAM,MAAM,CAAC;GACnH,OAAO;IAAE,GAAG;IAAQ,KAAK,QAAQ;GAAI;EACvC;EACA,MAAM,QAAQ,KAAa,MAAe,SAAS,WAAwE;GACzH,MAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,IAAI,EAAE,IAAI;GAChD,IAAI,CAAC,OAAO,SACV,OAAO,EAAE,cAAc,OAAO,IAAI;GACpC,MAAM,EAAE,MAAM,UAAU,OAAO,OAAO,QAAQ,IAAI;GAClD,MAAM,UAAU,qBAAqB;IAAE;IAAM,KAAK,OAAO;GAAI,CAAC;GAC9D,MAAM,SAAS,MAAM,QAAQ,MAAM,EAAE,KAAK,OAAO,IAAI,CAAC;GACtD,IAAI;IACF,MAAM,UAAU,MAAM,mBAAmB;KAAE;KAAS;KAAQ,KAAK,OAAO;KAAK;KAAO;IAAO,CAAC;IAC5F,OAAO;KAAE,cAAc,oBAAoB,MAAM,QAAQ,CAAC;KAAG;IAAQ;GACvE,UACQ;IACN,MAAM,QAAQ,QAAQ,MAAM;GAC9B;EACF;CACF;CACA,OAAO;EACL,GAAG;;EAEH,aAAa;GAAE,eAAe,QAAQ;GAAS,cAAc,QAAQ;GAAQ,eAAe,QAAQ;EAAQ;CAC9G;AACF;;AAGA,SAAgB,mBAAmB,UAAoD;CACrF,MAAM,QAAQ,SAAS;CACvB,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAA;AAC5E;;;;;AAeA,SAAS,oBAAoB,SAAwB,QAAgD;CACnG,IAAI;CACJ,MAAM,UAA6B,CAAC;CACpC,MAAM,YAAyC;EAC7C,IAAI,CAAC,QAAQ,QAAQ,GAAG;GACtB,OAAO,OAAO;GACd,KAAK,MAAM,MAAM,QAAQ,OAAO,CAAC,GAC/B,KAAK,QAAQ,EAAE;EACnB;EACA,OAAO;CACT;CACA,OAAO;EACL,YAAY,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC;EAC9B,MAAK,cAAa,IAAI,CAAC,EAAE,IAAI,SAAS;EACtC,OAAM,cAAa,IAAI,CAAC,EAAE,KAAK,SAAS;EACxC,OAAO,QAAQ,YAAY,MAAM;GAC/B,MAAM,WAAW,IAAI;GACrB,IAAI,CAAC,UACH,MAAM,IAAI,qBAAqB,iBAAiB,kBAAkB,0DAA0D;GAC9H,OAAO,SAAS,OAAO,QAAQ,YAAY,IAAI;EACjD;EACA,SAAQ,cAAa,IAAI,CAAC,EAAE,OAAO,SAAS,KAAK;EACjD,UAAU,WAAW,QAAQ,WAAW,IAAI,CAAC,EAAE,QAAQ,WAAW,QAAQ,MAAM;EAChF,QAAQ;GACN,IAAI,MACF,OAAO,KAAK,MAAM;GACpB,KAAK,MAAM,MAAM,QAAQ,OAAO,CAAC,GAC/B,IAAI;IACF,GAAG;GACL,QACM,CAEN;EAEJ;EACA,UAAS,OAAO,OAAO,KAAK,QAAQ,EAAE,IAAI,KAAK,QAAQ,KAAK,EAAE;CAChE;AACF;AAEA,SAAgB,eAAe,EAAE,KAAK,cAAc,WAAW,WAON;CACvD,MAAM,EAAE,KAAK,WAAW,WAAW;CACnC,MAAM,UAAU,WAAmB,UAAqC,SACtE,kBAAkB;EAAE;EAAW,OAAO,OAAO,IAAI,SAAS,CAAC,EAAE;EAAO;CAAU,GAAG;EAAE;EAAU,OAAO;CAAU,GAAG,IAAI;CACvH,MAAM,iCAAiB,IAAI,IAAyB;CACpD,MAAM,gBAAyB,IAAI,gBAAgB,KAAA,KAAa,gBAAgB,UAAU,IAAI,aAAa,CAAC;CAC5G,MAAM,WAAW,oBAAoB,eAAe,sBAAsB;EACxE,SAAS,IAAI,YAAY;EACzB;EACA,QAAQ;EACR,GAAI,IAAI,aAAa,gBAAgB,EAAE,eAAe,IAAI,YAAY,cAAc,IAAI,CAAC;EACzF,mBAAmB,mBAAmB,IAAI,aAAa,CAAC;EACxD,QAAQ;GACN,SAAS,WAAW;IAClB,UAAU;KAAE,MAAM;KAAkB,GAAG;IAAO,CAAC;IAC/C,IAAI,OAAO,WAAW,UACpB;IACF,KAAK,MAAM,aAAa,eAAe,IAAI,OAAO,IAAI,KAAK,CAAC,GAC1D,QAAQ,SAAS;IACnB,eAAe,OAAO,OAAO,IAAI;GACnC;GACA,UAAU,WAAW,SAAS,OAAO,WAAW,QAAQ,eAAe,KAAK,uDAAuD;GACnI,OAAO,WAAW,SAAS,OAAO,WAAW,QAAQ,GAAG,KAAK,UAAU;GACvE,SAAS,WAAW,MAAM,YAAY;IACpC,OAAO,WAAW,SAAS,GAAG,KAAK,sBAAsB,QAAQ,mBAAmB;IACpF,UAAU,SAAS;GACrB;EACF;CACF,CAAC,CAAC;CAEF,IAAI,QAAQ,GACV,SAAS,KAAK;CAUhB,OAAO;EAAE;EAAU,QAAA;GARjB,QAAO,SAAQ,gBAAgB,UAAU,IAAI;GAC7C,SAAQ,SAAQ,cAAc,UAAU,IAAI;GAC5C,UAAU,WAAW,SAAS;IAC5B,MAAM,WAAW,eAAe,IAAI,IAAI,qBAAK,IAAI,IAAY;IAC7D,SAAS,IAAI,SAAS;IACtB,eAAe,IAAI,MAAM,QAAQ;GACnC;EAEsB;CAAE;AAC5B;;;;;;;;;;;AC9MA,SAAgB,iBACd,OACA,MACgC;CAChC,IAAI,SAA6B;CACjC,IAAI,SAAwB;CAE5B,MAAM,qBAAoC;EACxC,IAAI,QACF,OAAO;EACT,IAAI;GAGF,UAAU,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC;GACvC,MAAM,IAAI,kBAAkB,KAAK,KAAK,KAAK,cAAc,GAAG,EAC1D,OAAO,IACT,CAAC;GACD,EAAE,GAAG,eAAe,CAAE,CAAC;GACvB,SAAS;GACT,SAAS,aAAa,YAAY;IAAE,QAAQ;IAAG,UAAU;GAAO,CAAC,CAAC;GAClE,OAAO;EACT,QACM;GACJ,OAAO;EACT;CACF;CAEA,MAAM,SAAS,MAAM,KAAK,aAAa,EAAE,MAAM,cAAc;EAC3D,aAAa,CAAC,EAAE,KAAK,YAAY;GAAE,QAAQ;GAAM;EAAQ,CAAC;CAC5D,CAAC;CAED,OAAO,EACL,OAAO,YAAY;EACjB,OAAO;EACP,MAAM,IAAI;EACV,SAAS;EACT,SAAS;EACT,IAAI,CAAC,GACH;EACF,MAAM,IAAI,SAAe,YAAY;GAGnC,EAAE,KAAK,eAAe,QAAQ,CAAC;GAC/B,EAAE,KAAK,eAAe,QAAQ,CAAC;GAC/B,EAAE,IAAI;EACR,CAAC;CACH,EACF;AACF;;;AC/CA,SAAS,YAAwC,SAA4B;CAC3E,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAW,CAAC;CAClB,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,KAAK,IAAI,MAAM,IAAI,GACrB;EACF,KAAK,IAAI,MAAM,IAAI;EACnB,IAAI,KAAK,KAAK;CAChB;CACA,OAAO;AACT;AAEA,SAAgB,0BAA0B,KAAa,QAAgB,UAAwB,UAAoC,CAAC,GAAsB;CAMxJ,MAAM,EAAE,SAAS,UAAU,oBAAoB;EAC7C;EACA;EACA,eAAe,SAAS,yBAAyB;EACjD,OAAO,SAAS,uBAAuB;CACzC,CAAC;CACD,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAI,UAAS,MAAM,OAAO,IAAI,CAAC;CAC7D,MAAM,iBAAiB,CAAC,GAAG,SAAS,GAAG,MAAM,QAAO,UAAS,CAAC,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC;CAM3F,OALmB,gBAAgB;EACjC,YAAY;EACZ,SAAS,SAAS;EAClB,GAAI,SAAS,mBAAmB,EAAE,eAAe,SAAS,iBAAiB,IAAI,CAAC;CAClF,CACgB;AAClB;AAEA,SAAgB,qBAAqB,OAKf;CAGpB,OAAO,YAAY;EAAC,GAAG,MAAM;EAAY,GAAG,MAAM;EAAQ,GAAI,MAAM,UAAU,CAAC;EAAI,GAAI,MAAM,UAAU,CAAC;CAAE,CAAC;AAC7G;AAEA,SAAgB,oBACd,KACA,oBACA,OACc;CAGd,QAAQ,SAAS,QAAQ,WACvB,kBACE,oBAAoB,SAAS,GAAG,GAChC,KAAA,GACA,MAAM,CAAC,CAAC,OACR;EACE,GAAI,QAAQ,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;EAC3D,GAAI,qBACA,EAAE,oBAAoB,WAA4B,IAAI,iBAAiB;GAAE,MAAM,OAAO;GAAM,OAAO,mBAAmB;EAAE,CAAC,EAAE,IAC3H,CAAC;CACP,CACF;AACJ;AAEA,SAAgB,wBAAwB,OAAc,cAAsB,WAAmD;CAO7H,OAAO,iBAAiB,MAAM,OAAO,EACnC,KAAK,sBAAsB;EAAE,SAAS;EAAc;CAAU,CAAC,EACjE,CAAC;AACH;AAEA,SAAgB,sBAAsB,EAAE,WAAW,OAAO,aAAqC;CAG7F,MAAM,MAAM,KAAK,sBAAsB,EAAE,MAAM,aAAa;EAC1D,UAAU;GAAE,MAAM;GAAY;GAAW;GAAM;EAAO,CAAC;CACzD,CAAC;CAID,MAAM,MAAM,KAAK,sBAAsB,QAAQ;EAC7C,IAAI,IAAI,IACN;EACF,MAAM,OAAQ,IAAI,MAA6B;EAC/C,UAAU;GACR,MAAM;GACN;GACA,MAAM,IAAI;GACV,QAAQ;GACR,WAAW,IAAI;GACf,OAAO,IAAI,MAAM;GACjB,GAAI,OAAO,SAAS,WAAW,EAAE,KAAK,IAAI,CAAC;EAC7C,CAAC;CACH,CAAC;CACD,MAAM,MAAM,KAAK,gBAAgB,EAAE,WAAW;EAC5C,UAAU;GAAE,MAAM;GAAc;GAAW;GAAM,QAAQ;EAAY,CAAC;CACxE,CAAC;CACD,MAAM,MAAM,KAAK,+BAA+B;EAC9C,UAAU;GAAE,MAAM;GAAe;EAAU,CAAC;CAC9C,CAAC;AACH;;;AC1GA,SAAgB,sBACd,WACA,cAA2B,aACP;CACpB,OAAO,UAAU,gBAAgB,UAAU,aAAa,kBAAkB;AAC5E;;AAGA,SAAS,oBACP,UACA,WACa;CACb,MAAM,MAAM,UAAU;CACtB,IAAI,OAAO,QAAQ,YAAY,OAAO,WACpC,OAAO;CACT,OAAO;AACT;;;;;;AAOA,SAAS,yBACP,UACA,WACS;CACT,MAAM,MAAM,UAAU;CACtB,OAAO,OAAO,QAAQ,YAAY,IAAI,SAAS,KAAK,EAAE,OAAO;AAC/D;AAEA,SAAS,iBACP,UACA,WACoB;CACpB,IAAI,yBAAyB,UAAU,SAAS,GAC9C,OAAO,KAAA;CACT,MAAM,MAAM,UAAU;CACtB,OAAO,OAAO,QAAQ,YAAY,IAAI,SAAS,IAAI,MAAM,KAAA;AAC3D;;;;;;;AAQA,SAAgB,sBAAsB,KAAgD;CACpF,OAAO,SAAS,cAAc,WAAyD,cAA2B,aAAa;EAC7H,IAAI,eAAe;EAEnB,MAAM,aAAa,sBAAsB,WAAW,WAAW;EAC/D,IAAI;GACF,OAAO,WAAW,QAAQ;EAC5B,SACO,KAAK;GACV,MAAM,UAAW,IAAc,WAAW,OAAO,GAAG;GACpD,IAAI,oDAAoD,KAAK,OAAO,GAClE,MAAM,IAAI,MAAM,sBAAsB,WAAW,MAAM,iCAAiC;GAC1F,MAAM;EACR;CACF;AACF;;;;;AAMA,SAAgB,aACd,WACA,aACA,UAC+C;CAC/C,MAAM,aAAa,sBAAsB,WAAW,WAAW;CAI/D,OAAO;EAAE;EAAa,SADN,YAAY,WAAW,gBAAgB,oBAAoB,gBAAgB;CAC7D;AAChC;AAEA,SAAgB,oBACd,UACA,WAOA;CACA,MAAM,cAAc,oBAAoB,UAAU,SAAS;CAC3D,MAAM,qBAAqB,sBAAsB,WAAW,WAAW;CAGvE,MAAM,gBAAgB,iBAAiB,UAAU,SAAS;CAC1D,MAAM,EAAE,SAAS,UAAU,aAAa,WAAW,aAAa,aAAa;CAa7E,OAAO;EAAE;EAAa;EAAoB;EAAe;EAAO,gBALzC,sBACrB,UAAU,YACV;GAAE,UAAU;GAAa;EAAM,IAC/B,MAAK,UAAU,OAAO,KAAA,CAEqD;CAAE;AACjF;AAEA,SAAgB,mBAAmB,OAUjC;CACA,MAAM,EAAE,WAAW,aAAa,gBAAgB,kBAAkB;CAQlE,MAAM,kBAAkB,cAAc,WAAW,WAAW;CAC5D,MAAM,oCAAoB,IAAI,IAAyB,CAAC,CAAC,aAAa,gBAAgB,IAAI,CAAC,CAAC;CAC5F,MAAM,iBAA6B,CAAC;CACpC,MAAM,oCAAoB,IAAI,IAAI,CAAC,gBAAgB,IAAI,CAAC;CACxD,KAAK,MAAM,SAAS,gBAAgB;EAClC,IAAI,kBAAkB,IAAI,MAAM,QAAQ,GACtC;EACF,MAAM,aAAa,UAAU,MAAM;EACnC,IAAI,CAAC,YACH;EACF,IAAI;EACJ,IAAI;GACF,WAAW,WAAW,QAAQ;EAChC,QACM;GACJ;EACF;EACA,IAAI,kBAAkB,IAAI,SAAS,IAAI,GACrC;EACF,kBAAkB,IAAI,SAAS,IAAI;EACnC,kBAAkB,IAAI,MAAM,UAAU,SAAS,IAAI;EACnD,eAAe,KAAK,QAAQ;CAC9B;CACA,OAAO;EAAE;EAAiB;EAAmB;EAAgB;CAAkB;AACjF;AAEA,SAAgB,0BAA0B,OAKd;CAC1B,MAAM,EAAE,UAAU,aAAa,mBAAmB,kBAAkB;CASpE,MAAM,oBAA6C,CAAC;CACpD,IAAI,SAAS,kBAAkB,eAAe,YAAY,WAAW,GAAG;EACtE,MAAM,UAA6B,CAAC;EACpC,KAAK,MAAM,CAAC,KAAK,iBAAiB,mBAChC,KAAK,MAAM,QAAQ,cAAc,UAAU,GAAG,GAC5C,QAAQ,KAAK;GAAE,UAAU;GAAc,OAAO;EAAK,CAAC;EAExD,IAAI,QAAQ,SAAS,GAAG;GACtB,kBAAkB,QAAQ,YAAY,WAAW,OAAO;GACxD,kBAAkB,eAAe,sBAAsB,OAAO;EAChE;CACF;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1IA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;AAyD3B,SAAgB,iBAAiB,OAAgC,CAAC,GAAmB;CACnF,MAAM,QAAuB,KAAK,SAAS;CAI3C,IAAI,UAAU,QACZ,OAAO;EAAE,OAAO,CAAC;EAAG,OAAO;CAAK;CAElC,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;CACpC,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAClC,MAAM,UAAU,KAAK,UAAU,UAAA,CAAW,QAAQ,OAAO,EAAE;CAC3D,MAAM,cAAcC,cAAY,GAAG,KAAK;CAWxC,MAAM,aAAa,KAAK,QAAQ,sBAAsB;EAAE;EAAK,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;CAAG,CAAC,IAAI,CAAC;CAE3H,MAAM,iBAAqD;EACzD;GAAE,MAAM,QAAQ,MAAM,mBAAmB;GAAG,QAAQ;EAAO;EAC3D;GAAE,MAAM,QAAQ,MAAM,IAAI,OAAO,WAAW;GAAG,QAAQ;EAAO;EAC9D;GAAE,MAAM,QAAQ,MAAM,mBAAmB;GAAG,QAAQ;EAAO;EAC3D,GAAG,WAAW,QAAO,MAAK,EAAE,WAAW,MAAM,CAAC,CAAC,KAAI,OAAM;GAAE,MAAM,EAAE;GAAM,QAAQ;EAAgB,EAAE;CACrG;CACA,MAAM,oBAA2D;EAC/D;GAAE,MAAM,QAAQ,aAAa,WAAW;GAAG,QAAQ;EAAU;EAC7D;GAAE,MAAM,QAAQ,aAAa,mBAAmB;GAAG,QAAQ;EAAU;EACrE;GAAE,MAAM,QAAQ,aAAa,IAAI,OAAO,WAAW;GAAG,QAAQ;EAAU;EACxE;GAAE,MAAM,QAAQ,aAAa,WAAW;GAAG,QAAQ;EAAU;EAC7D,GAAG,WAAW,QAAO,MAAK,EAAE,WAAW,SAAS,CAAC,CAAC,KAAI,OAAM;GAAE,MAAM,EAAE;GAAM,QAAQ;EAAmB,EAAE;CAC3G;CAUA,MAAM,mBAAmB,IAAI,IAAI,WAAW,KAAI,MAAK,EAAE,IAAI,CAAC;CAM5D,MAAM,4BAAY,IAAI,IAAiC;CACvD,KAAK,MAAM,KAAK,YACd,IAAI,CAAC,UAAU,IAAI,EAAE,IAAI,GACvB,UAAU,IAAI,EAAE,MAAM,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC;CAEzD,MAAM,qBAAqB;EACzB,SAAS,WAAW,MAAK,MAAK,EAAE,WAAW,aAAa,UAAU,IAAI,EAAE,IAAI,CAAC;EAC7E,MAAM,WAAW,MAAK,MAAK,EAAE,WAAW,UAAU,UAAU,IAAI,EAAE,IAAI,CAAC;CACzE;CAEA,MAAM,UAA4D,CAAC;CACnE,IAAI,UAAU,WACZ,QAAQ,KAAK,GAAG,cAAc;CAChC,IAAI,UAAU,QACZ,QAAQ,KAAK,GAAG,iBAAiB;CAEnC,MAAM,QAAwB,CAAC;CAC/B,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,KAAK,IAAI,EAAE,IAAI,GACjB;EACF,MAAM,OAAO,iBAAiB,IAAI,EAAE,IAAI,IACpC,UAAU,IAAI,EAAE,IAAI,KAAK,OACzB,cAAc,EAAE,MAAM,EAAE,MAAM;EAClC,IAAI,MAAM;GACR,KAAK,IAAI,EAAE,IAAI;GACf,IAAI,CAAC,iBAAiB,IAAI,EAAE,IAAI,KAAK,mBAAmB,EAAE,WAAW,iBAAiB,KAAK,QAAQ,GACjG;GACF,MAAM,KAAK,IAAI;EACjB;CACF;CAEA,IAAI,MAAM,WAAW,GACnB,OAAO;EAAE;EAAO,OAAO;CAAK;CAE9B,OAAO;EAAE;EAAO,OAAO,oBAAoB,KAAK;CAAE;AACpD;;;;;;;;;;;;;AAcA,SAAgB,oBAAoB,OAAwC;CAC1E,IAAI,MAAM,WAAW,GACnB,OAAO;CAKT,OAAO;EACL;EACA;EACA,GAPe,MAAM,KAAK,MAAM;GAChC,MAAM,QAAQ,EAAE,WAAW,YAAY,YAAY;GACnD,OAAO,MAAM,EAAE,KAAK,IAAI,MAAM,OAAO,EAAE,SAAS,KAAK;EACvD,CAIY;CACZ,CAAC,CAAC,KAAK,MAAM;AACf;AAEA,SAAS,cAAc,MAAc,QAAiD;CAKpF,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO;CACT,IAAI;CACJ,IAAI;EACF,MAAM,aAAa,MAAM,MAAM;CACjC,SACO,KAAK;EACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,4CAA4C,KAAK,KAAKC,eAAa,GAAG,EAAE,GAAG;EAClG,OAAO;CACT;CAGA,MAAM,WAAW,IAAI,SAAS,qBAC1B,GAAG,IAAI,MAAM,GAAG,kBAAkB,EAAE,sBAAsB,IAAI,SAAS,mBAAmB,mCAC1F;CACJ,IAAI,SAAS,KAAK,CAAC,CAAC,WAAW,GAC7B,OAAO;CACT,OAAO;EAAE;EAAM;EAAQ;CAAS;AAClC;;;;AC3NA,MAAa,yBAAyB;CACpC;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,GAAG;AAEV,MAAM,SAAS;CACb,KAAK;EAAE,MAAM;EAAU,aAAa;CAAiE;CACrG,UAAU;EACR,MAAM;EACN,aAAa;CACf;CACA,GAAG;EAAE,MAAM;EAAU,aAAa;CAAuD;CACzF,GAAG;EAAE,MAAM;EAAU,aAAa;CAAqC;AACzE;AAEA,MAAM,YAAY;CAChB,MAAM;CACN,aAAa;AACf;AAEA,SAAgB,mBAAmB,SAAiF;CAClH,MAAM,OAAO,OAA4B,IAAO,OAA2B,WAAwB;EACjG,MAAM,MAAM,MAAM,QAAQ,IAAI,OAAO,MAAM;EAC3C,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,GAAG,IAAI,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,EAAE;EAC5D,OAAO,IAAI;CACb;CACA,MAAM,QACJ,MACA,aACA,YACA,SACA,WAAqB,CAAC,OACT;EACb,MAAM;GACJ;GACA;GACA,aAAa;IAAE,MAAM;IAAU;IAAY,GAAI,SAAS,SAAS,EAAE,SAAS,IAAI,CAAC;IAAI,sBAAsB;GAAM;EACnH;EACA;CACF;CAEA,OAAO;EACL,cAAc,KACZ,gBACA,qPACA;GAAE,KAAK,EAAE,MAAM,SAAS;GAAG,MAAM,EAAE,MAAM,UAAU;EAAE,GACrD,OAAO,OAAO,QAAQC,aAAW,MAAM,KAAK,QAAQ,KAAK,OAAO,CAAC,OAAO,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAC/F;EACA,kBAAkB,KAChB,oBACA,gIACA;GACE,KAAK,EAAE,MAAM,SAAS;GACtB,QAAQ;IAAE,MAAM;IAAU,MAAM;KAAC;KAAQ;KAAW;IAAQ;GAAE;GAC9D,WAAW;IAAE,MAAM;IAAU,MAAM;KAAC;KAAQ;KAAoB;IAAM;GAAE;GACxE,WAAW,EAAE,MAAM,SAAS;EAC9B,GACA,OAAO,OAAO,QACZA,aAAW,MAAM,KAAK,YAAY,KAAK,OAAO;GAAC;GAAO;GAAU;GAAa;EAAW,CAAC,GAAG,IAAI,MAAM,CAAC,CAC3G;EACA,kBAAkB,KAChB,oBACA,6MACA,CAAC,GACD,OAAO,QAAQ,QAAQ,aAAa,MAAM,KAAK,YAAY,CAAC,GAAG,IAAI,MAAM,CAAC,CAC5E;EACA,oBAAoB,KAClB,sBACA,8IACA,EAAE,KAAK,OAAO,IAAI,GAClB,OAAO,OAAO,QAAsC;GAClD,MAAM,OAAO,MAAM,KAAK,cAAc,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,MAAM;GACtE,OAAO,CACL;IACE,MAAM;IACN,MAAM,cAAc,KAAK,MAAM,GAAG,KAAK,OAAO,UAAU,KAAK,MAAM;GACrE,GACA;IAAE,MAAM;IAAS,WAAW,KAAK;IAAW,MAAM,KAAK;GAAK,CAC9D;EACF,CACF;EACA,eAAe,KACb,iBACA,+GACA;GAAE,GAAG;GAAQ;EAAU,GACvB,OAAO,OAAO,QAAQ;GACpB,MAAM,MAAM,MAAM,KAAK,SAAS,KAAK,OAAO;IAAC;IAAO;IAAY;IAAK;IAAK;GAAW,CAAC,GAAG,IAAI,MAAM;GACnG,OAAO,WAAW,IAAI,SAAS,YAAY,IAAI,OAAO,MAAM,YAAY,GAAG;EAC7E,CACF;EACA,cAAc,KACZ,gBACA,6LACA;GACE,GAAG;GACH,MAAM,EAAE,MAAM,SAAS;GACvB,OAAO,EAAE,MAAM,UAAU;GACzB,QAAQ,EAAE,MAAM,UAAU;GAC1B;EACF,GACA,OAAO,OAAO,QAAQ;GACpB,MAAM,MAAM,MAAM,KAChB,QACA,KAAK,OAAO;IAAC;IAAO;IAAY;IAAK;IAAK;IAAQ;IAAS;IAAU;GAAW,CAAC,GACjF,IAAI,MACN;GACA,MAAM,OAAO,OAAO,MAAM,QAAQ,EAAE;GACpC,MAAM,SAAS,IAAI,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,EAAE,EAAE,KAAK,KAAK;GACrE,OAAO,WAAW,IAAI,SAAS,SAAS,OAAO,SAAS,IAAI,OAAO,MAAM,SAAS,OAAO,IAAI,GAAG;EAClG,GACA,CAAC,MAAM,CACT;EACA,eAAe,KACb,iBACA,2GACA;GACE,KAAK,EAAE,MAAM,SAAS;GACtB,WAAW;IAAE,MAAM;IAAS,OAAO;KAAE,MAAM;KAAU,MAAM;MAAC;MAAO;MAAW;MAAQ;KAAO;IAAE;GAAE;EACnG,GACA,OAAO,OAAO,QAAQ;GACpB,MAAM,MAAM,MAAM,KAAK,SAAS,KAAK,OAAO,CAAC,OAAO,WAAW,CAAC,GAA+B,IAAI,MAAM;GAEzG,OAAO,WAAW,WADL,MAAM,QAAQ,MAAM,SAAS,KAAK,MAAM,UAAU,SAAS,GAAI,MAAM,UAAuB,KAAK,GAAG,EAAE,KAAK,KACpF,OAAO,MAAM,GAAG,EAAE,IAAI,GAAG;EAC/D,GACA,CAAC,KAAK,CACR;EACA,gBAAgB,KACd,kBACA,qFACA;GAAE,KAAK,OAAO;GAAK,UAAU,OAAO;GAAU,IAAI,EAAE,MAAM,SAAS;GAAG,IAAI,EAAE,MAAM,SAAS;EAAE,GAC7F,OAAO,OAAO,QAAQ;GACpB,MAAM,MAAM,MAAM,KAAK,UAAU,KAAK,OAAO;IAAC;IAAO;IAAY;IAAM;GAAI,CAAC,GAAG,IAAI,MAAM;GAEzF,OAAO,GADU,IAAI,YAAY,KAAA,IAAY,eAAe,IAAI,WAAW,EAAE,IAAI,IAAI,QAAQ,KAAK,cAC7E,YAAY,GAAG;EACtC,CACF;EACA,kBAAkB,KAChB,oBACA,kIACA;GACE,MAAM,EAAE,MAAM,SAAS;GACvB,UAAU,EAAE,MAAM,SAAS;GAC3B,aAAa,EAAE,MAAM,SAAS;GAC9B,WAAW,EAAE,MAAM,SAAS;EAC9B,GACA,OAAO,OAAO,QACZA,aAAW,MAAM,KAAK,YAAY,KAAK,OAAO;GAAC;GAAQ;GAAY;GAAe;EAAW,CAAC,GAAG,IAAI,MAAM,CAAC,CAChH;EACA,kBAAkB,KAChB,oBACA,oJACA,EAAE,YAAY,EAAE,MAAM,SAAS,EAAE,GACjC,OAAO,OAAO,QAAQ;GACpB,MAAM,EAAE,UAAU,MAAM,KAAK,YAAY,KAAK,OAAO,CAAC,YAAY,CAAC,GAAkC,IAAI,MAAM;GAE/G,QADa,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,OAAO,MAAM,CAAC,MAC/D;EACjB,GACA,CAAC,YAAY,CACf;EACA,iBAAiB,KACf,mBACA,6KACA;GAAE,OAAO,EAAE,MAAM,SAAS;GAAG,OAAO;IAAE,MAAM;IAAU,MAAM;KAAC;KAAS;KAAW;IAAK;GAAE;EAAE,GAC1F,OAAO,OAAO,QAAQ,YAAY,MAAM,KAAK,WAAW,KAAK,OAAO,CAAC,SAAS,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,CACtG;CACF;AACF;AAEA,SAAS,KAAuB,OAAgC,MAAmB;CACjF,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,KAAK,MACd,IAAI,MAAM,OAAO,KAAA,KAAa,MAAM,OAAO,MACzC,IAAI,KAAK,MAAM;CAEnB,OAAO;AACT;AAEA,SAAgBA,aAAW,GAA0B;CACnD,MAAM,QAAQ,CAAC,SAAS,EAAE,SAAS,gBAAgB,QAAQ,EAAE,OAAO,eAAe;CACnF,IAAI,EAAE,SACJ,MAAM,KAAK,gBAAgB;CAC7B,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAgB,aAAa,GAA4B;CACvD,MAAM,QAAQ;EAACA,aAAW,EAAE,MAAM;EAAG;EAAI;EAAY,EAAE,WAAW;CAA2B;CAC7F,IAAI,EAAE,YAAY,GAChB,MAAM,KAAK,KAAK,EAAE,UAAU,iEAAiE;CAC/F,IAAI,EAAE,MACJ,MAAM,KAAK,IAAI,SAAS,EAAE,IAAI;CAChC,IAAI,EAAE,OAAO,QACX,MAAM,KAAK,IAAI,kBAAkB,GAAG,EAAE,OAAO,KAAI,MAAK,KAAK,GAAG,CAAC;CACjE,OAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,YAAY,GAA0B;CAC7C,MAAM,QAAkB,CAAC;CACzB,IAAI,EAAE,KACJ,MAAM,KAAK,SAAS,EAAE,KAAK;CAC7B,IAAI,EAAE,OACJ,MAAM,KAAK,WAAW,EAAE,OAAO;CACjC,IAAI,EAAE,QACJ,MAAM,KAAK,qBAAqB,EAAE,OAAO,KAAK,YAAY,EAAE,OAAO,QAAQ,aAAa,EAAE,OAAO,QAAQ,EAAE;CAC7G,IAAI,EAAE,QAAQ,QACZ,MAAM,KAAK,eAAe,GAAG,EAAE,OAAO,KAAI,MAAK,KAAK,GAAG,CAAC;CAC1D,IAAI,EAAE,WACJ,MAAM,KAAK,0DAA0D;CACvE,OAAO,MAAM,SAAS,KAAK,MAAM,KAAK,IAAI,MAAM;AAClD;;AAGA,SAAgB,WAAW,MAAc,GAA0B;CACjE,MAAM,QAAQ,YAAY,CAAC;CAC3B,OAAO,QAAQ,GAAG,OAAO,UAAU,GAAG,KAAK;AAC7C;AAEA,SAAS,YAAY,GAA6D;CAChF,IAAI,EAAE,QAAQ,WAAW,GACvB,OAAO,qBAAqB,EAAE;CAEhC,OAAO,GADO,EAAE,QAAQ,KAAI,MAAK,IAAI,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,EAAE,IAAI,KAAK,IACpE,CAAC,CAAC,KAAK,IAAI,EAAE,UAAU,EAAE;AACzC;;;;;;;ACtQA,MAAM,OAA+B;CACnC,SAAS;CACT,UAAU;CACV,OAAO;CACP,UAAU;CACV,OAAO;CACP,aAAa;CACb,UAAU;CACV,SAAS;CACT,MAAM;CACN,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,OAAO;CACP,UAAU;CACV,YAAY;CACZ,aAAa;AACf;;AAGA,SAAgB,SAAS,KAA4B;CACnD,MAAM,IAAI,IAAI,KAAK,CAAC,CAAC,YAAY;CACjC,IAAI,KAAK,MACP,OAAO,KAAK;CACd,MAAM,OAAO,8BAA8B,KAAK,CAAC;CACjD,IAAI,MAAM;EACR,MAAM,OAAO,KAAK,EAAE,CAAE,YAAY,CAAC,CAAC,WAAW,CAAC;EAChD,IAAI,QAAQ,MAAQ,QAAQ,IAC1B,OAAO,OAAO,aAAa,OAAO,EAAI;CAC1C;CACA,OAAO;AACT;;;;ACrBA,MAAa,0BAA0B;CACrC;CACA;CACA;CACA;AACF,CAAC,CAAC,KAAK,GAAG;AAEV,SAAS,SAAS,GAAyB;CAWzC,OAAO;EATL,EAAE;EACF,IAAI,EAAE,MAAM;EACZ,EAAE,WAAW,WAAW,SAAS,EAAE,aAAa,KAAA,IAAY,KAAK,EAAE,SAAS,KAAK,OAAO,EAAE;EAC1F,EAAE,UAAU,UAAU,YAAY,EAAE,SAAS,IAAI,EAAE,WAAW,OAAO;EACrE,EAAE;EACF,GAAI,EAAE,UAAU,CAAC,WAAW,EAAE,SAAS,IAAI,CAAC;EAC5C,GAAI,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC;EAC/D,OAAO,EAAE;CAED,CAAC,CAAC,KAAK,KAAK;AACxB;AAEA,SAAgB,oBAAoB,WAA4B,WAA0E;CACxI,OAAO;EACL,eAAe;GACb,MAAM;IACJ,MAAM;IACN,aAAa;IACb,aAAa;KAAE,MAAM;KAAU,YAAY,CAAC;KAAG,sBAAsB;IAAM;GAC7E;GACA,mBAAmB;GACnB,MAAM,UAAU;IACd,MAAM,OAAO,MAAM,UAAU,KAAK,SAAS;IAC3C,IAAI,KAAK,WAAW,GAClB,OAAO;IACT,OAAO,KAAK,KAAI,MAAK,KAAK,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI;GACpD;EACF;EACA,eAAe;GACb,MAAM;IACJ,MAAM;IACN,aAAa;IACb,aAAa;KACX,MAAM;KACN,YAAY;MACV,IAAI;OAAE,MAAM;OAAU,aAAa;MAAkC;MACrE,OAAO;OAAE,MAAM;OAAU,aAAa;MAAoC;MAC1E,OAAO;OAAE,MAAM;OAAU,aAAa;MAAiE;KACzG;KACA,UAAU,CAAC,IAAI;KACf,sBAAsB;IACxB;GACF;GACA,mBAAmB;GACnB,MAAM,QAAQ,OAAO;IACnB,MAAM,IAAI,MAAM,UAAU,KAAK,WAAW,OAAO,MAAM,EAAE,GAAG;KAC1D,GAAI,OAAO,MAAM,UAAU,WAAW,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;KAChE,GAAI,OAAO,MAAM,UAAU,WAAW,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;IAClE,CAAC;IAGD,OAAO,GAFM,SAAS,EAAE,QAEX,IADD,EAAE,YAAY,IAAI,MAAM,EAAE,UAAU,oHAAoH,GAC/I,MAAM,EAAE,QAAQ,cAAc,YAAY,EAAE;GACnE;EACF;EACA,gBAAgB;GACd,MAAM;IACJ,MAAM;IACN,aAAa;IACb,aAAa;KACX,MAAM;KACN,YAAY;MACV,IAAI;OAAE,MAAM;OAAU,aAAa;MAAkC;MACrE,MAAM;OAAE,MAAM;OAAU,aAAa;MAAiC;MACtE,MAAM;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,SAAS;OAAG,aAAa;MAAyC;MACxG,QAAQ;OAAE,MAAM;OAAU,aAAa;MAA+D;KACxG;KACA,UAAU,CAAC,IAAI;KACf,sBAAsB;IACxB;GACF;GACA,MAAM,QAAQ,OAAO,KAAK;IACxB,MAAM,KAAK,OAAO,MAAM,EAAE;IAC1B,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;IAC3D,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,CAAC;IACnE,MAAM,QAAkB,CAAC;IACzB,KAAK,MAAM,OAAO,MAAM;KACtB,MAAM,IAAI,SAAS,GAAG;KACtB,IAAI,MAAM,MACR,MAAM,IAAI,MAAM,gBAAgB,IAAI,gEAAgE;KACtG,MAAM,KAAK,CAAC;IACd;IACA,IAAI,CAAC,QAAQ,MAAM,WAAW,GAC5B,MAAM,IAAI,MAAM,6CAA6C;IAC/D,MAAM,SAAS,MAAM,UAAU,KAAK,WAAW,IAAI,EAAE,OAAO,EAAE,CAAC;IAC/D,MAAM,UAAU,MAAM,IAAI,OAAO,MAAM,KAAK,EAAE,CAAC;IAC/C,MAAM,SAAS,KAAK,IAAI,KAAK,IAAI,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,KAAM,CAAC,GAAG,GAAM;IACnG,MAAM,UAAU,OAAO,IAAI;KAAE,SAAS;KAAK,OAAO;KAAQ,QAAQ,IAAI;IAAO,CAAC;IAC9E,MAAM,QAAQ,MAAM,UAAU,KAAK,WAAW,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,IAAI,EAAE,CAAC;IACrF,OAAO,GAAG,SAAS,MAAM,QAAQ,EAAE,MAAM,MAAM,QAAQ,sBAAsB,YAAY,MAAM;GACjG;EACF;CACF;AACF;;;AC1FA,SAAS,sBAAsB,QAA4B,WAAkD;CAC3G,IAAI,UAAU,WAAW,GACvB,OAAO;CACT,MAAM,SAAS,UAAU,KAAK,MAAM;CACpC,OAAO,SAAS,GAAG,OAAO,MAAM,WAAW;AAC7C;;;;;;;;;;;AAYA,SAAgB,UAAU,KAAgD,SAAiB,KAAa,QAAgB,YAAoB,KAAK,gBAM/I;CACA,MAAM,WAAW,IAAI,aAAa;CAGlC,MAAM,mBAAmB,SAAS,oBAAoB;CACtD,MAAM,QAAQ,SAAS,yBAAyB;CAMhD,MAAM,qBAAqB,mBAAmB,KAAA;CAC9C,MAAM,aAAa,qBAAsB,UAAU,UAAU,UAAU,SAAS,SAAS,SAAU;CACnG,MAAM,eAAe,uBAAuB,UAAU,UAAU,UAAU;CAC1E,MAAM,aAAa,iBAAiB;EAClC;EACA;EACA,OAAO;EAEP,OAAO,SAAS,uBAAuB;CACzC,CAAC;CACD,MAAM,YAAY,eAAe,CAAC,GAAG,WAAW,OAAO,GAAG,eAAe,QAAQ,IAAI,WAAW;CAChG,MAAM,QAAQ;EAAE,OAAO;EAAW,OAAO,UAAU,SAAS,IAAI,oBAAoB,SAAS,IAAI;CAAK;CACtG,MAAM,mBAAmB,MAAM,SAAS,KAAA;CAmBxC,MAAM,gBAAgB,iBAAiB;EACrC;EACA;EACA,OAAO;CACT,CAAC;CAED,MAAM,gBAAgB,eAAe,eAAe,WAAW;CAC/D,MAAM,WAAW,gBACb;EAAE,MAAM;EAAe,UAAU,CAAC,GAAI,cAAc,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,GAAI,GAAG,cAAc,QAAQ;CAAE,IAClH;CACJ,MAAM,iBAAiB,SAAS,MAAM;CAOtC,MAAM,eAAe,gBAAgB,SAAS,cAAc,MAAMC,cAAY,GAAG,KAAK,MAAM;CAC5F,MAAM,WAAW;EAAE,KAAK;EAAW,GAAI,iBAAiB,YAAY,EAAE,aAAa,aAAa,IAAI,CAAC;CAAG;CAIxG,OAAO;EACL,QAJa,YAAY,SACvB,gBAAgB;GAAE,GAAG;GAAU;GAAkB;GAAkB,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;EAAG,CAAC,IAClH,iBAAiB;GAAE,GAAG;GAAU;GAAkB;GAAkB,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;EAAG,CAAC;EAGrH,GAAI,MAAM,QAAQ,EAAE,YAAY,MAAM,MAAM,IAAI,CAAC;EAGjD,GAAI,MAAM,MAAM,SAAS,IAAI,EAAE,YAAY,MAAM,MAAM,KAAI,OAAM;GAAE,MAAM,EAAE;GAAM,QAAQ,EAAE;GAAQ,UAAU,EAAE;EAAS,EAAE,EAAE,IAAI,CAAC;EACjI,GAAI,SAAS,OAAO,EAAE,YAAY,SAAS,KAAK,IAAI,CAAC;EACrD,GAAI,SAAS,SAAS,SAAS,IAAI,EAAE,qBAAqB,SAAS,SAAS,IAAI,CAAC;CACnF;AACF;AAEA,SAAgB,cAAc,OAQP;CACrB,MAAM,EAAE,UAAU,kBAAkB;CAOpC,OAAO,sBACL,MAAM,MACN;EACE,GAAI,eAAe,QAAQ,IACvB,CAAC,GAAG,MAAM,0BAA0B,sBAAsB,IAC1D,CAAC,GAAG,MAAM,0BAA0B,GAAG,aAAa;EACxD,GAAI,MAAM,eAAe,CAAC,sBAAsB,IAAI,CAAC;EACrD,GAAI,MAAM,gBAAgB,CAAC,uBAAuB,IAAI,CAAC;CACzD,CACF;AACF;AAEA,SAAgB,kBAAkB,EAAE,WAAW,aAAgE,eAA2C;CAOxJ,UAAU;EACR,MAAM;EACN;EACA,MAAM,eAAe,cAAc;EACnC,UAAU,eAAe,uBAAuB,CAAC;CACnD,CAAC;AACH;AAEA,SAAgB,oBAAoB,EAAE,KAAK,QAAQ,eAI2D;CAC5G,OAAO;EACL,gBAAgB,WAAW;GACzB,OAAO,OAAO,IAAI,SAAS,CAAC,EAAE,YAAY;EAC5C;;;;;;EAOA,MAAM,oBAAoB,WAAW;GACnC,IAAI,QAAQ,OAAO,IAAI,SAAS;GAChC,IAAI,CAAC,OACH,IAAI;IACF,QAAQ,MAAM,YAAY,SAAS;GACrC,QACM;IACJ,OAAO;GACT;GAEF,MAAM,aAAa,KAAK,IAAI;GAE5B,MAAM,UAAU,MAAM;GACtB,MAAM,aAAa,MAAM,sBAAsB,kBAAkB;GACjE,MAAM,YAAY,uBAAuB,iBAAiB,YAAY,OAAO,CAAC;GAE9E,MAAM,WAAW,IAAI,aAAa;GAClC,OAAO,MAAM,MAAM,oBAAoB;IACrC,OAAO;IACP,GAAI,cAAc,OAAO,EAAE,iBAAiB,UAAU,IAAI,CAAC;IAC3D,mBAAmB;IACnB,GAAI,SAAS,eAAe,SAAS,uBACjC,EAAE,kBAAkB,SAAS,qBAAqB,IAClD,CAAC;GACP,CAAC;EACH;EAEA,MAAM,mBAAmB,WAAW;GAClC,IAAI,QAAQ,OAAO,IAAI,SAAS;GAChC,IAAI,CAAC,OACH,IAAI;IACF,QAAQ,MAAM,YAAY,SAAS;GACrC,QACM;IACJ,OAAO;GACT;GAEF,MAAM,aAAa,KAAK,IAAI;GAE5B,MAAM,WAAW,MAAM,MAAM,MAAM,mBAAmB;IACpD,GAAI,MAAM,OAAO,aAAa,EAAE,YAAY,MAAM,MAAM,WAAW,IAAI,CAAC;IACxE,GAAI,MAAM,OAAO,aAAa,EAAE,YAAY,MAAM,MAAM,WAAW,IAAI,CAAC;IACxE,GAAI,MAAM,SAAS,OAAO,EAAE,YAAY,MAAM,SAAS,KAAK,KAAK,IAAI,CAAC;GACxE,CAAC;GASD,MAAM,UAAU,MAAM,MAAM,SAAS;GACrC,MAAM,mBAAmB,YAAY,WAAW,YAAY;GAC5D,MAAM,yBAAyB,uBAAuB,IAAI,aAAa,CAAC,CAAC,qBAAqB;GAC9F,MAAM,oBAAoB,oBAAoB;GAC9C,MAAM,oBAAoB,CAAC,mBACvB,YACA,CAAC,yBAAyB,UAAmB,KAAA;GACjD,MAAM,qBAAqB,MAAM,SAAS,SAAS,EAAE,EAAE;GAEvD,OAAO;IACL,UAAU,YAAY,CAAC;IACvB,MAAM;IACN;IACA,GAAI,oBAAoB,EAAE,kBAAkB,IAAI,CAAC;IACjD,GAAI,qBAAqB,EAAE,mBAAmB,IAAI,CAAC;GACrD;EACF;EAEA,MAAM,qBAAqB,WAAW;GACpC,MAAM,QAAQ,MAAM,YAAY,SAAS;GACzC,MAAM,WAAW,IAAI,aAAa;GAClC,MAAM,UAAU,MAAM,MAAM,SAAS;GAUrC,IAAI,YAAY,WAAW,YAAY,QACrC,MAAM,IAAI,MAAM,QAAQ,WAAW,UAAU,kFAAkF;GACjI,IAAI,CAAC,uBAAuB,SAAS,qBAAqB,GACxD,MAAM,IAAI,MAAM,6BAA6B,SAAS,yBAAyB,OAAO,6DAA6D;GAErJ,MAAM,gBAAgB,MAAM,IAAI,cAAc,MAAM,YAAY;GAChE,MAAM,OAAO,iBAAiB,EAAE,QAAQ,cAAc,OAAO,CAAC;GAC9D,IAAI,WAAW,IAAI,GACjB,OAAO;IAAE;IAAM,SAAS;GAAM;GAShC,MAAM,mBAAmB,SAAS,oBAAoB;GACtD,MAAM,eAAe,YAAY,SAC7B,gBAAgB;IAAE,KAAK,MAAM;IAAK;GAAiB,CAAC,IACpD,iBAAiB;IAAE,KAAK,MAAM;IAAK;GAAiB,CAAC;GACzD,MAAM,WAAW,kBAAkB,YAAY,CAAC,CAAC;GACjD,IAAI,SAAS,KAAK,CAAC,CAAC,WAAW,GAC7B,MAAM,IAAI,MAAM,6DAA6D;GAE/E,UAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;GAC5C,cAAc,MAAM,mBAAmB,UAAU,SAAS,qBAAqB,GAAG,MAAM;GACxF,OAAO;IAAE;IAAM,SAAS;GAAK;EAC/B;CACF;AACF;;;AC9RA,SAAgB,8BACd,OACA,MACY;CACZ,OAAO,MAAM,KAAK,wBAAwB,EAAE,WAAW,OAAO,OAAO,WAAW,gBAAgB,SAAS,OAAO,QAAQ,YAAY,mBAAmB,kBAAkB,aAAa,iBAAiB;EAErM,KAAK;GAAE;GAAW;GAAO;GAAO;GAAW;GAAgB;GAAS;GAAO;GAAQ,GAAG,mCAAmC;IAAE;IAAY;IAAmB;IAAkB;IAAa;GAAW,CAAC;EAAE,CAAC;CAC1M,CAAC;AACH;;;ACVA,MAAM,qBAAqB;AAC3B,MAAM,iBAAiB;AACvB,MAAM,oBAAoB;AAC1B,MAAM,iBAAiB;AAOvB,SAAgB,wBAAwB,SAA4C;CAClF,OAAO;EACL,mBAAmB;EACnB,MAAM;GACJ,MAAM;GACN,aAAa,YAAY;GACzB,aAAa;IACX,MAAM;IACN,YAAY;KACV,YAAY;MACV,MAAM;MACN,aAAa;KACf;KACA,MAAM;MACJ,MAAM;MACN,aAAa;KACf;KACA,OAAO;MACL,MAAM;MACN,aAAa,qCAAqC,mBAAmB,cAAc,eAAe;KACpG;KACA,WAAW;MACT,MAAM;MACN,aAAa,0CAA0C,kBAAkB,cAAc,eAAe;KACxG;IACF;IACA,UAAU,CAAC,YAAY;IACvB,sBAAsB;GACxB;EACF;EACA,MAAM,QAAQ,OAAO,MAAmB;GACtC,MAAM,eAAe,OAAO,MAAM,eAAe,WAAW,MAAM,WAAW,KAAK,CAAC,CAAC,QAAQ,MAAM,EAAE,IAAI;GACxG,IAAI,CAAC,cACH,OAAO;GAGT,MAAM,UAAU,gBADM,QAAQ,iBACc,CAAC;GAC7C,IAAI,QAAQ,WAAW,GACrB,OAAO,CACL,kFACA,wDACF,CAAC,CAAC,KAAK,GAAG;GAGZ,MAAM,WAAW,MAAM,wBAAwB,QAAQ,OAAO,cAAc,OAAO;GACnF,IAAI,SAAS,SAAS,SACpB,OAAO,SAAS;GAElB,MAAM,OAAO,MAAM,QAAQ,MAAM,KAAK,SAAS,SAAS;GACxD,IAAI,CAAC,MACH,OAAO,6BAA6B,SAAS,UAAU;GAEzD,MAAM,OAAO,SAAS,MAAM,MAAM,GAAG,OAAO,kBAAkB,CAAC;GAC/D,MAAM,QAAQ,SAAS,MAAM,OAAO,GAAG,gBAAgB,kBAAkB;GACzE,MAAM,WAAW,SAAS,MAAM,WAAW,GAAG,gBAAgB,iBAAiB;GAC/E,MAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC;GAClC,MAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,SAAS,WAAW,OAAO,KAAK;GAC3E,MAAM,QAAQ,mBAAmB,KAAK,OAAO,KAAK,QAAQ;GAC1D,MAAM,SAAS,CACb,aAAa,WAAW,KAAK,EAAE,EAAE,WAAW,WAAW,KAAK,EAAE,GAAG,KAAK,cAAc,aAAa,WAAW,KAAK,WAAW,EAAE,KAAK,GAAG,IACtI,gBAAgB,QAAQ,EAAE,cAAc,MAAM,OAAO,WAAW,KAAK,MAAM,OAAO,KACpF;GACA,MAAM,OAAO,YAAY,OAAO,KAAK;GACrC,MAAM,WAAW,GAAG,OAAO,KAAK,IAAI,EAAE,IAAI,KAAK;GAC/C,IAAI,SAAS,UAAU,UACrB,OAAO;GACT,OAAO,GAAG,SAAS,MAAM,GAAG,QAAQ,EAAE,sBAAsB,SAAS;EACvE;CACF;AACF;AAEA,SAAgB,6BAA6B,QAA0B;CACrE,OAAO,4BAA4B,MAAM;AAC3C;AAEA,SAAS,eAAe,OAAuB;CAC7C,OAAO,MAAM,QAAQ,MAAM,EAAE,CAAC,CAAC,QAAQ,MAAM,EAAE,CAAC,CAAC,YAAY;AAC/D;AAEA,SAAS,gBAAgB,QAAqC;CAC5D,MAAM,MAAgB,CAAC;CACvB,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,eAAe,KAAK;EACvC,IAAI,CAAC,cAAc,KAAK,IAAI,UAAU,GACpC;EACF,KAAK,IAAI,UAAU;EACnB,IAAI,KAAK,UAAU;CACrB;CACA,OAAO;AACT;AAEA,eAAe,wBACb,OACA,WACA,eACiF;CACjF,MAAM,gBAAgB,eAAe,SAAS;CAM9C,MAAM,WAJa,MADD,MAAM,KAAK,EAAA,CACN,QAAQ,OAAO;EACpC,MAAM,eAAe,eAAe,EAAE;EACtC,OAAO,cAAc,MAAK,UAAS,aAAa,WAAW,KAAK,KAAK,MAAM,WAAW,YAAY,CAAC;CACrG,CACyB,CAAC,CAAC,QAAQ,OAAO;EACxC,MAAM,eAAe,eAAe,EAAE;EACtC,OAAO,iBAAiB,iBACnB,aAAa,WAAW,aAAa,KACrC,cAAc,WAAW,YAAY;CAC5C,CAAC;CAED,IAAI,QAAQ,WAAW,GACrB,OAAO;EAAE,MAAM;EAAM,WAAW,QAAQ;CAAG;CAC7C,IAAI,QAAQ,SAAS,GACnB,OAAO;EACL,MAAM;EACN,SAAS,qBAAqB,UAAU,uBAAuB,QAAQ,OAAO;CAChF;CAGF,OAAO;EACL,MAAM;EACN,SAAS,uBAAuB,UAAU;CAC5C;AACF;AAEA,SAAS,SAAS,OAAgB,KAAa,KAAa,UAA0B;CACpF,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GACrD,OAAO;CACT,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,CAAC,CAAC;AACvD;AAEA,SAAS,YAAY,OAA+B,YAA4B;CAC9E,OAAO,MAAM,KAAK,MAAM,QAAQ;EAC9B,MAAM,UAAU,KAAK,QAAQ,IAAIC,aAAW,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM;EACzE,OAAO,gBAAgB,aAAa,MAAM,EAAE,QAAQ,WAAW,KAAK,EAAE,EAAE,UAAU,KAAK,KAAK,MAAM,QAAQ;CAC5G,CAAC,CAAC,CAAC,KAAK,IAAI;AACd;AAEA,SAASA,cAAY,OAAoC;CACvD,IAAI,MAAM,SAAS,QACjB,OAAO,MAAM;CACf,IAAI,MAAM,SAAS,YACjB,OAAO,eAAe,MAAM;CAC9B,IAAI,MAAM,SAAS,aACjB,OAAO,eAAe,MAAM,KAAK,KAAK,UAAU,MAAM,KAAK;CAC7D,IAAI,MAAM,SAAS,eACjB,OAAO,kBAAkB,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS,UAAU,MAAM,MAAM;CACnG,IAAI,MAAM,SAAS,mBACjB,OAAO,yBAAyB,MAAM;CACxC,OAAO;AACT;AAEA,SAAS,UAAU,OAAwB;CACzC,IAAI;EACF,OAAO,KAAK,UAAU,OAAO,MAAM,CAAC;CACtC,QACM;EACJ,OAAO,OAAO,KAAK;CACrB;AACF;AAEA,SAAS,WAAW,OAAuB;CACzC,OAAO,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,QAAQ,MAAM,QAAQ,CAAC,CAAC,QAAQ,MAAM,MAAM;AAClF;;;AClKA,SAAgB,qBAAqB,YAAyC;CAC5E,MAAM,EAAE,WAAW,MAAM,SAAS;CAClC,MAAM,QAAQ,OAAO,EAAE,KAAK,IAAI,CAAC;CACjC,IAAI,UAAU,WAAW,QAAQ,GAC/B,OAAO;EAAE,MAAM;EAAS;EAAW;EAAM,GAAG;CAAM;CACpD,IAAI,UAAU,WAAW,OAAO,GAC9B,OAAO;EAAE,MAAM;EAAY;EAAW,MAAM,OAAO,KAAK,MAAM,QAAQ,CAAC,CAAC,SAAS,OAAO;EAAG,UAAU;EAAQ,GAAG;CAAM;CACxH,IAAI,cAAc,4BAA4B;EAC5C,MAAM,UAAU,OAAO,KAAK,MAAM,QAAQ,CAAC,CAAC,SAAS,OAAO;EAC5D,IAAI,CAAC,YAAY,OAAO,GACtB,OAAO;GAAE,MAAM;GAAY,WAAW;GAAc,MAAM;GAAS,UAAU;GAAQ,GAAG;EAAM;CAClG;CACA,OAAO;EAAE,MAAM;EAAY;EAAW;EAAM,UAAU;EAAU,GAAG;CAAM;AAC3E;;;;;;;;;;;;;ACDA,SAAgB,wBAAwB,MAYxB;CACd,IAAI,CAAC,KAAK,SACR,OAAO;CACT,MAAM,gBAAgB,OAAO,KAAK,qBAAqB,YAClD,OAAO,SAAS,KAAK,gBAAgB,KACrC,KAAK,mBAAmB,IACzB,KAAK,mBACL;CACJ,OAAO;EACL,WAAW,KAAK;EAChB,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;EACzC,GAAI,KAAK,aAAa;GAAE,UAAU,KAAK,WAAW;GAAU,OAAO,KAAK,WAAW;EAAM,IAAI,CAAC;EAK9F,sBAAsB;CACxB;AACF;;;;;;;;;;AAWA,SAAgB,mBAAmB,MAGjC;CACA,MAAM,cAAc,wBAAwB,IAAI;CAChD,MAAM,gBAAgB,OAAO,KAAK,qBAAqB,YAClD,OAAO,SAAS,KAAK,gBAAgB,KACrC,KAAK,mBAAmB,IACzB,KAAK,mBACL,KAAA;CACJ,OAAO;EAAE;EAAa,GAAI,kBAAkB,KAAA,IAAY,EAAE,cAAc,IAAI,CAAC;CAAG;AAClF;;;;;;;;;;;;;;;;;;;AC9DA,SAAgB,4BAA4B,OAAsD;CAChG,UAAQ,IAAI,gCAAgC,SAAS;AACvD;;;ACUA,SAAgB,mBAAmB,KAAgB,KAA0B,MAAwD;CACnI,OAAO;EACL,aAAa,IAAI,iBAAiB,IAAI;EACtC,cAAc,CAAC;EACf,gBAAgB;GACd,MAAM,SAAS,IAAI,MAAM,SAAS,UAAU;GAC5C,OAAO,OAAO,WAAW,YAAY,gBAAgB,MAAM,IAAI,SAAS;EAC1E;EACA,cAAc,UAAU;GACtB,MAAM,UAAU,IAAI,MAAM;GAC1B,IAAI,CAAC,SACH,OAAO;GACT,QAAQ,QAAQ,UAAU,KAAK;GAC/B,QAAa,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;GACzC,OAAO;EACT;EACA,cAAc,YAAY;GAExB,QAAO,MADY,gBAAgB,IAAI,KAAK,EAAA,CAChC,KAAI,OAAM;IAAE,IAAI,EAAE;IAAI,GAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;IAAI,GAAI,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,IAAI,CAAC;GAAG,EAAE;EACjI;EACA,eAAe,YAAY;EAC3B,eAAe,YAAY;EAC3B,aAAa,WAAW;GACtB,IAAI,OAAO,WAAW,GACpB,OAAO;GACT,KAAK,WAAW,MAAM;GACtB,OAAO;EACT;EAIA,WAAW,YAAY;GACrB,MAAM,SAAS,MAAM,IAAI,MAAM,gBAAgB;GAC/C,OAAO;IAAE,WAAW,IAAI,MAAM;IAAW;GAAO;EAClD;EACA,0BAA0B;EAC1B,iBAAiB;GAEf,IAAI,IAAI,aAAa,CAAC,CAAC,cAAc,OACnC,OAAO;GACT,MAAM,UAAU,IAAI,MAAM;GAC1B,OAAO;IACL,OAAO,IAAI;IACX,GAAI,UAAU,EAAE,WAAW,QAAQ,GAAG,IAAI,CAAC;IAC3C,GAAI,SAAS,cAAc,EAAE,aAAa,QAAQ,YAAY,IAAI,CAAC;IAGnE,QAAQ,OAAO,aAAa;KAC1B,IAAI,CAAC,IAAI,MAAM,gBACb,OAAO;KACT,MAAM,SAAS,MAAM,IAAI,MAAM,eAAe,QAAQ;KACtD,IAAI,QACF,IAAI,UAAU;MAAE,MAAM;MAAoB,WAAW,OAAO;MAAW,IAAI;MAAU,YAAY,OAAO;MAAI,UAAU;KAAO,CAAC;KAChI,OAAO;IACT;GACF;EACF;CACF;AACF;;;ACzEA,SAAgB,sBAAsB,MAQxB;CACZ,MAAM,WAAsB,CAC1B;EACE,MAAM;EACN,aAAa;EACb,MAAM,QAAQ;GACZ,MAAM,MAAM,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;GAC/E,MAAM,OAAO,IAAI,WAAW,IACxB,kCACA,IAAI,KAAI,MAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,aAAa,CAAC,CAAC,KAAK,IAAI;GAChE,IAAI,KAAK,EAAE,MAAM,mBAAmB,OAAO,CAAC;EAC9C;CACF,CACF;CACA,IAAI,KAAK,kBAAkB;EACzB,MAAM,SAAS,KAAK;EACpB,SAAS,KAAK;GACZ,MAAM;GACN,aAAa;GACb,KAAK,OAAO,QAAQ;IAClB,IAAI,KAAK;KAAE,MAAM;KAAI,QAAQ,EAAE,OAAO,wBAAwB;IAAE,CAAC;IACjE,MAAM,EAAE,QAAQ,aAAa,MAAM,OAAO;IAC1C,IAAI,KAAK,EAAE,MAAM,eAAe,OAAO,WAAW,WAAW,IAAI,KAAK,SAAS,aAAa,GAAG,mDAAmD,CAAC;GACrJ;EACF,CAAC;CACH;CACA,OAAO;AACT;;;;;;;;;;;ACxBA,SAAgB,sBAAsB,OAmBlC,CAAC,GAAsB;CAEzB,OAAO;EACL,GAFa,iBAAiB;GAAE,SAAS;GAAU,GAAG;EAAK,CAEnD;EACR,GAAI,KAAK,gBAAgB,sBAAsB,IAAI,IAAI,CAAC;EACxD,GAAI,KAAK,QAAQ,oBAAoB,IAAI,IAAI,CAAC;CAChD;AACF;;;;;;;;;;AAWA,SAAgB,qBAAqB,MAMP;CAC5B,MAAM,QAAQ,IAAI,IAAI,KAAK,cAAc,CAAC,CAAC;CAC3C,MAAM,UAAU,KAAK,SAAS,kBAAkB,KAAA,IAAY,OAAO,IAAI,IAAI,KAAK,SAAS,aAAa;CACtG,MAAM,OAAO,sBAAsB;EACjC,KAAK,KAAK;EACV,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACrD,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC3D,eAAe,KAAK,SAAS,yBAAyB;EACtD,OAAO,KAAK,SAAS,uBAAuB;CAC9C,CAAC;CACD,QAAQ,SAAS;EACf,IAAI,MAAM,IAAI,IAAI,GAChB,OAAO;EACT,IAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,GAAG,KAAM,YAAY,QAAQ,CAAC,QAAQ,IAAI,IAAI,GACpF,OAAO;EACT,OAAO,KAAK,MAAK,MAAK,WAAW,KAAK,EAAE,MAAM,MAAM,UAAU,CAAC,CAAC;CAClE;AACF;;;;;;;;;;;;;AAcA,eAAsB,sBAAsB,OASxC,CAAC,GAA2B;CAC9B,MAAM,QAAQ,sBAAsB,IAAI,CAAC,CAAC,QAAO,MAAK,WAAW,EAAE,IAAI,CAAC;CACxE,OAAO,eAAe,OAAO,KAAK,MAAM;AAC1C;;;;;;;;;;;;;;;AAgBA,SAAgB,kBAAkB,MAGjB;CAMf,MAAM,OAAO,KAAK,KAAK,KAAI,OAAM;EAAE,MAAM,EAAE;EAAM,QAAQ,EAAE;CAAO,EAAE;CAWpE,IAAI,KAAK,YAAY,KAAA,KAAa,KAAK,QAAQ,WAAW,GACxD,OAAO;EAAE;EAAM,kBAAkB;EAAM,SAAS;CAAM;CAExD,OAAO;EACL;EACA,kBAAkB;EAClB,GAAI,KAAK,UAAU,EAAE,SAAS,CAAC,GAAG,KAAK,OAAO,EAAE,IAAI,CAAC;CACvD;AACF;;;AChJA,SAAgB,qBAAqB,KAInC;;;;;;CAMA,SAAS,eAAe,mBAAuC,KAAa,QAA4B,sBAAyC,CAAC,GAAc;EAC9J,IAAI,SAAoB,CAAC;EAGzB,MAAM,WAAW,sBAAsB,EAAE,mBAAmB,OAAO,CAAC;EACpE,MAAM,WAAW,IAAI,aAAa;EAClC,MAAM,OAAO,qBAAqB;GAChC;GACA;GACA,gBAAgB,SAAS,yBAAyB;GAClD,aAAa,qBAAqB;IAAE;IAAK;IAAQ;IAAU,YAAY;GAAoB,CAAC;EAC9F,CAAC;EACD,KAAK,MAAM,KAAK,KAAK,aACnB,UAAU,oBAAoB,EAAE,MAAM,EAAE,OAAO;EACjD,SAAS,cAAc;GAAE;GAAU,WAAW;GAAmB,MAAM,KAAK;EAAS,IAAI,SAAS,UAAU;GAC1G,UAAU,gCAAgC,OAAO,QAAQ,IAAI;EAC/D,CAAC;EACD,OAAO;CACT;CAEA,eAAe,aAAa,KAAwC;EAClE,IAAI;GACF,MAAM,gBAAgB,MAAM,IAAI,cAAc,GAAG;GAEjD,OAAO,eAAe,cAAc,WAAW,UAAU,KAAK,cAAc,QAAQ,cAAc,WAAW,OAAO,KAAI,UAAS,MAAM,IAAI,CAAC,CAAC,CAAC,KAAI,aAAY;IAC5J,MAAM,QAAQ;IACd,aAAa,QAAQ;IACrB,GAAI,QAAQ,WAAW,QAAQ,QAAQ,SAAS,IAAI,EAAE,SAAS,CAAC,GAAG,QAAQ,OAAO,EAAE,IAAI,CAAC;IACzF,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;IAChD,GAAI,QAAQ,eAAe,EAAE,kBAAkB,KAAK,IAAI,CAAC;GAC3D,EAAE;EACJ,QACM;GACJ,OAAO,CAAC;EACV;CACF;;;;;;CAOA,eAAe,oBACb,KACA,MACA,YACwC;EACxC,IAAI;GACF,MAAM,gBAAgB,MAAM,IAAI,cAAc,GAAG;GACjD,MAAM,UAAU,eAAe,cAAc,WAAW,UAAU,KAAK,cAAc,QAAQ,cAAc,WAAW,OAAO,KAAI,UAAS,MAAM,IAAI,CAAC,CAAC,CAAC,MACrJ,MAAK,EAAE,SAAS,SAAS,EAAE,SAAS,SAAS,IAAI,KAAK,MACxD;GAEA,IAAI,CAAC,SAAS,cACZ,OAAO,CAAC;GAIV,QAFqB,MAAM,QAAQ,aAAa,UAAU,KAAM,CAAC,EAAA,CAE9C,KAAI,OAAM;IAC3B,OAAO,EAAE;IACT,GAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpC,GAAI,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,IAAI,CAAC;GACxD,EAAE;EACJ,QACM;GACJ,OAAO,CAAC;EACV;CACF;CAEA,OAAO;EAAE;EAAgB;EAAc;CAAoB;AAC7D;;;AC9FA,SAAgB,aAAa,KAAsB;CACjD,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;;;AC2CA,MAAa,oBAAoB;AACjC,MAAa,gBAAgB;;AAG7B,SAAgB,kBAAkB,MAAuB;CACvD,OAAO,SAAA,kBAA8B,SAAA;AACvC;AAyLA,MAAa,oCACT;;;;;;;;AASJ,MAAa,6BAA6B;;;;;;;AAQ1C,SAAgB,mBAAmB,SAAsC;CACvE,OAAO,QAAQ,WAAW;AAC5B;;;;;;;AAQA,MAAM,6BAA6B;;;;;;;;;;AAWnC,SAAS,mBAAmB,UAAiC;CAC3D,QAAQ,SAAS,MAAjB;EAEE,KAAK,WACH,OAAO;EAGT,KAAK,UAAU;GACb,MAAM,SAAS,SAAS,QAAQ,EAAE,EAAE,MAAM;GAC1C,OAAO,SAAS,QAAS,SAAS,CAAC,MAAM,IAAI,CAAC,IAAK;EACrD;EACA,SACE,OAAO;CACX;AACF;;AAGA,SAAgB,mCAAmC,SAAkD;CACnG,IAAI,QAAQ,SAAS,QAInB,OAAO;EACL,MAAM;EACN,UAAU;EACV,WAAW;CACb;CAEF,MAAM,UAAuC,CAAC;CAC9C,KAAK,MAAM,YAAY,QAAQ,QAAQ,WACrC,QAAQ,SAAS,MAAM,mBAAmB,QAAQ;CACpD,OAAO;EAAE,MAAM;EAAY;EAAS,WAAW;CAAK;AACtD;;;;;;AAWA,SAAgB,6BAA6B,UAAuC;CAIlF,MAAM,YAAqC,SAAS,YAChD;EAAE,WAAW;EAAM,MAAM;CAAkC,IAC3D,CAAC;CACL,IAAI,SAAS,SAAS,QAAQ;EAC5B,MAAM,OAAgC;GAAE,GAAG;GAAW,UAAU,SAAS;EAAS;EAClF,IAAI,SAAS,WAAW,SAAS,QAAQ,KAAK,CAAC,CAAC,SAAS,GACvD,KAAK,UAAU,SAAS,QAAQ,KAAK;EACvC,OAAO,KAAK,UAAU,IAAI;CAC5B;CAGA,MAAM,UAAuC,CAAC;CAC9C,KAAK,MAAM,CAAC,IAAI,UAAU,OAAO,QAAQ,SAAS,OAAO,GACvD,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,UAAU,MAAM,KAAK;EAC3B,IAAI,QAAQ,SAAS,GACnB,QAAQ,MAAM;CAClB,OACK,IAAI,OAAO,UAAU,WACxB,QAAQ,MAAM;MAEX,IAAI,MAAM,QAAQ,KAAK,GAAG;EAE7B,MAAM,SAAS,MAAM,KAAI,MAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,CAAC;EACxE,IAAI,OAAO,SAAS,GAClB,QAAQ,MAAM;CAClB;CAEF,MAAM,OAAgC;EAAE,GAAG;EAAW;CAAQ;CAC9D,MAAM,eAAe,SAAS,cAAc,KAAK;CACjD,IAAI,cACF,KAAK,eAAe;CACtB,OAAO,KAAK,UAAU,IAAI;AAC5B;;;;;;;;;;;;;AAgCA,SAAgB,4BACd,UACA,WACA,SAaa;CACb,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,+DAA+D;CAEjF,MAAM,UAAiC,SAAS,KAAK,QAAQ;EAC3D,MAAM,WAAW,UAAU,IAAI,IAAI,EAAE;EACrC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,8DAA8D,IAAI,GAAG,SAC5D,SAAS,OAAO,wDAC3B;EAEF,OAAO;GACL,MAAM;GACN,QAAQ,IAAI;GACZ,QAAQ,6BAA6B,QAAQ;EAC/C;CACF,CAAC;CAED,OAAO;EACL,IAAI,QAAQ;EACZ,MAAM;EACN;EACA,WAAW,QAAQ,aAAa,KAAK,IAAI;EACzC,GAAI,QAAQ,QAAQ,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;CAClD;AACF;;;;;;;;;;;;AAqBA,SAAgB,6BAA6B,OAAqD;CAShG,MAAM,QAAoB,CAAC;CAC3B,MAAM,4BAAY,IAAI,IAAY;CAElC,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,SAAS,KAAK,SACvB,IAAI,MAAM,SAAS,eAAe,kBAAkB,MAAM,IAAI,GAC5D,MAAM,KAAK;EACT,QAAQ,MAAM;EACd,MAAM,MAAM;EACZ,OAAO,MAAM;EACb,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;EAC1C,QAAQ,KAAK;EACb,WAAW,KAAK;CAClB,CAAC;MAEE,IAAI,MAAM,SAAS,eACtB,UAAU,IAAI,MAAM,MAAM;CAKhC,MAAM,UAAgC,CAAC;CACvC,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,UAAU,IAAI,KAAK,MAAM,GAC3B;EACF,IAAI,KAAK,SAAA,gBAA4B;GACnC,MAAM,UAAU,iBAAiB,KAAK,KAAK;GAC3C,IAAI,CAAC,SACH;GACF,QAAQ,KAAK;IACX,IAAI,KAAK;IAGT,QAAQ;IACR,MAAM;IACN,MAAM;IACN;IACA,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;IAC1C,QAAQ,KAAK;IACb,WAAW,KAAK;GAClB,CAAC;EACH,OACK,IAAI,KAAK,SAAA,YAAwB;GACpC,MAAM,UAAU,qBAAqB,KAAK,KAAK;GAC/C,IAAI,CAAC,SACH;GACF,QAAQ,KAAK;IACX,IAAI,KAAK;IACT,QAAQ;IACR,MAAM;IACN,MAAM;IACN;IACA,GAAI,KAAK,QAAQ,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;IAC1C,QAAQ,KAAK;IACb,WAAW,KAAK;GAClB,CAAC;EACH;CACF;CACA,OAAO;AACT;;;;;;AAOA,SAAS,iBAAiB,OAAoD;CAC5E,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,IAAI;CACrE,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;CAC3D,IAAI,CAAC,SAAS,CAAC,MACb,OAAO;CACT,MAAM,WAAW,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,QAAQ,KAAA;CAC5D,MAAM,QAAoB,CAAC;CAC3B,IAAI,UACF,KAAK,MAAM,KAAK,UAAU;EACxB,IAAI,CAAC,KAAK,OAAO,MAAM,UACrB;EACF,MAAM,OAAO;EACb,IAAI,OAAO,KAAK,OAAO,YAAY,OAAO,KAAK,UAAU,UACvD;EACF,MAAM,KAAK;GACT,IAAI,KAAK;GACT,OAAO,KAAK;GACZ,GAAI,OAAO,KAAK,gBAAgB,WAAW,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAClF,CAAC;CACH;CAEF,OAAO;EACL;EACA;EACA,GAAI,MAAM,SAAS,IAAI,EAAE,MAAM,IAAI,CAAC;CACtC;AACF;;;;;;;;;;;;AAaA,SAAS,qBAAqB,OAAwD;CACpF,MAAM,QAAQ,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,IACzE,MAAM,QACN,KAAA;CAYJ,IAAI,MAAM,QAAQ,MAAM,SAAS,GAAG;EAClC,MAAM,YAAwB,CAAC;EAC/B,MAAM,uBAAO,IAAI,IAAY;EAC7B,KAAK,MAAM,OAAO,MAAM,WAAW;GACjC,MAAM,IAAI,cAAc,GAAG;GAC3B,IAAI,CAAC,GACH;GACF,IAAI,KAAK,IAAI,EAAE,EAAE,GACf;GACF,KAAK,IAAI,EAAE,EAAE;GACb,UAAU,KAAK,CAAC;EAClB;EACA,IAAI,UAAU,WAAW,GACvB,OAAO;EACT,OAAO;GAAE,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAAI;EAAU;CAClD;CAIA,MAAM,WAAW,OAAO,MAAM,aAAa,WAAW,MAAM,SAAS,KAAK,IAAI;CAC9E,IAAI,CAAC,UACH,OAAO;CACT,MAAM,UAAU,aAAa,MAAM,OAAO;CAC1C,MAAM,SAAmB,QAAQ,SAAS,IACtC;EAAE,IAAI;EAAU,QAAQ;EAAU,MAAM;EAAU;CAAQ,IAC1D;EAAE,IAAI;EAAU,QAAQ;EAAU,MAAM;CAAW;CACvD,OAAO;EAAE,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EAAI,WAAW,CAAC,MAAM;CAAE;AAC5D;AAEA,SAAS,cAAc,KAA+B;CACpD,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,OAAO;CACT,MAAM,OAAO;CAab,IAAI,OAAO,KAAK,OAAO,YAAY,CAAC,KAAK,IACvC,OAAO;CACT,IAAI,OAAO,KAAK,WAAW,YAAY,CAAC,KAAK,OAAO,KAAK,GACvD,OAAO;CACT,MAAM,OAAO,KAAK;CAClB,IAAI,SAAS,UAAU,SAAS,cAAc,SAAS,YAAY,SAAS,WAC1E,OAAO;CAET,MAAM,OAAO;EACX,IAAI,KAAK;EACT,QAAQ,KAAK;EACb,GAAI,OAAO,KAAK,gBAAgB,WAAW,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAChF,GAAI,OAAO,KAAK,aAAa,YAAY,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;CAC1E;CAEA,IAAI,SAAS,UAAU,SAAS,YAC9B,OAAO;EACL,GAAG;EACH;EACA,GAAI,OAAO,KAAK,gBAAgB,WAAW,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAChF,GAAI,OAAO,KAAK,YAAY,WAAW,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;CACtE;CAGF,IAAI,SAAS,UAAU;EACrB,MAAM,UAAU,aAAa,KAAK,OAAO;EACzC,IAAI,QAAQ,WAAW,GACrB,OAAO;EACT,OAAO;GAAE,GAAG;GAAM;GAAM;GAAS,GAAI,KAAK,UAAU,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;EAAG;CACnF;CAGA,OAAO;EACL,GAAG;EACH;EACA,GAAI,OAAO,KAAK,gBAAgB,WAAW,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;EAChF,GAAI,OAAO,KAAK,cAAc,WAAW,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;CAC5E;AACF;AAEA,SAAS,aAAa,KAAgC;CACpD,IAAI,CAAC,MAAM,QAAQ,GAAG,GACpB,OAAO,CAAC;CACV,MAAM,UAA4B,CAAC;CACnC,KAAK,MAAM,KAAK,KAAK;EACnB,IAAI,CAAC,KAAK,OAAO,MAAM,UACrB;EACF,MAAM,OAAO;EACb,IAAI,OAAO,KAAK,OAAO,YAAY,OAAO,KAAK,UAAU,UACvD;EACF,QAAQ,KAAK;GACX,IAAI,KAAK;GACT,OAAO,KAAK;GACZ,GAAI,OAAO,KAAK,gBAAgB,WAAW,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;GAIhF,GAAI,KAAK,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;EACrD,CAAC;CACH;CACA,OAAO;AACT;;;;;AAwBA,SAAgB,uBAAuB,MAA8D;CACnG,OAAO;GACJ,oBAAoB,eAAe,IAAI;GACvC,gBAAgB,mBAAmB,IAAI;CAC1C;AACF;AAEA,MAAM,mBACF;AAKJ,MAAM,uBACF;AAUJ,SAAS,eAAe,EAAE,oBAAoB,0BAAkE;CAC9G,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,YAAY;KACV,OAAO;MAAE,MAAM;MAAU,aAAa;KAAsC;KAC5E,MAAM;MAAE,MAAM;MAAU,aAAa;KAAuC;KAC5E,OAAO;MACL,MAAM;MACN,aAAa;MACb,OAAO;OACL,MAAM;OACN,YAAY;QACV,IAAI,EAAE,MAAM,SAAS;QACrB,OAAO,EAAE,MAAM,SAAS;QACxB,aAAa,EAAE,MAAM,SAAS;OAChC;OACA,UAAU,CAAC,MAAM,OAAO;MAC1B;KACF;IACF;IACA,UAAU,CAAC,SAAS,MAAM;GAC5B;EACF;EACA,MAAM,QAAQ,OAAO,KAAK;GACxB,MAAM,UAAU,iBAAiB,KAAK;GACtC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,6EAA6E;GAC/F,MAAM,UAAuB;IAC3B,IAAI,IAAI;IACR,QAAQ;IACR,MAAM;IACN,MAAM;IACN;IACA,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;IACxC,QAAQ,IAAI;IACZ,WAAW,KAAK,IAAI;GACtB;GACA,MAAM,WAAW,yBAAyB,IACtC,mCAAmC,OAAO,IAC1C,MAAM,mBAAmB,OAAO;GACpC,IAAI,SAAS,SAAS,QACpB,MAAM,IAAI,MAAM,2CAA2C,SAAS,KAAK,GAAG;GAC9E,OAAO,6BAA6B,QAAQ;EAC9C;CACF;AACF;AAEA,SAAS,mBAAmB,EAAE,oBAAoB,0BAAkE;CAClH,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,YAAY;KACV,OAAO;MACL,MAAM;MACN,aAAa;KACf;KACA,WAAW;MACT,MAAM;MACN,aAAa;MACb,UAAU;MACV,OAAO;OACL,MAAM;OACN,YAAY;QACV,IAAI;SACF,MAAM;SACN,aAAa;QACf;QACA,QAAQ;SACN,MAAM;SACN,aAAa;QACf;QACA,MAAM;SACJ,MAAM;SACN,MAAM;UAAC;UAAQ;UAAY;UAAU;SAAS;SAC9C,aAAa;QACf;QACA,aAAa;SACX,MAAM;SACN,aAAa;QACf;QACA,UAAU;SACR,MAAM;SACN,aAAa;QACf;QACA,aAAa;SACX,MAAM;SACN,aAAa;QACf;QACA,SAAS;SACP,MAAM;SACN,aAAa;QACf;QACA,SAAS;SACP,MAAM;SACN,aAAa;SACb,OAAO;UACL,MAAM;UACN,YAAY;WACV,IAAI,EAAE,MAAM,SAAS;WACrB,OAAO,EAAE,MAAM,SAAS;WACxB,aAAa,EAAE,MAAM,SAAS;WAC9B,UAAU;YACR,MAAM;YACN,aAAa;WACf;UACF;UACA,UAAU,CAAC,MAAM,OAAO;SAC1B;QACF;QACA,aAAa;SACX,MAAM;SACN,aAAa;QACf;QACA,WAAW;SACT,MAAM;SACN,aAAa;QACf;OACF;OACA,UAAU;QAAC;QAAM;QAAU;OAAM;MACnC;KACF;IACF;IACA,UAAU,CAAC,WAAW;GACxB;EACF;EACA,MAAM,QAAQ,OAAO,KAAK;GACxB,MAAM,UAAU,qBAAqB,KAAK;GAC1C,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,kEAAkE;GACpF,MAAM,UAA2B;IAC/B,IAAI,IAAI;IACR,QAAQ;IACR,MAAM;IACN,MAAM;IACN;IACA,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;IACxC,QAAQ,IAAI;IACZ,WAAW,KAAK,IAAI;GACtB;GACA,MAAM,WAAW,yBAAyB,IACtC,mCAAmC,OAAO,IAC1C,MAAM,mBAAmB,OAAO;GACpC,IAAI,SAAS,SAAS,YACpB,MAAM,IAAI,MAAM,uCAAuC,SAAS,KAAK,GAAG;GAC1E,OAAO,6BAA6B,QAAQ;EAC9C;CACF;AACF;AAiDA,MAAM,2BAA2B,cAAkD,CAAC,CAAC;AACrF,MAAM,6BAA6B,cAA0C,IAAI;AAEjF,SAAgB,qBAAqB,EAAE,YAAqC;CAC1E,MAAM,CAAC,OAAO,YAAY,SAA6C,CAAC,CAAC;CAIzE,MAAM,WAAW,OAA2C,CAAC,CAAC;CAC9D,SAAS,UAAU;CAOnB,sBAAsB;EACpB,KAAK,MAAM,SAAS,SAAS,SAC3B,MAAM,OAAO,iCAAiC;CAClD,GAAG,CAAC,CAAC;CAEL,MAAM,UAAU,aAAa,UAAmC;EAC9D,UAAS,SAAQ,CAAC,GAAG,MAAM,KAAK,CAAC;CACnC,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,aAAa,aAAkC;EACjE,UAAU,SAAS;GACjB,MAAM,CAAC,MAAM,GAAG,QAAQ;GACxB,IAAI,MACF,KAAK,QAAQ,QAAQ;GACvB,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,aAAa,WAAoB;EAClD,UAAU,SAAS;GACjB,MAAM,CAAC,MAAM,GAAG,QAAQ;GACxB,IAAI,MACF,KAAK,OAAO,MAAM;GACpB,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,YAAY,aAAa,WAAoB;EACjD,UAAU,SAAS;GACjB,KAAK,MAAM,SAAS,MAAM,MAAM,OAAO,MAAM;GAC7C,OAAO,CAAC;EACV,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,WAAW,aAAa,cAAsB;EAIlD,UAAS,SAAQ,KAAK,QAAO,UAAS,MAAM,QAAQ,OAAO,SAAS,CAAC;CACvE,GAAG,CAAC,CAAC;CAML,MAAM,aAAa,OAAmC,IAAI;CAC1D,IAAI,CAAC,WAAW,SACd,WAAW,UAAU;EAAE;EAAS;EAAa;EAAY;EAAW;CAAS;CAE/E,OACE,oBAAC,2BAA2B,UAA5B;EAAqC,OAAO,WAAW;EACrD,UAAA,oBAAC,yBAAyB,UAA1B;GAAmC,OAAO;GACvC;EACgC,CAAA;CACA,CAAA;AAEzC;;AAGA,SAAgB,uBAA2D;CACzE,OAAO,WAAW,wBAAwB;AAC5C;;AAGA,SAAgB,yBAA8C;CAC5D,MAAM,MAAM,WAAW,0BAA0B;CACjD,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,mEAAmE;CACrF,OAAO;AACT;;;;;;;AAaA,SAAgB,uBACd,SACqD;CACrD,QAAO,YAAW,IAAI,SAA8B,SAAS,WAAW;EACtE,QAAQ,QAAQ;GACd;GACA;GACA,SAAQ,WAAU,OAAO,IAAI,MAAM,UAAU,uBAAuB,CAAC;EACvE,CAAC;CACH,CAAC;AACH;;;AC1gCA,SAAgB,+BAA+B,EAAE,cAAc,WAAW,cAIR;CAChE,MAAM,qBAAqB,aAAa,sBAAsB,SAAS;CASvE,MAAM,6BAA6B,YAA8D;EAC/F,IAAI,WAAW,OAAO,SACpB,OAAO,QAAQ,uBAAO,IAAI,MAAM,iBAAiB,CAAC;EAEpD,MAAM,UAAU,mBAAmB,OAAO;EAC1C,MAAM,gBAAsB;GAC1B,aAAa,OAAO,QAAQ,IAAI,iBAAiB;EACnD;EACA,WAAW,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAEnE,OAAO,QAAQ,cAAc,WAAW,OAAO,oBAAoB,SAAS,OAAO,CAAC;CACtF;CAEA,OAAO;AACT;AAEA,SAAgB,yBACd,2BACmC;CACnC,OAAO;EACL,SAAS,OAAO,eAAe,gBAAgB;GAC7C,MAAM,WAAW,MAAM,0BAA0B;IAC/C,IAAI,GAAG,6BAA6B,WAAW;IAC/C,QAAQ;IACR,MAAM;IACN,MAAM;IACN,WAAW,KAAK,IAAI;IACpB,SAAS;KACP,GAAI,aAAa,QAAQ,EAAE,OAAO,YAAY,MAAM,IAAI,CAAC;KACzD,WAAW,CACT;MACE,IAAI;MACJ,MAAM;MACN,QAAQ;MACR,GAAI,aAAa,cAAc,EAAE,aAAa,YAAY,YAAY,IAAI,CAAC;MAC3E,GAAI,aAAa,YAAY,EAAE,WAAW,YAAY,UAAU,IAAI,CAAC;KACvE,CACF;IACF;GACF,CAAC;GAED,IAAI,SAAS,SAAS,YACpB,MAAM,IAAI,MAAM,+CAA+C;GAEjE,OAAO,SAAS,QAAQ,YAAY;EACtC;EACA,SAAS,OAAO,SAAS;GACvB,MAAM,WAAW,MAAM,0BAA0B;IAC/C,IAAI,GAAG,6BAA6B,WAAW;IAC/C,QAAQ;IACR,MAAM;IACN,MAAM;IACN,WAAW,KAAK,IAAI;IACpB,SAAS;GACX,CAAC;GAED,IAAI,SAAS,SAAS,YACpB,MAAM,IAAI,MAAM,+CAA+C;GAEjE,OAAO,SAAS;EAClB;EACA,aAAa,OAAO,SAAS;GAC3B,MAAM,WAAW,MAAM,0BAA0B;IAC/C,IAAI,GAAG,6BAA6B,WAAW;IAC/C,QAAQ;IACR,MAAM;IACN,MAAM;IACN,WAAW,KAAK,IAAI;IACpB,SAAS;GACX,CAAC;GAED,IAAI,SAAS,SAAS,QACpB,MAAM,IAAI,MAAM,mDAAmD;GAErE,OAAO;EACT;CACF;AACF;;;AC5EA,SAAgB,oBAAoB,EAAE,SAAS,aAG7B;CAChB,MAAM,QAAgC;EAAE,SAAS,CAAC;EAAG,eAAe;CAAK;CAEzE,MAAM,mBAAmB,YAA2B;EAClD,IAAI,MAAM,QAAQ,WAAW,GAC3B;EAEF,MAAM,UAAU,uBAAuB,MAAM,OAAO;EACpD,MAAM,SAAS,MAAM,iBAAiB,WAAW;EACjD,MAAM,UAAU,CAAC;EACjB,MAAM,gBAAgB;EACtB,MAAM,QAAQ,YAAY,CAAC;GAAE,IAAI;GAAQ,MAAM;GAAW,WAAW,KAAK,IAAI;GAAG;EAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CACpH;CAEA,MAAM,aAAa,UAAoC;EACrD,MAAM,kBAAkB,WAAW;EACnC,MAAM,QAAQ,KAAK,KAAK;EACxB,UAAU;GAAE,GAAG,oBAAoB,KAAK;GAAG,QAAQ,MAAM;EAAc,CAAC;CAC1E;CAWA,MAAM,mBAAmB,OAAO,SAAgC;EAC9D,MAAM,iBAAiB;EACvB,MAAM,SAAS;GAAE,UAAU;GAAkB,OAAO;EAAU;EAC9D,MAAM,SAAS,WAAW;EAC1B,MAAM,QACH,YAAY,CAAC;GAAE,IAAI;GAAQ,MAAM;GAAW,WAAW,KAAK,IAAI;GAAG,SAAS,kBAAkB,QAAQ,IAAI;EAAE,CAAC,CAAC,CAAC,CAC/G,YAAY,KAAA,CAAS;EACxB,UAAU;GAAE,MAAM;GAAS;GAAM;GAAQ;EAAO,CAAC;CACnD;CAEA,OAAO;EAAE;EAAO;EAAkB;EAAW;CAAiB;AAChE;;;ACrDA,SAAgB,sBAAsB,EAAE,KAAK,SAAS,WAAW,YAAY,WAAW,WAAW,WAAW,kBAAkB,sBAU7F;CACjC,OAAO,OAAO,aAAqB,cAA8C;EAC/E,IAAI,WAAW,OAAO,SACpB,MAAM,IAAI,MAAM,2BAA2B;EAI7C,MAAM,iBAAiB;EAIvB,KAAK,MAAM,QAAQ,IAAI,sBAAsB,CAAC,GAC5C,IAAI;GACF,MAAM,IAAI,MAAM,cAAc,IAAI;EACpC,QACM,CAEN;EAMF,UAAU;GACR,MAAM;GACN,OAAO,WAAW,UAAU,iBAAiB,UAAU,OAAO,IAAI;GAClE,MAAM;EACR,CAAC;EAED,MAAM,SAAS,QAAQ,MAAM;EAC7B,MAAM,aAAa,QAAQ,KAAK;EAChC,MAAM,EAAE,UAAU,cAAc,aAAa,SAAS,MAAM,mBAAmB,GAAG;EAClF,MAAM,QAAQ,WAAW;EAGzB,UAAU;GAAE,MAAM;GAAa;GAAW;EAAM,CAAC;EAEjD,IAAI;GACF,MAAM,IAAI,MAAM,IAAI;IAClB,QAAQ;IACR,QAAQ,WAAW;IACnB,UAAU;KAAE;KAAa,GAAG;IAAK;IACjC,GAAI,IAAI,gBAAgB,EAAE,OAAO,IAAI,cAAc,IAAI,CAAC;IACxD,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;IAC/B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;GACzC,CAAC;GACD,UAAU;IAAE,MAAM;IAAW;IAAW;IAAO,IAAI;GAAK,CAAC;EAC3D,SACO,KAAK;GACV,UAAU;IAAE,MAAM;IAAW;IAAW;IAAO,IAAI;IAAO,OAAO,aAAa,GAAG;GAAE,CAAC;GACpF,MAAM;EACR,UACQ;GAEN,UAAU,KAAK;EACjB;EAEA,MAAM,QAAQ,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EAI1C,KAAK,MAAM,cAAc,QAAQ,KAAK,MAAM,UAAU,GAAG;GACvD,IAAI,WAAW,aACb;GAEF,WAAW,SAAS;IAAE,MAAM;IAAW,GAAI,WAAW,UAAU,EAAE,SAAS,UAAU,QAAQ,IAAI,CAAC;GAAG;GACrG,MAAM,QAAQ,UAAU,UAAU,CAAC,CAAC,YAAY,KAAA,CAAS;EAC3D;EAQA,OAAO,EAAE,MANI,QAAQ,MAClB,MAAM,MAAM,CAAC,CACb,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CACnC,SAAQ,MAAK,EAAE,QAAQ,SAAQ,MAAM,EAAE,SAAS,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,CAAE,CAAC,CAAC,CACzE,KAAK,IAEI,EAAE;CAChB;AACF;;;;;;;;;;AChFA,SAAgB,oBAAoB,UAAgD;CAClF,MAAM,OAA+B,CAAC;CAEtC,IAAI,SAAS,mBACX,KAAK,oBAAoB;CAC3B,IAAI,SAAS,kBAAkB,GAC7B,KAAK,YAAY,SAAS;CAC5B,IAAI,SAAS,WAAW,GACtB,KAAK,WAAW,SAAS;CAC3B,IAAI,SAAS,aAAa,GACxB,KAAK,aAAa,SAAS;CAC7B,IAAI,SAAS,iBAAiB,GAC5B,KAAK,iBAAiB,SAAS;CACjC,IAAI,SAAS,iBAAiB,GAC5B,KAAK,YAAY,SAAS,iBAAiB;CAC7C,IAAI,SAAS,mBAAmB,GAC9B,KAAK,QAAQ,EAAE,aAAa,SAAS,iBAAiB;CAExD,OAAO;AACT;AASA,SAAgB,0BAA0B,EAAE,KAAK,iBAGG;;;;;;;CAOlD,OAAO,eAAe,mBAAmB,KAA6C;EACpF,IAAI;EACJ,IAAI;EAEJ,IAAI;GACF,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,IAAI,SAAS;GAC/C,MAAM,YAAY,MAAM,UAAU;GAElC,IAAI,OAAO,cAAc,YAAY,gBAAgB,SAAS,GAC5D,WAAW;GAEb,MAAM,aAAa,IAAI,sBAAsB,kBAAkB;GAC/D,MAAM,UAAU,IAAI,iBAAiB,IAAI;GACzC,MAAM,UAAU,oBAAoB,MAAM,UAAU,YAAY;GAChE,eAAe,oBAAoB,YAAY,SAAS,GAAG,UAAU,QAAQ,CAAC;EAChF,QACM,CAEN;EAEA,MAAM,WAAW,IAAI,aAAa;EAClC,MAAM,aAAa,kBAAkB,IAAI,gBAAgB,kBAAkB;EAM3E,MAAM,UAAU,MAAM,IAAI,cAAc,IAAI,YAAY;EACxD,MAAM,aAAa,4BACjB,SAAS,kBACT,QAAO,cAAc,QAAQ,WAAW,GAAG,GAC3C;GAAE,aAAa,IAAI;GAAa,OAAO,IAAI,iBAAiB,IAAI;EAAM,CACxE;EACA,MAAM,cAAc,wBAAwB;GAC1C,SAAS,SAAS;GAClB,WAAW,SAAS;GACpB,kBAAkB,iBAAiB,YAAY,IAAI,iBAAiB,IAAI,KAAK;GAC7E,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;EACrC,CAAC;EAID,OAAO;GACL,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;GAC/B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;GACvC;GACA,MAAM,oBAAoB,QAAQ;EACpC;CACF;AACF;;;AC/FA,SAAgB,kBAAkB,EAAE,KAAK,SAAS,YAAY,YAAY,YAAY,WAAW,oBAQ3D;CACpC,OAAO,OAAO,OAAO,cAAc;EACjC,MAAM,OAAO,IAAI,cAAc;EAC/B,MAAM,QAAQ,IAAI;EAElB,IAAI,CAAC,QAAQ,CAAC,YAAY,KAAK,SAAS,GACtC,MAAM,IAAI,MAAM,qDAAqD;EAEvE,IAAI,WAAW,OAAO,SACpB,MAAM,IAAI,MAAM,8BAA8B;EAEhD,IAAI,MAAM,WAAW,GACnB,OAAO,CAAC;EAEV,MAAM,iBAAiB;EAEvB,MAAM,eAAe,MAAM,WAAW,OAAO;EAC7C,MAAM,SAAS,MAAM,MAAM,gBAAgB;EAM3C,IAAI;EAEJ,IAAI;GACF,MAAM,QAAQ,KAAK,CACjB,MAAM,OAAO,GACb,IAAI,SAAe,iBAAiB;IAClC,IAAI,WAAW,OAAO,SAAS;KAC7B,aAAa;KAEb;IACF;IAEA,gBAAgB,aAAa;IAC7B,WAAW,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;GACrE,CAAC,CACH,CAAC;EACH,QACM,CAEN,UACQ;GACN,IAAI,SACF,WAAW,OAAO,oBAAoB,SAAS,OAAO;EAC1D;EAEA,IAAI,WAAW,OAAO,SACpB,MAAM,IAAI,MAAM,8BAA8B;EAEhD,MAAM,YAAY,MAAM;EACxB,MAAM,UAAgC,MAAM,KAAK,MAAM,OAAO;GAC5D,OAAO,KAAK,SAAS,QAAQ,IAAI;GACjC,GAAI,KAAK,UAAU,KAAA,IAAY,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GACxD,QAAQ;GACR,MAAM;GACN,SAAS;EACX,EAAE;EAMF,IAAI,SAAS;EACb,MAAM,SAAS,YAA2B;GACxC,OAAO,SAAS,MAAM,UAAU,CAAC,WAAW,OAAO,SAAS;IAC1D,MAAM,QAAQ;IACd,MAAM,YAAY,MAAM;IAExB,IAAI;KACF,MAAM,UAAU,MAAM,KAAK,UAAU,QACnC;MACE,MAAM,UAAU;MAChB,GAAI,UAAU,WAAW,KAAA,IAAY,EAAE,QAAQ,UAAU,OAAO,IAAI,CAAC;MACrE,GAAI,UAAU,UAAU,KAAA,IAAY,EAAE,OAAO,UAAU,MAAM,IAAI,CAAC;KACpE,GACA;MACE,UAAU,KAAK;MACf,WAAW,KAAK;MAChB,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;MACrD,OAAO,IAAI,iBAAiB,IAAI;MAChC,QAAQ,WAAW;MACnB,WAAW,MAAM;MACjB;MACA,OAAO,MAAM;MACb,GAAI,KAAK,WAAW,KAAA,IAAY,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;MAC3D,OAAO,KAAK;MACZ,YAAY,CAAC,GAAG,MAAM,UAAU;MAChC,GAAI,YAAY,EAAE,eAAe,iBAAiB,SAAS,EAAE,IAAI,CAAC;MAClE,QAAQ,KAAK;MACb,UAAU,KAAK;MACf,QAAQ,WAAW,WAAW;MAC9B,OAAO;MACP,QAAQ,iBAAiB,WAAW;MACpC;KACF,CACF;KAEA,QAAQ,SAAS;MACf,OAAO,UAAU,SAAS,QAAQ,MAAM,QAAQ,QAAQ;MACxD,GAAI,UAAU,UAAU,KAAA,IAAY,EAAE,OAAO,UAAU,MAAM,IAAI,CAAC;MAClE,QAAQ,QAAQ;MAChB,MAAM,QAAQ;MACd,SAAS,QAAQ;KACnB;IACF,SACO,KAAK;KACV,QAAQ,SAAS;MACf,OAAO,UAAU,SAAS,QAAQ,QAAQ;MAC1C,GAAI,UAAU,UAAU,KAAA,IAAY,EAAE,OAAO,UAAU,MAAM,IAAI,CAAC;MAClE,QAAQ;MACR,MAAM;MACN,SAAS,gBAAgB,aAAa,GAAG;KAC3C;IACF;GACF;EACF;EAEA,MAAM,MAAM,KAAK,UAAU;EAC3B,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,WAAW,iBAAiB,KAAK,KAAK,MAAM,MAAM,CAAC;EACtF,MAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,OAAO,CAAC,CAAC;EAC/D,UAAU,KAAK;EACf,MAAM,QAAQ,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;EAE1C,OAAO;CACT;AACF;;;ACnFA,SAAgB,oBAAoB,MAMlB;CAChB,MAAM,EAAE,KAAK,WAAW,aAAa,eAAe,iBAAiB;CACrE,MAAM,EAAE,gBAAgB,cAAc,wBAAwB,qBAAqB,GAAG;CACtF,MAAM,qBAAqB,0BAA0B;EAAE;EAAK;CAAc,CAAC;;;;;;;;CAS3E,eAAe,gBAAgB,MAAmB,YAA4G;EAC5J,MAAM,SAAS,KAAK,OAAO,KAAK;EAEhC,IAAI,CAAC,OAAO,WAAW,GAAG,GACxB,OAAO,EAAE,KAAK,MAAM;EAEtB,MAAM,MAAM,MAAM,YAAY,KAAK,SAAS;EAC5C,MAAM,gBAAgB,MAAM,IAAI,cAAc,IAAI,YAAY;EAC9D,MAAM,WAA+B,eAAe,cAAc,WAAW,UAAU,IAAI,cAAc,cAAc,QAAQ,cAAc,WAAW,OAAO,KAAI,UAAS,MAAM,IAAI,CAAC;EACvL,MAAM,aAAa,uBAAuB,QAAQ,QAAQ;EAE1D,IAAI,CAAC,YACH,OAAO,EAAE,KAAK,MAAM;EAEtB,MAAM,UAAU,SAAS,MAAK,MAAK,EAAE,SAAS,WAAW,IAAI;EAE7D,IAAI,CAAC,SACH,OAAO,EAAE,KAAK,MAAM;EAItB,aAAa;EAEb,IAAI,IAAI,MAAM,WACZ,MAAM,IAAI,MAAM,IAAI,WAAW,KAAK,+CAA+C;EAErF,MAAM,UAAU,IAAI,MAAM;EAE1B,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,IAAI,WAAW,KAAK,2BAA2B;EAEjE,MAAM,YAAY,KAAK;EACvB,MAAM,aAAa,IAAI,gBAAgB;EAEvC,MAAM,aAAa,uBAAuB,SAAS,UAAU;EAC7D,IAAI;EACJ,IAAI,eAAe;EAYnB,MAAM,gBAAgB,WAAW;EACjC,UAAU;GAAE,MAAM;GAAa;GAAW,OAAO;EAAc,CAAC;EAUhE,MAAM,YAAY,kBAAkB;GAAE;GAAK;GAAW,iBAAiB;GAAM,WAAW;EAAK,CAAC;EAE9F,MAAM,4BAA4B,+BAA+B;GAAE;GAAc;GAAW;EAAW,CAAC;EAExG,MAAM,aAAa,UAA6B;GAC9C,UAAU;IAAE,MAAM;IAAS;IAAW;GAAM,CAAC;EAC/C;EAEA,MAAM,SAAS,oBAAoB;GAAE;GAAS;EAAU,CAAC;EACzD,MAAM,EAAE,kBAAkB,WAAW,qBAAqB;EAC1D,MAAM,iBAAiB,IAAI,WAAW,OAAO,WAAW,OAAO,IAAI,WAAW,SAAS;EAEvF,MAAM,MAA0B;GAC9B,MAAM,WAAW;GACjB,MAAM,WAAW;GACjB,GAAI,WAAW,YAAY,EAAE,WAAW,WAAW,UAAU,IAAI,CAAC;GAClE,GAAI,KAAK,eAAe,KAAK,YAAY,SAAS,IAC9C,EACE,aAAa,KAAK,YAAY,KAAI,OAAM;IACtC,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE;IACb,MAAM,EAAE;GACV,EAAE,EACJ,IACA,CAAC;GACL,MAAM,CAAC;GACP,MAAM;GACN,UAAU,sBAAsB;IAAE;IAAK;IAAS;IAAW;IAAY;IAAW;IAAW;IAAW;IAAkB;GAAmB,CAAC;GAI9I,eAAe,OAAO,aAAyC;IAC7D,IAAI,WAAW,OAAO,SACpB,MAAM,IAAI,MAAM,+BAA+B;IAIjD,MAAM,WAAW,cAAc,cAAc,WAAW,IAAI,WAAW;IAEvE,OAAO,uBAAuB;KAC5B;KACA,OAAO,SAAS,SAAS,IAAI,iBAAiB,IAAI;KAClD,QAAQ,SAAS;KACjB,QAAQ,SAAS;KACjB,GAAI,SAAS,SAAS,EAAE,QAAQ,SAAS,OAAO,IAAI,CAAC;KACrD,GAAI,SAAS,sBAAsB,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;KAC/D,QAAQ,WAAW;IACrB,CAAC;GACH;GACA,QAAQ,aAAa,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,SAAS,WAAW,KAAK,CAAC;GAChE,QAAQ,WAAW;GACnB,KAAK,IAAI;GAIT,SAAS;IACP,IAAI,KAAK;KACP,OAAO,QAAQ;IACjB;IACA,IAAI,QAAQ;KACV,OAAO,QAAQ;IACjB;IACA,IAAI,OAAO;KACT,OAAO,QAAQ;IACjB;IACA,IAAI,WAAW;KACb,OAAO,QAAQ;IACjB;GACF;GACA,aAAa,yBAAyB,yBAAyB;GAK/D,aAAa,kBAAkB;IAAE;IAAK;IAAS;IAAY;IAAY;IAAY;IAAW;GAAiB,CAAC;GAOhH,eAAe,OAAO,MAAM,aAAa;IACvC,IAAI,WAAW,OAAO,SACpB,MAAM,IAAI,MAAM,gCAAgC;IAElD,MAAM,UAAU,KAAK,KAAK;IAE1B,IAAI,CAAC,SACH;IAEF,MAAM,iBAAiB;IAEvB,MAAM,UAAU,YAAY,UAAU,SAAS,OAAO;IACtD,MAAM,SAAS,MAAM,QAAQ,eAAe;IAC5C,IAAI,SACF,UAAU;KAAE,MAAM;KAAgB,MAAM,gBAAgB,SAAS,SAAS,cAAc;KAAG;IAAO,CAAC;IACrG,MAAM,QAAQ,YAAY,CACxB;KACE,IAAI;KACJ,MAAM;KACN,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM;KAAQ,CAAC;KACzC,WAAW,KAAK,IAAI;KACpB;IACF,CACF,CAAC;GACH;EACF;EAkBA,MAAM,gBAA2C,qBAAqB,eAAe,eAAe,SAAS,GAAG,CAAC;EACjH,MAAM,gBAAgB,IAAI,oBAChB,IAAI,YAAa,QAAQ,mBAAmB,KAAK,KAAK,EAAE,aAAY,WAAU,OAAO,QAAQ,SAAS,EAAE,CAAC,GAAG,OAAO,IACzH;EAKJ,IAAI;GACF,IAAI,QAAQ,MAAM,SAAS,GACzB,UAAU;IAAE,MAAM;IAAa,MAAM;GAAG,CAAC;GAI3C,OAAO,MAAM,gBAAgB,WAAW;GACxC,OAAO,MAAM,QAAQ,KAAK,EAAE,MAAM,mBAAmB,cAAc,EAAE,CAAC;GACtE,UAAU;IAAE,MAAM;IAAe,MAAM;IAAgB,WAAW;IAAM,QAAQ,OAAO,MAAM;GAAc,CAAC;EAC9G,SACO,KAAK;GAGV,IAAI,IAAI,iBAAiB,YACvB,OAAO,IAAI;GAEb,MAAM,UAAU,IAAI,MAAM;GAC1B,MAAM;EACR;EA0CA,OAAO;GAAE,KAAK;GAAM,OAAO;GAAe,aAnCtB,YAA2B;IAC7C,IAAI;KACF,MAAM,SAAS,MAAM,cAAc;KAEnC,IAAI,OAAO,OAAO;MAChB,eAAe,aAAa,OAAO,KAAK;MACxC,MAAM,iBAAiB,IAAI,WAAW,KAAK,IAAI,cAAc;KAC/D;IACF,SACO,KAAK;KAGV,eAAe,aAAa,GAAG;KAC/B,MAAM,iBAAiB,IAAI,WAAW,KAAK,IAAI,aAAa,GAAG,GAAG,CAAC,CAAC,YAAY,KAAA,CAAS;IAC3F,UACQ;KACN,IAAI,IAAI,iBAAiB,YACvB,OAAO,IAAI;KAEb,MAAM,iBAAiB,CAAC,CAAC,YAAY,KAAA,CAAS;KAC9C,MAAM,WAAW,OAAO;MAAE,SAAS,WAAW,OAAO;MAAS,GAAI,iBAAiB,KAAA,IAAY,EAAE,OAAO,aAAa,IAAI,CAAC;KAAG,CAAC;KAC9H,MAAM,QAAQ,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;KAC1C,IAAI,aAAa,KAAK,IAAI;KAM1B,MAAM,UAAU,IAAI,WAAW,OAAO,UAAU,SAAS,iBAAiB,KAAA,IAAY,UAAU,WAAW;KAC3G,IAAI,iBAAiB,KAAK,IAAI;IAChC;GACF,EAAA,CAImD;EAAE;CACvD;CAEA,OAAO;EAAE;EAAc;EAAqB;CAAgB;AAC9D;;;;;;;;;;;;AC5RA,SAAgB,gBAAgB,OAAwC;CACtE,OAAO;EACL,OAAO,MAAM;EACb,OAAO,CAAC,GAAG,MAAM,KAAK;EACtB,SAAS,CAAC,GAAG,MAAM,OAAO;EAC1B,YAAY,MAAM;EAClB,OAAO,MAAM;CACf;AACF;;;ACpDA,SAAgB,uBAAuB,WAAyC,OAAkD;CAChI,MAAM,UAAU,MAAM,MAAM;CAC5B,IAAI,CAAC,SACH;CACF,UAAU;EACR,MAAM;EACN,WAAW,MAAM;EACjB,UAAU,gBAAgB,kBAAkB,OAAO,CAAC;CACtD,CAAC;AACH;AAEA,SAAgB,kBAAkB,EAAE,QAAQ,aAGQ;CAClD,OAAO;;;;;;;EAOL,iBAAiB,WAAW;GAC1B,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,CAAC,OACH,OAAO;GACT,MAAM,aAAa,KAAK,IAAI;GAC5B,MAAM,UAAU,MAAM,MAAM;GAC5B,OAAO,UAAU,kBAAkB,OAAO,IAAI;EAChD;;;;;;;;;;;;;;;;;;;;;;;;EAyBA,MAAM,SAAS,WAAW,OAAO;GAC/B,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,MAAM,UAAU,OAAO,MAAM;GAC7B,IAAI,CAAC,SACH,OAAO;GACT,MAAO,aAAa,KAAK,IAAI;GAC7B,MAAM,QAAQ,kBAAkB,OAAO,CAAC,CAAC;GACzC,IAAI,CAAC,OACH,OAAO;GAUT,MAAM,YAAY,kBAAkB,KAAK;GASzC,IAAI,MAAM,SAAS,KAAK,UAAU,WAAW,GAC3C,OAAO,kBAAkB,OAAO;GAIlC,eAAe,SAAS,OAAO,WAAW,EAAE,cAAc,KAAK,CAAC;GAChE,MAAM,QAAQ,KAAK;GAEnB,uBAAuB,WAAW,KAAM;GACxC,OAAO,kBAAkB,OAAO;EAClC;CACF;AACF;;;;;;;;;AC/FA,MAAa,sBAAsB;;;;;;;;;;;;;;;AAgBnC,eAAsB,iBACpB,KACA,WACA,KACA,UACkB;CAClB,IAAI,CAAC,IAAI,gBAAgB,IAAI,aAAa,CAAC,CAAC,cAAc,MACxD,OAAO;CAKT,MAAM,YAAY,IAAI,MAAM,UACxB,MAAM,IAAI,MAAM,QAAQ,SAAS,IACjC,MAAM,IAAI,MAAM,KAAK,SAAS;CAClC,IAAI,WAAW,WAAW,aAAa,KAAK,IAAI,IAAI,UAAU,aAAA,KAC5D,OAAO;CAWT,MAAM,cAAc,IAAI;CAIxB,OAAO,EAHkB,UAAU,oBAAoB,SAE/B,gBAAgB,KAAA,KAAa,UAAU,aAAa,cAAc;AAE5F;;;;;;;;;;AC9CA,SAAgB,oBAAoB,WAAyC,OAAkD;CAC7H,MAAM,UAAU,MAAM,MAAM;CAC5B,IAAI,CAAC,SACH;CACF,MAAM,SAAS,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAK,MAAK,EAAE,gBAAgB,KAAA,CAAS;CAChF,IAAI,CAAC,QACH;CACF,MAAM,UAAU,kBAAkB,MAAM;CACxC,IAAI,CAAC,cAAc,OAAO,GACxB;CAGF,MAAM,aAAa,QAAQ,MAAM,GAAG,EAAE,CAAC,EAAE;CACzC,UAAU;EACR,MAAM;EACN,WAAW,MAAM;EACjB,OAAO;GAAE,MAAM;GAAe,MAAM,qBAAqB,OAAO;GAAG,YAAY;GAAS,GAAI,aAAa,EAAE,QAAQ,WAAW,IAAI,CAAC;EAAG;CACxI,CAAC;AACH;;;;;;;;;;ACQA,MAAM,gCAAgC;AAEtC,SAAgB,qBAAqB,EAAE,KAAK,aAAa,UAAU,eAAe,qBAAqB,iBAAiB,kBAQrH;CACD,MAAM,EAAE,KAAK,WAAW,gBAAgB,WAAW,uBAAuB;CAE1E,eAAe,cACb,MAUA,UACA,iBAC4B;EAC5B,MAAM,aAAa,UAAU;EAC7B,MAAM,WAAW,IAAI,aAAa;EAGlC,4BAA4B,SAAS,eAAe;EACpD,MAAM,MAAM,MAAM,YAAY,KAAK,SAAS;EAC5C,mBAAmB,UAAU;EAQ7B,IAAI,IAAI,MAAM,WACZ,MAAM,IAAI,MACR,YAAY,KAAK,UAAU,0FAC7B;EAIF,IAAI,MAAM,iBAAiB,KAAK,KAAK,WAAW,KAAK,QAAQ,GAAG;GAC9D,UAAU,eAAe;GACzB,MAAM,IAAI,MACR,YAAY,KAAK,UAAU,mHAE7B;EACF;EASA,IAAI,CAAC,KAAK,MACR,eAAe,OAAO,KAAK,SAAS;EAWtC,mBAAmB,UAAU;EAC7B,MAAM,gBAAgB,MAAM,SAAS,gBAAgB,YAAY,mBAAmB,UAAU,CAAC;EAC/F,IAAI,cAAc,KAAK;GAIrB,gBAAgB,cAAc,UAAU;GACxC,UAAU,YAAY;GACtB,OAAO,EAAE,OAAO,cAAc,MAAM;EACtC;EACA,mBAAmB,UAAU;EAK7B,IAAI,KAAK,cAAc,KAAA,GACrB,MAAM,IAAI,MACR,qBAAqB,KAAK,UAAU,wJACtC;EAUF,IAAI,CAAC,KAAK,MACR,oBAAoB,WAAW,IAAI;EASrC,IAAI,IAAI,YACN,MAAM,uBAAuB,IAAI,YAAY,KAAK,WAAW,KAAK,SAAS;EAe7E,KAAK,MAAM,wBAAQ,IAAI,IAAI,CAAC,GAAI,IAAI,sBAAsB,CAAC,GAAI,GAAI,KAAK,mBAAmB,CAAC,CAAE,CAAC,GAC7F,IAAI;GACF,MAAM,IAAI,MAAM,cAAc,IAAI;EACpC,QACM,CAEN;EAGF,MAAM,QAAQ,WAAW;EAQzB,MAAM,kBAAkB,MAAM,qBAC5B,IAAI,IAAI,CAAC,GAAI,KAAK,mBAAmB,CAAC,GAAI,GAAI,IAAI,sBAAsB,CAAC,CAAE,CAAC,CAC9E;EAEA,MAAM,cACF,gBAAgB,SAAS,IACvB,uEAAuE,gBACtE,KAAI,MAAK,KAAK,EAAE,GAAG,CAAC,CACpB,KAAK,IAAI,EAAE,mJACZ,KAAA;EAON,IAAI;EACJ,MAAM,gBAAgB,IAAI;EAC1B,IAAI;EAEJ,IAAI;GACF,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,KAAK,SAAS;GAChD,MAAM,YAAY,MAAM,UAAU;GAElC,IAAI,OAAO,cAAc,YAAY,gBAAgB,SAAS,GAC5D,WAAW;GAEb,MAAM,aAAa,IAAI,sBAAsB,kBAAkB;GAC/D,MAAM,UAAU,iBAAiB,IAAI;GACrC,MAAM,UAAU,oBAAoB,MAAM,UAAU,YAAY;GAChE,eAAe,oBAAoB,YAAY,SAAS,GAAG,UAAU,QAAQ,CAAC;EAChF,QACM,CAEN;EAMA,MAAM,cACF,KAAK,eAAe,KAAK,YAAY,SAAS,IAC5C,CACE,GAAI,KAAK,OAAO,SAAS,IAAI,CAAC;GAAE,MAAM;GAAiB,MAAM,KAAK;EAAO,CAAC,IAAI,CAAC,GAC/E,GAAG,KAAK,YAAY,IAAI,oBAAoB,CAC9C,IACA,KAAK;EAOX,MAAM,cAAc,MAAM,IAAI,cAAc,IAAI,YAAY;EAQ5D,MAAM,wBAAwB,YAAY,UAAU,IAAI,gBAAgB,kBAAkB,IAAI,gBAAgB,kBAAkB;EAChI,mBAAmB,UAAU;EAC7B,MAAM,aAAa,4BACjB,SAAS,kBACT,QAAO,cAAc,YAAY,WAAW,GAAG,GAC/C;GAAE,aAAa,IAAI;GAAa,OAAO,iBAAiB,IAAI;EAAM,CACpE;EACA,MAAM,YAAY,mBAAmB;GACnC,SAAS,SAAS;GAClB,WAAW,SAAS;GACpB,kBAAkB,iBAAiB,uBAAuB,iBAAiB,IAAI,KAAK;GACpF,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;EACrC,CAAC;EAED,UAAU;GAAE;GAAK;GAAW;GAAoB;GAAqB;GAAiB;EAAe,GAAG;GACtG;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EAED,OAAO,EAAE,MAAM;CACjB;CAEA,OAAO;AACT;;AAGA,SAAS,oBAAoB,WAAyC,MAAyB;CAC7F,MAAM,aAAa,gBAAgB,KAAK,MAAM;CAC9C,UAAU;EACR,MAAM;EACN,WAAW,KAAK;EAIhB,MAAM;EACN,OAAO;GACL,MAAM;GACN,MAAM,KAAK;GAEX,GAAI,WAAW,SAAS,IAAI,EAAE,MAAM,WAAW,IAAI,CAAC;GAGpD,GAAI,KAAK,aAAa,SAClB,EACE,aAAa,KAAK,YAAY,KAAI,OAAM;IACtC,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE;IAEb,MAAO,EAAE,KAAK,SAAS,IAAK,KAAK,EAAE,KAAK,SAAS,IAAI,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,IAAI,IAAI;GAC1F,EAAE,EACJ,IACA,CAAC;EACP;CACF,CAAC;AACH;;AAGA,eAAe,uBACb,YACA,KACA,WACA,WACe;CACf,IAAI;CACJ,MAAM,WAAW,MAAM,QAAQ,KAAK,CAClC,WAAW,WACH,aACA,KACR,GACA,IAAI,SAAkB,YAAY;EAChC,eAAe,WAAW,SAAS,+BAA+B,IAAI;CACxE,CAAC,CACH,CAAC;CACD,IAAI,cACF,aAAa,YAAY;CAC3B,IAAI,UAAU;EACZ,IAAI,sBAAsB,MAAM;EAChC,UAAU;GACR,MAAM;GACN;GACA,OAAO;IACL,MAAM;IACN,MAAM,8BAA8B,8BAA8B;GACpE;EACF,CAAC;CACH;AACF;;AAYA,SAAS,UAAU,MAAkB,OAc5B;CACP,MAAM,EAAE,KAAK,WAAW,oBAAoB,qBAAqB,iBAAiB,mBAAmB;CACrG,MAAM,EAAE,MAAM,KAAK,OAAO,YAAY,UAAU,aAAa,aAAa,WAAW,eAAe,aAAa,UAAU,cAAc,oBAAoB;CAQ7J,MAAM,OAAO,oBAAoB,QAAQ;CAEzC,IAAI,oBAAoB,UAAU,6BAA6B,KAAK,MAAM;CAS1E,IAAI,aAAa,IAAI,gBAAgB;CAKrC,MAAM,YAAY,kBAAkB;EAClC;EACA,WAAW,KAAK;EAChB,iBAAiB,IAAI,MAAM;CAC7B,CAAC;CASD,MAAM,iBAAmC,IAAI,MAC1C,IAAI;EACH,QAAQ;EACR,QAAQ,eAAe,IAAI,SAAS,GAAG,IAAI,OAAO,MAAM,gBAAgB;EACxE,QAAQ,IAAI,WAAW;EACvB,UAAU;GAAE,GAAG;GAAW,GAAG;EAAK;EAGlC,GAAI,IAAI,SAAS,CAAC,cAAc,EAAE,iBAAiB,IAAI,MAAM,IAAI,CAAC;EAUlE,GAAI,gBACA,EACE,OAAO,IAAI,eAAe,SAAS,IAC/B,cACE,CAAC;GAAE,UAAU,IAAI;GAAa,OAAO;EAAc,GAAG,GAAG,IAAI,cAAc,IAC3E,MAAK,IAAI,kBAAkB,IAAI,CAAC,IAC/B,UAAU;GACT,MAAM,IAAI,YAAY,UAAU,MAAM;GACtC,OAAO,IAAK,iBAAiB,GAAG,MAAM,KAAK,KAAK,KAAA,IAAa,KAAA;EAC/D,CACF,IACA,cACN,IACA,CAAC;EACL,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAC/B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;CACzC,CAAC;CACH,UAAU;EAAE,MAAM;EAAa,WAAW,KAAK;EAAW;CAAM,CAAC;CACjE,uBAAuB,WAAW,GAAG;CACrC,MAAM,YAAY,QAAQ,QAAQ,CAAC,CAAC,WAAW;EAC7C,mBAAmB,UAAU;EAC7B,OAAO,IAAI,cACP,IAAI,YAAY,QAAQ,mBAAmB,KAAK,KAAK,EAAE,aAAa,WAAW;GAAE,eAAoB,KAAK,MAAM;EAAE,EAAE,CAAC,GAAG,QAAQ,IAChI,SAAS;CACf,CAAC;CACD,IAAI,UAA2C,EAAE,IAAI,KAAK;CAC1D,gBAAgB,UACb,OAAO,QAAQ;EACd,UAAU;GAAE,IAAI;GAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAAE;CACjF,CAAC,CAAC,CACD,KAAK,YAAY;EAChB,IAAI,iBAAiB,KAAK,IAAI;EAE9B,MAAM,SAAS,UAAU,IAAI,IAAI,MAAM,SAAS,MAAM;EACtD,IAAI;GACF,IAAI;IACF,oBAAoB,WAAW,GAAG;GACpC,UACQ;IACN,IAAI,oBAAoB,UAAU,CAAC;IACnC,IAAI,aAAa,KAAK,IAAI;IAE1B,oBAAoB,KAAK,SAAS;IAClC,gBAAgB;GAClB;EACF,UACQ;GAEN,MAAM;EACR;EACA,UAAU;GAAE,MAAM;GAAW,WAAW,KAAK;GAAW;GAAO,GAAG;EAAQ,CAAC;EAC3E,uBAAuB,WAAW,GAAG;CACvC,CAAC,CAAC;AACN;;;;ACvdA,SAAgB,kBACd,EAAE,QAAQ,kBACV,MACoD;CACpD,SAAS,iBAAiB,WAAyB;EACjD,eAAe,IAAI,SAAS;EAC5B,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,IAAI,OAAO;GACT,MAAM,cAAc,MAAM;GAC1B,MAAM,WAAW,MAAM;GACvB,MAAM,MAAM,MAAM;EACpB;EAQA,KAAK,UAAU,QAAQ,SAAS;EAChC,KAAK,MAAM,WAAW,KAAK,aAAa,KAAK,SAAS,GACpD,IAAI,QAAQ,MACV,KAAK,aAAa,OAAO,QAAQ,QAAQ,IAAI,kBAAkB;CAErE;CAEA,SAAS,aAAa,WAAmB,SAA0B;EACjE,MAAM,QAAQ,OAAO,IAAI,SAAS;EAGlC,IAAI,CAAC,OAAO,MAAM,MAAM,OAAO,GAC7B,OAAO;EACT,MAAM,kBAAkB,KAAK,OAAO;EACpC,OAAO;CACT;CAEA,OAAO;EACL,WAAW;EACX,OAAO;EAEP,SAAS,WAAW,SAAS;GAC3B,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,CAAC,OAAO,MAAM,SAAS,OAAO,GAChC,OAAO;GACT,MAAM,kBAAkB,KAAK,OAAO;GACpC,OAAO;EACT;CACF;AACF;;;ACpDA,SAAgB,qBAAqB,EAAE,WAAW,OAAO,aAA+B,KAAsB;CAU5G,MAAM,MAAM,KAAK,iBAAiB,EAAE,cAAc;EAChD,MAAM,QAAQ,IAAI,kBAAkB,QAAQ,OAAO;EACnD,IAAI,QAAQ,GACV;EACF,IAAI,kBAAkB,OAAO,OAAO,CAAC;EACrC,UAAU;GAAE,MAAM;GAAS;GAAW,MAAM;GAAM,OAAO;IAAE,MAAM;IAAe,MAAM;GAAQ;EAAE,CAAC;CACnG,CAAC;CACD,MAAM,MAAM,KAAK,oBAAoB;EACnC,IAAI,kBAAkB,SAAS;CACjC,CAAC;AACH;;;ACFA,SAAgB,WAAW,EAAE,KAAK,iBAAiB,aAAa,UAAU,eAAe,qBAAqB,iBAAiB,YAAY,kBAUxI;CACD,MAAM,EAAE,WAAW,YAAY,WAAW,oBAAoB,kBAAkB;CAChF,MAAM,gBAAgB,qBAAqB;EAAE;EAAK;EAAa;EAAU;EAAe;EAAqB;EAAiB;CAAe,CAAC;CAE9I,eAAe,WACb,MACA,UAC4B;EAC5B,mBAAmB;EACnB,IAAI,cAAc,KAAK,SAAS,GAC9B,MAAM,IAAI,MAAM,YAAY,KAAK,UAAU,0FAA0F;EAEvI,MAAM,aAAa,UAAU;EAC7B,MAAM,WAAW,QAAQ,cAAoB;EAC7C,WAAW,IAAI,KAAK,WAAW,SAAS,OAAO;EAC/C,IAAI;EACJ,IAAI,WAAW;EACf,MAAM,UAAU,EAAE,OAAO,WAAW,EAAE;EACtC,gBAAgB,IAAI,KAAK,WAAW,OAAO;EAC3C,IAAI,UAA2C,EAAE,IAAI,KAAK;EAC1D,MAAM,gBAAgB;GACpB,IAAI,WAAW,IAAI,KAAK,SAAS,MAAM,SAAS,SAC9C,WAAW,OAAO,KAAK,SAAS;GAClC,gBAAgB,OAAO,KAAK,SAAS;GAKrC,IAAI,CAAC,cAAc,KAAK,SAAS,GAC/B,oBAAoB,KAAK,SAAS;GACpC,IAAI;IACF,UAAU;KAAE,MAAM;KAAW,WAAW,KAAK;KAAW,OAAO,QAAQ;KAAO,GAAI,QAAQ,OAAO;KAAU,GAAI,CAAC,QAAQ,KAAK,UAAU,CAAC;IAAG,CAAC;GAC9I,UACQ;IACN,SAAS,QAAQ;GACnB;EACF;EACA,IAAI;GACF,MAAM,SAAS,MAAM,cAAc,MAAM,WAAW,eAAe;IAAE,aAAa;GAAW,CAAC;GAC9F,IAAI,CAAC,QAAQ,KACX,QAAQ,QAAQ,OAAO;GACzB,WAAW;GACX,OAAO;EACT,SACO,KAAK;GACV,UAAU;IAAE,IAAI;IAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAAE;GAC/E,MAAM;EACR,UACQ;GACN,MAAM,cAAc;IAClB,IAAI,CAAC,UAAU,UAAU,eAAe,UAAU,oBAChD,WAAW,KAAK,SAAS;GAC7B;GACA,IAAI,YACF,WAAgB,OAAO,QAAQ;IAC7B,UAAU;KAAE,IAAI;KAAO,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IAAE;GACjF,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,YAAY,KAAA,CAAS;QAElD;IACH,QAAQ;IACR,IAAI,UACF,WAAW,OAAO,CAAC;GACvB;EACF;CACF;CAEA,OAAO,EAAE,WAAW;AACtB;;;;;;;;;;;;;;;;ACnFA,MAAa,yBAAyB;;;;;;AAOtC,SAAgB,iBAAiB,KAA2B;CAC1D,IAAI,CAAC,MAAM,QAAQ,GAAG,GACpB,uBAAO,IAAI,IAAY;CACzB,OAAO,IAAI,IAAI,IAAI,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,CAAC,CAAC;AACtF;;AAGA,SAAgB,kBAAkB,MAAqC;CACrE,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,KAAK;AAC/B;;;;;;AAOA,SAAgB,wBAAwB,QAAyB;CAC/D,OAAO,WAAW;AACpB;;;ACvBA,SAAgB,wBAAwB,UAGtC;CAOA,MAAM,sBAAsB,WAAW;CAUvC,OAAO;EAAE,iBATe,OAAO,wBAAwB,YAAY,wBAAwB;EASjE,iBADF,oBAAoB,WAAW,wBACf;CAAE;AAC5C;AAEA,SAAgB,qBAAqB,OAWI;CACvC,MAAM,EAAE,KAAK,UAAU,gBAAgB,qBAAqB,iBAAiB,oBAAoB;CAMjG,MAAM,sBAAsB,eAAe,OAAO,KAAI,UAAS,MAAM,IAAI;CAOzE,MAAM,mBAAmB,oBAAoB,OAAO,KAAI,UAAS,MAAM,IAAI;CAC3E,MAAM,sBAAsB,SAAS,kBAAkB,KAAA,IACnD,KAAA,IACA,MAAM,qBAAK,IAAI,IAAI;EAAC,GAAG,SAAS;EAAe,GAAG;EAAqB,GAAG;CAAgB,CAAC,CAAC;CAoBhG,MAAM,eAAe;EAAE,GAnBF,kBAAkB;GAKrC,MAAM,sBAAsB;IAC1B;IACA,QAAQ,MAAM;IACd,eAAe,SAAS,yBAAyB;IACjD,OAAO,SAAS,uBAAuB;GACzC,CAAC;GACD,SAAS;EACX,CAOqC;EAAG,GAAI,MAAM,gBAAgB,CAAC;CAAG;CAEtE,MAAM,qBADuB,mBAAmB,mBAAmB,GAAG,MAAM,OAC1B,yBAAyB,cAAc,EAAE,IAAI,CAAC,IAAI;CAEpG,MAAM,gBAAgB,kBAClB,yBAAyB,oBAAoB,iBAAiB,EAAE,IAAI,CAAC,IACrE;CAQJ,MAAM,eAAe,CAAC,GAAI,MAAM,iBAAiB,CAAC,GAAI,GAAG,oBAAoB,MAAM;CAInF,OAHoB,aAAa,SAAS,IACtC;EAAE,GAAG;EAAe,SAAS,CAAC,GAAG,cAAc,GAAI,cAAc,WAAW,CAAC,CAAE;CAAE,IACjF;AAEN;AAEA,SAAgB,kBAAkB,EAAE,WAAW,OAAO,aAAqC;CAKzF,MAAM,wBAA8B;EAClC,UAAU;GACR,MAAM;GACN;GACA,QAAQ,MAAM,aAAa,KAAI,UAAS,MAAM,MAAM,IAAI;EAC1D,CAAC;CACH;CAMA,IAAI,YAAY;CAChB,MAAM,iBAAuB;EAC3B,YAAY;EACZ,MAAW,SAAS,KAAK,CAAC,CAAC,OAAM,QAAO,UAAU,UAAU,oBAAoB,OAAO,GAAG,GAAG,CAAC;CAChG;CACA,MAAM,MAAM,KAAK,oBAAoB;EACnC,IAAI,WACF,SAAS;CACb,CAAC;CACD,MAAM,cAAc,OAAe,WAA0B;EAC3D,MAAM,UAAU,MAAM;EACtB,IAAI,CAAC,SACH;EACF,MAAM,OAAO,iBAAiB,QAAQ,SAAS,uBAAuB;EACtE,IAAI,KAAK,IAAI,KAAK,MAAM,QACtB;EACF,IAAI,QACF,KAAK,IAAI,KAAK;OAEd,KAAK,OAAO,KAAK;EACnB,QAAQ,QAAQ,wBAAwB,kBAAkB,IAAI,CAAC;EAC/D,IAAI,MAAM,WACR,YAAY;OAEZ,SAAS;CACb;CACA,MAAM,MAAM,KAAK,oBAAoB,EAAE,YAAY;EACjD,WAAW,MAAM,MAAM,IAAI;EAC3B,gBAAgB;CAClB,CAAC;CACD,MAAM,MAAM,KAAK,sBAAsB,EAAE,OAAO,aAAa;EAM3D,IAAI,CAAC,wBAAwB,MAAM,GACjC;EACF,WAAW,MAAM,MAAM,KAAK;EAC5B,gBAAgB;CAClB,CAAC;AACH;;;AC9JA,SAAgB,kBAAkB,OAKpB;CACZ,MAAM,EAAE,WAAW,KAAK,cAAc,eAAe,YAAY,OAAO,aAAa,oBAAoB,OAAO,eAAe,QAAQ,MAAM,qBAAqB,SAAS,gBAAgB,mBAAmB,QAAQ,eAAe,iBAAiB,iBAAiB,gBAAgB;CACvR,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA,YAAY,IAAI,gBAAgB;EAChC;EACA;EACA;EACA,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;EACzC;EACA;EACA;EACA;EACA;EACA;EACA,UAAU;GACR,MAAM,eAAe,cAAc;GACnC,UAAU,eAAe,uBAAuB,CAAC;EACnD;EACA,mBAAmB,CAAC;EACpB,YAAY,KAAK,IAAI;EACrB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,mBAAmB,kBACnB,EACE,oBAAoB,CAClB,GAAI,kBAAkB,CAAC,2BAA2B,IAAI,CAAC,GACvD,GAAI,kBAAkB,CAAC,4BAA4B,IAAI,CAAC,CAC1D,EACF,IACA,CAAC;EACL,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;EACrC,GAAK,eAAe,cAAc,eAAe,aAC7C,EAAE,OAAO;GAAE,YAAY,cAAc;GAAY,YAAY,cAAc;EAAW,EAAE,IACxF,CAAC;CACP;AACF;;;AC3CA,SAAgB,kBAAkB,OAcO;CACvC,MAAM,EAAE,gBAAgB,iBAAiB,gBAAgB,mBAAmB,mBAAmB,WAAW,eAAe,WAAW;CAmBpI,IAAI;CACJ,OAAO,kBAAkB,YAAY,cAAc,UACvB;EACtB,IAAI,WACF,OAAO;EACT,MAAM,gBAA4B,CAAC,iBAAiB,GAAG,cAAc;EACrE,MAAM,cAAiC,CAAC;EACxC,KAAK,MAAM,CAAC,KAAK,iBAAiB,mBAChC,KAAK,MAAM,QAAQ,cAAc,UAAU,GAAG,GAC5C,YAAY,KAAK;GAAE,UAAU;GAAc,OAAO;EAAK,CAAC;EAE5D,KAAK,MAAM,QAAQ,WAAW,MAAM,aAAa,SAAS,GAAG;GAC3D,MAAM,aAAa,UAAU,KAAK;GAClC,IAAI,CAAC,KAAK,aAAa,kBAAkB,IAAI,KAAK,GAAG,KAAK,CAAC,YACzD;GACF,MAAM,SAAS,cAAc,UAAU,KAAK,GAAG;GAC/C,IAAI,OAAO,WAAW,GACpB;GACF,IAAI;IACF,MAAM,QAAQ,WAAW,QAAQ;IACjC,IAAI,kBAAkB,IAAI,MAAM,IAAI,GAClC;IACF,cAAc,KAAK,KAAK;IACxB,KAAK,MAAM,QAAQ,QACjB,YAAY,KAAK;KAAE,UAAU,MAAM;KAAM,OAAO;IAAK,CAAC;GAC1D,SACO,KAAK;IAGV,UAAU,kBAAkB,KAAK,IAAI,wBAAwB,GAAG;GAClE;EACF;EACA,YAAY;GACV,WAAW,YAAY,WAAW,IAAI,iBAAiB,eAAe,WAAW,WAAW;GAC5F,UAAU;GACV,WAAW;GACX,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAC3B,OAAO,MAAM;GACb,QAAQ,MAAM;GACd,UAAU,MAAM;GAChB,MAAM,MAAM;EACd;EACA,OAAO;CACT,IACA,KAAA;AACN;;;;;;;;AChDA,SAAgB,yBAAyB,WAAqF;CAC5H,IAAI,CAAC,WACH,OAAO;CACT,MAAM,MAAM,UAAU,OAAO,UAAU,IAAI,SAAS,IAAI,UAAU,MAAM,KAAA;CACxE,MAAM,YAAY,UAAU,aAAa,UAAU,UAAU,YAAY,YAAY,UAAU,YAAY,KAAA;CAC3G,MAAM,MAAM,UAAU,OAAO,KAAA;CAC7B,IAAI,UAAU,WAAW,KAAA,KAAa,CAAC,OAAO,CAAC,aAAa,CAAC,KAC3D,OAAO;CACT,OAAO;EACL,GAAI,UAAU,WAAW,KAAA,IAAY,EAAE,QAAQ,UAAU,OAAO,IAAI,CAAC;EACrE,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;EACrB,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;EACjC,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;CACvB;AACF;;;;;;AAOA,SAAgB,oBACd,QACA,UAC+B;CAC/B,OAAO,yBAAyB;EAC9B,GAAI,YAAY,SAAS,QAAQ,SAAS,gBAAgB,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC;EACnF,GAAG,WAAW,MAAM;CACtB,CAAC;AACH;AAEA,SAAS,WAAW,QAA+E;CACjG,IAAI,CAAC,QACH,OAAO,CAAC;CACV,OAAO;EACL,GAAI,OAAO,WAAW,KAAA,IAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;EAC/D,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;EACxC,GAAI,OAAO,UACP,EACE,WAAW;GACT,SAAS,OAAO;GAChB,GAAI,OAAO,UAAU,KAAA,IAAY,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;GAC5D,GAAI,OAAO,QAAQ,KAAA,IAAY,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;GACtD,GAAI,OAAO,YAAY,KAAA,IAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;GAClE,GAAI,OAAO,cAAc,KAAA,IAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;GACxE,GAAI,OAAO,qBAAqB,KAAA,IAAY,EAAE,kBAAkB,OAAO,iBAAiB,IAAI,CAAC;EAC/F,EACF,IACA,CAAC;CACP;AACF;;;ACxEA,SAAgB,iBAAiB,iBAAsD,sBAAgD,KAAA,GAA6D;;;;;;;;;;CAUlM,SAAS,WAAW,WAAmB,MAA2B;EAChE,MAAM,WAAW,gBAAgB,IAAI,SAAS,CAAC,EAAE;EACjD,IAAI,aAAa,KAAA,GACf,OAAO;EAGT,SAFiB,OAAO,KAAK,UAAU,QAAQ,WAAW,KAAK,SAAS,MAAM,OACnD,KAAK,cAAc,KAAA,IAAY,cAAc,MACvD,kBAAkB;GAAE,UAAU,KAAK;GAAU,aAAa,KAAK,eAAe,KAAA;EAAU,CAAC;CAC5G;CACA,OAAO;AACT;AAOA,SAAgB,aAAa,WAA+B,SAAoC;CAC9F,OAAO,cAAc,KAAA,KAAa,QAAQ,SAAS;AACrD;AAEA,SAAgB,gBACd,EAAE,WAAW,SACb,OASM;CACN,MAAM,EAAE,QAAQ,iBAAiB,KAAK,eAAe,eAAe;CASpE,IAAI,YAEF,MAAM,MAAM,KAAK,oBAAoB,EAAE,aAAa;EAClD,MAAM,OAAO,OAAO,IAAI,SAAS;EACjC,IAAI,MAAM,UAAU,SAAS,OAAO,QAAQ,KAAK,KAC/C,OAAO,MAAM,KAAK;CACtB,CAAC;CAEH,IAAI,MAAM,iBAAiB,YACzB,MAAM,MAAM,KAAK,qBAAqB,QAAQ;EAC5C,MAAM,OAAO,gBAAgB,IAAI,SAAS,CAAC,EAAE,OAAO;EACpD,IAAI,SAAS,KACX;EACF,MAAM,cAAcC,cAAY,IAAI,KAAK;EACzC,IAAI,SAAS,sBAAsB,IAAI,QAAQ,WAAW;GACxD,KAAK;GACL,GAAI,gBAAgB,OAAO,EAAE,YAAY,IAAI,CAAC;EAChD,CAAC,CAAC;CACJ,CAAC;AAEL;AAEA,SAAgB,4BAA4B,OAK8B;CACxE,MAAM,EAAE,iBAAiB,QAAQ,wBAAwB,cAAc;;;;;;CAMvE,MAAM,cAAc,WAAmB,QAAgD;EACrF,IAAI,CAAC,KACH,OAAO;EACT,IAAI;GACF,OAAO,UAAU,YAAY,GAAG;EAClC,SACO,KAAK;GAEV,UAAU,gCAAgC,UAAU,QAAQ,KAAK,UAAU,GAAG,EAAE,yCAAyC,GAAG;GAC5H;EACF;CACF;CACA,OAAO,SAAS,mBAAmB,WAAW,WAAW;EACvD,MAAM,EAAE,KAAK,GAAG,SAAS,aAAa,CAAC;EACvC,MAAM,UAAU,WAAW,WAAW,GAAG;EACzC,MAAM,OAAO,yBAAyB,YAAY;GAAE,GAAG;GAAM,GAAI,YAAY,KAAA,IAAY,EAAE,KAAK,QAAQ,IAAI,CAAC;EAAG,IAAI,IAAI;EAGxH,MAAM,WAAW,gBAAgB,IAAI,SAAS,KAAK;EACnD,IAAI,gBAAgB,QAAQ,MAAM,gBAAgB,IAAI,GACpD;EACF,IAAI,MACF,gBAAgB,IAAI,WAAW,IAAI;OAEnC,gBAAgB,OAAO,SAAS;EAClC,MAAM,EAAE,KAAK,cAAc,GAAG,kBAAkB,YAAY,CAAC;EAC7D,MAAM,EAAE,KAAK,UAAU,GAAG,cAAc,QAAQ,CAAC;EACjD,IAAI,gBAAgB,aAAa,MAAM,gBAAgB,SAAS,GAAG;GACjE,uBAA4B,SAAS;GACrC;EACF;EAUA,MAAM,MAAM,OAAO,IAAI,SAAS;EAChC,IAAI,CAAC,KAAK,YACR;EACF,IAAI,MAAM,MAAM,OAAO,IAAI;EAE3B,IAAI,IAAI,MAAM,QACZ,IAAI,MAAM,OAAO,MAAM,IAAI;CAC/B;AACF;;;;AC1IA,MAAM,0BAA0B;AAEhC,SAAgB,yBAAyB,OAA6F;CAQpI,MAAM,mBAAmB,OAAO,MAAc,UAAgE;EAC5G,MAAM,SAAS,MAAM;EACrB,IAAI,CAAC,gBAAgB,IAAI,IAAI,KAAK,CAAC,UAAU,OAAO,MAAM,SAAS,UACjE,OAAO,KAAA;EACT,IAAI;GACF,MAAM,OAAO,MAAM,MAAM,UAAU,WAAW,QAAQ,MAAM,IAAI;GAChE,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,OAAO,yBAChD,OAAO,KAAA;GACT,OAAO,MAAM,MAAM,UAAU,SAAS,QAAQ,MAAM,IAAI;EAC1D,QACM;GAEJ;EACF;CACF;CACA,OAAO;AACT;AAEA,SAAgB,2BAA2B,OAAc,QAAiC;;;;;;;CAOxF,MAAM,sBACJ,QACA,UACA,WACmC;EACnC,MAAM,UAAU,OAAO,MAAM,MAAM;EACnC,IAAI,CAAC,SACH,OAAO,KAAA;EAQT,MAAM,eAAe,4BAA4B,MAA2D;EAC5G,MAAM,SAAS,6BAA6B,QAAQ,UAAU,YAAY;EAC1E,MAAM,aAAa,4BAA4B,MAAM;EAErD,IAAI,OAAO,WAAW,UAAU;GAC9B,IAAI,OAAO,4BAA4B,MAAM;GAQ7C,IAAI,aAAa,cAAc;IAG7B,MAAM,UAAW,QAAQ,cAAqC;IAC9D,MAAM,OAAO,OAAO,YAAY,WAAW,UAAU;IACrD,IAAI,MACF,OAAO,uBAAuB,MAAM,QAAQ,IAAI;GACpD;GAEA,OAAO,KAAK,WAAW,IAAI,aAAa,GAAG,KAAK,MAAM;EACxD;EAWA,OAAO,CAAC,GALQ,OAAsD,KAAI,UACxE,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,WAC3C;GAAE,GAAG;GAAO,MAAM,4BAA4B,MAAM,IAAI;EAAE,IAC1D,KAEU,GAAG;GAAE,MAAM;GAAQ,MAAM,KAAK;EAAa,CAAC;CAC9D;CAEA,MAAM,MAAM,KAAK,mBAAmB,QAAQ;EAC1C,MAAM,OAAO,mBAAmB,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM;EAChE,IAAI,SAAS,KAAA,GACX,IAAI,SAAS;CACjB,CAAC;CAED,MAAM,MAAM,KAAK,yBAAyB,QAAQ;EAChD,MAAM,OAAO,mBAAmB,IAAI,QAAQ,IAAI,MAAM,IAAI,MAAM;EAChE,IAAI,SAAS,KAAA,GACX,IAAI,SAAS;CACjB,CAAC;AACH;AAEA,SAAgB,0BAA0B,OAAc,EAAE,QAAQ,6BAA0G;;;;;;CAM1K,MAAM,MAAM,KAAK,oBAAoB;EACnC,OAAO,MAAM;EACb,0BAA0B,MAAM;EAKhC,MAAM,UAAU,MAAM;EACtB,IAAI,WAAW,gBAAgB,OAAO,CAAC,CAAC,QAAQ,SAAS,GACvD,QAAa,KAAK,CAAC,CAAC,OAAM,QAAO,UAAU,SAAS,sBAAsB,OAAO,GAAG,GAAG,CAAC;CAC5F,CAAC;AACH;;;ACtHA,SAAgB,kBAAkB,EAAE,WAAW,OAAO,aAA+B,YAA8B;CAgBjH,MAAM,iCAAiB,IAAI,IAA8B;CACzD,MAAM,WAAW,QAAwB;EAMvC,MAAM,YAAY,KAAK,IAAI;EAC3B,eAAe,IAAI,IAAI,IAAI;GACzB;GACA,MAAM,IAAI;GACV,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;EAC1C,CAAC;EACD,UAAU;GAAE,MAAM;GAAS;GAAW,OAAO,qBAAqB,KAAK,SAAS;EAAE,CAAC;CACrF;CACA,MAAM,cAAc,QAAsB;EACxC,MAAM,SAAS,eAAe,IAAI,IAAI,EAAE;EACxC,eAAe,OAAO,IAAI,EAAE;EAC5B,UAAU;GAAE,MAAM;GAAS;GAAW,OAAO,mBAAmB,KAAK,MAAM;EAAE,CAAC;CAChF;CACA,MAAM,WAAW,EAAE,IAAI,OAAO,YAA+C;EAG3E,eAAe,OAAO,EAAE;EAExB,WAAW;GAAE,UAAU;GAAS,OAAO;EAAW,GAAG,IAAI,GAAG,IAAI,MAAM,WAAW;GAAE,SAAS;GAAI,OAAO,SAAS;EAAE,CAAC;CACrH;CAEA,MAAM,MAAM,KAAK,iBAAgB,QAAO,UAAU;EAAE,MAAM;EAAS;EAAW,OAAO,sBAAsB,GAAG;CAAE,CAAC,CAAC;CAClH,MAAM,MAAM,KAAK,gBAAgB,OAAO;CACxC,MAAM,MAAM,KAAK,kBAAkB,UAAU;CAC7C,MAAM,MAAM,KAAK,eAAe,OAAO;CACvC,MAAM,MAAM,KAAK,sBAAsB,OAAO;CAC9C,MAAM,MAAM,KAAK,wBAAwB,UAAU;CACnD,MAAM,MAAM,KAAK,qBAAqB,OAAO;AAC/C;;;;ACxDA,SAAgB,mBAAmB,EAAE,WAAW,OAAO,aAA4C;CAajG,MAAM,2BAAW,IAAI,IAAY;CACjC,MAAM,WAAW,WAAyB;EACxC,IAAI,SAAS,OAAO,MAAM,GACxB,UAAU;GAAE,MAAM;GAAwB;GAAW;EAAO,CAAC;CACjE;CAEA,MAAM,MAAM,KAAK,gBAAgB,QAAQ;EACvC,QAAQ,QAAQ;EAEhB,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IADT,MAAM;IAAY,MAAM,IAAI;IAAO,WAAW;IAAM,QAAQ,IAAI;GACnD;EAAE,CAAC;CAC/C,CAAC;CAED,MAAM,MAAM,KAAK,oBAAoB,QAAQ;EAC3C,QAAQ,QAAQ;EAEhB,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IADT,MAAM;IAAY,MAAM,IAAI;IAAO,QAAQ,IAAI;GAClC;EAAE,CAAC;CAC/C,CAAC;CAcD,MAAM,MAAM,KAAK,sBAAsB,QAAQ;EAC7C,QAAQ,IAAI,OAAO;EASnB,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IAPpC,MAAM;IACN,MAAM,IAAI;IACV,WAAW;IACX,QAAQ,IAAI;IACZ,SAAS,IAAI;IACb,GAAI,OAAO,IAAI,UAAU,WAAW,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;GAEpB;EAAE,CAAC;CAC/C,CAAC;CAED,MAAM,MAAM,KAAK,0BAA0B,QAAQ;EACjD,QAAQ,IAAI,OAAO;EAQnB,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IANpC,MAAM;IACN,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,SAAS,IAAI;IACb,GAAI,OAAO,IAAI,UAAU,WAAW,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;GAEpB;EAAE,CAAC;CAC/C,CAAC;CACD,OAAO;AACT;AAEA,SAAgB,kBAAkB,EAAE,WAAW,OAAO,aAA+B,UAA6B;CAMhH,MAAM,MAAM,KAAK,iBAAiB,EAAE,aAAa,kBAAkB;EACjE,SAAS,IAAI,QAAQ;EACrB,UAAU;GAAE,MAAM;GAAgB;GAAW,SAAS;GAAa,KAAK;GAAa,QAAQ;EAAS,CAAC;CACzG,CAAC;CACD,MAAM,MAAM,KAAK,uBAAuB,EAAE,aAAa,aAAa,cAAc;EAChF,SAAS,IAAI,OAAO;EACpB,UAAU;GAAE,MAAM;GAAgB;GAAW,SAAS;GAAa,KAAK;GAAa,QAAQ;EAAQ,CAAC;CACxG,CAAC;CAOD,MAAM,MAAM,KAAK,sBAAsB;EACrC,SAAS,OAAO,QAAQ;EACxB,UAAU;GAAE,MAAM;GAAwB;GAAW,QAAQ;EAAS,CAAC;CACzE,CAAC;CACD,MAAM,MAAM,KAAK,uBAAuB,EAAE,cAAc;EACtD,SAAS,OAAO,OAAO;EACvB,UAAU;GAAE,MAAM;GAAwB;GAAW,QAAQ;EAAQ,CAAC;CACxE,CAAC;CAGD,MAAM,MAAM,KAAK,oBAAoB;EACnC,SAAS,MAAM;CACjB,CAAC;AACH;;;;;;;AC5FA,SAAS,aAAa,QAAyB;CAC7C,IAAI,OAAO,WAAW,UACpB,OAAO;CACT,IAAI;EACF,OAAO,eAAe,MAA8C;CACtE,QACM;EACJ,OAAO,KAAK,UAAU,MAAM;CAC9B;AACF;AAEA,SAAgB,qBACd,EAAE,WAAW,WAAW,SACxB,OAM4C;CAC5C,MAAM,EAAE,QAAQ,2BAA2B,qBAAqB;CAChE,MAAM,EAAE,cAAc,aAAa,MAAM;;;;;;;;;;;CAWzC,MAAM,iBACJ,QACA,MACA,WACA,cACA,QACA,cACS;EACT,MAAM,UAAU,OAAO,KAAK,MAAM;EAElC,IAAI;EACJ,IAAI;EAEJ,IAAI,SAAS;GACX,gBAAgB,QAAQ;GACxB,OAAO;IAAE,GAAG,QAAQ;IAAiB,UAAU,QAAQ,SAAS,MAAM;GAAE;EAC1E,OACK;GACH,gBAAgB;GAChB,IAAI,SAAS,cACX,OAAO,mBAAmB,MAAM,WAAW,gBAAgB,EAAE;QAC1D,IAAI,SAAS,UAAU,SAAS,cACnC,OAAO,mBAAmB,MAAM,WAAW,YAAY;EAC3D;EAYA,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IATpC,MAAM;IACN,MAAM,gBAAgB,MAAM,aAAa;IACzC,MAAM;IACN;IACA,OAAO;IACP,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAC3B,GAAI,YAAY;KAAE,SAAS,UAAU;KAAS,OAAO,UAAU;IAAM,IAAI,CAAC;IAC1E,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;GAEiB;EAAE,CAAC;CAC/C;CAIA,MAAM,MAAM,KAAK,eAAe,OAAO,QAAQ;EAC7C,IAAI,IAAI,qBAAqB,KAAA,GAC3B;EACF,aAAa;GAAE,MAAM;GAAQ,IAAI,IAAI;GAAQ,OAAO,IAAI;GAAM,WAAW,KAAK,IAAI;EAAE,CAAC;EACrF,MAAM,QAAQ,IAAI;EAClB,MAAM,eAAe,IAAI,gBAAgB,MAAM,iBAAiB,IAAI,MAAM,KAAK;EAC/E,cAAc,IAAI,QAAQ,IAAI,MAAM,OAAO,cAAc,IAAI,MAAM;CACrE,CAAC;CAED,MAAM,MAAM,KAAK,sBAAsB,QAAQ;EAC7C,IAAI,IAAI,qBAAqB,KAAA,GAC3B;EACF,aAAa;GACX,MAAM;GACN,IAAI,IAAI;GACR,OAAO,IAAI;GACX,WAAW,KAAK,IAAI;GACpB,SAAS,IAAI;EACf,CAAC;EACD,cAAc,IAAI,QAAQ,IAAI,MAAM,IAAI,OAAkC,IAAI,cAAc,IAAI,QAAQ;GACtG,SAAS,IAAI;GACb,OAAO,IAAI;EACb,CAAC;CACH,CAAC;CAgBD,MAAM,mCAAmB,IAAI,IAAkC;CAC/D,MAAM,oCAAoB,IAAI,IAAoB;CAClD,MAAM,oCAAoB,IAAI,IAAoB;CAClD,MAAM,MAAM,KAAK,iBAAiB,QAAQ;EACxC,iBAAiB,IAAI,IAAI,QAAQ,GAAG;CACtC,CAAC;CACD,MAAM,MAAM,KAAK,sBAAsB,QAAQ;EAC7C,kBAAkB,IAAI,IAAI,QAAQ,IAAI,MAAM;CAC9C,CAAC;CACD,MAAM,MAAM,KAAK,4BAA4B,QAAQ;EACnD,kBAAkB,IAAI,IAAI,QAAQ,IAAI,MAAM;CAC9C,CAAC;CACD,MAAM,sBAAsB,QAAsG;EAChI,MAAM,cAAc,iBAAiB,IAAI,IAAI,MAAM,CAAC,EAAE;EACtD,MAAM,UAAU,kBAAkB,IAAI,IAAI,MAAM;EAChD,MAAM,UAAU,kBAAkB,IAAI,IAAI,MAAM;EAChD,iBAAiB,OAAO,IAAI,MAAM;EAClC,kBAAkB,OAAO,IAAI,MAAM;EACnC,kBAAkB,OAAO,IAAI,MAAM;EACnC,QAAQ,IAAI,SAAZ;GAGE,KAAK;IACH,IAAI,gBAAgB,KAAA,GAClB,OAAO;KAAE,MAAM,aAAa,WAAW;KAAG,SAAS;IAAM;IAC3D,OAAO;KAAE,MAAM,eAAe,WAAW,iBAAiB,IAAI;KAAU,SAAS;IAAK;GACxF,KAAK,cACH,OAAO,IAAI,SAAS;IAAE,MAAM,YAAY,IAAI;IAAU,SAAS;GAAM,IAAI,KAAA;GAC3E,KAAK,iBACH,OAAO,YAAY,KAAA,IAAY;IAAE,MAAM,qBAAqB;IAAW,SAAS;GAAK,IAAI,KAAA;GAC3F,SACE;EACJ;CACF;CACA,MAAM,gBACJ,KACA,cACS;EACT,IAAI,IAAI,YAAY,aAAa,IAAI,qBAAqB,KAAA,GACxD;EACF,SAAS,IAAI,MAAM;EACnB,MAAM,kBAAkB,IAAI,YAAY,gBAAgB,0BAA0B,OAAO,IAAI,MAAM;EACnG,MAAM,SAAS,mBAAmB,GAAG;EACrC,IAAI,iBACF;EACF,IAAI,IAAI,YAAY,WAClB,cAAc,IAAI,QAAQ,IAAI,MAAM,IAAI,OAAkC,KAAA,GAAW,IAAI,QAAQ,SAAS;EAC5G,IAAI,WAAW,KAAA,GACb;EAUF,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IARpC,MAAM;IACN,MAAM,OAAO;IACb,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;IAC3C,GAAI,YAAY;KAAE,SAAS,UAAU;KAAS,OAAO,UAAU;IAAM,IAAI,CAAC;IAC1E,GAAI,OAAO,UAAU,EAAE,SAAS,KAAc,IAAI,CAAC;GAEX;EAAE,CAAC;CAC/C;CACA,MAAM,MAAM,KAAK,oBAAmB,QAAO,aAAa,GAAG,CAAC;CAC5D,MAAM,MAAM,KAAK,0BAAyB,QAAO,aAAa,KAAK;EAAE,SAAS,IAAI;EAAS,OAAO,IAAI;CAAM,CAAC,CAAC;CAC9G,OAAO,EAAE,kBAAkB;AAC7B;AAEA,SAAgB,uBACd,EAAE,WAAW,WAAW,SACxB,OAMM;CACN,MAAM,EAAE,QAAQ,mBAAmB,2BAA2B;CAC9D,MAAM,EAAE,aAAa,MAAM;CAM3B,MAAM,mBAAmB,MAAc,WAA4B;EACjE,MAAM,OAAO,aAAa,MAAM;EAChC,OAAO,SAAS,UAAU,qBAAqB,IAAI,IAAI;CACzD;CAEA,MAAM,MAAM,KAAK,eAAe,QAAQ;EACtC,IAAI,IAAI,qBAAqB,KAAA,GAC3B;EACF,SAAS,IAAI,MAAM;EACnB,kBAAkB,OAAO,IAAI,MAAM;EASnC,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IAPpC,MAAM;IACN,MAAM,gBAAgB,IAAI,MAAM,IAAI,MAAM;IAC1C,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,QAAQ,IAAI;IACZ,GAAI,IAAI,UAAU,EAAE,SAAS,KAAc,IAAI,CAAC;GAER;EAAE,CAAC;EAK7C,IAAI,WAAW,IAAI,IAAI,GACrB,uBAAuB;GAAE;GAAW;EAAM,CAAC;CAC/C,CAAC;CAMD,MAAM,MAAM,KAAK,sBAAsB,QAAQ;EAC7C,UAAU;GAAE,MAAM;GAAqB;GAAW,UAAU,IAAI;EAAS,CAAC;CAC5E,CAAC;CACD,MAAM,MAAM,KAAK,4BAA4B,QAAQ;EACnD,UAAU;GAAE,MAAM;GAAqB;GAAW,UAAU,IAAI;EAAS,CAAC;CAC5E,CAAC;CAED,MAAM,MAAM,KAAK,qBAAqB,QAAQ;EAC5C,IAAI,IAAI,qBAAqB,KAAA,GAC3B;EACF,SAAS,IAAI,MAAM;EACnB,kBAAkB,OAAO,IAAI,MAAM;EAWnC,UAAU;GAAE,MAAM;GAAS;GAAW,OAAA;IATpC,MAAM;IACN,MAAM,gBAAgB,IAAI,MAAM,IAAI,MAAM;IAC1C,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,QAAQ,IAAI;IACZ,SAAS,IAAI;IACb,OAAO,IAAI;IACX,GAAI,IAAI,UAAU,EAAE,SAAS,KAAc,IAAI,CAAC;GAER;EAAE,CAAC;EAE7C,IAAI,WAAW,IAAI,IAAI,GACrB,uBAAuB;GAAE;GAAW;EAAM,CAAC;CAC/C,CAAC;CAED,MAAM,MAAM,KAAK,eAAe,QAAQ;EACtC,SAAS,IAAI,MAAM;EAKnB,OAAO,QAAQ,IAAI,MAAM;EAKzB,IAAI,IAAI,qBAAqB,KAAA,GAC3B,kBAAkB,IAAI,IAAI,QAAQ,IAAI,MAAM,OAAO;CACvD,CAAC;CAED,MAAM,MAAM,KAAK,qBAAqB,QAAQ;EAC5C,SAAS,IAAI,MAAM;EACnB,OAAO,QAAQ,IAAI,MAAM;EACzB,IAAI,IAAI,qBAAqB,KAAA,GAC3B,kBAAkB,IAAI,IAAI,QAAQ,IAAI,MAAM,OAAO;CACvD,CAAC;CAED,MAAM,MAAM,KAAK,mBAAmB,QAAQ;EAC1C,SAAS,IAAI,MAAM;EACnB,kBAAkB,OAAO,IAAI,MAAM;CACrC,CAAC;CAED,MAAM,MAAM,KAAK,yBAAyB,QAAQ;EAChD,SAAS,IAAI,MAAM;EACnB,kBAAkB,OAAO,IAAI,MAAM;CACrC,CAAC;AACH;;;ACrSA,SAAgB,iBAAiB,EAAE,WAAW,OAAO,aAAqC;CAOxF,MAAM,MAAM,KAAK,2BAA2B,EAAE,IAAI,MAAM,OAAO,aAAa;EAC1E,UAAU;GACR,MAAM;GACN;GACA,OAAO;IAAE,MAAM;IAAQ,MAAM,gBAAgB,MAAM,KAAK;IAAG,MAAM;IAAM;IAAO,QAAQ;IAAI;GAAO;EACnG,CAAC;CACH,CAAC;CACD,MAAM,MAAM,KAAK,8BAA8B,EAAE,WAAW,UAAU,SAAS,aAAa;EAC1F,UAAU;GACR,MAAM;GACN;GACA,OAAO;IAAE,MAAM;IAAe,MAAM,wBAAwB,OAAO;IAAG,MAAM;IAAU,QAAQ;IAAW;GAAO;EAClH,CAAC;CACH,CAAC;CACD,MAAM,MAAM,KAAK,iCAAiC,EAAE,IAAI,MAAM,OAAO,SAAS,OAAO,aAAa;EAChG,UAAU;GACR,MAAM;GACN;GACA,OAAO;IAAE,MAAM;IAAQ,MAAM,gBAAgB,MAAM,KAAK;IAAG,MAAM;IAAM;IAAO,QAAQ;IAAI;IAAS;IAAO;GAAO;EACnH,CAAC;CACH,CAAC;CACD,MAAM,MAAM,KAAK,oCAAoC,EAAE,WAAW,UAAU,SAAS,SAAS,OAAO,aAAa;EAChH,UAAU;GACR,MAAM;GACN;GACA,OAAO;IAAE,MAAM;IAAe,MAAM,wBAAwB,OAAO;IAAG,MAAM;IAAU,QAAQ;IAAW;IAAS;IAAO;GAAO;EAClI,CAAC;CACH,CAAC;CAED,MAAM,MAAM,KAAK,kBAAkB,EAAE,OAAO,eAAe;EACzD,MAAM,OAAO,eAAe,QAAQ;EACpC,IAAI,KAAK,SAAS,GAChB,UAAU;GAAE,MAAM;GAAgB;GAAW;EAAK,CAAC;CACvD,CAAC;CAGD,MAAM,MAAM,KAAK,oBAAoB,EAAE,QAAQ,cAAc,WAAW,WAAW,iBAAiB;EAClG,UAAU;GACR,MAAM;GACN;GACA;GACA;GACA;GACA;GACA,GAAI,eAAe,KAAA,IAAY,EAAE,WAAW,IAAI,CAAC;EACnD,CAAC;CACH,CAAC;CAED,MAAM,MAAM,KAAK,eAAe,QAAQ;EACtC,UAAU;GACR,MAAM;GACN;GACA,QAAQ,IAAI;GACZ,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;EAC1C,CAAC;CACH,CAAC;CAID,MAAM,MAAM,KAAK,qBAAqB,QAAQ;EAC5C,UAAU;GACR,MAAM;GACN;GACA,QAAQ,IAAI;GACZ,SAAS,IAAI;GACb,OAAO,IAAI;GACX,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;EAC1C,CAAC;CACH,CAAC;AACH;;;ACrEA,SAAgB,iBAAiB,OAAkE;CACjG,OAAO,CAAC,GAAG,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,QAAO,SAAQ,KAAK,YAAY,KAAA,CAAS;AAC3E;AAEA,SAAgB,sBAAsB,WAAyC,OAAwE;CACrJ,UAAU;EAAE,MAAM;EAAiB,WAAW,MAAM;EAAW,OAAO,iBAAiB,KAAK;CAAE,CAAC;AACjG;AAEA,SAAgB,kBAAkB,EAAE,WAAW,aAAgE,MAAiD;CAC9J,MAAM,gBAAgB,SAAgC;EACpD,KAAK,IAAI,KAAK,IAAI,IAAI;EACtB,UAAU;GAAE,MAAM;GAAiB;GAAW,OAAO,iBAAiB,EAAE,KAAK,CAAC;EAAE,CAAC;CACnF;CAEA,MAAM,YAAY,OAAqB;EACrC,IAAI,CAAC,KAAK,OAAO,EAAE,GACjB;EACF,UAAU;GAAE,MAAM;GAAiB;GAAW,OAAO,iBAAiB,EAAE,KAAK,CAAC;EAAE,CAAC;CACnF;CACA,OAAO;EAAE;EAAc;CAAS;AAClC;AAEA,SAAgB,2BACd,EAAE,WAAW,OAAO,aACpB,EAAE,MAAM,SAAS,aACX;CACN,MAAM,EAAE,cAAc,aAAa;CACnC,MAAM,0BAA0B,QAAwF;EACtH,aAAa;GACX,MAAM;GACN,IAAI,IAAI;GACR,OAAO,uBAAuB,YAAY,IAAI,SAAS,EAAE;GACzD,WAAW,IAAI;GACf,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;EAChD,CAAC;CACH;CAEA,MAAM,mCAAmC,QAU7B;EACV,SAAS,IAAI,MAAM;EACnB,UAAU;GACR,MAAM;GACN;GACA,OAAO;IACL,MAAM;IACN,MAAM,kBAAkB,GAAG;IAC3B,MAAM;KACJ,QAAQ,IAAI;KACZ,QAAQ,IAAI;KACZ,UAAU,IAAI;KACd,YAAY,IAAI;KAChB,SAAS,IAAI;KACb,YAAY,IAAI;IAClB;IACA,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;IAC9C,GAAI,OAAO,IAAI,UAAU,WAAW,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;GAC9D;EACF,CAAC;CACH;CAEA,MAAM,MAAM,KAAK,qBAAoB,QAAO,uBAAuB,GAAG,CAAC;CAEvE,MAAM,MAAM,KAAK,qBAAoB,QAAO,uBAAuB,GAAG,CAAC;CACvE,MAAM,MAAM,KAAK,oBAAoB,QAAQ;EAC3C,gCAAgC,GAAG;EAGnC,UAAU,SAAS;CACrB,CAAC;CACD,MAAM,MAAM,KAAK,wBAAwB,QAAQ;EAC/C,MAAM,WAAW,KAAK,IAAI,IAAI,MAAM;EACpC,IAAI,CAAC,UACH;EACF,KAAK,IAAI,IAAI,QAAQ;GAAE,MAAM;GAAQ,IAAI,SAAS;GAAI,OAAO,SAAS;GAAO,WAAW,SAAS;EAAU,CAAC;EAC5G,UAAU;GAAE,MAAM;GAAiB;GAAW,OAAO,iBAAiB,EAAE,KAAK,CAAC;EAAE,CAAC;CACnF,CAAC;CACD,MAAM,MAAM,KAAK,2BAA0B,QAAO,uBAAuB,GAAG,CAAC;CAC7E,MAAM,MAAM,KAAK,0BAAyB,QAAO,gCAAgC,GAAG,CAAC;AACvF;AAEA,SAAgB,kBAAkB,QAAyF;CACzH,OAAO;EACL,gBAAgB,WAAW;GACzB,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,OACF,MAAM,aAAa,KAAK,IAAI;GAC9B,OAAO,QAAQ,iBAAiB,KAAK,IAAI,CAAC;EAC5C;EAEA,MAAM,kBAAkB,WAAW,IAAI,QAAQ;GAC7C,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,CAAC,OACH,OAAO;GACT,MAAM,aAAa,KAAK,IAAI;GAE5B,MAAM,UAAU,OAAO,QAAQ,iBAAiB,KAAK,IAAI,iBAAiB,KAAK,CAAC,CAAC,QAAO,SAAQ,KAAK,OAAO,EAAE;GAC9G,IAAI,YAAY;GAEhB,KAAK,MAAM,QAAQ,SACjB,IAAI,KAAK,SAAS,QAChB,YAAa,MAAM,MAAM,MAAM,mBAAmB,KAAK,EAAE,KAAM;QAE/D,YAAY,MAAM,MAAM,WAAW,KAAK,IAAI,UAAU,qBAAqB,KAAK;GAGpF,OAAO;EACT;CACF;AACF;;;;;;;;AC3EA,SAAgB,oBAAoB,OAKlC;CACA,MAAM,EAAE,WAAW,OAAO,WAAW,KAAK,QAAQ,iBAAiB,WAAW,WAAW,cAAc,WAAW,KAAK,eAAe,WAAW,eAAe,QAAQ,SAAS,QAAQ,MAAM,iBAAiB,oBAAoB;CAQpO,MAAM,cAAgC;EAAE;EAAW;EAAO;CAAU;CACpE,MAAM,aAAa,aAAa,WAAW,MAAM,gBAAgB;CACjE,gBAAgB,aAAa;EAC3B;EACA;EACA;EACA;EACA;EACA,eAAe,kBAAkB,QAAQ,QAAQ,WAAW,KAAA;CAC9D,CAAC;CACD,MAAM,aAAa,eAAe,WAAW;CAC7C,kBAAkB,aAAa,aAAa;CAC5C,wBAAwB,aAAa,OAAO;CAE5C,MAAM,cAAc,MAAM,kBAAkB;CAC5C,MAAM,UAAU,wBAAwB,OAAO,aAAa,GAAG,SAAS;CAExE,MAAM,WAAW,mBAAmB,WAAW;CAC/C,MAAM,4CAA4B,IAAI,IAAY;CAClD,MAAM,cAAc,kBAAkB,aAAa,IAAI;CAEvD,MAAM,EAAE,sBAAsB,qBAAqB,aAAa;EAAE;EAAQ;EAA2B,MAAM;EAAa,kBAD/F,yBAAyB,KACsE;CAAiB,CAAC;CAC1I,2BAA2B,OAAO,MAAM;CACxC,uBAAuB,aAAa;EAClC;EACA,MAAM;EACN;EACA,yBAAwB,UAAS,uBAAuB,WAAW,KAAK;CAC1E,CAAC;CACD,2BAA2B,aAAa;EAAE;EAAM,SAAS;EAAa;CAAU,CAAC;CACjF,0BAA0B,OAAO;EAAE;EAAQ;CAA0B,CAAC;CACtE,oBAAoB,OAAO,UAAU;CACrC,oBAAoB,aAAa;EAC/B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;CACD,kBAAkB,aAAa,UAAU;CACzC,kBAAkB,WAAW;CAC7B,sBAAsB,WAAW;CACjC,kBAAkB,aAAa,QAAQ;CACvC,iBAAiB,WAAW;CAC5B,2BAA2B,aAAa,UAAU;CAClD,uBAAuB,aAAa,UAAU;CAE9C,OAAO;EAAE;EAAa;EAAY;EAAa;CAAQ;AACzD;;;;AC/GA,SAAgB,qBAAqB,EAAE,UAAU,eAAe,SAAS,iBAKtE;CAkBD,MAAM,iBAAiB,sBACrB,cAAc,YACd,SAAS,gBACT,IAAI,IAAI,cAAc,KAAI,MAAK,EAAE,IAAI,CAAC,CACxC;CAOA,MAAM,mBAAmB,SAAS,cAAc;CAKhD,OAAO;EAAE;EAAgB;EAAkB,gBAJpB,sBAAsB,uBAC3C,gBACA,mBAAmB,eAAeC,mBAAiB,QAAQ,MAAM,IAAI,QAAQ,MAC/E,CACwD;CAAE;AAC5D;;;;;;;AAQA,SAAgB,sBAAsB,QAAgB,EAAE,KAAK,QAAQ,UAAU,eAKpE;CACT,MAAM,iBAAiB,mBAAmB;EACxC;EACA;EACA,gBAAgB,SAAS,yBAAyB;EAClD,cAAc,EAAE,gBAAgB,YAAY;CAC9C,CAAC;CACD,KAAK,MAAM,KAAK,eAAe,aAC7B,UAAU,qBAAqB,EAAE,MAAM,EAAE,OAAO;CAClD,OAAO,uBAAuB,QAAQ,eAAe,SAAS;AAChE;;;;;;;;ACzDA,MAAM,oBAAoB;AAE1B,SAAgB,eAAe,MAAyB,OAA2B;CAKjF,MAAM,WAAW,SAAyB;EACxC,MAAM,KAAK,MAAM,UAAU,IAAI,IAAI,KAAK,KAAK;EAC7C,MAAM,UAAU,IAAI,MAAM,CAAC;EAC3B,OAAO;CACT;;;;;;;;CASA,SAAS,QAAQ,MAAc,UAAwB,MAAqB;EAC1E,MAAM,QAAsB;GAAE,GAAG;GAAU,KAAK,QAAQ,IAAI;EAAE;EAG9D,KAAK,UAAU;GACb,MAAM;GACN,WAAW;GACX,OAAO;IAAE,MAAM;IAAiB,MAAM,kBAAkB,KAAK;IAAG,cAAc;GAAM;EACtF,CAAC;EAED,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC;EAC1C,MAAM,KAAK;GAAE;GAAO;EAAK,CAAC;EAC1B,MAAM,QAAQ,IAAI,MAAM,KAAK;EAC7B,cAAc,IAAI;CACpB;;CAGA,SAAS,cAAc,MAAoB;EACzC,IAAI,MAAM,YAAY,IAAI,IAAI,GAC5B;EACF,MAAM,QAAQ,iBAAiB;GAC7B,MAAM,YAAY,OAAO,IAAI;GAC7B,MAAW,IAAI;EACjB,GAAG,iBAAiB;EAGpB,MAAM,QAAQ;EACd,MAAM,YAAY,IAAI,MAAM,KAAK;CACnC;CAEA,eAAe,MAAM,MAA6B;EAChD,IAAI,MAAM,SAAS,IAAI,IAAI,KAAK,KAAK,UAAU,IAAI,GACjD;EACF,MAAM,SAAS,MAAM,QAAQ,IAAI,IAAI;EACrC,IAAI,CAAC,UAAU,OAAO,WAAW,GAC/B;EACF,MAAM,SAAS,IAAI,IAAI;EACvB,MAAM,QAAQ,OAAO,IAAI;EAOzB,IAAI,WAAW;EACf,IAAI;GASF,MAAM,UADO,KAAK,YAAY,IACX,KAAK,MAAM,YAAY,KAAK,OAAO,IAAI;GAC1D,IAAI,CAAC,SACH;GASF,IAAI,KAAK,UAAU,IAAI,GACrB;GACF,MAAM,MAAM,KAAK,IAAI;GACrB,MAAM,QAAuB,OAAO,KAAK,EAAE,SAAS,OAAO;IACzD,IAAI,WAAW;IACf,MAAM;IACN,WAAW,MAAM;IACjB,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,sBAAsB,KAAK;IAAE,CAAC;GAChE,EAAE;GACF,MAAM,QAAQ,YAAY,KAAK;GAU/B,MAAM,QAAQ,KAAK;GACnB,WAAW;GAcX,IAAI,OAAO,MAAK,MAAK,EAAE,IAAI,GACzB,MAAM,KAAK,KAAK,IAAI;EACxB,QACM,CAIN,UACQ;GAON,IAAI,CAAC,UAAU;IACb,MAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,KAAK,CAAC;IAC1C,MAAM,QAAQ,IAAI,MAAM,CAAC,GAAG,QAAQ,GAAG,KAAK,CAAC;GAC/C;GACA,MAAM,SAAS,OAAO,IAAI;EAC5B;CACF;CAEA,OAAO;EAAE;EAAS;CAAM;AAC1B;;;ACrJA,SAAgB,gBAAgB,MAAyB,OAA2B;CAClF,MAAM,gBAAyB,KAAK,aAAa,CAAC,CAAC,kBAAkB;;;;;;;;;;CAWrE,SAAS,iBAAuB;EAC9B,IAAI,CAAC,QAAQ,GACX,MAAM,IAAI,MAAM,2BAA2B;CAC/C;;;;;;CAOA,eAAe,kBAAkB,MAA6B;EAC5D,eAAe;EACf,IAAI,CAAC,cAAe,MAAM,WAAW,IAAI,KAAM,KAAA,CAAS,GACtD,MAAM,IAAI,MAAM,qCAAqC;CACzD;CAEA,eAAe,WAAW,WAA4D;EACpF,MAAM,OAAO,KAAK,YAAY,SAAS;EACvC,IAAI,MACF,OAAO,KAAK;EAEd,QAAO,MADY,KAAK,MAAM,KAAK,SAAS,EAAA,EAC/B,YAAY;CAC3B;CAEA,eAAe,OAAO,WAA2C;EAC/D,IAAI,MAAM,QAAQ,IAAI,SAAS,GAC7B,OAAO,MAAM,QAAQ,IAAI,SAAS;EACpC,MAAM,OAAO,MAAM,WAAW,SAAS;EACvC,MAAM,OAAO,eAAe,QAAQ,KAAA,CAAS;EAC7C,MAAM,QAAQ,IAAI,WAAW,IAAI;EACjC,OAAO;CACT;;;;;;;CAQA,eAAe,UAAU,WAAqF;EAC5G,MAAM,OAAO,MAAM,OAAO;EAC1B,IAAI,CAAC,QAAQ,cAAc,MACzB,OAAO;EACT,MAAM,OAAO,MAAM,WAAW,SAAS;EACvC,IAAI,CAAC,QAAQ,cAAc,IAAI,GAC7B,OAAO;EACT,MAAM,SAAU,MAAM,OAAO,SAAS,MAAO;EAC7C,OAAO;GAAE;GAAM;GAAQ,MAAM,MAAM,WAAW,IAAI,SAAS,KAAK;EAAO;CACzE;;;;;;;;;;;;;CAcA,eAAe,OAA2B;EACxC,IAAI,KAAK,MAAM,UACb,IAAI;GAEF,QAAO,MADY,KAAK,MAAM,SAAS,EAAA,CAC3B,KAAK,QAAQ;IACvB,MAAM,OAAO,KAAK,YAAY,IAAI,EAAE;IACpC,OAAO;KACL,IAAI,IAAI;KAGR,UAAU,MAAM,YAAY,IAAI;KAChC,WAAW,IAAI;KACf,OAAO,MAAM,MAAM,UAAU,IAAI;KACjC,GAAI,IAAI,gBAAgB,KAAA,IAAY,EAAE,aAAa,IAAI,YAAY,IAAI,CAAC;IAC1E;GACF,CAAC;EACH,QACM,CAEN;EAEF,MAAM,MAAM,MAAM,KAAK,MAAM,KAAK;EAQlC,QAAO,MAPY,QAAQ,IAAI,IAAI,IAAI,OAAO,OAAgC;GAC5E,MAAM,OAAO,KAAK,YAAY,EAAE;GAChC,IAAI,MACF,OAAO;IAAE;IAAI,UAAU,KAAK;IAAU,WAAW,KAAK,IAAI;IAAG,OAAO,KAAK,MAAM;IAAQ,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;GAAG;GACtK,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,EAAE;GACrC,OAAO,OAAO;IAAE;IAAI,UAAU,KAAK;IAAU,WAAW,KAAK;IAAW,OAAO,KAAK,MAAM;IAAQ,GAAI,KAAK,gBAAgB,KAAA,IAAY,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;GAAG,IAAI;EACrL,CAAC,CAAC,EAAA,CACU,QAAQ,MAAoB,MAAM,IAAI;CACpD;CAEA,eAAe,SAAiC;EAC9C,IAAI,CAAC,QAAQ,GACX,OAAO;EACT,IAAI,MAAM,eAAe,KAAA,GACvB,OAAO,MAAM;EAEf,MAAM,cADS,MAAM,KAAK,EAAA,CAAG,MAAK,QAAO,cAAc,IAAI,QAAQ,CAC5C,CAAC,EAAE,MAAM;EAChC,OAAO,MAAM;CACf;CAEA,eAAe,aAAqC;EAClD,IAAI,CAAC,QAAQ,GACX,OAAO;EACT,IAAI,MAAM,UACR,OAAO,MAAM;EAKf,MAAM,YAAY,YAAoC;GACpD,MAAM,WAAW,MAAM,OAAO;GAC9B,IAAI,UAAU;IACZ,MAAM,sBAAsB,QAAQ;IACpC,OAAO;GACT;GAEA,MAAM,KAAK,MAAM,KAAK,cAAc;IAAE,KAAK;IAAI,OAAO;GAAmB,CAAC;GAC1E,MAAM,UAAU,MAAM,YAAY,KAAK,OAAO,EAAE;GAChD,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,gBAAgB,GAAG,yBAAyB;GAC9D,QAAQ,QAAQ,kBAAkB,MAAM;GACxC,MAAM,QAAQ,KAAK;GACnB,MAAM,aAAa;GAGnB,KAAK,UAAU;IAAE,MAAM;IAAoB,IAAI;IAAU,WAAW;GAAG,CAAC;GACxE,OAAO;EACT,EAAA,CAAG;EACH,MAAM,WAAW;EACjB,IAAI;GACF,OAAO,MAAM;EACf,UACQ;GACN,MAAM,WAAW,KAAA;EACnB;CACF;;;;;;;CAQA,eAAe,sBAAsB,MAA6B;EAChE,IAAI,KAAK,YAAY,IAAI,GACvB;EACF,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,IAAI;EACvC,IAAI,CAAC,MACH;EACF,MAAM,MAAM,KAAK,SAAS;EAC1B,KAAK,OAAO,QAAQ,YAAY,QAAQ,OAAO,KAAK,gBAAgB,KAAA,GAClE;EACF,KAAK,SAAS,MAAM;EACpB,OAAO,KAAK;EACZ,MAAM,KAAK,MAAM,KAAK,IAAI;EAC1B,KAAK,UAAU;GAAE,MAAM;GAAoB,IAAI;GAAU,WAAW;EAAK,CAAC;CAC5E;CAEA,OAAO;EAAE;EAAS;EAAgB;EAAmB;EAAY;EAAQ;EAAW;EAAM;EAAQ;CAAW;AAC/G;;;;;;;;;;;;;;AC1KA,SAAgB,WACd,MACA,KACmE;CAcnE,MAAM,MAAM,KAAK,KAAK,QAAO,OAAM,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE;CAC7D,IAAI,CAAC,KACH,OAAO,CAAC;CACV,MAAM,WAAW,KAAK,MAAM,QAAO,MAAK,EAAE,UAAU,IAAI,EAAE;CAC1D,MAAM,QAAQ,IAAI,cACb,IAAI,WAAW,QAAQ,KAAK,OAAO;EAAE,OAAO,IAAI,QAAQ,EAAE;EAAO,QAAQ,IAAI,SAAS,EAAE;CAAO,IAAI;EAAE,OAAO;EAAG,QAAQ;CAAE,CAAC;CAC/H,MAAM,SAAS,QACX,MAAM,QAAQ,MAAM,SACpB,SAAS,QAAQ,GAAG,MAAM,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,EAAE,MAAM,SAAS,IAAI,CAAC;CACnF,MAAM,QAAQ,IAAI,SAAS,SAAS;CACpC,MAAM,cAAc,IAAI,WAAW,OAAO,IAAI;CAC9C,MAAM,OAAO,IAAI,QAAQ,IAAI,WAAW,QAAQ,GAAG,MAAM,KAAK,EAAE,QAAQ,IAAI,CAAC,KAAK;CAClF,OAAO;EACL,GAAI,aAAa,IAAI,EAAE,WAAW,IAAI,CAAC;EACvC,GAAI,SAAS,IAAI,EAAE,OAAO,IAAI,CAAC;EAC/B,GAAI,QAAQ,IAAI,EAAE,MAAM,IAAI,CAAC;EAC7B,GAAI,OAAO,IAAI,EAAE,SAAS,KAAK,IAAI,CAAC;CACtC;AACF;;;;;;AAOA,SAAgB,gBAAgB,QAAuG;CACrI,IAAI,OAAO,SAAS,oBAAoB;EACtC,MAAM,IAAI,OAAO;EACjB,MAAM,SAAS,EAAE,MAAM,SAAS,OAAO,EAAE,OAAO,YAAY,WAAW,EAAE,MAAM,UAAU,KAAA;EACzF,OAAO,SAAS,WAAW,EAAE,KAAK,IAAI,SAAS,QAAQ,GAAG,MAAM,WAAW,EAAE;CAC/E;CACA,MAAM,MAAM,OAAO;CACnB,IAAI,IAAI,SAAS,QACf,OAAO,gBAAgB,SAAS,IAAI,QAAQ,OAAO,GAAG;CACxD,IAAI,IAAI,SAAS,YAAY;EAC3B,MAAM,QAAQ,IAAI,QAAQ,UAAU;EACpC,MAAM,OAAO,IAAI,QAAQ,SAAS,OAAO;EACzC,OAAO,OAAO,aAAa,SAAS,MAAM,GAAG,MAAM;CACrD;AAEF;AAMA,SAAgB,QAAQ,UAA+C,UAA0B;CAC/F,MAAM,QAAQ,UAAU;CACxB,OAAO,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,QAAQ;AAC7D;AAEA,SAAgB,MAAM,UAAuD;CAC3E,MAAM,MAAM,UAAU;CACtB,OAAO,OAAO,QAAQ,WAAW,MAAM;AACzC;AAEA,SAAgB,cAAc,MAA2B;CACvD,OAAO,KAAK,QACT,QAAQ,MAA2C,EAAE,SAAS,MAAM,CAAC,CACrE,KAAI,MAAK,EAAE,IAAI,CAAC,CAChB,KAAK,IAAI,CAAC,CACV,KAAK;AACV;AAEA,SAAgB,SAAS,MAAc,KAAqB;CAC1D,OAAO,KAAK,UAAU,MAAM,OAAO,GAAG,KAAK,MAAM,GAAG,MAAM,CAAC,EAAE;AAC/D;;;ACvFA,SAAgB,qBACd,MACA,OACA,WACA,UACA,MAC8B;CAC9B,MAAM,EAAE,SAAS,cAAc;CAC/B,MAAM,EAAE,SAAS,UAAU;CAE3B,OAAO,SAAS,SAAS,QAA0B;EAGjD,QAAQ,OAAO,MAAf;GACE,KAAK;IACH,IAAI,CAAC,QAAQ,GACX;IACF,CAAM,YAAY;KAGhB,MAAM,QAAQ,OAAO,OAAO,SAAS;KAErC,IAAI,MAAM,QAAQ,IAAI,OAAO,SAAS,GAAG;MACvC,MAAM,MAAM,OAAO,SAAS;MAC5B;KACF;KACA,MAAM,SAAS,MAAM,UAAU,OAAO,SAAS;KAC/C,IAAI,CAAC,QACH;KAGF,MAAM,WAAW,OAAO,OAAO,SAAS;KACxC,MAAM,UAAU,MAAM,KAAK,OAAO,SAAS;KAC3C,MAAM,MAAM,KAAK,IAAI;KACrB,MAAM,OAAO,KAAK,YAAY,OAAO,SAAS,KAAK,MAAM,KAAK,MAAM,KAAK,OAAO,SAAS;KACzF,MAAM,UAAU,OAAO,WAAW,MAAM,GAAG,IAAI,CAAC;KAQhD,MAAM,SAAS,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAK,MAAK,EAAE,gBAAgB,KAAA,CAAS,IAAI,KAAA;KACxF,MAAM,WAAW,UAAU,OAAO,KAAK,MAAM,QAAO,MAAK,EAAE,UAAU,OAAO,EAAE,IAAI,CAAC;KAEnF,MAAM,SADgB,CAAC,GAAG,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAK,MAAK,EAAE,SAAS,WACxC,CAAC,EAAE,OAAO;KACrC,MAAM,YAAY,mBAAmB,QAAQ;KAC7C,QAAQ,OAAO,MAAM;MACnB,WAAW,OAAO;MAClB,OAAO,SAAS,SAAS,OAAO;MAChC,QAAQ,OAAO,KAAK,SAAS;MAC7B,SAAS,OAAO,KACX,SAAS,eAAe,6BACzB,WAAW,OAAO,SAAS;MAC/B,IAAI;MACJ,QAAQ,OAAO;MAGf,KAAK,SAAS,OAAO;MACrB,GAAI,QAAQ,SAAS,EAAE,MAAM,SAAS,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC;MAC/D,GAAI,WAAW,YAAY,WAAW,WAAW,WAAW,mBAAmB,EAAE,cAAc,OAAO,IAAI,CAAC;MAC3G,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;MACjC,GAAI,CAAC,OAAO,MAAM,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;MAC5D,GAAG;KACL,GAAG,OAAO,IAAI;IAChB,EAAA,CAAG;IACH;GAEF,KAAK;GACL,KAAK,uBAAuB;IAC1B,IAAI,CAAC,QAAQ,GACX;IACF,MAAM,YAAY,OAAO,SAAS,qBAAqB,OAAO,QAAQ,YAAY,OAAO;IACzF,MAAM,SAAS,gBAAgB,MAAM;IAErC,MAAM,MAAM,UAAU,OAAO;IAC7B,IAAI,MAAM,QAAQ,IAAI,SAAS,CAAC,EAAE,IAAI,GAAG,GACvC;IACF,CAAM,YAAY;KAChB,MAAM,SAAS,MAAM,UAAU,SAAS;KACxC,IAAI,CAAC,QACH;KAGF,MAAM,OAAO,MAAM,QAAQ,IAAI,SAAS,qBAAK,IAAI,IAAY;KAC7D,IAAI,KAAK,IAAI,GAAG,GACd;KACF,KAAK,IAAI,GAAG;KACZ,MAAM,QAAQ,IAAI,WAAW,IAAI;KACjC,MAAM,UAAU,MAAM,KAAK,SAAS;KAEpC,QAAQ,OAAO,MAAM;MACnB;MACA,OAAO,SAAS,SAAS;MACzB,QAAQ;MACR,SAAS,OAAO,SAAS,qBACrB,yBAAyB,OAAO,QAAQ,SACxC;MACJ,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;MAC3B,IAAI,KAAK,IAAI;MACb,QAAQ,OAAO;MACf,GAAI,SAAS,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;KAC7C,GAAG,IAAI;IACT,EAAA,CAAG;IACH;GACF;GAGA,KAAK,oBACH,IAAI,OAAO,OAAO,UAAU;IAC1B,MAAM,QAAQ,OAAO,OAAO,SAAS;IACrC,MAAM,WAAW,OAAO,OAAO,SAAS;IACxC,MAAM,QAAQ,OAAO,OAAO,SAAS;IACrC,MAAM,QAAQ,OAAO,OAAO,SAAS;IACrC,MAAM,QAAQ,MAAM,YAAY,IAAI,OAAO,SAAS;IACpD,IAAI,OAAO;KACT,aAAa,KAAK;KAClB,MAAM,YAAY,OAAO,OAAO,SAAS;IAC3C;IACA,IAAI,MAAM,eAAe,OAAO,WAC9B,MAAM,aAAa,KAAA;GACvB,OAYK,IAAI,MAAM,eAAe,MAC5B,MAAM,aAAa,KAAA;EAMzB;CACF;AACF;;;AClFA,SAAgB,2BAA+C;CAC7D,OAAO;EACL,yBAAS,IAAI,IAAI;EACjB,yBAAS,IAAI,IAAI;EACjB,0BAAU,IAAI,IAAI;EAClB,2BAAW,IAAI,IAAI;EACnB,yBAAS,IAAI,IAAI;EACjB,6BAAa,IAAI,IAAI;EACrB,4BAAY,IAAI,IAAI;EACpB,YAAY,KAAA;EACZ,UAAU,KAAA;CACZ;AACF;;AC3DA,MAAM,iBAAiB;;AAGvB,MAAM,cAAc;AAEpB,SAAgB,YAAY,MAAyB,QAA4B,WAAsB,UAAqC;CAC1I,MAAM,EAAE,SAAS,gBAAgB,mBAAmB,YAAY,QAAQ,SAAS;CACjF,MAAM,EAAE,YAAY;CAEpB,eAAe,aAAa,MAAc,QAA6C;EAOrF,eAAe;EACf,MAAM,OAAO,MAAM,WAAW,IAAI;EAClC,IAAI,CAAC,cAAc,QAAQ,KAAA,CAAS,GAClC,MAAM,IAAI,MAAM,wCAAwC;EAC1D,MAAM,KAAK,MAAM,KAAK,cAAc;GAClC,KAAK,OAAO;GACZ,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;GAC9C,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;GACpD,GAAI,OAAO,cAAc,EAAE,aAAa,OAAO,YAAY,IAAI,CAAC;GAChE,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EACtD,CAAC;EACD,MAAM,UAAU,MAAM,YAAY,KAAK,OAAO,EAAE;EAChD,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,kBAAkB,GAAG,yBAAyB;EAChE,QAAQ,QAAQ,qBAAqB,IAAI;EACzC,MAAM,QAAQ,KAAK;EACnB,OAAO,QAAQ,IAAI,IAAI,IAAI;EAC3B,OAAO,WAAW,IAAI,IAAI,OAAO,QAAQ,IAAI;EAC7C,KAAK,UAAU;GAAE,MAAM;GAAoB,IAAI;GAAU,WAAW;EAAG,CAAC;EAWxE,KAAU,WAAW;GAAE,WAAW;GAAI,QAAQ,OAAO;EAAO,CAAC,CAAC,CAAC,OAAO,QAAiB;GACrF,QAAQ,MAAM;IACZ,WAAW;IACX,OAAO,OAAO,SAAS;IACvB,QAAQ;IACR,SAAS,kBAAkB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IAC1E,IAAI,KAAK,IAAI;IACb,KAAK,OAAO;GACd,GAAG,IAAI;EACT,CAAC;EACD,OAAO;CACT;CAEA,eAAe,KAAK,MAAc,QAAA,IAAkD;EAClF,MAAM,kBAAkB,IAAI;EAG5B,MAAM,QAAQ,MAAM,KAAK,EAAA,CACtB,QAAO,QAAO,IAAI,OAAO,QAAQ,CAAC,cAAc,IAAI,QAAQ,CAAC,CAAC,CAC9D,KAAK,QAAQ;GACZ,MAAM,UAAU,KAAK,UAAU,IAAI,EAAE;GACrC,OAAO;IACL,WAAW,IAAI;IACf,OAAO,QAAQ,IAAI,UAAU,IAAI,EAAE;IACnC,KAAK,MAAM,IAAI,QAAQ;IACvB;IACA,QAAQ,eAAe,IAAI,QAAQ,MAAM;IACzC,QAAQ,OAAO,QAAQ,IAAI,IAAI,EAAE,CAAC,EAAE,QAAQ,KAAK,IAAI,YAAqB,UAAU,YAAqB;IACzG,WAAW,IAAI;IACf,OAAO,IAAI;GACb;EACF,CAAC;EAEH,KAAK,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;EAC7C,OAAO,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,cAAc,CAAC,CAAC;CACnE;CAEA,eAAe,SAAS,QAAA,IAAyD;EAC/E,IAAI,CAAC,QAAQ,GACX,OAAO,CAAC;EACV,MAAM,yBAAS,IAAI,IAA0B;EAC7C,KAAK,MAAM,OAAO,MAAM,KAAK,GAAG;GAC9B,IAAI,cAAc,IAAI,QAAQ,GAC5B;GAGF,MAAM,OAAO,IAAI,eAAe,MAAM,IAAI,QAAQ;GAClD,IAAI,CAAC,MACH;GACF,MAAM,UAAU,KAAK,UAAU,IAAI,EAAE;GACrC,MAAM,SAAS,OAAO,QAAQ,IAAI,IAAI,EAAE,CAAC,EAAE,QAAQ,KAAK,IAAI,YAAqB,UAAU,YAAqB;GAChH,MAAM,SAAS,UAAU,SAAS,IAAI;GACtC,MAAM,SAAS;IAAE,WAAW,IAAI;IAAI,OAAO,QAAQ,IAAI,UAAU,IAAI,EAAE;IAAG;GAAM;GAChF,MAAM,OAAO,OAAO,IAAI,IAAI;GAC5B,IAAI,CAAC,MAAM;IACT,OAAO,IAAI,MAAM;KAAE;KAAM,UAAU;KAAG,cAAc,IAAI;KAAW;KAAQ;IAAO,CAAC;IACnF;GACF;GACA,KAAK,YAAY;GACjB,KAAK,UAAU;GACf,IAAI,IAAI,YAAY,KAAK,cAAc;IACrC,KAAK,eAAe,IAAI;IACxB,KAAK,SAAS;GAChB;EACF;EACA,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC,CAAC,CACxB,MAAM,GAAG,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,CAC/C,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;CAChC;CAEA,eAAe,KAAK,WAAkD;EACpE,IAAI,CAAC,QAAQ,GACX,OAAO;EACT,MAAM,OAAO,KAAK,YAAY,SAAS,KAAK,MAAM,KAAK,MAAM,KAAK,SAAS;EAC3E,IAAI,CAAC,MACH,OAAO;EACT,MAAM,gBAAgB,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAK,MAAK,EAAE,SAAS,WAAW;EAChF,MAAM,cAAc,gBAAgB,cAAc,aAAa,IAAI;EACnE,MAAM,UAAU,KAAK,UAAU,SAAS;EACxC,OAAO;GACL;GACA,OAAO,QAAQ,KAAK,UAAU,SAAS;GACvC,KAAK,MAAM,KAAK,QAAQ;GACxB;GACA,QAAQ,eAAe,KAAK,QAAQ,MAAM;GAC1C,QAAQ,OAAO,QAAQ,IAAI,SAAS,CAAC,EAAE,QAAQ,KAAK,IAAI,YAAY,UAAU,YAAY;GAC1F,WAAW,eAAe,QAAQ,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,KAAK,IAAI;GACjG,aAAa,cAAc,SAAS,aAAa,WAAW,IAAI;GAChE,OAAO,KAAK,MAAM;EACpB;CACF;CAEA,eAAe,WAAW,MAAc,WAAqC;EAC3E,OAAQ,MAAM,OAAO,SAAS,MAAO;CACvC;CAaA,eAAe,sBAAsB,MAAc,WAAkC;EACnF,eAAe;EACf,IAAI,cAAc,MAChB,MAAM,IAAI,MAAM,0CAA0C;EAC5D,MAAM,kBAAkB,IAAI;EAC5B,MAAM,OAAO,MAAM,WAAW,SAAS;EACvC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,mBAAmB,WAAW;EAChD,IAAI,cAAc,IAAI,GACpB,MAAM,IAAI,MAAM,GAAG,UAAU,8CAA8C;CAC/E;CAEA,eAAe,eAAe,MAAc,WAAqC;EAC/E,IAAI;GACF,MAAM,sBAAsB,MAAM,SAAS;GAC3C,OAAO;EACT,QACM;GACJ,OAAO;EACT;CACF;CAEA,eAAe,KAAK,MAAc,WAAmB,QAAgB,OAAO,MAAqB;EAC/F,MAAM,sBAAsB,MAAM,SAAS;EAG3C,OAAO,WAAW,IAAI,WAAW,IAAI;EACrC,MAAM,KAAK,WAAW;GAAE;GAAW;EAAO,CAAC;CAC7C;CAEA,eAAe,MAAM,MAAc,WAAmB,SAAgC;EACpF,MAAM,sBAAsB,MAAM,SAAS;EAC3C,KAAK,MAAM,WAAW,OAAO;CAC/B;CAEA,eAAe,OAAO,MAAc,WAAkC;EACpE,MAAM,sBAAsB,MAAM,SAAS;EAC3C,KAAK,UAAU,SAAS;CAC1B;CAEA,eAAe,WAAW,MAAc,WAAmB,QAAQ,IAAqB;EACtF,MAAM,sBAAsB,MAAM,SAAS;EAC3C,MAAM,OAAO,KAAK,YAAY,SAAS,KAAK,MAAM,KAAK,MAAM,KAAK,SAAS;EAC3E,IAAI,CAAC,MACH,OAAO;EACT,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;EAC9C,OAAO,KAAK,MACT,QAAO,MAAK,EAAE,SAAS,UAAU,EAAE,SAAS,WAAW,CAAC,CACxD,MAAM,CAAC,MAAM,CAAC,CACd,KAAK,MAAM;GACV,MAAM,OAAO,EAAE,QACZ,QAAQ,MAA2C,EAAE,SAAS,MAAM,CAAC,CACrE,KAAI,MAAK,EAAE,IAAI,CAAC,CAChB,KAAK,IAAI,CAAC,CACV,KAAK;GACR,MAAM,QAAQ,EAAE,QACb,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CAEnC,KAAI,MAAK,eAAe,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI;GAC3D,MAAM,OAAO,SAAS,MAAM,SAAS,gBAAgB,MAAM,KAAK,IAAI,EAAE,KAAK;GAC3E,OAAO,GAAG,EAAE,KAAK,IAAI,SAAS,MAAM,IAAI;EAC1C,CAAC,CAAC,CACD,KAAK,MAAM;CAChB;CAEA,OAAO;EAAE;EAAc;EAAM;EAAU;EAAM;EAAY;EAAgB;EAAM;EAAO;EAAQ;CAAW;AAC3G;;;AC7OA,MAAa,gBAAgB;AAE7B,MAAM,uBAAuB;;;;;;;;;;;;;;;;;AAkB7B,SAAgB,mBAAmB,MAAqB,QAAyB;CAC/E,MAAM,OAAO,GAAY,SAAyB;EAChD,IAAI,OAAO,MAAM,YAAY,CAAC,EAAE,KAAK,GACnC,MAAM,IAAI,MAAM,eAAe,KAAK,eAAe;EACrD,OAAO;CACT;CACA,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,YAAY;KACV,MAAM;MAAE,MAAM;MAAU,MAAM;OAAC;OAAU;OAAQ;OAAS;OAAU;OAAQ;OAAQ;MAAY;KAAE;KAClG,WAAW;MAAE,MAAM;MAAU,aAAa;KAA8D;KACxG,KAAK;MAAE,MAAM;MAAU,aAAa;KAAwC;KAC5E,QAAQ;MAAE,MAAM;MAAU,aAAa;KAA6B;KACpE,SAAS;MAAE,MAAM;MAAU,aAAa;KAAuC;KAC/E,OAAO;MAAE,MAAM;MAAU,aAAa;KAAiC;KACvE,SAAS;MAAE,MAAM;MAAU,aAAa;KAAqC;KAC7E,OAAO;MAAE,MAAM;MAAU,aAAa;KAA2G;KACjJ,MAAM;MAAE,MAAM;MAAW,aAAa;KAAsK;IAC9M;IACA,UAAU,CAAC,MAAM;GACnB;EACF;EACA,MAAM,QAAQ,OAAgC;GAC5C,MAAM,OAAO,IAAI,MAAM,MAAM,MAAM;GACnC,QAAQ,MAAR;IACE,KAAK,UAAU;KACb,MAAM,KAAK,MAAM,KAAK,aAAa,QAAQ;MACzC,KAAK,IAAI,MAAM,KAAK,KAAK;MACzB,QAAQ,IAAI,MAAM,QAAQ,QAAQ;MAClC,GAAI,OAAO,MAAM,UAAU,WAAW,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;MAChE,GAAI,OAAO,MAAM,YAAY,WAAW,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;MACtE,GAAI,OAAO,MAAM,SAAS,YAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;KAChE,CAAC;KACD,OAAO,MAAM,SAAS,QAClB,kBAAkB,GAAG,iFACrB,kBAAkB,GAAG;IAC3B;IACA,KAAK,QAAQ;KACX,MAAM,KAAK,IAAI,MAAM,WAAW,WAAW;KAC3C,MAAM,KAAK,KAAK,QAAQ,IAAI,IAAI,MAAM,QAAQ,QAAQ,GAAG,OAAO,MAAM,SAAS,YAAY,MAAM,OAAO,IAAI;KAC5G,OAAO,MAAM,SAAS,QAAQ,WAAW,GAAG,wBAAwB,WAAW;IACjF;IACA,KAAK,SAAS;KACZ,MAAM,KAAK,IAAI,MAAM,WAAW,WAAW;KAC3C,MAAM,KAAK,MAAM,QAAQ,IAAI,IAAI,MAAM,SAAS,SAAS,CAAC;KAC1D,OAAO,WAAW;IACpB;IACA,KAAK,UAAU;KACb,MAAM,KAAK,IAAI,MAAM,WAAW,WAAW;KAC3C,MAAM,KAAK,OAAO,QAAQ,EAAE;KAC5B,OAAO,aAAa;IACtB;IACA,KAAK,QAAQ;KACX,MAAM,KAAK,IAAI,MAAM,WAAW,WAAW;KAC3C,IAAI,CAAE,MAAM,KAAK,eAAe,QAAQ,EAAE,GACxC,MAAM,IAAI,MAAM,aAAa,GAAG,qDAAqD;KACvF,OAAO,KAAK,UAAU,MAAM,KAAK,KAAK,EAAE,CAAC;IAC3C;IACA,KAAK,QAAQ;KAGX,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,KAAA;KAC9D,OAAO,KAAK,UAAU,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;IACtD;IACA,KAAK,cAAc;KACjB,MAAM,KAAK,IAAI,MAAM,WAAW,WAAW;KAC3C,MAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,KAAA;KAC9D,OAAO,MAAM,KAAK,WAAW,QAAQ,IAAI,KAAK;IAChD;IACA,SACE,MAAM,IAAI,MAAM,0BAA0B,MAAM;GACpD;EACF;CACF;AACF;;;AC5DA,SAAgB,oBAAoB,MAAwC;CAC1E,MAAM,QAAQ,yBAAyB;CACvC,MAAM,YAAY,gBAAgB,MAAM,KAAK;CAC7C,MAAM,WAAW,eAAe,MAAM,KAAK;CAC3C,MAAM,QAAQ,YAAY,MAAM,OAAO,WAAW,QAAQ;CAC1D,MAAM,WAAW,qBAAqB,MAAM,OAAO,WAAW,UAAU,MAAM,IAAI;CAClF,MAAM,EAAE,QAAQ,eAAe;CAC/B,MAAM,EAAE,cAAc,MAAM,UAAU,MAAM,YAAY,gBAAgB,MAAM,OAAO,QAAQ,eAAe;CAE5G,OAAO;EAAE;EAAU;EAAQ;EAAY;EAAc;EAAM;EAAU;EAAM;EAAY;EAAgB;EAAM;EAAO;EAAQ;CAAW;AACzI;;;AChCA,SAAgB,8BAA8B,EAAE,KAAK,cAAc,aAIhE;CACD,MAAM,QAAQ,IAAI;CAmBlB,MAAM,qBAAqB,aAAa,sBAAsB,SAAS;CACvE,MAAM,mBAAmB,uBAAuB;EAC9C,qBAAqB,YAAgC;GACnD,IAAI,IAAI,aAAa,CAAC,CAAC,oBAAoB,YACzC,OAAO,QAAQ,uBAAO,IAAI,MAAM,6CAA6C,CAAC;GAChF,OAAO,mBAAmB,OAAO;EACnC;EACA,8BAA8B,IAAI,aAAa,CAAC,CAAC,oBAAoB;CACvE,CAAC;CACD,MAAM,sBAAsB,EAAE,SAAS,CAAC,EAAuB;CAK/D,OAAO;EAAE;EAAkB;EAAqB,mBAJtB,wBAAwB;GAChD;GACA,wBAAwB,oBAAoB;EAC9C,CACgE;CAAE;AACpE;AAEA,SAAgB,uBAAuB,EAAE,KAAK,UAAU,SAAS,WAAW,WAAW,SAAS,iBAAiB,qBAU9G;CAMD,MAAM,eAAe,QAAQ,QAAQ,IACjC,oBAAoB,IAAI,OAAO,WAAW,QAAQ,QAAQ,WAAW,IAAI,OAAO,MAAM,CAAC,IACvF;CAYJ,MAAM,cAAc,IAAI,cAAc,SAAS,YAAY,KAAK,SAAS,aAAa;CAOtF,OAAO;EAAE;EAAc,eAND,eAAe,SAAS,kBAAkB,SAAS,UAAU,UAAU,IACzF,oBAAoB,WAAW,SAAS,IACxC;EAIkC,gBAHf,eAAe,SAAS,uBAAuB,QAClE,kBAAkB,SAAS,WAAW,eAAe,IACrD;CACiD;AACvD;AAEA,SAAgB,gBAAgB,EAAE,UAAU,kBAAkB,QAAQ,eAAe,WAAW,mBAAmB,cAAc,eAAe,aAAa,qBAWjI;CAM1B,OAAO;EACL,GAAI,SAAS,oBAAoB,aAAa,CAAC,IAAI;EAKnD,GAAI,SAAS,GAAG,gBAAgB,mBAAmB,eAAe,SAAS,EAAE,IAAI,CAAC;EAClF,eAAe;EACf,GAAI,gBAAgB,CAAC;EACrB,GAAI,iBAAiB,CAAC;EACtB,GAAI,eAAe,CAAC;EACpB,GAAG;CACL;AACF;AAEA,SAAgB,qBAAqB,EAAE,gBAAgB,iBAAiB,UAAU,YAK/E;CACD,OAAO;EACL,GAAG;EACH,GAAG;EAIH,GAAI,SAAS,iBACT,EAAE,YAAY;GAAE,GAAI,gBAAgB,cAAc,CAAC;GAAI,MAAM;EAAoB,EAAE,IACnF,CAAC;EAIL,GAAI,SAAS,WACT,EAAE,UAAU,gBAAgB,YAAY,KAAK,IAC7C,EAAE,UAAU,KAAA,EAAU;EAC1B;CACF;AACF;;;ACrJA,SAAgB,sBAAqC;CAmBnD,MAAM,qCAAqB,IAAI,IAAkD;CAEjF,SAAS,cAAc,KAAa,QAAgB,WAAoE;EACtH,MAAM,WAAW,mBAAmB,IAAI,GAAG;EAC3C,IAAI,UACF,OAAO;EACT,MAAM,OAAO,uBAAuB;GAClC;GACA;GAEA,GAAI,UAAU,SAAS,IAAI,EAAE,YAAY,UAAU,IAAI,CAAC;EAC1D,CAAC,CAAC,CACC,MAAM,EAAE,SAAS,aAAa;GAI7B,KAAK,MAAM,SAAS,QAClB,UAAU,0BAA0B,GAAG,MAAM,OAAO,IAAI,MAAM,KAAK,IAAI,MAAM,SAAS;GACxF,OAAO;EACT,CAAC,CAAC,CACD,OAAO,QAAQ;GAGd,UAAU,iCAAiC,GAAG;GAC9C,mBAAmB,OAAO,GAAG;GAC7B,OAAO,CAAC;EACV,CAAC;EACH,mBAAmB,IAAI,KAAK,IAAI;EAChC,OAAO;CACT;CAEA,OAAO;EAAE;EAAe,aAAa,mBAAmB,MAAM;CAAE;AAClE;;;;;;;;ACoBA,SAAS,UAAU,QAA4B,QAA+B;CAC5E,IAAI,UAAU,UAAU,QACtB,OAAO;CACT,OAAO;AACT;;AAGA,eAAe,sBAAsB,MAA6D,OAAgM;CAChS,MAAM,EAAE,WAAW,MAAM,KAAK,QAAQ,cAAc;CACpD,MAAM,WAAW,KAAK;CACtB,MAAM,QAAQ,UAAU,MAAM,IAAI;CAClC,IAAI,CAAC,YAAY,CAAC,OAChB,OAAO,KAAA;CACT,MAAM,UAAU,SAAuB,kBAAkB;EAAE;EAAW,OAAO,KAAA;EAAW,WAAW,KAAK;CAAU,GAAG;EAAE,UAAU;EAAQ,OAAO;CAAU,GAAG,IAAI;CAEjK,IAAI,CAAC,SAAS,OAAO,IAAI,GAAG;EAC1B,MAAM,OAAO,iBAAiB,IAAI,CAAC,EAAE,QAAQ;EAC7C,SAAS,QAAQ,WAAW,IAAI;EAChC,OAAO,GAAG,KAAK,oFAAoF;EACnG;CACF;CACA,IAAI;EACF,MAAM,UAAU,MAAM,mBAAmB;GAAE,SAAS,UAAU;GAAS,QAAQ,MAAM,UAAU,OAAO;GAAG;GAAK;GAAO;EAAO,CAAC;EAC7H,KAAK,MAAM,QAAQ,QAAQ,SACzB,OAAO,IAAI;EACb,OAAO;CACT,SACO,KAAK;EACV,OAAO,qFAAsF,IAAc,SAAS;EACpH;CACF;AACF;AAEA,SAAgB,mBAAmB,MAAuF;CACxH,MAAM,EAAE,KAAK,WAAW,QAAQ,iBAAiB,YAAY,cAAc,cAAc,WAAW,SAAS,WAAW,eAAe,oBAAoB,kBAAkB,mBAAmB,eAAe,cAAc;CAC7N,MAAM,EAAE,kBAAkB,KAAK;CAE/B,eAAe,eAAe,WAAuC;EACnE,MAAM,WAAW,IAAI,aAAa;EAClC,MAAM,QAAQ,IAAI;EAClB,MAAM,OAAO,MAAM,MAAM,KAAK,SAAS;EAEvC,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,yDAAyD;EAOjG,MAAM,cAAc,uBAAuB,KAAK,QAAQ;EACxD,uBAAuB,WAAW;EAElC,MAAM,MAAM,WAAW,WAAW,IAAI;EACtC,MAAM,gBAAgB,kBAAkB;GAAE,UAAU,KAAK;GAAU,aAAa,KAAK,eAAe,KAAA;EAAU,CAAC;EAE/G,MAAM,EAAE,iBAAiB,oBAAoB,wBAAwB,KAAK,QAAQ;EAQlF,MAAM,eAAe,gBAAgB,YAAY,MAAM,KAAK,IAAI,YAAY,CAAC;EAC7E,MAAM,YAAY,iBAAiB;EAEnC,MAAM,gBAAgB,MAAM,IAAI,cAAc,YAAY;EAE1D,MAAM,SAAS,gBAAgB,cAAc,QAAQ,QAAQ;EAC7D,MAAM,YAAY,cAAc;EAChC,MAAM,UAAU,UAAU,KAAK,SAAS,MAAM;EAC9C,MAAM,UAAU,OAAO,YAAY,OAAA,YAA4B,OAAO,OAAO,MAAM,CAAC,CAAC;EACrF,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,mCAAmC;EAQrD,MAAM,gBAAgB,MAAM,cAAc,cAAc,cAAc,QAAQ,cAAc,mBAAmB,CAAC,CAAC;EACjH,MAAM,EAAE,gBAAgB,kBAAkB,gBAAgB,oBAAoB,qBAAqB;GAAE;GAAU;GAAe;GAAS;EAAc,CAAC;EAUtJ,MAAM,UAAU,MAAM,YAAY,OAAO,SAAS;EAClD,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,YAAY,UAAU,yDAAyD;EAajG,MAAM,sBAAsB,yBAAyB;GACnD,YAAY;GACZ,SAAS,SAAS;EACpB,CAAC;EAKD,MAAM,EAAE,WAAW,wBAAwB,SAAS,cAAc,MAAM,iBAAiB,WAAW;GAAE;GAAK;GAAa;EAAS,CAAC;EAClI,MAAM,iBAAiB,YAAY,MAAM,sBAAsB,MAAM;GAAE;GAAW,MAAM,YAAY;GAAM;GAAK,QAAQ,cAAc;GAAQ,WAAW;EAAuB,CAAC,IAAI,KAAA;EAEpL,MAAM,cAAc,qBAAqB;GACvC,KAAK;GACL,GAAI,iBAAiB,EAAE,eAAe,eAAe,OAAO,IAAI,CAAC;GACjE,QAAQ,cAAc;GACtB;GACA;GACA;GACA,cAAc,gBAAgB;GAC9B;GACA;EACF,CAAC;EAED,MAAM,aAAa,0BAA0B,cAAc,cAAc,QAAQ,UAAU,gBAAgB,IAAI;EAO/G,MAAM,aAAa,kBAAkB;GAAE,SAAS,aAAa;GAAG;EAAU,CAAC;EAC3E,MAAM,WAAW,gBAAgB;GAAE,SAAS,aAAa;GAAG;EAAU,CAAC;EACvE,MAAM,kBAAkB,SAAS,qBAAqB,EAAE,WAAW,IAAI;GAAE,kBAAkB;GAAG;EAAW;EAEzG,MAAM,kBAAkB,wBAAwB;GAAE;GAAK;GAAW;EAAuB,CAAC;EAE1F,MAAM,EAAE,aAAa,oBAAoB,eAAe,OAAO,mBAAmB,oBAAoB,KAAK,UAAU,SAAS;EAG9H,MAAM,iBAAiB,sBAAsB,iBAAiB;GAAE,KAAK;GAAc,QAAQ,cAAc;GAAQ;GAAU;EAAY,CAAC;EAExI,MAAM,EAAE,kBAAkB,qBAAqB,sBAAsB,8BAA8B;GAAE;GAAK;GAAc;EAAU,CAAC;EAOnI,MAAM,SAAS,IAAI,kBAAkB;EAErC,MAAM,gBAAgB,YAAY,WAAW,YAAY,SACrD,UAAU,KAAK,SAAS,cAAc,cAAc,QAAQ,aAAa,KAAK,cAAc,IAC5F;EACJ,MAAM,SAAS,cAAc,QAAQ,QAAQ,KAAK,SAAS,kBAAkB;EAO7E,MAAM,gBAAgB,SAClB,CAAC,wBAAwB,uBAAuB,MAAM,cAAc,SAAS,GAAG,KAAK,IAAI,CAAC,CAAC,IAC3F,CAAC;EACL,MAAM,EAAE,cAAc,eAAe,mBAAmB,uBAAuB;GAC7E;GACA;GACA;GACA;GACA;GACA,SAAS,uBAAuB;GAChC,iBAAiB,YAAY;GAC7B;EACF,CAAC;EAED,MAAM,SAAS,gBAAgB,IAAI,SAAS;EAC5C,MAAM,SAAS,cAAc;GAC3B,MAAM,QAAQ,UAAU,eAAe,UAAU,eAAe;GAChE,UAAU,QAAQ;GAClB,0BAA0B,cAAc;GACxC;GACA,cAAc,iBAAiB;GAC/B,eAAe,kBAAkB;EACnC,CAAC;EACD,MAAM,uBAAO,IAAI,IAA6B;EAC9C,MAAM,kBAAkB,mBAAmB,SAAS;EAEpD,MAAM,qBAAqB,IAAI;EAE/B,MAAM,EAAE,iBAAiB,mBAAmB,gBAAgB,sBAAsB,mBAAmB;GAAE;GAAW;GAAa;GAAgB;EAAc,CAAC;EAE9J,MAAM,oBAAoB,0BAA0B;GAAE;GAAU,aAAa,eAAe,OAAO;GAAO;GAAmB;EAAc,CAAC;EAE5I,MAAM,aAAa,gBAAgB;GACjC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,aAAa,eAAe;GAC5B;EACF,CAAC;EAED,MAAM,gBAAgB,qBAAqB;GAAE,gBAAgB,eAAe;GAAU;GAAiB;GAAU;EAAS,CAAC;EAE3H,MAAM,QAAQ,YAAY;GACxB,GAAG;GACH,UAAU,eAAe,SAAS,IAAI,CAAC,iBAAiB,GAAG,cAAc,IAAI;GAC7E,MAAM,QAAQ;GACd,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAC3B;GACA,WAAW;GAIX,WAAW;GACX,QAAQ,uBAAuB;GAC/B,QAAQ;GACR,YAAY,qBAAqB;IAC/B,YAAY;IACZ,QAAQ,oBAAoB;IAC5B,QAAQ,QAAQ;IAChB,QAAQ,eAAe;GACzB,CAAC;GACD,cAAc,oBAAoB,KAAK,0BAA0B,KAAK;GAEtE,OAAO;GACP,0BAA0B,CACxB,GAAG,eAAe,0BAClB,GAAG,eAAe,oBACpB;GACA,UAAU;EACZ,CAAC;EACD,uBAAuB,MAAM,OAAO,EAAE,SAAS,IAAI,YAAY,EAAE,CAAC;EAClE,8BAA8B,MAAM,QAAQ,eAAe;GACzD,UAAU;IAAE,MAAM;IAAuB;IAAW;GAAW,CAAC;EAClE,CAAC;EACD,IAAI,kBAAkB,OAAO,EAAE,UAAU,CAAC;EAE1C,MAAM,EAAE,aAAa,YAAY,aAAa,YAAY,oBAAoB;GAC5E;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,kBAAkB,uBAAuB;GACzC;GACA;GACA;GACA;GACA;GACA;GACA;GACA,yBAAyB,kBAAkB;IACzC,iBAAiB,eAAe,SAAS,CAAC,EAAA,CAAG;IAC7C;IACA;IACA;IACA;IACA;IACA;IACA,aAAa,IAAI,YAAY;IAC7B;IACA,OAAO;IACP,QAAQ;IACR,UAAU;IACV,MAAM,QAAQ;GAChB,CAAC;EACH,CAAC;EAED,MAAM,MAAM,kBAAkB;GAC5B;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC;EAED,qBAAqB,aAAa,GAAG;EAErC,OAAO;CACT;CAEA,OAAO,EAAE,eAAe;AAC1B;;;AC/XA,MAAM,yBAAyB;AAE/B,SAAgB,qBAAqB,EAAE,KAAK,cAAc,WAAW,WAAW,gBAAgB,oBAAoB,gBAAgB,iBASjI;CACD,MAAM,EAAE,WAAW,QAAQ,eAAe,WAAW,WAAW,oBAAoB,kBAAkB;;;;;CAMtG,MAAM,iCAAiB,IAAI,IAAY;;CAEvC,MAAM,wCAAwB,IAAI,IAA+B;;;;;;;;;CAUjE,SAAS,YAAY,KAAgB,MAA0C;EAC7E,IAAI,cAAc,MAAM;EACxB,IAAI,sBAAsB,MAAM;EAChC,IAAI,WAAW,MAAM;EACrB,IAAI,IAAI,SACN,UAAU,IAAI,QAAQ,MAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EACtD,IAAI,OAAO,MAAM;EACjB,IAAI,KAAK,MAAM;EACf,IAAI,MAAM,kBAAkB,OAC1B,sBAAsB,WAAW,GAAG;EACtC,UAAU,IAAI,MAAM,QAAQ,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CACtD;;CAGA,SAAS,WAAW,KAAsB;EACxC,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;CAC3C;CAEA,SAAS,mBAAmB,WAAmB,OAAwB;EACrE,YAAY,KAAK;EACjB,OAAO,OAAO,SAAS;CACzB;CAEA,SAAS,kBAAwB;EAC/B,MAAM,OAAO,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC,CAG/B,QAAQ,CAAC,WAAW,WAAW,CAAC,cAAc,SAAS,KAAK,CAAC,MAAM,cAAc,MAAM,iBAAiB,KAAA,KAAa,MAAM,KAAK,SAAS,CAAC,CAAC,CAC3I,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,UAAU;EACnD,MAAM,WAAW,OAAO,OAAO;EAC/B,IAAI,YAAY,GACd;EACF,KAAK,MAAM,CAAC,cAAc,KAAK,MAAM,GAAG,QAAQ,GAC9C,iBAAiB,WAAW,EAAE,oBAAoB,KAAK,CAAC;CAC5D;;;;;;;;CASA,SAAS,iBAAiB,WAAmB,UAA4C,CAAC,GAAS;EACjG,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,IAAI,OAAO;GACT,aAAa,aAAa,SAAS;GACnC,UAAU,QAAQ,SAAS;GAC3B,mBAAmB,WAAW,KAAK;EACrC;EAGA,IAAI,UAAU,KAAK,SAAS,KAAK,UAAU,eAAe,SAAS,GACjE;EACF,MAAM,gBAAyB,CAAC,OAAO,IAAI,SAAS,KAAK,CAAC,cAAc,IAAI,SAAS;EACrF,UAAU,eAAe,cAAc,WAAW,OAAO,CAAC,CAAC,MAAK,aAAY,WAExE,mBAAmB,iBAAiB,QAAQ,KAAK,CAAC,eAAe,SAAS,CAAC,CAAC,SAAS,SAAS,GAAG,OAAO,IACxG,KAAA,CAAS,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;CACvC;CAEA,eAAe,YAAY,WAAuC;EAChE,mBAAmB;EACnB,MAAM,WAAW,OAAO,IAAI,SAAS;EACrC,IAAI,UAAU;GACZ,SAAS,aAAa,KAAK,IAAI;GAC/B,OAAO;EACT;EAEA,MAAM,WAAW,cAAc,IAAI,SAAS;EAC5C,IAAI,UACF,OAAO;EAET,MAAM,aAAa,UAAU;EAE7B,MAAM,QAAQ,eAAe,SAAS,CAAC,CAAC,MAAM,QAAQ;GAOpD,IAAI,eAAe,UAAU,sBAAsB,cAAc,IAAI,SAAS,MAAM,OAAO;IACzF,WAAW,GAAG;IAId,UAAU,eAAe,cAAc,iBAAiB,CAAC,OAAO,IAAI,SAAS,KAAK,CAAC,KAAA,GAAW,KAAK,CAAC,CAAC,SAAS,cAAc,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;IACnK,MAAM,IAAI,MAAM,YAAY,UAAU,4DAA4D;GACpG;GACA,OAAO,IAAI,WAAW,GAAG;GAGzB,UAAU,eAAe,MAAM,WAAW,IAAI,MAAM,KAAK,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;GACjF,gBAAgB;GAChB,OAAO;EACT,CAAC;EAED,cAAc,IAAI,WAAW,KAAK;EAClC,UAAU,KAAK;EAEf,MACG,YAAY,KAAA,CAAS,CAAC,CACtB,cAAc;GACb,IAAI,cAAc,IAAI,SAAS,MAAM,OACnC,cAAc,OAAO,SAAS;EAClC,CAAC;EAEH,OAAO;CACT;;;;;;;CAQA,SAAS,iBAAiB,WAAyB;EAIjD,cAAc,OAAO,SAAS;EAC9B,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,IAAI,CAAC,OACH;EACF,mBAAmB,WAAW,KAAK;CACrC;;CAGA,SAAS,oBAAoB,WAAyB;EACpD,IAAI,CAAC,eAAe,OAAO,SAAS,GAClC;EACF,iBAAiB,SAAS;EAC1B,MAAM,UAAU,sBAAsB,IAAI,SAAS,KAAK,CAAC;EACzD,sBAAsB,OAAO,SAAS;EACtC,KAAK,MAAM,WAAW,SACpB,QAAQ;CACZ;;;;;;;;CASA,SAAS,uBAAuB,WAAkC;EAChE,IAAI,CAAC,cAAc,SAAS,GAAG;GAC7B,iBAAiB,SAAS;GAC1B,OAAO,QAAQ,QAAQ;EACzB;EACA,eAAe,IAAI,SAAS;EAC5B,OAAO,IAAI,SAAS,YAAY;GAC9B,MAAM,UAAU,sBAAsB,IAAI,SAAS,KAAK,CAAC;GACzD,QAAQ,KAAK,OAAO;GACpB,sBAAsB,IAAI,WAAW,OAAO;EAC9C,CAAC;CACH;CAEA,MAAM,UAA8C,EAClD,iBAAiB,UAAU,CAAC,GAAG;EAC7B,IAAI,QAAQ,YACV,cAAc,MAAM;EAItB,MAAM,WAAW,CAAC,GAAG,aAAa,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,OAAO,IAAI,SAAS,CAAC;EAClF,OAAO,QAAQ,IAAI,CACjB,GAAG,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,KAAI,cAAa,uBAAuB,SAAS,CAAC,GACxE,GAAG,SAAS,KAAK,CAAC,WAAW,WAC3B,MAAM,MAAK,QAAO,OAAO,IAAI,SAAS,MAAM,MAAM,uBAAuB,SAAS,IAAI,KAAA,SAAiB,KAAA,CAAS,CAAC,CACrH,CAAC,CAAC,CAAC,WAAW,KAAA,CAAS;CACzB,EACF;;CAGA,SAAS,0BAAgC;EAGvC,eAAe,MAAM;EACrB,KAAK,MAAM,WAAW,sBAAsB,OAAO,GACjD,KAAK,MAAM,WAAW,SACpB,QAAQ;EAEZ,sBAAsB,MAAM;CAC9B;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;ACzOA,SAAgB,oBAAoB,KAKlC;CACA,MAAM,cAAc,IAAI,eAAe,QAAQ,IAAI,4BAA4B;CAI/E,IAAI;CACJ,MAAM,kCAAmC,IAAI,IAAI;CACjD,MAAM,aAAa,WAA6B;EAC9C,IAAI,OAAO,SAAS,eAAe,OAAO,SAAS,WAAW;GAC5D,MAAM,WAAW,gBAAgB,IAAI,OAAO,SAAS;GACrD,IAAI,UAAU;IACZ,IAAI,OAAO,SAAS,WAAW;KAC7B,SAAS,MAAM;KACf;IACF;IAEA,MAAM,WAAW,SAAS;IAC1B,SAAS,MAAM,KAAA;IACf,IAAI,UAAU;KACZ,gBAAgB,OAAO,OAAO,SAAS;KACvC,IAAI;MACF,UAAU,QAAQ;KACpB,UACQ;MACN,gBAAgB,IAAI,OAAO,WAAW,QAAQ;KAChD;IACF;IACA,SAAS,QAAQ,OAAO;GAC1B;EACF;EACA,IAAI,aAAa;GACf,MAAM,UACF,OAAO,SAAS,WAAW,OAAO,MAAM,SAAS,aAC/C,aAAa,OAAO,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI,OAAO,MAAM,KAAK,SAAS,KAAK,MAAM,GAAG,KACvF,OAAO,SAAS,UACd,SAAS,OAAO,MAAM,OAAO,OAAO,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,gBAAgB,IAAI,OAAO,MAAM,KAAK,KAAK,OAC9H,OAAO;GACf,QAAQ,IAAI,gBAAgB,SAAS;EACvC;EACA,IAAI,UAAU,MAAM;EAIpB,kBAAkB,SAAS,MAAM;CACnC;CAEA,OAAO;EACL;EACA;EACA,iBAAiB,kBAAkB;GACjC,mBAAmB;EACrB;CACF;AACF;;;;AC7BA,SAAgB,qBAAqB,IAAe,OAAwC;CAC1F,MAAM,MAAM,OAAO,MAAM,cAAc,WAAW,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,SAAS,GAAG,mBAAmB,IAAI;CAChH,QAAQ,IAAR;EACE,KAAK,QAEH,OAAO,yBAAyB,OAAO,QAAU;EACnD,KAAK,YACH,QAAQ,OAAO,QAAU;EAC3B,KAAK,YACH,QAAQ,OAAA,OAAkC;EAC5C,KAAK;EACL,KAAK,QACH,QAAQ,OAAA,OAAoC,MAAQ;EACtD,KAAK;EACL,KAAK,cACH,OAAO,OAAS;EAClB,SACE,OAAO,MAAS;CACpB;AACF;AAEA,SAAgB,iBAAiB,EAAE,aAAsE;CACvG,MAAM,QAAkB,CAAC;CACzB,MAAM,0BAAU,IAAI,IAAqB;CACzC,MAAM,4BAAY,IAAI,IAAkC;CACxD,MAAM,UAAU,cAAuB;EACrC,KAAK,MAAM,KAAK,WAAW,EAAE,SAAS;CACxC;CAEA,MAAM,UAAU,WAAmB,aAA8B;EAC/D,MAAM,QAAQ,QAAQ,IAAI,SAAS;EACnC,IAAI,CAAC,OACH,OAAO;EACT,QAAQ,OAAO,SAAS;EACxB,MAAM,QAAQ,QAAQ;EACtB,OAAO;CACT;CAEA,OAAO;EACL,aAAa,QAAQ;GACnB,MAAM,MAAM,MAAM,SAAS;GAC3B,MAAM,IAAI,MAAM,QAAQ,MAAM;GAC9B,IAAI,KAAK,GACP,MAAM,OAAO,GAAG,CAAC;GACnB,MAAM,KAAK,MAAM;GACjB,IAAI,CAAC,KACH,OAAO,IAAI;EACf;EACA,eAAe,QAAQ;GACrB,MAAM,IAAI,MAAM,QAAQ,MAAM;GAC9B,IAAI,IAAI,GACN;GACF,MAAM,OAAO,GAAG,CAAC;GACjB,KAAK,MAAM,CAAC,WAAW,UAAU,SAC/B,IAAI,MAAM,WAAW,QACnB,OAAO,WAAW;IAAE,IAAI;IAAO,OAAO;KAAE,MAAM;KAAc,SAAS;IAAsC;GAAE,CAAC;GAElH,IAAI,MAAM,WAAW,GACnB,OAAO,KAAK;EAChB;EACA,eAAe,MAAM,SAAS;EAC9B,qBAAqB,UAAU;GAC7B,UAAU,IAAI,QAAQ;GACtB,aAAa,UAAU,OAAO,QAAQ;EACxC;EACA,QAAQ,WAAW,IAAI,OAAO,QAAQ;GACpC,MAAM,SAAS,MAAM,GAAG,EAAE;GAC1B,IAAI,CAAC,QACH,OAAO,QAAQ,QAAQ;IACrB,IAAI;IACJ,OAAO;KAAE,MAAM;KAAc,SAAS;IAA0D;GAClG,CAAC;GAEH,IAAI,OAAO,SACT,OAAO,QAAQ,QAAQ;IAAE,IAAI;IAAO,OAAO;KAAE,MAAM;KAAa,SAAS;IAAa;GAAE,CAAC;GAC3F,MAAM,YAAY,qBAAqB,IAAK,SAAS,CAAC,CAA6B;GACnF,MAAM,UAA0B;IAAE,WAAW,WAAW;IAAG;IAAW;IAAI;IAAO;GAAU;GAC3F,OAAO,IAAI,SAAS,YAAY;IAC9B,MAAM,UAAU,MAA+B,YAAoB;KACjE,IAAI,OAAO,QAAQ,WAAW;MAAE,IAAI;MAAO,OAAO;OAAE;OAAM;MAAQ;KAAE,CAAC,GACnE,UAAU;MAAE,MAAM;MAAkB;MAAW;MAAQ,WAAW,QAAQ;KAAU,CAAC;IACzF;IACA,MAAM,gBAAgB,OAAO,aAAa,YAAY;IACtD,MAAM,QAAQ,WAAW,QAAQ,WAAW,WAAW,qCAAqC,KAAK,MAAM,YAAY,GAAI,EAAE,GAAG;IAC5H,QAAQ,IAAI,QAAQ,WAAW;KAC7B;KACA;KACA,UAAU,aAAa;MACrB,aAAa,KAAK;MAClB,OAAO,oBAAoB,SAAS,OAAO;MAC3C,QAAQ,QAAiB;KAC3B;IACF,CAAC;IACD,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;IACxD,UAAU;KAAE,MAAM;KAAmB;KAAW;KAAQ;IAAQ,CAAC;GACnE,CAAC;EACH;EACA,QAAQ,WAAW,UAAU,WAAW;GACtC,MAAM,QAAQ,QAAQ,IAAI,SAAS;GACnC,IAAI,CAAC,SAAU,aAAa,CAAC,UAAU,IAAI,MAAM,MAAM,GACrD,OAAO,EAAE,IAAI,MAAM;GACrB,OAAO,EAAE,IAAI,OAAO,WAAW,QAAQ,EAAE;EAC3C;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;ACnGA,SAAgB,SAAS,MAAc,MAAuB;CAC5D,OAAO,SAAS,QAAQ,KAAK,WAAW,KAAK,SAAS,GAAG,IAAI,OAAO,OAAO,GAAG;AAChF;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI;CACJ,IAAI;EACF,OAAO,aAAa,OAAO,IAAI;CACjC,QACM;EACJ,MAAM,IAAI,MAAM,GAAG,KAAK,iBAAiB;CAC3C;CACA,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,YAAY,GAC9B,MAAM,IAAI,MAAM,GAAG,KAAK,kBAAkB;CAC5C,OAAO;AACT;;AAGA,SAAS,mBAAmB,OAAoC;CAC9D,OAAO,MAAM,KAAK,SAAS;EACzB,IAAI;GACF,OAAO,WAAW,IAAI;EACxB,SACO,KAAK;GACV,MAAM,IAAI,MAAM,kBAAmB,IAAc,SAAS;EAC5D;CACF,CAAC;AACH;;AAGA,SAAS,mBAAmB,MAAsB;CAChD,IAAI,UAAU;CACd,MAAM,OAAiB,CAAC;CACxB,SACE,IAAI;EACF,OAAO,QAAQ,aAAa,OAAO,OAAO,GAAG,GAAG,KAAK,QAAQ,CAAC;CAChE,QACM;EACJ,MAAM,SAAS,QAAQ,OAAO;EAC9B,IAAI,WAAW,SACb,OAAO;EACT,KAAK,KAAK,QAAQ,MAAM,OAAO,MAAM,CAAC,CAAC,QAAQ,WAAW,EAAE,CAAC;EAC7D,UAAU;CACZ;AAEJ;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI;EACF,OAAO,aAAa,OAAO,IAAI;CACjC,QACM;EACJ,OAAO,QAAQ,IAAI;CACrB;AACF;AAEA,SAAgB,2BACd,YACA,UAWI,CAAC,GACiB;CACtB,MAAM,WAAW,eAAe,KAAA;CAChC,MAAM,QAAQ,QAAQ,SAAS;EAAE,OAAO;EAAuB,SAAS;CAA2D;CACnI,MAAM,QAAQ,WAAW,mBAAmB,UAAU,IAAI,CAAC,aAAa,OAAO,QAAQ,CAAC,CAAC;CACzF,MAAM,UAAU,QAAQ,UAAU,WAAW,QAAQ,OAAO,IAAI,KAAA;CAChE,MAAM,cAAc,CAAC,GAAG,IAAI,KAAK,QAAQ,eAAe,CAAC,EAAA,CAAG,IAAI,kBAAkB,CAAC,CAAC;;CAGpF,MAAM,aAAa,KAAa,SAC9B,MAAM,MAAK,SAAQ,SAAS,KAAK,IAAI,KAAK,SAAS,MAAM,IAAI,CAAC;;CAGhE,MAAM,mBAAmB,MAAc,SAAuB;EAC5D,IAAI,CAAC,MAAM,MAAK,SAAQ,SAAS,MAAM,IAAI,CAAC,GAC1C,MAAM,IAAI,MAAM,GAAG,KAAK,cAAc,MAAM,MAAM,IAAI,MAAM,KAAK,IAAI,EAAE,GAAG;EAC5E,IAAI,CAAC,UACH;EACF,IAAI,WAAW,SAAS,SAAS,IAAI,KAAK,CAAC,UAAU,SAAS,IAAI,GAChE,MAAM,IAAI,MAAM,GAAG,KAAK,SAAS,MAAM,QAAQ,EAAE;EACnD,MAAM,SAAS,YAAY,MAAK,QAAO,SAAS,KAAK,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;EACnF,IAAI,QACF,MAAM,IAAI,MAAM,GAAG,KAAK,eAAe,OAAO,iEAAiE;CACnH;CAEA,MAAM,iBAAiB,SAAyB;EAC9C,IAAI,CAAC,WAAW,IAAI,GAClB,MAAM,IAAI,MAAM,IAAI,KAAK,2BAA2B;EACtD,MAAM,OAAO,WAAW,IAAI;EAC5B,gBAAgB,MAAM,IAAI;EAC1B,OAAO;CACT;CAEA,OAAO;EACL;EACA;EACA;EACA,cAAa,QAAQ,YAAY,QAAQ,KAAK,cAAc,GAAG,IAAI;EACnE,gBAAe,QAAQ,WAAW,cAAc,QAAQ,KAAK,MAAM,KAAM,GAAG,IAAI;EAChF,qBAAsB,WAAW,MAAM,KAAK,KAAA;EAC5C,UAAU,MAAM,iBAAiB;GAC/B,IAAI,CAAC,UACH;GACF,IAAI,CAAC,WAAW,IAAI,GAClB,MAAM,IAAI,MAAM,IAAI,KAAK,2BAA2B;GACtD,MAAM,OAAO,mBAAmB,IAAI;GACpC,IAAI,mBAAmB,SAAS,WAAW,eAAe,GAAG,IAAI,GAC/D;GACF,gBAAgB,MAAM,IAAI;EAC5B;CACF;AACF;;;ACzHA,SAAgB,kBAAkB,KAA0B,WAAsD;CAChH,MAAM,yBAAS,IAAI,IAAuB;;CAE1C,MAAM,kCAAkB,IAAI,IAAoC;;CAEhE,MAAM,qBAA6B,IAAI,WAAW,KAAK,IAAI,YAAY;CACvE,MAAM,YAAY,2BAA2B,IAAI,gBAAgB,EAAE,SAAS,IAAI,YAAY,EAAE,CAAC;CAC/F,MAAM,aAAa,iBAAiB,iBAAiB,UAAU,aAAa;;;;;;CAM5E,MAAM,iCAAiB,IAAI,IAAY;;;;;;;;CASvC,MAAM,gCAAgB,IAAI,IAAgC;CAE1D,MAAM,YAA2B;EAAE,QAAQ;EAAO,oBAAoB;CAAE;CACxE,MAAM,6BAAa,IAAI,IAA2B;CAClD,MAAM,gCAAgB,IAAI,IAAsB;CAEhD,SAAS,UAAa,MAA8B;EAClD,cAAc,IAAI,IAAI;EACtB,KAAU,cAAc,cAAc,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EACzE,OAAO;CACT;CAEA,SAAS,mBAAmB,aAAa,UAAU,oBAA4B;EAC7E,IAAI,UAAU,UAAU,eAAe,UAAU,oBAC/C,MAAM,IAAI,MAAM,qDAAqD;EACvE,OAAO;CACT;CAEA,SAAS,cAAc,WAA4B;EACjD,OAAO,WAAW,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,CAAC,EAAE,MAAM,cAAc;CACjF;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;ACtEA,MAAM,WAAW,eAAe,iBAAiB;AA2DjD,SAAgB,8BAAqD;CACnE,MAAM,0BAAU,IAAI,IAAmB;;CAEvC,MAAM,6BAAa,IAAI,IAA2B;;CAGlD,SAAS,OAAO,WAAmB,OAA6B;EAC9D,IAAI,QAAQ,IAAI,SAAS,MAAM,OAC7B,QAAQ,OAAO,SAAS;EAG1B,MAAM,UAAU,QAAQ,IAAI,CAAC,WAAW,IAAI,SAAS,GAAG,aAAa,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;EAC3F,WAAW,IAAI,WAAW,OAAO;EACjC,QAAa,cAAc;GACzB,IAAI,WAAW,IAAI,SAAS,MAAM,SAChC,WAAW,OAAO,SAAS;EAC/B,CAAC;EACD,OAAO;CACT;CAEA,SAAS,cAAc,OAAwC;EAG7D,IAAI,MAAM,UACR,OAAO,QAAQ,uBAAO,IAAI,MAAM,gCAAgC,CAAC;EACnE,IAAI,MAAM,QACR,OAAO,QAAQ,QAAQ,MAAM,MAAM;EAGrC,MAAM,aAAa,MAAM,QAAQ,MAAM,CAAC,CAAC,MACtC,WAAW;GACV,MAAM,SAAS;GACf,MAAM,WAAW;GACjB,OAAO;EACT,IACC,QAAiB;GAChB,MAAM,WAAW;GACjB,MAAM;EACR,CACF;EACA,OAAO,MAAM;CACf;CAEA,eAAe,aAAa,OAA6B;EACvD,IAAI,MAAM,UACR;EACF,MAAM,WAAW;EACjB,MAAM,SAAS,MAAM,UAAU,MAAM,MAAM,UAAU,YAAY,IAAI,KAAK;EAC1E,IAAI,CAAC,QACH;EACF,MAAM,SAAS;EACf,IAAI;GACF,MAAM,MAAM,QAAQ,QAAQ,MAAM;EACpC,SACO,KAAK;GACV,SAAS,kBAAkB,GAAG;EAChC;CACF;CAEA,eAAe,aAAa,OAA0B;EACpD,IAAI,CAAC,OAAO,UAAU,CAAC,MAAM,QAAQ,gBACnC,OAAO,CAAC;EACV,IAAI;GACF,QAAQ,MAAM,MAAM,QAAQ,eAAe,MAAM,MAAM,EAAA,CAAG,QAAO,SAAQ,KAAK,WAAW,SAAS;EACpG,SACO,KAAK;GACV,SAAS,yBAAyB,GAAG;GACrC,OAAO,CAAC;EACV;CACF;CAEA,MAAM,QAA+B;EACnC,QAAQ,WAAW,KAAK,QAAQ;GAC9B,IAAI,QAAQ,QAAQ,IAAI,SAAS;GACjC,IAAI,SAAS,MAAM,QAAQ,KAAK;IAC9B,OAAY,WAAW,KAAK;IAC5B,QAAQ,KAAA;GACV;GACA,IAAI,CAAC,OAAO;IACV,QAAQ;KAAE;KAAK,SAAS,OAAO;KAAG,QAAQ;KAAM,UAAU;KAAM,UAAU;IAAM;IAChF,QAAQ,IAAI,WAAW,KAAK;GAC9B;GACA,MAAM,QAAQ;GACd,OAAO;IAAE,SAAS,MAAM;IAAS,cAAc,cAAc,KAAK;GAAE;EACtE;EAEA,KAAK,WAAW;GACd,MAAM,QAAQ,QAAQ,IAAI,SAAS;GACnC,OAAO,QAAQ;IAAE,SAAS,MAAM;IAAS,cAAc,cAAc,KAAK;GAAE,IAAI,KAAA;EAClF;EAEA,MAAM,MAAM,WAAW,OAAO;GAC5B,MAAM,QAAQ,QAAQ,IAAI,SAAS;GACnC,MAAM,SAAS,OAAO;GACtB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,QAAQ,yBACtC,OAAO;GACT,IAAI;GACJ,IAAI;IACF,UAAU,MAAM,MAAM,QAAQ,wBAC5B,QACA,SACC,SAAS;KACR,QAAQ,QAAQ,MAAM,SAAS,mBAAmB,IAAI,CAAC,CAAC,CAAC,OAAM,QAAO,SAAS,iCAAiC,GAAG,CAAC;IACtH,IACC,SAAS;KACR,QAAQ,QAAQ,MAAM,SAAS,oBAAoB,IAAI,CAAC,CAAC,CAAC,OAAM,QAAO,SAAS,kCAAkC,GAAG,CAAC;IACxH,CACF;GACF,SACO,KAAK;IACV,SAAS,gBAAgB,GAAG;IAC5B,OAAO;GACT;GACA,KAAK,MAAM,QAAQ,SACjB,MAAM,QAAQ,QAAQ,MAAM,SAAS,oBAAoB;IACvD,QAAQ,KAAK;IACb,KAAK,KAAK;IACV,SAAS,KAAK;IACd,KAAK,KAAK;IACV,YAAY,KAAK;IACjB,WAAW,KAAK;GAClB,CAAC,CAAC,CAAC,CAAC,OAAM,QAAO,SAAS,kCAAkC,GAAG,CAAC;GAElE,OAAO,QAAQ;EACjB;EAEA,MAAM,gBAAgB,WAAW;GAC/B,QAAQ,MAAM,aAAa,QAAQ,IAAI,SAAS,CAAC,EAAA,CAAG,SAAS;EAC/D;EAEA,MAAM,QAAQ,WAAW;GACvB,MAAM,QAAQ,QAAQ,IAAI,SAAS;GACnC,IAAI,CAAC,OACH,OAAO,WAAW,IAAI,SAAS;GACjC,MAAM,OAAO,WAAW,KAAK;EAC/B;EAEA,MAAM,cAAc,WAAW,WAAW;GACxC,MAAM,QAAQ,QAAQ,IAAI,SAAS;GACnC,IAAI,CAAC,OACH,OAAO;GACT,KAAK,MAAM,aAAa,KAAK,EAAA,CAAG,SAAS,GACvC,OAAO;GAGT,IAAI,QAAQ,IAAI,SAAS,MAAM,SAAU,aAAa,CAAC,UAAU,GAC/D,OAAO;GACT,MAAM,MAAM,QAAQ,SAAS;GAC7B,OAAO;EACT;EAEA,gBAAgB,CAAC,GAAG,QAAQ,KAAK,CAAC;EAElC,MAAM,aAAa;GACjB,MAAM,MAAM,CAAC,GAAG,OAAO;GACvB,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,WAAW,WAAW,OAAO,WAAW,KAAK,CAAC,GAAG,GAAG,WAAW,OAAO,CAAC,CAAC;EAC1G;CACF;CACA,OAAO;AACT;;;AC1OA,MAAMC,cAAY;AAElB,SAAgB,2BAA2B,SAAyB;CAClE,OAAO,QAAQ,SAAS,8BAA8B;AACxD;;AAKA,SAAS,SAAS,MAA2B;CAC3C,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,MAAM,SAAS,KAAK,MAAM,aAAa,MAAM,OAAO,CAAC;CACrD,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,MAAM,IAAI,MAAM,mBAAmB;CACrC,MAAM,MAAmB,CAAC;CAC1B,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,MAAiC,GAAG;EAC9E,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D;EACF,IAAI,QAAQ,OAAO,YAAY,OAAO,QAAQ,MAAiC,CAAC,CAAC,QAAQ,UAAqC,OAAO,MAAM,OAAO,QAAQ,CAAC;CAC7J;CACA,OAAO;AACT;AAEA,SAASC,UAAQ,SAA8B;CAC7C,IAAI;EACF,OAAO,SAAS,2BAA2B,OAAO,CAAC;CACrD,QACM;EACJ,OAAO,CAAC;CACV;AACF;;AAGA,SAAS,gBAAgB,SAA8B;CACrD,MAAM,OAAO,2BAA2B,OAAO;CAC/C,IAAI;EACF,OAAO,SAAS,IAAI;CACtB,QACM;EACJ,WAAW,MAAM,GAAG,KAAK,WAAW,KAAK,IAAI,GAAG;EAChD,OAAO,CAAC;CACV;AACF;AAEA,SAAgB,6BAA6B,SAAqC;CAChF,OAAO;EACL,MAAM,MAAM,QAAQA,UAAQ,OAAO,CAAC,CAAC,KAAK,GAAG;EAC7C,MAAM,MAAM,KAAK,UAAU;GACzB,MAAM,MAAM,gBAAgB,OAAO;GACnC,MAAM,SAAS,EAAE,GAAG,IAAI,MAAM;GAC9B,IAAI,UAAU,MACZ,OAAO,OAAO;QAEd,OAAO,OAAO;GAChB,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GACjC,OAAO,IAAI;QAEX,IAAI,QAAQ;GACd,gBAAgB,2BAA2B,OAAO,GAAG,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,KAAK;IAAE,WAAW;IAAM,MAAMD;GAAU,CAAC;EAChI;CACF;AACF;;AAGA,SAAgB,+BAA+B,UAAkD,CAAC,GAAuB;CACvH,MAAM,MAAmB,KAAK,MAAM,KAAK,UAAU,OAAO,CAAC;CAC3D,OAAO;EACL,MAAM,MAAM,QAAQ,IAAI,KAAK,GAAG;EAChC,MAAM,MAAM,KAAK,UAAU;GACzB,MAAM,SAAS,EAAE,GAAG,IAAI,MAAM;GAC9B,IAAI,UAAU,MACZ,OAAO,OAAO;QAEd,OAAO,OAAO;GAChB,IAAI,QAAQ;EACd;CACF;AACF;;;AC7CA,SAAS,aAAa,UAAiD,KAAsB;CAC3F,OAAQ,WAAmD;AAC7D;;AAGA,SAAgB,wBAAwB,UAAgF;CACtH,MAAM,MAAO,UAAqD;CAClE,MAAM,SAAS,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,IAAI,MAAiC,CAAC;CACzG,MAAM,SAAS,UAA6B,MAAM,QAAQ,KAAK,IAC3D,CAAC,GAAG,IAAI,IAAI,MAAM,QAAQ,SAAyB,OAAO,SAAS,YAAY,SAAS,kBAAkB,IAAI,CAAC,CAAC,IAChH,CAAC;CACL,MAAM,WAAW,MAAM,OAAO,QAAQ;CACtC,MAAM,UAAU,MAAM,OAAO,OAAO;CACpC,MAAM,SAAiE,CAAC;CACxE,IAAI,OAAO,UAAU,OAAO,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,OAAO,MAAM,GACpF,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,OAAO,MAAiC,GAAG;EACrF,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D;EACF,MAAM,UAAU,OAAO,QAAQ,MAAiC,CAAC,CAC9D,QAAQ,UAAqD;GAAC;GAAU;GAAU;EAAS,CAAC,CAAC,SAAS,OAAO,MAAM,EAAE,CAAC;EACzH,OAAO,QAAQ,OAAO,YAAY,OAAO;CAC3C;CAEF,OAAO;EACL,aAAa,OAAO,OAAO,gBAAgB,YAAY,OAAO,cAAc,OAAO,cAAc,kBAAkB;EACnH;EACA;EACA;CACF;AACF;;;;;AAMA,SAAgB,qBAAqB,UAAiD,MAAc,UAA+D;CACjK,IAAI,SAAS,kBAAkB,MAC7B,OAAO;CACT,MAAM,EAAE,UAAU,YAAY,wBAAwB,QAAQ;CAC9D,IAAI,SAAS,SAAS,IAAI,GACxB,OAAO;CACT,OAAO,UAAU,eAAe,QAAQ,SAAS,IAAI,IAAI;AAC3D;;AAGA,SAAgB,uBAAuB,UAA+B,UAAyD;CAC7H,MAAM,EAAE,gBAAgB,wBAAwB,QAAQ;CACxD,MAAM,WAAW,SAAS,IAAI,WAAW;CACzC,OAAO,YAAY,qBAAqB,UAAU,aAAa,QAAQ,IAAI,cAAc,kBAAkB;AAC7G;;AAGA,SAAS,OAAO,OAA+B,OAAoD;CACjG,QAAQ,MAAM,MAAd;EACE,KAAK,WACH,OAAO,OAAO,UAAU,YAAY,QAAQ,UAAU,SAAS,OAAO,UAAU,UAAU,QAAQ,KAAA;EACpG,KAAK,UAAU;GACb,MAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,OAAO,UAAU,YAAY,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI;GAC1G,OAAO,OAAO,SAAS,CAAC,IAAI,IAAI,KAAA;EAClC;EACA,KAAK,UACH,OAAO,OAAO,UAAU,YAAY,MAAM,SAAS,MAAK,WAAU,OAAO,UAAU,KAAK,IAAI,QAAQ,KAAA;EACtG,SACE,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;CAC/C;AACF;;;;;AAaA,SAAgB,sBAAsB,UAA+B,SAAkD;CACrH,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,SAAS,wBAAwB,QAAQ,QAAQ,CAAC,CAAC,OAAO,SAAS,SAAS,CAAC;CACnF,MAAM,MAA0D,CAAC;CACjE,KAAK,MAAM,SAAS,SAAS,gBAAgB,CAAC,GAAG;EAC/C,IAAI;EACJ,IAAI,MAAM,SACR,QAAQ,OAAO,OAAO,aAAa,QAAQ,UAAU,MAAM,OAAO,CAAC;OAChE,IAAI,MAAM,SAAS,UACtB,QAAQ,QAAQ,QAAQ,IAAI,SAAS,MAAM,MAAM,GAAG,KAAK,KAAA;OAEzD,QAAQ,OAAO,OAAO,OAAO,MAAM,IAAI;EACzC,IAAI,UAAU,KAAA,KAAa,MAAM,OAAO,IAAI,MAAM,MAChD,QAAQ,OAAO,OAAO,IAAI,MAAM,IAAI;EACtC,IAAI,MAAM,OAAO,SAAS,MAAM;CAClC;CACA,OAAO;AACT;;AA6CA,eAAsB,qBACpB,UACA,SACkC;CAClC,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,cAAc,uBAAuB,UAAU,QAAQ,QAAQ;CAErE,MAAM,SAAS,SAAS,KAAK,CAAC,CAAC,QAAO,aAAY,CAAC,SAAS,WAAW,SAAS,QAAQ,MAAM,KAAA,CAAS;CACvG,OAAO,QAAQ,IAAI,OAAO,IAAI,OAAO,aAAa;EAChD,MAAM,SAAS,sBAAsB,UAAU,OAAO;EACtD,MAAM,UAAU,SAAS,UAAU;EACnC,MAAM,eAAe,MAAM,iBAAiB,UAAU;GAAE,KAAK,QAAQ;GAAK;EAAO,CAAC;EAClF,MAAM,cAAc,uBAAuB,UAAU,MAAM;EAC3D,MAAM,OAAO,aAAa,KAAK,MAAM,SAAS,OAAO;GAAE,KAAK,QAAQ;GAAK;EAAO,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS,IAAI,KAAA;EAC5G,OAAO;GACL,MAAM,SAAS;GACf,OAAO,SAAS;GAChB,GAAI,SAAS,cAAc,EAAE,aAAa,SAAS,YAAY,IAAI,CAAC;GACpE,SAAS,qBAAqB,QAAQ,UAAU,SAAS,MAAM,QAAQ;GACvE,WAAW,SAAS,SAAS;GAC7B,WAAW,aAAa;GACxB,GAAI,aAAa,KAAK,CAAC,IAAI,EAAE,QAAQ,aAAa,OAAO;GACzD;GACA,GAAI,eAAe,SAAS,gBAAgB,EAAE,iBAAiB,SAAS,cAAc,MAAM,EAAE,IAAI,CAAC;GACnG,WAAW,SAAS,WAAW,KAAA;GAC/B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;GACvB,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;GAC7B,SAAS,SAAS,gBAAgB,CAAC,EAAA,CAAG,KAAK,UAAsC;IAC/E,MAAM,SAAS,MAAM,SAAS;IAC9B,MAAM,SAAS,SAAS,QAAQ,QAAQ,IAAI,SAAS,MAAM,MAAM,GAAG,IAAI,KAAA;IACxE,MAAM,cAAc,MAAM,OAAO,IAAI,MAAM,SAAS,SAAS,CAAC,SAAS,OAAO,MAAM,SAAS,OAAO,OAAO,IAAI,MAAM,IAAI,KAAK,MAAM,MAAM,KAAA;IAC1I,OAAO;KACL,KAAK,MAAM;KACX,OAAO,MAAM;KACb,GAAI,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;KAC9D,MAAM,MAAM;KACZ,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;KAClD,GAAI,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;KAC9D,GAAI,SAAS,EAAE,YAAY,QAAQ,MAAM,KAAK,QAAQ,WAAW,EAAE,IAAI,EAAE,OAAO,OAAO,MAAM,KAAK;KAClG,GAAI,MAAM,YAAY,KAAA,KAAa,CAAC,SAAS,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;KAC3E,GAAI,cAAc,EAAE,SAAS,YAAY,IAAI,CAAC;KAC9C,SAAS,CAAC,MAAM,QAAQ,OAAO,MAAM,KAAK,SAAS,MAAM,KAAK;IAChE;GACF,CAAC;EACH;CACF,CAAC,CAAC;AACJ;;;;;;AA4BA,SAAgB,+BACd,UACA,UACA,QAC0B;CAC1B,MAAM,WAAW,SAAS,IAAI,OAAO,IAAI;CACzC,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,wBAAwB,OAAO,KAAK,GAAG;CACzD,MAAM,UAAU,wBAAwB,QAAQ;CAChD,MAAM,OAAsC;EAC1C,aAAa,QAAQ;EACrB,UAAU,CAAC,GAAG,QAAQ,QAAQ;EAC9B,SAAS,CAAC,GAAG,QAAQ,OAAO;EAC5B,QAAQ;GAAE,GAAG,QAAQ;IAAS,OAAO,OAAO,EAAE,GAAG,QAAQ,OAAO,OAAO,MAAM;EAAE;CACjF;CACA,MAAM,gBAAyC,CAAC;CAChD,MAAM,UAAwD,CAAC;CAE/D,IAAI,OAAO,YAAY,OAAO;EAC5B,IAAI,OAAO,SAAS,kBAAkB,MACpC,MAAM,IAAI,MAAM,0DAA2D;EAC7E,IAAI,CAAC,KAAK,SAAS,SAAS,OAAO,IAAI,GACrC,KAAK,SAAS,KAAK,OAAO,IAAI;EAChC,KAAK,UAAU,KAAK,QAAQ,QAAO,SAAQ,SAAS,OAAO,IAAI;EAC/D,IAAI,KAAK,gBAAgB,OAAO,MAC9B,KAAK,cAAc,kBAAkB;CACzC;CACA,IAAI,OAAO,YAAY,QAAQ,OAAO,aAAa;EACjD,KAAK,WAAW,KAAK,SAAS,QAAO,SAAQ,SAAS,OAAO,IAAI;EACjE,IAAI,SAAS,gBAAgB,CAAC,KAAK,QAAQ,SAAS,OAAO,IAAI,GAC7D,KAAK,QAAQ,KAAK,OAAO,IAAI;CACjC;CACA,IAAI,OAAO,aACT,KAAK,cAAc,OAAO;CAE5B,KAAK,MAAM,CAAC,KAAK,QAAQ,OAAO,QAAQ,OAAO,UAAU,CAAC,CAAC,GAAG;EAC5D,MAAM,QAAQ,SAAS,cAAc,MAAK,cAAa,UAAU,QAAQ,GAAG;EAC5E,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,GAAG,SAAS,MAAM,kBAAkB,IAAI,GAAG;EAC7D,IAAI,MAAM,SAAS,UAAU;GAC3B,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UACjC,MAAM,IAAI,MAAM,GAAG,MAAM,MAAM,eAAe;GAChD,QAAQ,KAAK;IAAE;IAAK,OAAO,QAAQ,QAAQ,QAAQ,KAAK,OAAO;GAAI,CAAC;GACpE;EACF;EACA,MAAM,QAAQ,QAAQ,OAAO,OAAO,OAAO,OAAO,GAAG;EACrD,IAAI,UAAU,KAAA,GACZ,MAAM,IAAI,MAAM,GAAG,MAAM,MAAM,IAAI,MAAM,SAAS,WAAW,eAAe,MAAM,SAAS,KAAI,WAAU,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,MAAM,cAAc,MAAM,OAAO,EAAE;EACrK,IAAI,MAAM,SAAS;GACjB,cAAc,MAAM,WAAW,SAAS,MAAM;GAC9C;EACF;EACA,IAAI,UAAU,MACZ,OAAO,KAAK,OAAO,OAAO,KAAK,CAAE;OAEjC,KAAK,OAAO,OAAO,KAAK,CAAE,OAAO;CACrC;CACA,IAAI,OAAO,KAAK,KAAK,OAAO,OAAO,KAAM,CAAC,CAAC,WAAW,GACpD,OAAO,KAAK,OAAO,OAAO;CAC5B,cAAc,eAAe;CAC7B,OAAO;EAAE;EAAe;CAAQ;AAClC;;;;AC3TA,SAAgB,gBAAgB,GAAuB,GAAgC;CACrF,OAAO,EAAE,QAAQ,KAAA,KAAa,EAAE,SAAS,EAAE,QAAQ,KAAK,UAAU,EAAE,GAAG,MAAM,KAAK,UAAU,EAAE,GAAG;AACnG;AAQA,SAAgB,uBAAuB,KAA4C;;CAEjF,MAAM,eAAe,IAAI,gBAAgB,0BAA0B,4BAA4B,EAAE,SAAS,IAAI,YAAY,EAAE,CAAC,CAAC;;CAE9H,MAAM,qBAAqB,IAAI,qBAAqB,KAAK,6BAA6B,IAAI,YAAY,CAAC;;CAEvG,MAAM,qBAAqB,SAAoC;EAC7D,MAAM,WAAW,aAAa,IAAI,IAAI;EACtC,OAAO,WAAW,sBAAsB,UAAU;GAAE,UAAU,IAAI,aAAa;GAAG,SAAS;EAAmB,CAAC,IAAI,CAAC;CACtH;CACA,OAAO;EAAE;EAAc;EAAoB;CAAkB;AAC/D;;;ACOA,SAAgB,uBAAuB,EAAE,KAAK,MAAM,OAAO,cAAc,qBAAqB,kBAAkB,yBAAyB,gBAAgB,WAAW,oBAU/I;CACnB,MAAM,EAAE,KAAK,WAAW,iBAAiB,YAAY,cAAc,WAAW,gBAAgB;CAC9F,MAAM,EAAE,cAAc,oBAAoB,sBAAsB;CAChE,MAAM,gBAAgB,qBAAqB;EAAE;EAAc,WAAW;CAAY,CAAC;CACnF,MAAM,EAAE,cAAc,sBAAsB,sBAAsB;CAClE,MAAM,EAAE,kBAAkB,qBAAqB;;;;;;CAO/C,eAAe,uBAAuB,WAAmB,MAA+E;EACtI,MAAM,MAAM,uBAAuB,KAAK,QAAQ;EAChD,IAAI,IAAI,UAAU,SAAS,IAAI,QAAQ,KAAA,GACrC,OAAO,CAAC;EACV,MAAM,SAAS,EAAE,aAAa,KAAK,eAAe,KAAK;EAIvD,QAHc,IAAI,MAAM,YACnB,MAAM,IAAI,MAAM,SAAS,MAAM,EAAA,CAAG,KAAI,SAAQ;GAAE,IAAI,IAAI;GAAI,UAAU,IAAI;EAAS,EAAE,IACrF,MAAM,QAAQ,KAAK,MAAM,IAAI,MAAM,KAAK,MAAM,EAAA,CAAG,IAAI,OAAM,QAAO;GAAE;GAAI,WAAW,MAAM,IAAI,MAAM,KAAK,EAAE,EAAA,EAAI;EAAS,EAAE,CAAC,EAAA,CAClH,SAAS,EAAE,IAAI,eAAe;GACzC,IAAI,OAAO,aAAa,CAAC,UACvB,OAAO,CAAC;GACV,MAAM,QAAQ,uBAAuB,QAAQ;GAC7C,OAAO,MAAM,UAAU,SAAS,gBAAgB,OAAO,GAAG,IAAI,CAAC;IAAE;IAAI,aAAa;GAAM,CAAC,IAAI,CAAC;EAChG,CAAC;CACH;;;;;;CAOA,eAAe,gBAAgB,WAAmB,MAA0B;EAC1E,MAAM,YAAY,MAAM,iBAAiB,SAAS;EAClD,MAAM,SAAS,SAAS,KAAA,IAAY,UAAU,OAAO,cAAc,UAAU,MAAM,IAAI;EACvF,IAAI,UAAU,UAAU,QAAQ,SAAS,WACvC,YAAY,UAAU,QAAQ,UAAU,eAAe;EACzD,OAAO;GAAE;GAAW;GAAQ,QAAQ,MAAM,UAAU,UAAU,OAAO;EAAE;CACzE;CAkIA,OAAO;EA/HL,eAAe;EAEf;EACA;EACA,MAAM,iBAAiB,KAAK,MAAM;GAChC,MAAM,SAAS,cAAc,KAAK,IAAI;GACtC,MAAM,YAAY,MAAM,qBAAqB,cAAc;IAAE,KAAK,OAAO;IAAK,UAAU,IAAI,aAAa;IAAG,SAAS;GAAmB,CAAC;GAEzI,MAAM,UAAU,OAAO;GACvB,OAAO,UACH,UAAU,KAAI,UAAU,MAAM,UAAU,QAAQ;IAAE,GAAG;IAAO,WAAW;IAAO,QAAQ,oBAAoB,QAAQ,KAAK;GAAG,CAAE,IAC5H;EACN;EACA,oBAAmB,SAAQ,kBAAkB,cAAc,MAAM,kBAAkB,IAAI,CAAC;EAExF,MAAM,uBAAuB,WAAW;GACtC,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,IAAI,CAAC,MACH,OAAO,CAAC;GACV,MAAM,cAAc,uBAAuB,KAAK,QAAQ;GACxD,OAAO,2BAA2B,cAAc,aAAa,kBAAkB,YAAY,IAAI,CAAC;EAClG;EAEA,MAAM,cAAc,WAAW,SAAS,UAAU,CAAC,GAAG;GACpD,MAAM,EAAE,WAAW,QAAQ,WAAW,MAAM,gBAAgB,WAAW,QAAQ,GAAG;GAClF,OAAO,UAAU,UAAU,QAAQ,KAAK,QAAQ,SAAS;IACvD,KAAK;IACL,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;IAC1C,SAAS,QAAQ,kBAAkB;GACrC,CAAC;EACH;EAEA,MAAM,oBAAoB,WAAW,SAAS,UAAU,CAAC,GAAG;GAC1D,MAAM,EAAE,WAAW,QAAQ,WAAW,MAAM,gBAAgB,WAAW,QAAQ,GAAG;GAClF,MAAM,EAAE,YAAY,UAAU;GAC9B,IAAI,CAAC,QAAQ,YACX,OAAO;GACT,OAAO,QAAQ,WAAW,QAAQ,SAAS;IAAE,KAAK;IAAQ,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;GAAG,CAAC;EAC1G;EAEA,MAAM,kBAAkB,WAAW,MAAM;GACvC,MAAM,EAAE,WAAW,QAAQ,WAAW,MAAM,gBAAgB,WAAW,IAAI;GAC3E,OAAO,UAAU,UAAU,QAAQ,SAAS,QAAQ,MAAM;EAC5D;EAEA,MAAM,mBAAmB,WAAW,MAAM,SAAS;GACjD,MAAM,EAAE,WAAW,QAAQ,WAAW,MAAM,gBAAgB,WAAW,IAAI;GAC3E,MAAM,UAAU,UAAU,QAAQ,UAAU,QAAQ,QAAQ,OAAO;EACrE;EAEA,MAAM,mBAAmB,WAAW,MAAM,SAAS;GACjD,MAAM,EAAE,WAAW,QAAQ,WAAW,MAAM,gBAAgB,WAAW,IAAI;GAC3E,OAAO,UAAU,UAAU,QAAQ,UAAU,QAAQ,QAAQ,OAAO;EACtE;EAEA,MAAM,kBAAkB,WAAW,MAAM;GACvC,MAAM,EAAE,WAAW,QAAQ,WAAW,MAAM,gBAAgB,WAAW,IAAI;GAC3E,OAAO,MAAM,UAAU,UAAU,QAAQ,WAAW,QAAQ,MAAM,KAAK;EACzE;EAEA,MAAM,qBAAqB,WAAW,UAAU;GAC9C,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;GACrD,MAAM,cAAc,uBAAuB,KAAK,QAAQ;GACxD,uBAAuB,WAAW;GAClC,MAAM,MAAM,WAAW,WAAW,IAAI;GACtC,MAAM,EAAE,cAAc,MAAM,iBAAiB,WAAW;IAAE;IAAK;IAAa,UAAU,IAAI,aAAa;GAAE,CAAC;GAC1G,OAAO,4BAA4B;IAAE,UAAU;IAAc;IAAW;IAAU;IAAa,QAAQ,kBAAkB,YAAY,IAAI;IAAG;IAAK;GAAU,CAAC;EAC9J;EAEA,MAAM,iBAAiB,WAAW,MAAM;GACtC,IAAI,aAAa,IAAI,SAAS,GAC5B;GACF,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;GACrD,MAAM,UAAU,uBAAuB,KAAK,QAAQ;GACpD,IAAI,QAAQ,UAAU,SACpB;GAGF,IAAI,QAAQ,UAAU,YAAY,CAAC,aAAa,IAAI,SAAS,GAAG;IAC9D,MAAM,EAAE,OAAO,gBAAgB,OAAO,QAAQ,GAAG,SAAS;IAC1D,MAAM,KAAK,CAAC,CAAC,iBAAiB,WAAW,oBAAoB;KAAE,GAAG;KAAM,OAAO;IAAe,CAAC,CAAC;IAChG,UAAU;KAAE,MAAM;KAAoB,IAAI;KAAU;IAAU,CAAC;GACjE;GACA,MAAM,OAAO,kBAAkB,SAAS;GACxC,IAAI,CAAC,MAAM,YACT,MAAM;EACV;EAEA,MAAM,cAAc,WAAW;GAE7B,MAAM,WAAW,aAAa,IAAI,SAAS;GAC3C,UAAU,WAAW,MAAM;GAG3B,KAAK,CAAC,CAAC,eAAe,SAAS;GAC/B,iBAAiB,OAAO,SAAS;GACjC,gBAAgB,OAAO,SAAS;GAGhC,MAAM,UAAU,aAAa,SAAS;GACtC,MAAM,eAAe,QAAQ,SAAS;GACtC,MAAM,cAAc,MAAM,UAAU;GACpC,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,MAAM,UAAU,aAAa,YAAY,CAAC,OAAO,CAAC,IAAI,MAAM,uBAAuB,WAAW,IAAI;GAElG,IAAI,QAAQ,SAAS,GAAG;IACtB,MAAM,EAAE,OAAO,QAAQ,GAAG,SAAS,QAAQ,EAAE,CAAE;IAC/C,MAAM,KAAK,CAAC,CAAC,iBAAiB,QAAQ,EAAE,CAAE,IAAI,oBAAoB,IAAI,CAAC;IACvE,UAAU;KAAE,MAAM;KAAoB,IAAI;KAAU,WAAW,QAAQ,EAAE,CAAE;IAAG,CAAC;GACjF;GACA,MAAM,cAAc,aAAa,YAAY,CAAC,OAC1C,EAAE,SAAS,KAAK,IAChB,QAAQ,SAAS,IACf;IAAE,SAAS;IAAO,QAAQ,iBAAiB,QAAQ,OAAO,iBAAiB,QAAQ,WAAW,IAAI,KAAK;GAAM,IAC7G,MAAM,2BAA2B,cAAc,KAAK,UAAU;IAC5D,QAAQ;IACR,KAAK,kBAAkB;KAAE,UAAU,KAAK;KAAU,aAAa,KAAK,eAAe,KAAA;IAAU,CAAC;GAChG,CAAC;GACP,MAAM,kBAAkB,IAAI,OAAO,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;GACzE,OAAO,EAAE,YAAY;EACvB;CAGW;AACf;;;ACzLA,eAAsB,4BAA4B,OAAqF;CACrI,MAAM,EAAE,WAAW,UAAU,QAAQ,SAAS,WAAW;CACzD,MAAM,OAAO,MAAM,MAAM,KAAK;CAC9B,IAAI,CAAC,MACH,OAAO,EAAE,UAAU,MAAM;CAC3B,MAAM,UAAU,uBAAuB,KAAK,QAAQ;CACpD,IAAI,QAAQ,UAAU,SACpB,OAAO;EAAE,UAAU;EAAO,aAAa;CAAQ;CACjD,MAAM,MAAM,kBAAkB;EAAE,UAAU,KAAK;EAAU,aAAa,KAAK,eAAe,KAAA;CAAU,CAAC;CAGrG,MAAM,EAAE,OAAO,gBAAgB,OAAO,QAAQ,GAAG,SAAS;CAC1D,MAAM,UAA8B;EAAE,GAAG;EAAM,OAAO;CAAe;CAErE,IAAI,QAAQ,UAAU,YAAY,CAAC,MAAM,QAAQ,oBAAoB,OAAO,CAAC,GAC3E,OAAO,EAAE,UAAU,MAAM;CAE3B,MAAM,WAAW,SAAS,IAAI,QAAQ,IAAI;CAC1C,IAAI;CACJ,IAAI;CACJ,IAAI;EACF,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,gCAAgC,QAAQ,KAAK,8CAA8C;EAC7G,WAAW,SAAS,UAChB,MAAM,SAAS,QAAQ;GAAE;GAAW;GAAK,aAAa;GAAS,QAAQ,OAAO,QAAQ,IAAI;GAAG,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAG,CAAC,IAC5H,CAAC;CACP,SACO,KAAK;EACV,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;CAC3D;CAEA,MAAM,UAA8B,YAAY,KAAA,IAC5C;EAAE,GAAG;EAAS,OAAO;EAAU,OAAO;CAAQ,IAC9C;EAAE,GAAG;EAAS,GAAG,UAAU;EAAa,OAAO;CAAQ;CAC3D,MAAM,aAAa,UAAU,OAAO;CACpC,MAAM,UAAU,YAAwD;EACtE,MAAM,2BAA2B,UAAU,oBAAoB,OAAO,GAAG;GAAE,KAAK;GAAY;EAAO,CAAC;EACpG,OAAO,EAAE,UAAU,KAAK;CAC1B;CACA,IAAI,QAAQ,SACV,OAAO,QAAQ;CACjB,IAAI;CACJ,IAAI;EACF,YAAY,MAAM,QAAQ;GACxB,GAAG,oBAAoB,OAAO;GAC9B,GAAI,UAAU,MAAM,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC;EAC/C,CAAC;CACH,SACO,KAAK;EAGV,MAAM,SAAS,MAAM,QAAQ;EAC7B,MAAM,SAA6B;GAAE,GAAG;GAAS,OAAO;GAAU,OAAO,kCAAkC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAAI;EAC9J,MAAM,QAAQ,oBAAoB,MAAM,CAAC,CAAC,CAAC,YAAY,KAAK;EAC5D,OAAO;GAAE,GAAG;GAAQ,aAAa;EAAO;CAC1C;CAEA,OAAO,YAAY;EAAE,UAAU;EAAO,aAAa;CAAQ,IAAI,QAAQ;AACzE;;;ACtEA,SAAgB,mBAAmB,EAAE,KAAK,MAAM,OAAO,cAKtC;CACf,MAAM,EAAE,KAAK,WAAW,WAAW,cAAc;CACjD,MAAM,EAAE,cAAc,sBAAsB;CAC5C,MAAM,+BAA6C,IAAI,IAAI;;;;;;;;CAS3D,eAAeE,uBAAqB,SAAgD;EAClF,MAAM,EAAE,aAAa,oBAAoB,GAAG,cAAc;EAE1D,MAAM,aAAa,qBAAqB,aAAa,IAAI,mBAAmB,IAAI,CAAC,EAAE,cAAc,KAAA;EACjG,MAAM,SAAS;GAAE,GAAG;GAAW,KAAK,aAAa,WAAW,UAAU,GAAG,IAAI,UAAU,YAAY,UAAU,GAAG;EAAE;EAClH,IAAI,sBAAsB,CAAC,qBAAqB,IAAI,aAAa,GAAG,mBAAmB,MAAM,aAAa,IAAI,mBAAmB,IAAI,CAAC,GACpI,MAAM,IAAI,MAAM,QAAQ,mBAAmB,KAAK,sDAAsD;EACxG,MAAM,cAAc,qBAChB,MAAM,mBAAmB,cAAc,oBAAoB;GAAE,KAAK,OAAO;GAAK,QAAQ,kBAAkB,mBAAmB,IAAI;EAAE,CAAC,IAClI,KAAA;EACJ,MAAM,KAAK,MAAMC,qBAA2B,IAAI,OAAO;GAAE,GAAG;GAAQ,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;EAAG,CAAC;EAC7G,IAAI,aAAa,UAAU,gBACzB,kBAAkB,EAAE;EACtB,OAAO;CACT;CAEA,SAAS,kBAAkB,WAAmD;EAC5E,MAAM,WAAW,aAAa,IAAI,SAAS;EAC3C,IAAI,UACF,OAAO,SAAS;EAClB,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,OAAO,qBAAqB,WAAW,WAAW,MAAM,CAAC,CAC5D,OAAO,QAAiB;GACvB,UAAU,oCAAoC,GAAG;GACjD,OAAO,EAAE,UAAU,MAAM;EAC3B,CAAC,CAAC,CACD,cAAc;GACb,IAAI,aAAa,IAAI,SAAS,CAAC,EAAE,SAAS,MACxC,aAAa,OAAO,SAAS;GAG/B,WAAW,SAAS;EACtB,CAAC;EACH,aAAa,IAAI,WAAW;GAAE;GAAY;EAAK,CAAC;EAChD,UAAU,IAAI,CAAC,CAAC,YAAY,KAAA,CAAS;EACrC,OAAO;CACT;;;;;;CAOA,eAAe,qBAAqB,WAAmB,QAAqD;EAC1G,MAAM,EAAE,aAAa,MAAM,4BAA4B;GACrD;GACA,YAAY,IAAI,MAAM,KAAK,SAAS;GACpC,UAAU;GACV,QAAQ;GACR;GACA,SAAS,OAAO,UAAU;IACxB,IAAI;KACF,MAAM,KAAK,CAAC,CAAC,iBAAiB,WAAW,KAAK;IAChD,SACO,KAAK;KACV,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,YAAY,IAAI,GACnD,OAAO;KACT,MAAM;IACR;IACA,UAAU;KAAE,MAAM;KAAoB,IAAI;KAAU;IAAU,CAAC;IAC/D,OAAO;GACT;EACF,CAAC;EACD,OAAO,EAAE,SAAS;CACpB;CAEA,OAAO;EAAE;EAAc,sBAAA;EAAsB;CAAkB;AACjE;;;AC3EA,MAAM,YAAY;AAElB,SAAgB,mBAAmB,SAAyB;CAC1D,OAAO,QAAQ,SAAS,sBAAsB;AAChD;AAIA,SAAS,QAAQ,SAAkC;CACjD,MAAM,OAAO,mBAAmB,OAAO;CACvC,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,IAAI;EACF,MAAM,MAAM,aAAa,MAAM,OAAO;EACtC,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,OAAO,CAAC;EACV,OAAO;CACT,QACM;EAGJ,OAAO,CAAC;CACV;AACF;AAEA,SAAS,SAAS,SAAiB,KAA4B;CAC7D,gBACE,mBAAmB,OAAO,GAC1B,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,KAChC;EAAE,WAAW;EAAM,MAAM;CAAU,CACrC;AACF;;;;;;;;;;;;AAaA,SAAgB,6BAA6B,SAAqC;CAChF,OAAO;EACL,KAAK,MAA8C;GACjD,OAAO,QAAQ,OAAO,CAAC,CAAC;EAC1B;EACA,KAAK,MAAc,OAAiC;GAClD,MAAM,MAAM,QAAQ,OAAO;GAC3B,IAAI,QAAQ;GACZ,SAAS,SAAS,GAAG;EACvB;EACA,OAAO,MAAoB;GACzB,MAAM,MAAM,QAAQ,OAAO;GAC3B,IAAI,EAAE,QAAQ,MACZ;GACF,OAAO,IAAI;GACX,SAAS,SAAS,GAAG;EACvB;CACF;AACF;;;;;;AAOA,SAAgB,mBACd,OACA,MACA,OACM;CACN,MAAM,WAAW,MAAM,KAAK,IAAI,KAAK,CAAC;CACtC,MAAM,KAAK,MAAM;EAAE,GAAG;EAAU,GAAG;CAAM,CAAC;AAC5C;;;AC5DA,MAAM,MAAuB;CAAE,WAAW,KAAA;CAAW,SAAS,KAAA;AAAU;;;;;;AAOxE,SAAgB,sBAAsB,SAAuC;CAC3E,MAAM,OAAO,sBAAsB,uBAAuB;CAC1D,IAAI,SACF,KAAK,KAAK,gBAAgB,OAAO,GAAG,mBAAmB,OAAO,CAAC;CACjE,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC;AAC1B;AAEA,SAAS,OAAO,UAA2B,eAAyB,SAAkD;CACpH,MAAM,YAA6B;EACjC;EACA,SAAS,SAAS,kBAAkB;EACpC,gBAAgB,sBAAsB,QAAQ,OAAO;CACvD;CACA,MAAM,eAAe,sBAAsB;CAI3C,OAAO;EAAE;EAAW,SAHJ,aAAa,KACzB,KAAA,IACA,0DAA0D,aAAa,OAAO;CACtD;AAC9B;;AAWA,eAAsB,gCAAgC,UAA2B,KAAa,UAAkC,CAAC,GAA6B;CAC5J,IAAI,CAAC,SAAS,SACZ,OAAO;CACT,MAAM,QAAQ,uBAAuB,SAAS,qBAAqB,IAAI,GAAG;CAC1E,OAAO,OAAO,UAAU,MAAM,0BAA0B,KAAK,EAAE,MAAM,CAAC,GAAG,OAAO;AAClF;AAUA,SAAgB,uBAAuB,UAAgC,OAA0B,UAA0E,CAAC,GAAoB;CAC9L,IAAI,CAAC,SAAS,WAAW,MAAM,WAAW,GACxC,OAAO;CACT,MAAM,WAAW,MAAM,SAAQ,SAAQ,qBAAqB,MAAM,EAAE,OAAO,uBAAuB,SAAS,qBAAqB,IAAI,IAAI,EAAE,CAAC,CAAC;CAC5I,OAAO,OAAO;EAAE,SAAS;EAAM,gBAAgB,SAAS,kBAAkB;EAAS,mBAAmB,SAAS,qBAAqB;CAAG,GAAG,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,UAAU,GAAI,QAAQ,iBAAiB,CAAC,CAAE,CAAC,CAAC,GAAG,OAAO;AAClN;;;AC9FA,SAAgB,gBAAgB,WAA4B,KAA8D;CACxH,OAAO;EACL,KAAK,UAAU,gBAAgB;GAAE;GAAW;EAAI,CAAC;EACjD,cAAc,mBAAmB,UAAU,SAAS;GAClD,GAAI,UAAU,UAAU,KAAA,IAAY,EAAE,OAAO,UAAU,MAAM,IAAI,CAAC;GAGlE,GAAI,UAAU,YAAY,WAAW,EAAE,IAAI,IAAI,CAAC;GAChD,GAAI,UAAU,QAAQ,KAAA,IAAY,EAAE,KAAK,UAAU,IAAI,IAAI,CAAC;GAC5D,GAAI,UAAU,YAAY,KAAA,IAAY,EAAE,SAAS,UAAU,QAAQ,IAAI,CAAC;GACxE,GAAI,UAAU,cAAc,KAAA,IAAY,EAAE,WAAW,UAAU,UAAU,IAAI,CAAC;GAC9E,GAAI,UAAU,qBAAqB,KAAA,IAAY,EAAE,kBAAkB,UAAU,iBAAiB,IAAI,CAAC;EACrG,CAAC;CACH;AACF;;;ACZA,SAAgB,uBAAuB,EAAE,KAAK,OAAO,gBAAgB,cAKlE;CACD,MAAM,EAAE,KAAK,iBAAiB,eAAe;CAC7C,MAAM,EAAE,cAAc,sBAAsB;CAC5C,MAAM,EAAE,eAAe,kBAAkB;;;;;;;;;CAUzC,eAAe,iBAAiB,WAAmB,OAAiF;EAClI,MAAM,EAAE,KAAK,aAAa,aAAa;EAMvC,MAAM,WAAW,gBAAgB,IAAI,SAAS,CAAC,EAAE;EACjD,IAAI,UAAU;GACZ,MAAM,WAAW,gBAAgB,UAAU,GAAG;GAC9C,MAAM,YAAY,eAAe,QAAQ,WAAW,SAAS,KAAK,SAAS,MAAM;GACjF,cAAc,SAAS;GACvB,OAAO;IAAE;IAAW,SAAS;KAAE,WAAW,KAAA;KAAW,SAAS,KAAA;IAAU;GAAE;EAC5E;EAGA,MAAM,UADY,aAAa,IAAI,YAAY,IAAI,CAAC,EAAE,YAAY,KAAA,IACtC;GAAE,WAAW,KAAA;GAAW,SAAS,KAAA;EAAU,IAAI,MAAM,gCAAgC,UAAU,KAAK,EAAE,SAAS,IAAI,YAAY,EAAE,CAAC;EAC9J,MAAM,WAAW,iBAAiB,cAAc;GAC9C;GACA;GACA;GACA,QAAQ,kBAAkB,YAAY,IAAI;GAC1C,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;EAC9D,CAAC;EACD,MAAM,YAAY,eAAe,QAAQ,WAAW,SAAS,KAAK,SAAS,MAAM;EACjF,cAAc,SAAS;EACvB,IAAI,YAAY,WACd,MAAM,cAAc,WAAW,aAAa,KAAK;EACnD,OAAO;GAAE;GAAW;GAAS,GAAI,SAAS,YAAY,EAAE,WAAW,SAAS,UAAU,IAAI,CAAC;EAAG;CAChG;;;;;;CAOA,eAAe,iBAAiB,WAAmB;EACjD,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;EAC3C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;EACrD,MAAM,cAAc,uBAAuB,KAAK,QAAQ;EACxD,uBAAuB,WAAW;EAClC,MAAM,MAAM,WAAW,WAAW,IAAI;EACtC,MAAM,EAAE,cAAc,MAAM,iBAAiB,WAAW;GAAE;GAAK;GAAa,UAAU,IAAI,aAAa;EAAE,CAAC;EAE1G,OAAO;GAAE,MAAM,YAAY,WAAW;GAAK,GAAI,YAAY,UAAU,EAAE,iBAAiB,YAAY,QAAQ,IAAI,CAAC;GAAI;EAAU;CACjI;CAEA,OAAO;EAAE;EAAkB;CAAiB;AAC9C;;;;AChEA,MAAM,gBAAgB;AAStB,SAAgB,qBAAqB,EAAE,KAAK,MAAM,OAAO,gBAAgB,cAAc,oBAOpE;CACjB,MAAM,EAAE,KAAK,WAAW,QAAQ,eAAe,WAAW,kBAAkB;CAC5E,MAAM,EAAE,cAAc,sBAAsB;;;;;;;;;CAU5C,MAAM,+BAAe,IAAI,IAAoB;CAC7C,MAAM,iBAAiB,cAA4B;EACjD,aAAa,IAAI,WAAW,KAAK,IAAI,CAAC;CACxC;CACA,MAAM,YAAY,kBAAkB;EAClC,sBAA2B,CAAC,CAAC,OAAM,QAAO,UAAU,iCAAiC,GAAG,CAAC;CAC3F,GAAG,IAAI,0BAA0B,aAAa;CAC9C,UAAU,QAAQ;CAElB,eAAe,wBAAuC;EACpD,MAAM,MAAM,KAAK,IAAI;EACrB,KAAK,MAAM,aAAa,eAAe,SAAS,GAAG;GACjD,IAAI,UAAU,QACZ;GACF,IAAI,cAAc,SAAS,KAAK,cAAc,IAAI,SAAS,KAAK,aAAa,IAAI,SAAS,GACxF;GACF,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,UAAU,MAAM,cAAc,MAAM,iBAAiB,KAAA,KAAa,MAAM,KAAK,OAAO,IACtF;GACF,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,IAAI,CAAC,MACH;GACF,MAAM,cAAc,uBAAuB,KAAK,QAAQ;GAExD,MAAM,UADW,aAAa,IAAI,YAAY,IACvB,CAAC,EAAE,qBAAqB,kBAAkB,YAAY,IAAI,CAAC;GAClF,IAAI,CAAC,WAAW,WAAW,GACzB;GAEF,IAAI,MADS,KAAK,IAAI,OAAO,cAAc,GAAG,aAAa,IAAI,SAAS,KAAK,CAChE,KAAK,UAAU,KAC1B,iBAAiB,SAAS;EAC9B;CACF;;;;;;CAOA,eAAe,0BAA0B,WAAmB,aAAmD;EAC7G,IAAI,YAAY,QAAQ,KAAA,GACtB,OAAO;EACT,MAAM,yBAAS,IAAI,IAAI,CAAC,GAAG,eAAe,SAAS,GAAG,GAAG,cAAc,KAAK,CAAC,CAAC;EAC9E,OAAO,OAAO,SAAS;EACvB,KAAK,MAAM,MAAM,QAAQ;GACvB,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,EAAE;GACpC,IAAI,QAAQ,gBAAgB,uBAAuB,KAAK,QAAQ,GAAG,WAAW,GAC5E,OAAO;EACX;EACA,OAAO;CACT;;CAGA,eAAe,cAAc,WAAmB,aAAiC,WAAmC;EAClH,MAAM,EAAE,WAAW,WAAW,GAAG,SAAS;EAC1C,IAAI;GACF,MAAM,KAAK,CAAC,CAAC,iBAAiB,WAAW,oBAAoB,YAAY;IAAE,GAAG;IAAM,WAAW;GAAK,IAAI,IAAI,GAAG,EAAE,eAAe,MAAM,CAAC;GACvI,UAAU;IAAE,MAAM;IAAoB,IAAI;IAAU;GAAU,CAAC;EACjE,SACO,KAAK;GACV,UAAU,4CAA4C,GAAG;EAC3D;CACF;CAEA,OAAO;EAAE;EAAe,qBAAqB,cAAc,SAAS;EAAG;EAAe;CAA0B;AAClH;AAEA,SAAgB,yBAAyB,EAAE,KAAK,OAAO,WAAW,cAK8C;CAC9G,MAAM,EAAE,cAAc,sBAAsB;CAC5C,MAAM,EAAE,eAAe,8BAA8B;;;;;;CAOrD,OAAO,eAAe,mBAAmB,WAAmB,kBAAiC,MAAM,UAA4C,CAAC,GAAkB;EAChK,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;EAC3C,IAAI,CAAC,MACH;EACF,MAAM,cAAc,uBAAuB,KAAK,QAAQ;EACxD,MAAM,WAAW,aAAa,IAAI,YAAY,IAAI;EAClD,IAAI,YAAY,UAAU,WAAW,CAAC,UAAU,WAAW,CAAC,UAAU,GACpE;EACF,IAAI,QAAQ,sBAAsB,GAAG,SAAS,qBAAqB,kBAAkB,YAAY,IAAI,CAAC,KAAK,KAAK,IAC9G;EACF,IAAI,MAAM,0BAA0B,WAAW,WAAW,GACxD;EAEF,IAAI,UAAU,KAAK,SAAS,GAC1B;EAEF,MAAM,UAAU,eAAe,SAAS;EACxC,IAAI;GACF,MAAM,SAAS,QAAQ,aAAa,EAAE,QAAQ,kBAAkB,YAAY,IAAI,EAAE,CAAC;EACrF,SACO,KAAK;GACV,UAAU,8BAA8B,GAAG;GAC3C;EACF;EAEA,IAAI,UAAU,GACZ,MAAM,cAAc,WAAW,aAAa,IAAI;CACpD;AACF;;;AC3IA,SAAgB,mBACd,UACA,QACA,WACc;CACd,MAAM,EAAE,SAAS,OAAO,SAAS,UAAU,YAAY;CACvD,MAAM,EAAE,UAAU,UAAU;CAC5B,MAAM,EAAE,UAAU;CAElB,OAAO;EACL,UAAS,eAAc,QAAQ,IAAI,UAAU,CAAC,EAAE,KAAK;EAErD,MAAM,KAAK,WAAW,OAAO,CAAC,GAAG;GAC/B,MAAM,QAAQ,SAAS;GACvB,OAAO,MAAM,SAAS,CAAC,CAAC,QAAO,MAAK,KAAK,iBAAiB,CAAC,EAAE,eAAe;EAC9E;EAEA,MAAM,KAAK,WAAW,YAAY,OAAO,CAAC,GAAG;GAC3C,MAAM,QAAQ,QAAQ,IAAI,UAAU;GACpC,IAAI,CAAC,SAAS,MAAM,KAAK,cAAc,aAAa,MAAM,KAAK,iBAC7D,MAAM,IAAI,cAAc,aAAa,eAAe,WAAW,sCAAsC;GACvG,MAAM,KAAK;GACX,MAAM,MAAM,MAAM,WAAW,MAAM,MAAM;GACzC,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,SAAS,KAAK,uBAAuB,CAAC;GAC7E,IAAI,OAAO,KAAK,UAAU,KAAA,IAAY,KAAK,IAAI,KAAK,OAAO,MAAM,QAAQ,IAAI,KAAK,IAAI,MAAM,UAAU,MAAM,IAAI;GAChH,OAAO,KAAK,IAAI,MAAM,GAAG;GACzB,MAAM,WAAW,MAAM,MAAM,MAAM,OAAO,MAAM,QAAQ;GACxD,MAAM,UAAU,MAAM,SAAS,QAAQ;GACvC,IAAI,SACF,SAAS,KAAK,OAAO;GACvB,MAAM,QAAQ,MAAM;GACpB,IAAI,KAAK,UAAU,KAAA,KAAa,OAAO,SAAS,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,IAAI,GAAG;IAC3F,MAAM,OAAO,SAAS,EAAE,CAAC,MAAM,MAAM,KAAK,MAAM;IAChD,IAAI,MACF,SAAS,KAAK;SAEd,SAAS,MAAM;GACnB;GACA,MAAM,eAAe,UAAU;IAAE,MAAM;IAAK,MAAM;GAAQ,IAAI,KAAA;GAC9D,IAAI,YAAY;GAChB,IAAI,OAAO,SAAS,QAAQ,GAAG,MAAM,IAAI,EAAE,SAAS,GAAG,CAAC;GACxD,OAAO,OAAA,SAAkC,SAAS,SAAS,GAAG;IAC5D,QAAQ,SAAS,MAAM,CAAC,CAAE,SAAS;IACnC;GACF;GACA,IAAI,OAAO,SAAS,KAAK,IAAI;GAC7B,IAAI,KAAK,SAAA,OACP,OAAO,KAAK,MAAM,CAAC,uBAAuB;GAC5C,OAAO;IAAE,UAAU,EAAE,GAAG,MAAM,KAAK;IAAG;IAAM,MAAM;IAAK;GAAU;EACnE;EAEA,OAAO,YAAY,OAAO,CAAC,GAAG;GAC5B,MAAM,QAAQ,QAAQ,IAAI,UAAU;GACpC,IAAI,CAAC,OACH,OAAO,QAAQ,QAAQ;GACzB,MAAM,UAAU,KAAK,WAAW;GAChC,MAAM,QAAQ,KAAK,SAAS;GAC5B,OAAO,IAAI,SAAe,YAAY;IACpC,IAAI;IACJ,IAAI;IACJ,SAAS,OAAa;KACpB,aAAa,KAAK;KAClB,aAAa,GAAG;KAChB,MAAO,aAAa,OAAO,IAAI;KAC/B,KAAK,QAAQ,oBAAoB,SAAS,IAAI;KAC9C,QAAQ;IACV;IACA,SAAS,OAAa;KACpB,aAAa,KAAK;KAClB,QAAQ,WAAW,MAAM,MAAO,UAAU,UAAU,CAAC;IACvD;IACA,MAAM,WAAW,MAAM,KAAK;IAC5B,MAAM,aAAa,IAAI,IAAI;IAC3B,KAAK,QAAQ,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;IAC3D,KAAK;GACP,CAAC;EACH;EAEA,UAAU,WAAW,EAAE,SAAS,KAAK,eAAe;GAClD,MAAM,MAAM,KAAK,IAAI;GACrB,MAAM,UAAU,QAAQ,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;GAClD,MAAM,QAAQ,SAAS;IACrB,IAAI,QAAQ,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;IACnC;IACA,OAAO,QAAQ,SAAS,KAAK,GAAG,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK;IAC1D,OAAO;IACP,QAAQ;IACR;IACA;IACA,QAAQ;IACR,MAAM;IACN,MAAM;IACN,iBAAiB;IACjB,SAAS;IACT,WAAW;IACX,gBAAgB;GAClB,CAAC;GACD,IAAI,KAA0G;GAC9G,IAAI,iBAAyC,CAAC;GAC9C,MAAM,SAAS,IAAI,SAAiB,YAAY;IAC9C,WAAW;GACb,CAAC;GACD,OAAO;IACL,SAAS;KACP,MAAM,MAAM,KAAK;KACjB,MAAM,MAAM,KAAK;KACjB,SAAQ,SAAQ,SAAS,OAAO,IAAI;KACpC,UAAU,UAAU;MAClB,KAAK;KACP;IACF;IACA,UAAU,EAAE,QAAQ,UAAU,WAAW;KACvC,IAAI,CAAC,UAAU;MAEb,QAAQ,OAAO,MAAM,KAAK,EAAE;MAC5B;KACF;KACA,MAAM,KAAK,SAAS;KACpB,MAAM,WAAW;KAUjB,MAAM,OAAO;MARX,IAAI;MACJ,eAAe;MACf,QAAO,SAAQ,IAAI,MAAM,IAAI;MAC7B,SAAS,GAAG,MAAM,IAAI,OAAO,GAAG,CAAC;MACjC;MACA,QAAQ,YAAY,CAAC;MACrB;KAEc,CAAC;KACjB,QAAQ,SAAS;IACnB;IACA,SAAS,SAAS;KAChB,IAAI,CAAC,QAAQ,IAAI,MAAM,KAAK,EAAE,GAC5B;KACF,IAAI,MAAM,SACR,SAAS,QAAQ,CAAC;UAElB,QAAQ,OAAO,MAAM,KAAK,EAAE;KAC9B,QAAQ,SAAS;IACnB;GACF;EACF;CACF;AACF;;;;;;;;;;;ACpJA,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAK;CAAQ;CAAQ;AAAM,CAAC;AAM5D,MAAM,gBAAgB;AAGtB,MAAM,SAAS;AACf,MAAM,cAAc;AAQpB,SAAgB,yBAA2C;CACzD,MAAM,qBAAK,IAAI,IAAY;CAC3B,IAAI,OAAO;CACX,OAAO;EACL,KAAK,QAAQ;GACX,MAAM,OAAO,OAAO;GACpB,cAAc,YAAY;GAC1B,KAAK,IAAI,IAAI,cAAc,KAAK,IAAI,GAAG,MAAM,MAAM,IAAI,cAAc,KAAK,IAAI,GAAG;IAC/E,IAAI,EAAE,OAAO,SAAS;KACpB,GAAG,MAAM;KACT;IACF;IACA,KAAK,MAAM,QAAQ,EAAE,EAAE,CAAE,MAAM,GAAG,GAAG;KACnC,IAAI,CAAC,eAAe,IAAI,IAAI,GAC1B;KACF,IAAI,EAAE,OAAO,KACX,GAAG,IAAI,IAAI;UAEX,GAAG,OAAO,IAAI;IAClB;GACF;GAGA,OAAO,KAAK,MAAM,GAAK;GACvB,OAAO,GAAG,OAAO;EACnB;EACA,IAAI,WAAW;GACb,OAAO,GAAG,OAAO;EACnB;CACF;AACF;;AAGA,SAAgB,kBAAkB,OAAuB;CACvD,IAAI,MAAM,WAAW,WAAW,GAC9B,OAAO;CACT,OAAO,MAAM,QAAQ,QAAQ,EAAE;AACjC;;;ACpDA,MAAM,gBAAgB;;AAEtB,MAAM,6BAA6B;AAEnC,SAAgB,wBAAwB,MAA2B,UAA4B,QAAoD;CACjJ,MAAM,EAAE,SAAS,WAAW,SAAS,SAAS,QAAQ,qBAAqB;CAC3E,MAAM,EAAE,UAAU,UAAU;CAE5B,SAAS,OAAO,OAAc,MAAuB,MAAoB;EACvE,IAAI,MAAM,YAAY,MACpB;EACF,MAAM,KAAK;EACX,MAAM,UAAU;EAChB,WAAW,KAAK;EAChB,MAAM,OAAO,MAAM,SAAS,YAAY;EACxC,IAAI,MACF,MAAM,MAAM,KAAK,IAAI;EACvB,IAAI,SAAS,MAAM,MAAM,UACvB,MAAM,KAAK,SAAS;OAEjB;GACH,MAAM,KAAK,SAAS;GACpB,MAAM,KAAK,WAAW;GACtB,OAAO,MAAM,KAAK;EACpB;EACA,KAAK,MAAM,QAAQ,MAAM,cAAc,KAAK;EAI5C,IAAI,MAAM,KAAK,UAAU,UAAU,MAAM,KAAK,WAAW,YAAY,SAAS,KAAK,KAAK,mBAAmB,MAAM,MAAM;GACrH,IAAI,MAAM,YACR,aAAa,MAAM,UAAU;GAC/B,QAAQ,OAAO,MAAM,KAAK,EAAE;EAC9B,OACK,IAAI,MAAM,KAAK,UAAU,SAC5B,0BAA0B,MAAM,KAAK,SAAS;EAEhD,QAAQ,MAAM,KAAK,SAAS;EAC5B,QAAQ,MAAM,KAAK,SAAS;CAC9B;;CAGA,SAAS,0BAA0B,WAAyB;EAC1D,MAAM,OAAO,UAAU,SAAS,CAAC,CAAC,QAAO,MAAK,EAAE,KAAK,UAAU,WAAW,EAAE,KAAK,WAAW,YAAY,EAAE,QAAQ,SAAS,CAAC;EAC5H,KAAK,MAAM,KAAK,KAAK,MAAM,GAAG,KAAK,IAAI,GAAG,KAAK,SAAS,0BAA0B,CAAC,GACjF,QAAQ,OAAO,EAAE,KAAK,EAAE;CAC5B;CAEA,SAAS,MAAM,OAAc,MAA6B;EACxD,MAAM,UAAU;EAChB,MAAM,WAAW,KAAK,gBAAgB,KAAK,KAAK,KAAA;EAChD,MAAM,KAAK,SAAS;EACpB,OAAO,MAAM,KAAK;EAClB,OAAO,MAAM,KAAK;EAClB,KAAU,OAAO,MAAK,SAAQ,OAAO,OAAO,MAAM,IAAI,CAAC;EACvD,YAAY,KAAK;CACnB;;CAGA,SAAS,YAAY,OAAoB;EACvC,MAAM,MAAM,MAAM,SAAS;EAC3B,IAAI,CAAC,OAAO,MAAM,YAChB;EACF,MAAM,aAAa;GACjB,IAAI,MAAM,QAAQ,SAAS,GACzB;GACF,kBAAkB,GAAG,CAAC,CAAC,MAAM,YAAY;IACvC,IAAI,YAAY,MAAM,KAAK,SAAS;KAClC,IAAI,SACF,MAAM,KAAK,UAAU;UAErB,OAAO,MAAM,KAAK;KACpB,QAAQ,MAAM,KAAK,SAAS;IAC9B;GACF,SAAS,CAAC,CAAC;EACb;EACA,MAAM,aAAa,YAAY,MAAM,aAAa;EAClD,MAAM,WAAW,QAAQ;CAC3B;CAEA,SAAS,WAAW,OAAoB;EACtC,IAAI,MAAM,YACR,cAAc,MAAM,UAAU;EAChC,MAAM,aAAa;CACrB;;CAGA,eAAe,kBAAkB,OAAc,MAAsC;EACnF,IAAI,OAAO,KAAK,GAAG;GACjB,MAAM,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;GAChC;EACF;EACA,MAAM,OAAO,IAAI;CACnB;CAEA,eAAe,QAAQ,OAAc,MAA2C;EAC9E,MAAM,YAAY,MAAM,KAAK;EAC7B,MAAM,YAAY,MAAM,KAAK,QAAQ,WAAW,MAAM,KAAK,MAAM;EACjE,IAAI,OAAO,KAAK,GACd;EACF,MAAM,YAAY;EAClB,MAAM,UAAU;GACd,KAAK,MAAM,KAAK,OAAO,KAAA;GACvB,MAAM,MAAM,KAAK;GACjB,MAAM,MAAM,KAAK;GACjB,GAAI,KAAK,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;GACnD,SAAS,SAAqB,SAAS,OAAO,IAAI;EACpD;EACA,IAAI,SAAS,aAAa;GACxB,MAAM,OAAO,MAAM,YAAY,UAAU,QAAQ,oBAC7C,MAAM,UAAU,QAAQ,kBAAkB,UAAU,QAAQ,MAAM,UAAU,OAAO,IACnF;GACJ,IAAI,CAAC,MAAM;IACT,MAAM,KAAK,SAAS;IACpB,MAAM,KAAK,QAAQ;IACnB,MAAM,WAAW,KAAA;IACjB;GACF;GACA,MAAM,kBAAkB,OAAO,IAAI;GACnC;EACF;EACA,IAAI,CAAC,UAAU,QAAQ,cACrB,MAAM,IAAI,cAAc,eAAe,kCAAkC,UAAU,YAAY,eAAe;EAChH,IAAI,CAAC,MAAM,KAAK,KACd,MAAM,KAAK,MAAM,UAAU,OAAO;EACpC,MAAM,KAAK,cAAc,UAAU;EACnC,MAAM,kBAAkB,OAAO,MAAM,UAAU,QAAQ,aAAa,UAAU,QAAQ;GAAE,GAAG;GAAS,KAAK,MAAM,KAAK;EAAI,CAAC,CAAC;CAC5H;;CAGA,eAAe,gBAAgB,OAA6B;EAC1D,IAAI,MAAM,KAAK,WAAW,UACxB;EAEF,iBAAiB;EACjB,MAAM,eAAe,QAAQ,OAAO,WAAW,CAAC,CAC7C,OAAO,QAAQ;GACd,MAAM,KAAK,SAAS;GACpB,MAAM,KAAK,QAAQ,UAAU,GAAG;EAClC,CAAC,CAAC,CACD,cAAc;GACb,MAAM,aAAa;GACnB,QAAQ,MAAM,KAAK,SAAS;GAC5B,QAAQ,MAAM,KAAK,SAAS;EAC9B,CAAC;EACH,MAAM,MAAM;CACd;CAEA,eAAe,IAAI,OAA6B;EAC9C,WAAW,KAAK;EAChB,IAAI,MAAM,YACR,aAAa,MAAM,UAAU;EAC/B,MAAM,OAAO,MAAM;EACnB,MAAM,UAAU;EAChB,IAAI,MAAM,UACR,MAAM,MAAM,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;OAErC,MAAM,MAAM,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;EACnC,KAAK,MAAM,QAAQ,MAAM,cAAc,KAAK;CAC9C;CAEA,OAAO;EAAE;EAAQ;EAAO;EAAY;EAAS;EAAiB;CAAI;AACpE;AAIA,SAAgB,UAAU,KAAsB;CAC9C,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;AAEA,SAAS,IAAI,MAAc,MAAiC;CAC1D,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,SAAS,MAAM,MAAM,EAAE,SAAS,KAAK,IAAI,KAAK,WAAW,MAAM,OAAO,GAAG,IAAI,QAAQ,OAAO,MAAM,CAAC,CAAC;CACtG,CAAC;AACH;;AAGA,eAAe,kBAAkB,UAA+C;CAC9E,MAAM,QAAQ,OAAO,UAAU,MAAM,IAAI,MAAM;EAAC;EAAM;EAAU;EAAM,OAAO,QAAQ;CAAC,CAAC,EAAA,CAAG,KAAK,GAAG,EAAE;CACpG,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,KAAK,UAAU,UACrD,OAAO,KAAA;CACT,MAAM,QAAQ,MAAM,IAAI,MAAM;EAAC;EAAM;EAAS;EAAM,OAAO,KAAK;CAAC,CAAC,EAAA,CAAG,KAAK;CAC1E,OAAO,OAAO,SAAS,IAAI,CAAC,CAAC,QAAQ,MAAM,EAAE,IAAI,KAAA;AACnD;;;ACnLA,SAAgB,oBACd,MACA,UACA,QACA,WACA,OACe;CACf,MAAM,EAAE,SAAS,WAAW,OAAO,SAAS,WAAW,SAAS,UAAU,SAAS,KAAK,qBAAqB;CAC7G,MAAM,EAAE,UAAU,QAAQ,KAAK,OAAO,UAAU,UAAU;CAC1D,MAAM,EAAE,SAAS,iBAAiB,QAAQ;CAC1C,MAAM,EAAE,WAAW,WAAW;CAE9B,OAAO;EACL,MAAM,MAAM,WAAW;GACrB,MAAM,KAAK,KAAK,UAAU;GAC1B,MAAM,QAAQ,SAAS;GACvB,MAAM,cAAc,MAAM,KAAK,cAAc,SAAS,CAAC,CAAC,aAAa;IAAE,MAAM;IAAS,QAAQ;GAAM,EAAE;GACtG,OAAO;IACL,WAAW,GAAG;IACd,GAAI,GAAG,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO;IACrC;IACA,WAAW,MAAM,SAAS;GAC5B;EACF;EAEA,MAAM,KAAK,EAAE,WAAW,SAAS,WAAW,MAAM,QAAQ;GACxD,iBAAiB;GACjB,MAAM,QAAQ,SAAS;GAIvB,IAFa,UAAU,SAAS,CAAC,CAAC,QAAO,MAAK,EAAE,KAAK,UAAU,WACzD,EAAE,KAAK,WAAW,aAAa,EAAE,KAAK,WAAW,cAAc,EAAE,KAAK,WAAW,SAChF,CAAC,CAAC,UAAA,IACP,MAAM,IAAI,cAAc,SAAS,wDAAiF;GAIpH,MAAM,qBAAqB,WAAW,YAChC,MAAM,KAAK,cAAc,SAAS,CAAC,CAAC,aAAa,EAAE,QAAQ,KAAK,EAAE,EAAA,CAAG;GAC3E,MAAM,MAAM,KAAK,IAAI;GACrB,MAAM,QAAQ,SAAS;IACrB,IAAI,QAAQ,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC;IACnC;IACA,OAAO,UAAU,SAAS;IAC1B,OAAO;IACP;IACA,aAAa,WAAW,UAAU,UAAU;IAC5C,KAAK;IACL,QAAQ;IACR;IACA;IACA,iBAAiB;IACjB,SAAS;IACT,WAAW;IACX,gBAAgB;GAClB,CAAC;GACD,QAAQ,SAAS;GACjB,IAAI;IACF,MAAM,QAAQ,OAAO,MAAM;GAC7B,SACO,KAAK;IACV,MAAM,KAAK,SAAS;IACpB,MAAM,KAAK,QAAQ,UAAU,GAAG;GAClC;GACA,QAAQ,SAAS;GACjB,QAAQ,SAAS;GACjB,OAAO,EAAE,GAAG,MAAM,KAAK;EACzB;EAEA,MAAM,OAAO,YAAY,UAAU;GACjC,MAAM,QAAQ,IAAI,UAAU;GAC5B,MAAM,gBAAgB,KAAK;GAC3B,MAAM,KAAK;GACX,MAAM,QAAQ,IAAI,UAAU,MAAM,KAAK;GACvC,IAAI,MAAM,QAAQ,SAAS,GAAG;IAC5B,MAAM,OAAO,MAAM;IACnB,MAAM,UAAU;GAClB;GACA,OAAO;IAAE,UAAU,EAAE,GAAG,MAAM,KAAK;IAAG,MAAM,SAAS,KAAK;IAAG,QAAQ,MAAM;GAAM;EACnF;EAEA;EAEA,aAAa,UAAU;GACrB,KAAK,MAAM,SAAS,QAAQ,OAAO,GACjC,IAAI,MAAM,QAAQ,IAAI,QAAQ,GAC5B,OAAO,MAAM,KAAK,IAAI,QAAQ;EAEpC;EAEA,MAAM,MAAM,YAAY,MAAM,MAAM;GAClC,MAAM,QAAQ,IAAI,UAAU;GAO5B,IAAI,MAAM,UAAU;IAClB,IAAI,CAAC,MAAM,WAAY,MAAM,cAAc,KAAA,KAAa,MAAM,cAAc,KAAK,UAC/E;IACF,MAAM,QAAQ,MAAM,IAAI;IACxB;GACF;GACA,MAAM,gBAAgB,KAAK;GAC3B,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,cAAc,eAAe,GAAG,MAAM,KAAK,MAAM,iBAAiB;GAC9E,SAAS,KAAK;GAKd,MAAM,QAAQ,MAAM,MAAM,WAAW,OAAO,kBAAkB,IAAI;GAClE,IAAI,OACF,MAAM,QAAQ,MAAM,KAAK;EAC7B;EAEA,OAAO,YAAY,UAAU,MAAM,MAAM,QAAQ,OAAO;GACtD,MAAM,QAAQ,QAAQ,IAAI,UAAU;GACpC,IAAI,CAAC,SAAS,CAAC,OAAO,SAAS,IAAI,KAAK,CAAC,OAAO,SAAS,IAAI,KAAK,OAAO,KAAK,OAAO,GACnF;GACF,IAAI,MAAM,QAAQ,IAAI,QAAQ,GAAG;IAC/B,MAAM,aAAa,OAAO,QAAQ;IAClC,MAAM,aAAa,IAAI,UAAU;KAAE;KAAM;IAAK,CAAC;GACjD;GACA,IAAI,CAAC,SAAS,MAAM,cAAc,KAAA,KAAa,MAAM,cAAc,UACjE;GACF,UAAU,OAAO,UAAU,MAAM,IAAI;EACvC;EAEA,IAAI,YAAY,UAAU,QAAQ;GAChC,MAAM,QAAQ,QAAQ,IAAI,UAAU;GACpC,IAAI,CAAC,SAAS,CAAC,MAAM,QAAQ,IAAI,QAAQ,KAAK,CAAC,OAAO,SAAS,MAAM,GACnE;GACF,MAAM,QAAQ,IAAI,UAAU,KAAK,IAAI,MAAM,QAAQ,IAAI,QAAQ,GAAI,KAAK,IAAI,QAAQ,MAAM,IAAI,CAAC,CAAC;GAChG,IAAI,MAAM,WAAW,IAAI,KAAK,KAAA,QAC5B,MAAM,KAAK;EACf;EAEA,MAAM,QAAQ,YAAY;GACxB,iBAAiB;GACjB,MAAM,QAAQ,IAAI,UAAU;GAC5B,IAAI,MAAM,KAAK,UAAU,SACvB,MAAM,IAAI,cAAc,UAAU,qEAAqE;GACzG,MAAM,IAAI,KAAK;GACf,MAAM,WAAW,KAAA;GACjB,MAAM,SAAS;GACf,OAAO,OAAO,MAAM;GACpB,MAAM,WAAW;GACjB,MAAM,KAAK;GACX,MAAM,KAAK,SAAS;GACpB,QAAQ,MAAM,KAAK,SAAS;GAC5B,IAAI;IACF,MAAM,QAAQ,OAAO,MAAM;GAC7B,SACO,KAAK;IACV,MAAM,KAAK,SAAS;IACpB,MAAM,KAAK,QAAQ,UAAU,GAAG;GAClC;GACA,QAAQ,MAAM,KAAK,SAAS;GAC5B,QAAQ,MAAM,KAAK,SAAS;GAC5B,OAAO,EAAE,GAAG,MAAM,KAAK;EACzB;EAEA,MAAM,MAAM,YAAY;GACtB,MAAM,QAAQ,QAAQ,IAAI,UAAU;GACpC,IAAI,CAAC,OACH;GACF,QAAQ,OAAO,UAAU;GACzB,MAAM,IAAI,KAAK;GACf,QAAQ,MAAM,KAAK,SAAS;GAC5B,QAAQ,MAAM,KAAK,SAAS;EAC9B;EAEA,UAAU,YAAY,QAAQ;GAC5B,MAAM,QAAQ,IAAI,UAAU;GAC5B,IAAI,MAAM,KAAK,oBAAoB,QACjC;GACF,MAAM,KAAK,kBAAkB;GAC7B,QAAQ,MAAM,KAAK,SAAS;GAC5B,QAAQ,MAAM,KAAK,SAAS;EAC9B;CACF;AACF;;;AC9LA,MAAM,WAAW;AACjB,MAAM,iBAAiB;AAEvB,SAAgB,qBAAqB,MAA2B;CAC9D,SAAS,SAAS,OAAoB;EACpC,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,KAAK,iBAAiB;EAC5B,IAAI,MAAM,MAAM,YAAY,gBAAgB;GAC1C,MAAM,YAAY;GAClB,KAAK,MAAM,MAAM,KAAK,SAAS;EACjC;CACF;CAEA,SAAS,OAAO,OAAc,MAAoB;EAChD,MAAM,QAAQ,KAAK,IAAI;EACvB,MAAM,gBAAgB,KAAK;EAC3B,OAAO,MAAM,eAAA,WAA6C,MAAM,QAAQ,SAAS,GAC/E,MAAM,gBAAgB,MAAM,QAAQ,MAAM,CAAC,CAAE;EAC/C,MAAM,SAAS,KAAK;EACpB,MAAM,YAAY,MAAM,SAAS,KAAK,IAAI;EAC1C,IAAI,WAAW;GACb,MAAM,QAAQ,UAAU,MAAM,IAAI;GAClC,MAAM,IAAI;GACV,MAAM,MAAM,KAAK,GAAG,KAAK;GACzB,MAAM,OAAO,MAAM,MAAM,SAAS;GAClC,IAAI,OAAO,GAAG;IACZ,MAAM,MAAM,OAAO,GAAG,IAAI;IAC1B,MAAM,YAAY;GACpB;EACF;CACF;CAEA,SAAS,SAAS,OAAc,MAAwB;EACtD,MAAM,OAAO,MAAM,QAAQ,OAAO,MAAM,EAAE,QAAQ,KAAK,CAAC;EACxD,IAAI,CAAC,MACH;EACF,MAAM,MAAM,KAAK,IAAI;EACrB,OAAO,OAAO,IAAI;EAClB,SAAS,KAAK;EACd,MAAM,WAAW;EACjB,MAAM,eAAe,WAAW,OAAO,UAAU,KAAK;EACtD,KAAK,MAAM,QAAQ,MAAM,cAAc,KAAK;CAC9C;CAEA,SAAS,IAAI,OAAsB;EACjC,IAAI,UAAU,MAAM;EACpB,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,GAAG,UAAU,KAAK,IAAI,SAAS,KAAK;EAC7E,OAAO,MAAM,OAAO;CACtB;CAEA,SAAS,MAAM,OAAoB;EACjC,IAAI,MAAM,YACR,aAAa,MAAM,UAAU;EAC/B,MAAM,aAAa;EACnB,MAAM,OAAO,MAAM;EACnB,MAAM,UAAU;EAChB,IAAI,CAAC,MACH;EACF,IAAI,MAAM,QAAQ,SAAS,GAAG;GAC5B,MAAM,OAAO,MAAM;GACnB;EACF;EACA,IAAI,MAAM,WAAW,IAAI,KAAK,IAAA,QAA4B;GACxD,MAAM,UAAU;GAChB;EACF;EACA,MAAM,SAAS,MAAM;EACrB,MAAM,QAAQ,KAAK;EACnB,KAAK,UAAU;GAAE,MAAM;GAAmB,WAAW,MAAM,KAAK;GAAW,YAAY,MAAM,KAAK;GAAI;GAAQ;EAAK,CAAC;CACtH;;CAGA,SAAS,SAAS,OAAc,WAAW,UAAkB;EAC3D,IAAI,MAAM,gBAAgB,UACxB,OAAO,MAAM,QAAQ,KAAK,EAAE;EAC9B,MAAM,OAAiB,CAAC;EACxB,IAAI,OAAO;EACX,KAAK,IAAI,IAAI,MAAM,QAAQ,SAAS,GAAG,KAAK,KAAK,OAAO,UAAU,KAAK;GACrE,KAAK,QAAQ,MAAM,QAAQ,EAAG;GAC9B,QAAQ,MAAM,QAAQ,EAAE,CAAE;EAC5B;EACA,OAAO,KAAK,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ;CACtC;CAEA,SAAS,MAAM,OAAoB;EACjC,MAAM,KAAK;EACX,MAAM,UAAU;EAChB,MAAM,UAAU;EAChB,MAAM,OAAO,MAAM;EACnB,KAAK,MAAM,MAAM,MAAM,QAAQ,KAAK,GAAG,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK;EAGxE,KAAK,UAAU;GAAE,MAAM;GAAkB,WAAW,MAAM,KAAK;GAAW,YAAY,MAAM,KAAK;GAAI,QAAQ,MAAM;GAAO,MAAM,SAAS,OAAO,sBAAsB;EAAE,CAAC;CAC3K;CAEA,OAAO;EAAE;EAAU;EAAQ;EAAU;EAAK;EAAO;EAAU;CAAM;AACnE;;;AC7FA,SAAgB,uBAAuB,MAA2B;CAChE,MAAM,0BAAU,IAAI,IAAmB;;CAEvC,MAAM,2BAAW,IAAI,IAA2B;CAChD,MAAM,2BAAW,IAAI,IAAoB;;CAEzC,MAAM,4BAAY,IAAI,IAAoB;CAE1C,MAAM,aAAa,cAAsB,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,QAAO,MAAK,EAAE,KAAK,cAAc,SAAS;CACzG,MAAM,SAAS,cAAsB,UAAU,SAAS,CAAC,CAAC,KAAI,OAAM,EAAE,GAAG,EAAE,KAAK,EAAE;CAElF,MAAM,WAAW,cAAsB,KAAK,UAAU;EAAE,MAAM;EAAoB;EAAW,WAAW,MAAM,SAAS;CAAE,CAAC;CAE1H,SAAS,UAAU,WAA2B;EAC5C,MAAM,KAAK,SAAS,IAAI,SAAS,KAAK,KAAK;EAC3C,SAAS,IAAI,WAAW,CAAC;EACzB,OAAO,YAAY;CACrB;CAEA,SAAS,QAAQ,WAAyB;EACxC,MAAM,UAA+B,UAAU,SAAS,CAAC,CAAC,SAAQ,MAChE,EAAE,YAAY,EAAE,KAAK,UAAU,WAAW,EAAE,KAAK,WAAW,aAAa,EAAE,KAAK,WAAW,YACvF,CAAC;GACC,IAAI,EAAE,KAAK;GACX,OAAO,EAAE,KAAK;GACd,QAAQ,EAAE,KAAK;GACf,aAAa,EAAE,KAAK;GACpB,KAAK,EAAE,KAAK;GACZ,UAAU,EAAE;GACZ,WAAW,EAAE,KAAK;GAClB,GAAI,EAAE,KAAK,kBAAkB,EAAE,iBAAiB,KAAK,IAAI,CAAC;EAC5D,CAAC,IACD,CAAC,CAAC;EAER,IAAI,CAAC,UAAU,IAAI,SAAS,GAC1B;EACF,MAAM,MAAM,KAAK,UAAU,OAAO;EAClC,IAAI,UAAU,IAAI,SAAS,MAAM,KAC/B;EACF,UAAU,IAAI,WAAW,GAAG;EAC5B,KAAU,YAAY,WAAW,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC;CAC1D;CAEA,SAAS,SAAS,MAA2B;EAC3C,MAAM,QAAe;GACnB;GACA,SAAS;GACT,SAAS,CAAC;GACV,cAAc;GACd,OAAO;GACP,SAAS,IAAI,YAAY;GACzB,OAAO,uBAAuB;GAC9B,UAAU,mBAAmB,EAC3B,UAAU,UAAU;IAClB,IAAI,MAAM,KAAK,UAAU,OAAO;KAC9B,MAAM,KAAK,QAAQ;KACnB,QAAQ,MAAM,KAAK,SAAS;IAC9B;GACF,EACF,CAAC;GACD,OAAO,CAAC;GACR,UAAU;GACV,yBAAS,IAAI,IAAI;GACjB,8BAAc,IAAI,IAAI;GACtB,MAAM;GACN,SAAS;GACT,YAAY;GACZ,SAAS;GACT,WAAW;GACX,8BAAc,IAAI,IAAI;GACtB,YAAY;GACZ,YAAY;EACd;EACA,QAAQ,IAAI,KAAK,IAAI,KAAK;EAC1B,OAAO;CACT;;CAGA,MAAM,UAAU,UAA0B,QAAQ,IAAI,MAAM,KAAK,EAAE,MAAM;CAEzE,SAAS,QAAQ,WAAkC;EACjD,IAAI,UAAU,SAAS,IAAI,SAAS;EACpC,IAAI,CAAC,SAAS;GACZ,UAAU,KAAK,YAAY,SAAS,CAAC,CAAC,MAAM,YAAY;IACtD,UAAU,IAAI,WAAW,KAAK,UAAU,OAAO,CAAC;IAChD,KAAK,MAAM,KAAK,SAAS;KACvB,IAAI,QAAQ,IAAI,EAAE,EAAE,GAClB;KACF,MAAM,IAAI,OAAO,SAAS,EAAE,MAAM,QAAQ,cAAc,EAAE,GAAG,EAAE;KAC/D,IAAI,OAAO,SAAS,CAAC,GACnB,SAAS,IAAI,WAAW,KAAK,IAAI,SAAS,IAAI,SAAS,KAAK,GAAG,CAAC,CAAC;KACnE,MAAM,QAAQ,SAAS;MACrB,IAAI,EAAE;MACN;MACA,OAAO,EAAE;MACT,OAAO;MACP,QAAQ,EAAE;MACV,aAAa,EAAE;MACf,KAAK,EAAE;MACP,QAAQ;MACR,MAAM;MACN,MAAM;MACN,iBAAiB,EAAE,oBAAoB;MACvC,SAAS;MACT,WAAW,EAAE;MACb,gBAAgB,EAAE;KACpB,CAAC;KACD,MAAM,WAAW,EAAE;IACrB;IAEA,QAAQ,SAAS;GACnB,SAAS;IAEP,SAAS,OAAO,SAAS;GAC3B,CAAC;GACD,SAAS,IAAI,WAAW,OAAO;EACjC;EACA,OAAO;CACT;CAEA,SAAS,IAAI,YAA2B;EACtC,MAAM,QAAQ,QAAQ,IAAI,UAAU;EACpC,IAAI,CAAC,OACH,MAAM,IAAI,cAAc,aAAa,eAAe,WAAW,EAAE;EACnE,OAAO;CACT;CAEA,SAAS,mBAAyB;EAChC,MAAM,KAAK,KAAK,UAAU;EAC1B,IAAI,CAAC,GAAG,IACN,MAAM,IAAI,cAAc,eAAe,GAAG,MAAM;CACpD;CAEA,OAAO;EAAE;EAAS;EAAU;EAAU;EAAW;EAAW;EAAO;EAAS;EAAW;EAAS;EAAU;EAAQ;EAAS;EAAK;CAAiB;AACnJ;;;ACxIA,MAAM,kBAAkB;AAIxB,SAAgB,qBACd,MACA,UACA,WACgB;CAChB,MAAM,EAAE,SAAS,UAAU,UAAU,WAAW,WAAW,SAAS,YAAY;CAChF,MAAM,EAAE,YAAY,QAAQ;CAE5B,OAAO;EACL,KAAK,WAAW,WAAW,iBAAiB;GAC1C,MAAM,MAAM,KAAK,IAAI;GACrB,OAAO,UAAU,SAAS,CAAC,CAAC,MAAK,MAAK,EAAE,YAAY,SAC9C,EAAE,KAAK,UAAU,WAAW,MAAM,EAAE,KAAK,iBAAiB,SAAS;EAC3E;EAEA,eAAe,WAAW;GACxB,OAAO,UAAU,SAAS,CAAC,CAAC,MAAK,MAAK,EAAE,KAAK,UAAU,UAAU,EAAE,KAAK,WAAW,aAC9E,EAAE,YAAY,QAAQ,CAAC,EAAE,QAAQ,aAAa;EACrD;EAEA,kBAAkB;GAChB,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAK,MAAK,EAAE,KAAK,UAAU,UAAU,EAAE,YAAY,QAAQ,CAAC,EAAE,QAAQ,aAAa;EAClH;EAEA,MAAM,eAAe,WAAW;GAC9B,MAAM,QAAQ,IAAI,UAAU,SAAS,CAAC,CAAC,IAAI,OAAO,UAAU;IAC1D,MAAM,OAAO,MAAM;IACnB,IAAI,CAAC,QAAQ,CAAC,KAAK,eACjB;IACF,MAAM,UAAU;IAChB,WAAW,KAAK;IAChB,MAAM,KAAK,SAAS;IACpB,MAAM,KAAK,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC;GACpC,CAAC,CAAC;GACF,QAAQ,SAAS;GACjB,QAAQ,SAAS;EACnB;EAEA,MAAM,qBAAqB;GACzB,MAAM,OAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,QAAO,MAAK,EAAE,KAAK,UAAU,MAAM;GACtE,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,MAAM,KAAK,EAAE;GACtD,MAAM,QAAQ,IAAI,KAAK,IAAI,OAAO,UAAU;IAC1C,MAAM,IAAI,KAAK;IAGf,MAAM,WAAW,MAAM;IACvB,MAAM,WAAW,KAAA;IACjB,IAAI,CAAC,YAAY,MAAM,KAAK,WAAW,UACrC;IACF,IAAI;KACF,MAAM,YAAY,MAAM,KAAK,QAAQ,MAAM,KAAK,WAAW,MAAM,KAAK,MAAM;KAM5E,OAAM,MALa,UAAU,QAAQ,oBAAoB,UAAU,QAAQ,UAAU;MACnF,MAAM,MAAM,KAAK;MACjB,MAAM,MAAM,KAAK;MACjB,cAAc,CAAC;KACjB,CAAC,EAAA,EACW,KAAK;IACnB,QACM,CAAC;GACT,CAAC,CAAC;GACF,KAAK,MAAM,aAAa,IAAI,IAAI,KAAK,KAAI,MAAK,EAAE,KAAK,SAAS,CAAC,GAAG;IAChE,QAAQ,SAAS;IACjB,QAAQ,SAAS;GACnB;EACF;EAEA,MAAM,aAAa,WAAW;GAC5B,MAAM,OAAO,UAAU,SAAS;GAChC,KAAK,MAAM,SAAS,MAAM,QAAQ,OAAO,MAAM,KAAK,EAAE;GACtD,SAAS,OAAO,SAAS;GACzB,SAAS,OAAO,SAAS;GACzB,UAAU,OAAO,SAAS;GAC1B,MAAM,QAAQ,IAAI,KAAK,IAAI,GAAG,CAAC;EACjC;EAEA,MAAM,WAAW;GACf,MAAM,QAAQ,IAAI,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,UAAU;IAC3D,MAAM,OAAO,MAAM;IACnB,WAAW,KAAK;IAChB,IAAI,CAAC,MACH;IACF,MAAM,UAAU;IAEhB,IAAI,KAAK,eACP,MAAM,KAAK,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC;SAC/B,IAAI,MAAM,UACb,MAAM,MAAM,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC;SAErC,MAAM,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;GACpC,CAAC,CAAC;EACJ;CACF;AACF;;;AChGA,SAAgB,oBAAoB,UAAyD,QAA+C;CAC1I,MAAM,EAAE,SAAS,YAAY;CAC7B,MAAM,EAAE,KAAK,UAAU;CAEvB,SAAS,UAAU,OAAc,UAAkB,MAAc,MAAoB;EACnF,MAAM,YAAY;EAClB,MAAM,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,GAAG,GAAI;EACzC,MAAM,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,GAAG,GAAI;EACzC,IAAI,MAAM,MAAM,KAAK,QAAQ,MAAM,MAAM,KAAK,MAC5C;EACF,MAAM,KAAK,OAAO;EAClB,MAAM,KAAK,OAAO;EAClB,MAAM,KAAK;EACX,MAAM,SAAS,OAAO,GAAG,CAAC;EAC1B,QAAQ,MAAM,KAAK,SAAS;CAC9B;CAEA,SAAS,OAAO,YAAoB,UAAwB;EAC1D,MAAM,QAAQ,QAAQ,IAAI,UAAU;EACpC,IAAI,CAAC,OACH;EACF,MAAM,QAAQ,OAAO,QAAQ;EAC7B,MAAM,aAAa,OAAO,QAAQ;EAClC,IAAI,MAAM,cAAc,UAAU;GAChC,OAAO,MAAM;GAEb,MAAM,OAAO,CAAC,GAAG,MAAM,YAAY,CAAC,CAAC,GAAG,EAAE;GAC1C,IAAI,MACF,UAAU,OAAO,KAAK,IAAI,KAAK,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,IAAI;EACxD;EACA,IAAI,MAAM,WAAW,IAAI,KAAK,KAAA,QAC5B,MAAM,KAAK;CACf;CAEA,MAAM,0BAAU,IAAI,IAAY;CAChC,MAAM,kCAAkB,IAAI,IAAkC;CAC9D,MAAM,iBAAiB,cAA6B;EAClD,KAAK,MAAM,YAAY,iBACrB,SAAS,SAAS;CACtB;CAoBA,OAAO;EAAE;EAAW;EAAQ,SAAA;GAjB1B,eAAe,UAAU;IACvB,MAAM,MAAM,QAAQ,OAAO;IAC3B,QAAQ,IAAI,QAAQ;IACpB,IAAI,CAAC,KACH,cAAc,IAAI;GACtB;GACA,iBAAiB,UAAU;IACzB,IAAI,QAAQ,OAAO,QAAQ,KAAK,QAAQ,SAAS,GAC/C,cAAc,KAAK;GACvB;GACA,iBAAiB,QAAQ,OAAO;GAChC,eAAe,UAAU;IACvB,gBAAgB,IAAI,QAAQ;IAC5B,aAAa,gBAAgB,OAAO,QAAQ;GAC9C;EAGgC;CAAE;AACtC;;;AC3CA,SAAgB,sBAAsB,MAA4C;CAChF,MAAM,WAAW,uBAAuB,IAAI;CAC5C,MAAM,SAAS,qBAAqB,IAAI;CACxC,MAAM,YAAY,wBAAwB,MAAM,UAAU,MAAM;CAChE,MAAM,QAAQ,oBAAoB,UAAU,MAAM;CAElD,OAAO;EACL,GAAG,MAAM;EACT,GAAG,oBAAoB,MAAM,UAAU,QAAQ,WAAW,KAAK;EAC/D,GAAG,mBAAmB,UAAU,QAAQ,SAAS;EACjD,GAAG,qBAAqB,MAAM,UAAU,SAAS;CACnD;AACF;;;;ACpBA,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,SAAS,oBAAoB,MAAuB;CAClD,OAAO,SAAS,WAAW,SAAS;AACtC;AAEA,SAAgB,oBAAoB,EAAE,KAAK,WAAW,YAAY,gBAAgB,kBAAkB,eAAe,eAQ/F;;;;;;;;CAQlB,MAAM,uBAAuB,qBAAqB;CAClD,OAAO,sBAAsB;EAC3B;EACA,wBAAwB,IAAI,aAAa,CAAC,CAAC,6BAA6B;EACxE,iBAAiB,IAAI,aAAa,CAAC,CAAC,aAAa,QAC7C;GAAE,IAAI;GAAO,QAAQ;EAAwC,IAC7D,YAAY,IACV,EAAE,IAAI,KAAK,IACX;GAAE,IAAI;GAAO,QAAQ;EAA8D;EACzF,MAAM,QAAQ,WAAW,QAAQ;GAC/B,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;GACrD,MAAM,cAAc,uBAAuB,KAAK,QAAQ;GACxD,MAAM,MAAM,WAAW,WAAW,IAAI;GACtC,IAAI,WAAW,SAAS;IACtB,MAAM,WAAW,oBAAoB,YAAY,IAAI,IAAK,KAAK,eAAe,MAAO;IACrF,OAAO;KAAE,SAAS;KAAsB,QAAQ,MAAM,qBAAqB,MAAM,EAAE,KAAK,SAAS,CAAC;KAAG,aAAa;IAAQ;GAC5H;GACA,uBAAuB,WAAW;GAClC,MAAM,YAAY,eAAe,KAAK,SAAS,MACzC,MAAM,iBAAiB,WAAW;IAAE;IAAK;IAAa,UAAU,IAAI,aAAa;GAAE,CAAC,EAAA,CAAG;GAC7F,OAAO;IAAE,SAAS,UAAU;IAAS,QAAQ,MAAM,UAAU,OAAO;IAAG,aAAa,YAAY;GAAK;EACvG;EACA,MAAM,cAAc,WAAW;GAC7B,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;GAC3C,MAAM,OAAO,OAAO,uBAAuB,KAAK,QAAQ,CAAC,CAAC,OAAO;GACjE,OAAO;IAAE;IAAM,QAAQ,oBAAoB,IAAI;GAAE;EACnD;EACA,MAAM,YAAY,WAAW;GAE3B,MAAM,UAAS,MADI,IAAI,MAAM,KAAK,SAAS,EAAA,EACtB,UAAU;GAC/B,OAAO,MAAM,QAAQ,MAAM,IAAI,SAAgC,CAAC;EAClE;EACA;EACA,OAAO;EACP,UAAU;CACZ,CAAC;AACH;AAEA,SAAgB,0BAA0B,WAAyH;;;;;;;CAOjK,SAAS,kBAAkB,SAA2B,WAAmB,iBAA2C;EAClH,MAAM,iBAAiB,QAAQ;EAC/B,IAAI,CAAC,gBACH,OAAO;EACT,OAAO;GACL,GAAG;GACH,MAAM,eAAe,QAAQ,SAAS,SAAS;IAC7C,IAAI,QAAQ,UACV,OAAO,eAAe,QAAQ,SAAS,OAAO;IAChD,MAAM,MAAM,UAAU,UAAU,WAAW;KAAE;KAAS,KAAK,QAAQ,OAAO,OAAO;KAAK,aAAa;IAAgB,CAAC;IACpH,IAAI;IACJ,IAAI;KACF,OAAO,MAAM,eAAe,QAAQ,SAAS;MAAE,GAAG;MAAS,UAAU,IAAI;KAAQ,CAAC;IACpF,SACO,KAAK;KACV,IAAI,OAAO,IAAI;KACf,MAAM;IACR;IACA,IAAI,QAAQ;KACV,QAAQ,KAAK;KACb,UAAU,KAAK,aAAa;KAC5B,MAAM,YAAY;MAChB,MAAM,QAAQ,iBAAiB,QAAQ,KAAK,MAAM;KACpD;IACF,CAAC;IACD,CAAM,QAAQ,iBAAiB,QAAQ,KAAK,MAAM,KAAK,QAAQ,QAAQ,IAAI,EAAA,CACxE,MAAK,SAAQ,IAAI,OAAO,MAAM,YAAY,IAAI,SAAS,IAAI,OAAO,IAAI,CAAC;IAC1E,OAAO;GACT;EACF;CACF;CACA,OAAO;AACT;;;AC7GA,SAAgB,gBAAgB,EAAE,KAAK,MAAM,YAAY,kBAAkB,oBAQxE;CACD,MAAM,EAAE,KAAK,WAAW,eAAe;CAQvC,MAAM,iBAAiB,4BAA4B;CAEnD,MAAM,QAAQ,uBAAuB,GAAG;CACxC,MAAM,eAAe,mBAAmB;EAAE;EAAK;EAAM;EAAO;CAAW,CAAC;CACxE,MAAM,aAAa,qBAAqB;EAAE;EAAK;EAAM;EAAO;EAAgB,cAAc,aAAa;EAAc;CAAiB,CAAC;CACvI,MAAM,YAAY,uBAAuB;EAAE;EAAK;EAAO;EAAgB;CAAW,CAAC;CACnF,MAAM,EAAE,qBAAqB;CAE7B,IAAI,uBAAqD,YAAY,CAAC;CACtE,MAAM,YAAY,oBAAoB;EACpC;EACA;EACA;EACA;EACA;EACA,eAAe,WAAW;EAE1B,cAAc,WAAW,YAAY,qBAAqB,WAAW,EAAE,WAAW,QAAQ,GAAG,EAAE,eAAe,MAAM,CAAC;CACvH,CAAC;CACD,MAAM,oBAAoB,0BAA0B,SAAS;CAC7D,MAAM,qBAAqB,yBAAyB;EAAE;EAAK;EAAO;EAAW;CAAW,CAAC;CAEzF,MAAM,UAAU,uBAAuB;EAAE;EAAK;EAAM;EAAO;EAAc,kBAAkB;EAAW;EAAgB;EAAW;CAAiB,CAAC;CAEnJ,OAAO;EACL;EACA,cAAc,aAAa;EAC3B;EACA;EACA;EACA;EACA,sBAAsB,aAAa;EACnC,eAAe,WAAW;EAC1B,oBAAoB,UAAwC;GAC1D,uBAAuB;EACzB;EACA;CACF;AACF;;;ACbA,SAAgB,qBAAqB,SAmBlB;CACjB,MAAM,EAAE,WAAW,OAAO,cAAc,mBAAmB;;CAG3D,MAAM,0BAAU,IAAI,IAAkB;;;;;;CAOtC,MAAM,mCAAmB,IAAI,IAA8C;;;;;CAM3E,MAAM,8BAAc,IAAI,IAA2B;CAEnD,SAAS,cAAc,WAAyB;EAE9C,MAAM,QADQ,YAAY,IAAI,SAAS,KAAK,QAAQ,QAAQ,EAAA,CACzC,YAAY,KAAA,CAAS,CAAC,CAAC,WAAW,kBAAkB,SAAS,CAAC;EACjF,YAAY,IAAI,WAAW,IAAI;EAC/B,KAAK,cAAc;GACjB,IAAI,YAAY,IAAI,SAAS,MAAM,MACjC,YAAY,OAAO,SAAS;EAChC,CAAC;CACH;CAEA,eAAe,kBAAkB,WAAkC;EACjE,MAAM,YAAY,iBAAiB,IAAI,SAAS;EAChD,IAAI,CAAC,aAAa,UAAU,SAAS,GACnC;EAEF,MAAM,OAAO,MAAM,MAAM,KAAK,SAAS;EACvC,IAAI,CAAC,MACH;EAMF,MAAM,UAAU,6BAA6B,KAAK,KAAK;EACvD,IAAI,QAAQ,WAAW,GAAG;GACxB,iBAAiB,OAAO,SAAS;GACjC;EACF;EAOA,IAAI,CAAC,QAAQ,OAAO,MAA0B,UAAU,IAAI,EAAE,EAAE,CAAC,GAC/D;EAEF,MAAM,OAAO,4BAA4B,SAAS,WAAW,EAAE,QAAQ,WAAW,EAAE,CAAC;EACrF,MAAM,MAAM,YAAY,WAAW,CAAC,IAAI,CAAC;EAEzC,KAAK,MAAM,KAAK,SACd,QAAQ,OAAO,EAAE,EAAE;EACrB,iBAAiB,OAAO,SAAS;CACnC;CAEA,MAAM,MAAsB;EAC1B,sBAAsB,WAAW;GAC/B,QAAO,YAAW,IAAI,SAA8B,SAAS,WAAW;IACtE,QAAQ,IAAI,QAAQ,IAAI;KAAE;KAAW;KAAS;KAAS;KAAQ,MAAM;IAAK,CAAC;IAC3E,UAAU;KAAE,MAAM;KAAuB;KAAW;KAAS,MAAM;IAAK,CAAC;GAC3E,CAAC;EACH;EAEA,QAAQ,WAAW,UAAU;GAC3B,MAAM,OAAO,QAAQ,IAAI,SAAS;GAClC,IAAI,CAAC,MACH,OAAO,EAAE,IAAI,MAAM;GAErB,QAAQ,OAAO,SAAS;GAExB,IAAI,KAAK,MAAM;IACb,KAAK,QAAQ,QAAQ;IACrB,UAAU;KAAE,MAAM;KAAwB,WAAW,KAAK;KAAW;IAAU,CAAC;IAChF,IAAI,SAAS,SAAS,UAAU,SAAS,aAAa,UACpD,iBAAiB,KAAK,SAAS;IACjC,OAAO,EAAE,IAAI,KAAK;GACpB;GAMA,MAAM,SAAS,iBAAiB,IAAI,KAAK,SAAS,qBAAK,IAAI,IAAiC;GAC5F,OAAO,IAAI,WAAW,QAAQ;GAC9B,iBAAiB,IAAI,KAAK,WAAW,MAAM;GAC3C,cAAc,KAAK,SAAS;GAE5B,UAAU;IAAE,MAAM;IAAwB,WAAW,KAAK;IAAW;GAAU,CAAC;GAChF,OAAO,EAAE,IAAI,KAAK;EACpB;EAEA,OAAO,WAAW,SAAS,kCAAkC;GAC3D,MAAM,OAAO,QAAQ,IAAI,SAAS;GAClC,IAAI,CAAC,MACH,OAAO,EAAE,IAAI,MAAM;GAErB,QAAQ,OAAO,SAAS;GAExB,IAAI,KAAK,MACP,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;GAE/B,UAAU;IAAE,MAAM;IAAwB,WAAW,KAAK;IAAW;GAAU,CAAC;GAChF,OAAO,EAAE,IAAI,KAAK;EACpB;EAEA,KAAK,WAAW;GACd,MAAM,MAA4B,CAAC;GACnC,KAAK,MAAM,QAAQ,QAAQ,OAAO,GAAG;IACnC,IAAI,aAAa,KAAK,cAAc,WAClC;IACF,IAAI,KAAK;KAAE,WAAW,KAAK;KAAW,SAAS,KAAK;KAAS,MAAM,KAAK;IAAK,CAAC;GAChF;GACA,OAAO;EACT;EAEA,MAAM,UAAU,WAAW;GACzB,MAAM,OAAO,MAAM,MAAM,KAAK,SAAS;GACvC,IAAI,CAAC,MACH,OAAO,CAAC;GAEV,MAAM,UAAU,6BAA6B,KAAK,KAAK;GACvD,MAAM,SAA+B,CAAC;GAUtC,MAAM,YAAY,aAAa,CAAC,CAAC,oBAAoB;GACrD,MAAM,eAAqC,CAAC;GAE5C,KAAK,MAAM,WAAW,SAAS;IAC7B,IAAI,QAAQ,IAAI,QAAQ,EAAE,GACxB;IAEF,QAAQ,IAAI,QAAQ,IAAI;KACtB;KACA;KACA,MAAM;KAGN,eAAe,KAAA;KACf,cAAc,KAAA;IAChB,CAAC;IACD,IAAI,aAAa,mBAAmB,OAAO,GAAG;KAC5C,aAAa,KAAK,OAAO;KACzB;IACF;IACA,OAAO,KAAK;KAAE;KAAW;KAAS,MAAM;IAAM,CAAC;IAC/C,UAAU;KAAE,MAAM;KAAuB;KAAW;KAAS,MAAM;IAAM,CAAC;GAC5E;GAGA,KAAK,MAAM,WAAW,cACpB,IAAI,QAAQ,QAAQ,IAAI,mCAAmC,OAAO,CAAC;GACrE,OAAO;EACT;EAEA,qBAAqB,WAAW;GAC9B,MAAM,QAAQ,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,QAAO,UACxC,CAAC,aAAa,KAAK,cAAc,cAAc,mBAAmB,KAAK,OAAO,CAAC;GAClF,KAAK,MAAM,QAAQ,OACjB,IAAI,QAAQ,KAAK,QAAQ,IAAI,mCAAmC,KAAK,OAAO,CAAC;GAC/E,OAAO,MAAM;EACf;EAEA,aAAa,WAAW;GACtB,KAAK,MAAM,CAAC,IAAI,SAAS,SAAS;IAChC,IAAI,KAAK,cAAc,WACrB;IACF,IAAI,KAAK,MACP,KAAK,uBAAO,IAAI,MAAM,+CAA+C,CAAC;IACxE,QAAQ,OAAO,EAAE;GACnB;GACA,iBAAiB,OAAO,SAAS;EACnC;CACF;CACA,OAAO;AACT;;;ACpQA,SAAgB,mBAAmB,EAAE,KAAK,OAAO,YAAY,kBAK5C;CACf,MAAM,EAAE,QAAQ,oBAAoB,eAAe,QAAQ;CAC3D,MAAM,EAAE,QAAQ,cAAc,mBAAmB;CAkNjD,OAAO;EA/ML,MAAM,WAAW,WAAW,SAAS,iBAAiB;GACpD,mBAAmB;GACnB,MAAM,mBAA4C;IAChD,MAAM,QAAQ,OAAO,IAAI,SAAS,KAAK,CAAC;IACxC,MAAM,KAAK;KACT,IAAI,WAAW;KACf,MAAM;KACN,GAAI,iBAAiB,SAAS,EAAE,gBAAgB,IAAI,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,WAAW,KAAK;IAC3B,eAAe,SAAS;IACxB,OAAO,EAAE,WAAW,SAAkB;GACxC;GAEA,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,OAAO,MAAM,cAAc,MAAM;IAInC,IAAI,MAAM,MAAM,MAAM,OAAO,GAAG;KAC9B,MAAM,kBAAkB,KAAK,OAAO;KACpC,OAAO,EAAE,WAAW,QAAiB;IACvC;IAEA,OAAO,WAAW;GACpB;GAEA,IAAI,cAAc,SAAS,KAAK,eAAe,SAAS,GACtD,OAAO,WAAW;GAEpB,IAAI,UAAU;GACd,IAAI,UAAU;GACd,IAAI;IACF,MAAM,WAAW;KACf;KACA,QAAQ;KACR,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;IAC/C,GAAG;KAAE,iBAAiB;MAAE,UAAU;KAAK;KAAG,oBAAoB;MAAE,UAAU;KAAK;IAAE,CAAC;IAClF,OAAO,EAAE,WAAW,UAAU,YAAqB,OAAgB;GACrE,SACO,KAAK;IAOV,mBAAmB;IACnB,IAAI,WAAW,cAAc,SAAS,GACpC,OAAO,WAAW;IACpB,MAAM;GACR;EACF;EAEA,MAAM,SAAS,WAAW,MAAM,iBAAiB,aAAa,WAAW;GACvE,mBAAmB;GAGnB,MAAM,OAAO,OAAO,IAAI,SAAS;GACjC,IAAI,IAAI,aAAa,CAAC,CAAC,kBAAkB,SAAS,CAAC,aAAa,CAAC,aAAa,UAAU,MAAM,MAAM,cAAc,MAAM;IAEtH,KAAK,MAAM,QAAQ,mBAAmB,CAAC,GACrC,IAAI;KACF,MAAM,KAAK,MAAM,cAAc,IAAI;IACrC,QACM,CAEN;IAGF,IAAI,KAAK,MAAM,MAAM,IAAI,GAAG;KAC1B,KAAK,kBAAkB,KAAK,IAAI;KAChC,OAAO,EAAE,WAAW,QAAiB;IACvC;GAEF;GAEA,MAAM,gBAAyC;IAC7C,MAAM,QAAQ,OAAO,IAAI,SAAS,KAAK,CAAC;IACxC,MAAM,KAAK;KACT,IAAI,WAAW;KACf;KACA,GAAI,iBAAiB,SAAS,EAAE,gBAAgB,IAAI,CAAC;KACrD,GAAI,aAAa,SAAS,EAAE,YAAY,IAAI,CAAC;KAC7C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;IACnC,CAAC;IACD,OAAO,IAAI,WAAW,KAAK;IAC3B,eAAe,SAAS;IACxB,OAAO,EAAE,WAAW,SAAkB;GACxC;GAGA,IAAI,cAAc,SAAS,KAAK,eAAe,SAAS,GACtD,OAAO,QAAQ;GAEjB,IAAI;IACF,MAAM,WAAW;KACf;KACA,QAAQ;KACR,GAAI,iBAAiB,SAAS,EAAE,gBAAgB,IAAI,CAAC;KACrD,GAAI,aAAa,SAAS,EAAE,YAAY,IAAI,CAAC;KAC7C,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;IACnC,CAAC;IACD,OAAO,EAAE,WAAW,OAAgB;GACtC,SACO,KAAK;IAGV,mBAAmB;IACnB,IAAI,cAAc,SAAS,GACzB,OAAO,QAAQ;IACjB,MAAM;GACR;EACF;EAEA,YAAY,WAAW,IAAI;GACzB,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,CAAC,OACH,OAAO;GACT,MAAM,QAAQ,MAAM,WAAU,SAAQ,KAAK,OAAO,EAAE;GACpD,IAAI,QAAQ,GACV,OAAO;GACT,MAAM,OAAO,OAAO,CAAC;GACrB,IAAI,MAAM,WAAW,GACnB,OAAO,OAAO,SAAS;GACzB,eAAe,SAAS;GACxB,OAAO;EACT;EAEA,UAAU,WAAW;GACnB,QAAQ,OAAO,IAAI,SAAS,KAAK,CAAC,EAAA,CAAG,IAAI,YAAY;EACvD;EAEA,YAAY,WAAW,IAAI,MAAM,aAAa;GAC5C,MAAM,QAAQ,OAAO,IAAI,SAAS,CAAC,EAAE,MAAK,SAAQ,KAAK,OAAO,EAAE;GAChE,IAAI,CAAC,OACH,OAAO;GACT,IAAI,UAAU;GACd,IAAI,MAAM,SAAS,MAAM;IACvB,MAAM,OAAO;IACb,UAAU;GACZ;GACA,IAAI,eAAe,CAAC,gBAAgB,MAAM,eAAe,CAAC,GAAG,WAAW,GAAG;IACzE,IAAI,YAAY,SAAS,GACvB,MAAM,cAAc;SAEpB,OAAO,MAAM;IACf,UAAU;GACZ;GACA,IAAI,SACF,eAAe,SAAS;GAC1B,OAAO;EACT;EAEA,iBAAiB,WAAW,IAAI;GAC9B,MAAM,QAAQ,OAAO,IAAI,SAAS,CAAC,EAAE,MAAK,SAAQ,KAAK,OAAO,EAAE;GAChE,OAAO,QAAQ,CAAC,GAAI,MAAM,eAAe,CAAC,CAAE,IAAI;EAClD;EAEA,MAAM,aAAa,WAAW,IAAI;GAChC,mBAAmB;GACnB,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,MAAM,QAAQ,OAAO,MAAK,SAAQ,KAAK,OAAO,EAAE;GAChD,IAAI,CAAC,SAAS,CAAC,OACb,OAAO,EAAE,WAAW,UAAmB;GAQzC,MAAM,2BAAiC;IACrC,MAAM,OAAO,OAAO,IAAI,SAAS;IACjC,MAAM,QAAQ,MAAM,WAAU,SAAQ,KAAK,OAAO,EAAE,KAAK;IACzD,IAAI,QAAQ,SAAS,GAAG;KACtB,KAAK,OAAO,OAAO,CAAC;KACpB,IAAI,KAAK,WAAW,GAClB,OAAO,OAAO,SAAS;IAC3B;IACA,eAAe,SAAS;GAC1B;GAKA,IAAI,MAAM,aAAa,cAAc,SAAS,GAC5C,OAAO,EAAE,WAAW,SAAkB;GACxC,MAAM,OAAO,OAAO,IAAI,SAAS;GACjC,IAAI,CAAC,MAAM,aAAa,MAAM,MAAM,cAAc,QAAQ,KAAK,MAAM,MAAM,MAAM,IAAI,GAAG;IACtF,KAAK,kBAAkB,KAAK,MAAM,IAAI;IACtC,mBAAmB;IACnB,OAAO,EAAE,WAAW,QAAiB;GACvC;GACA,MAAM,WAAW;IACf;IACA,QAAQ,MAAM;IACd,GAAI,MAAM,iBAAiB,SAAS,EAAE,iBAAiB,MAAM,gBAAgB,IAAI,CAAC;IAClF,GAAI,MAAM,aAAa,SAAS,EAAE,aAAa,MAAM,YAAY,IAAI,CAAC;IACtE,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GAC1D,CAAC;GACD,mBAAmB;GACnB,OAAO,EAAE,WAAW,OAAgB;EACtC;CAIW;AACf;AAEA,SAAS,gBAAgB,GAAgC,GAAyC;CAChG,OAAO,EAAE,WAAW,EAAE,UACjB,EAAE,OAAO,GAAG,MAAM,EAAE,cAAc,EAAE,EAAE,CAAE,aAAa,EAAE,SAAS,EAAE,EAAE,CAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,CAAE,IAAI;AAC1G;;;ACtNA,SAAgB,iBAAiB,WAAqD;CACpF,MAAM,yBAAS,IAAI,IAA2B;;CAG9C,SAAS,aAAa,EAAE,IAAI,MAAM,eAAwC;EACxE,OAAO;GACL;GACA;GACA,GAAI,aAAa,SACb,EAAE,aAAa,YAAY,KAAI,OAAM;IAAE,WAAW,EAAE;IAAW,GAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;GAAG,EAAE,EAAE,IACvG,CAAC;EACP;CACF;CAEA,SAAS,eAAe,WAAyB;EAC/C,UAAU;GAAE,MAAM;GAAiB;GAAW,QAAQ,OAAO,IAAI,SAAS,KAAK,CAAC,EAAA,CAAG,IAAI,YAAY;EAAE,CAAC;CACxG;;CAGA,SAAS,UAAU,WAAyB;EAC1C,IAAI,OAAO,OAAO,SAAS,GACzB,eAAe,SAAS;CAC5B;;CAGA,SAAS,gBAAsB;EAC7B,KAAK,MAAM,aAAa,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG;GAC1C,OAAO,OAAO,SAAS;GACvB,eAAe,SAAS;EAC1B;CACF;CAEA,OAAO;EAAE;EAAQ;EAAc;EAAgB;EAAW;CAAc;AAC1E;;;ACxCA,SAAgB,YAAY,EAAE,KAAK,YAAY,kBAK5C;CACD,MAAM,EAAE,WAAW,QAAQ,WAAW,eAAe,mBAAmB;CAExE,MAAM,QAAQ,iBAAiB,SAAS;CACxC,MAAM,EAAE,QAAQ,gBAAgB,WAAW,kBAAkB;;CAG7D,MAAM,2BAAW,IAAI,IAAY;;;;;;;;;CAUjC,SAAS,UAAU,WAAyB;EAC1C,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,IAAI,UAAU,UAAU,CAAC,SAAS,cAAc,SAAS,KAAK,CAAC,MAAM,MAAM,6BACzE;EACF,QAAa,SAAS,CAAC,CAAC,YAAY,KAAA,CAAS;CAC/C;;;;;;;;;;;;;;;CAgBA,eAAe,QAAQ,WAAkC;EACvD,IAAI,UAAU,UAAU,eAAe,IAAI,SAAS,GAClD;EACF,KAAK,OAAO,IAAI,SAAS,CAAC,EAAE,UAAU,KAAK,GACzC;EACF,MAAM,WAAW;GAAE;GAAW,QAAQ;GAAI,MAAM;EAAK,GAAG,EAAE,iBAAiB,MAAM,CAAC;CACpF;;;;;;;;;;CAWA,SAAS,WAAW,WAAmB,UAAU,GAAS;EAExD,IAAI,UAAU,UAAU,SAAS,IAAI,SAAS,KAAK,eAAe,SAAS,GACzE;EACF,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,IAAI,CAAC,SAAS,MAAM,WAAW,GAAG;GAChC,UAAU,SAAS;GACnB;EACF;EACA,IAAI,cAAc,SAAS,GAAG;GAC5B,IAAI,UAAU,KACZ,WAAW,YAAY,IAAI,WAAW,UAAU,CAAC;GACnD;EACF;EAEA,MAAM,OAAO,MAAM;EACnB,SAAS,IAAI,SAAS;EAEtB,WAAgB;GACd;GACA,QAAQ,KAAK;GACb,GAAI,KAAK,iBAAiB,SAAS,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;GAChF,GAAI,KAAK,aAAa,SAAS,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;GACpE,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;EACxD,GAAG,EAAE,iBAAiB,MAAM,CAAC,CAAC,CAC3B,WAAW;GACV,MAAM,OAAO,OAAO,IAAI,SAAS;GACjC,MAAM,QAAQ,MAAM,WAAU,SAAQ,KAAK,OAAO,KAAK,EAAE,KAAK;GAC9D,IAAI,QAAQ,SAAS,GAAG;IACtB,KAAK,OAAO,OAAO,CAAC;IACpB,IAAI,KAAK,WAAW,GAClB,OAAO,OAAO,SAAS;GAC3B;GACA,eAAe,SAAS;EAC1B,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,UAAU;IACR,MAAM;IACN;IACA,OAAO;KAAE,MAAM;KAAS,MAAM,kCAAmC,IAAc;IAAU;GAC3F,CAAC;EACH,CAAC,CAAC,CACD,cAAc;GACb,SAAS,OAAO,SAAS;EAC3B,CAAC;CACL;CAIA,OAAO;EAAE;EAAW;EAAS;EAAY;EAAW;EAAe,SAFnD,mBAAmB;GAAE;GAAK;GAAO;GAAY;EAAe,CAEH;CAAE;AAC7E;;;ACjFA,SAAgB,iBAAiB,EAAE,KAAK,MAAM,kBAAkB,qBAAqB,wBAAwB,cAQ1G;CACD,MAAM,EAAE,KAAK,WAAW,QAAQ,eAAe,YAAY,WAAW,cAAc,kBAAkB;;;;;;;CAQtG,SAAS,eAAe,KAAgB,QAAsD;EAC5F,MAAM,UAAU,IAAI,MAAM;EAC1B,IAAI,CAAC,SACH,OAAO,QAAQ,QAAQ;EACzB,MAAM,SAAS,WAAW;EAC1B,KAAK,MAAM,SAAS,QAClB,UAAU;GAAE,MAAM;GAAS,WAAW,IAAI;GAAW,OAAO;IAAE,GAAG,oBAAoB,KAAK;IAAG;GAAO;EAAE,CAAC;EACzG,OAAO,QACJ,YAAY,CAAC;GAAE,IAAI;GAAQ,MAAM;GAAW,WAAW,KAAK,IAAI;GAAG,SAAS,uBAAuB,MAAM;EAAE,CAAC,CAAC,CAAC,CAC9G,OAAM,QAAO,UAAU,eAAe,mBAAmB,OAAO,GAAG,GAAG,CAAC;CAC5E;;;;;;;;;CAcA,eAAe,oBAAuB,WAAmB,MAAc,MAAoC;EACzG,MAAM,UAAU,UAAU,KAAK;EAC/B,IAAI,cAAc,SAAS,GACzB,MAAM,IAAI,MAAM,OAAO;EACzB,MAAM,cAAc,QAAQ,cAAoB;EAChD,WAAW,IAAI,WAAW,YAAY,OAAO;EAC7C,IAAI;GACF,MAAM,OAAO,OAAO,IAAI,MAAM,UAAU,IAAI,MAAM,QAAQ,SAAS,IAAI,IAAI,MAAM,KAAK,SAAS;GAC/F,IAAI,MAAM,WAAW,aAAa,KAAK,IAAI,IAAI,KAAK,YAAA,KAClD,MAAM,IAAI,MAAM,OAAO;GAGzB,iBAAiB,SAAS;GAC1B,OAAO,MAAM,KAAK;EACpB,UACQ;GACN,IAAI,WAAW,IAAI,SAAS,MAAM,YAAY,SAC5C,WAAW,OAAO,SAAS;GAC7B,YAAY,QAAQ;GACpB,IAAI,CAAC,cAAc,SAAS,GAC1B,oBAAoB,SAAS;GAE/B,IAAI,CAAC,UAAU,QACb,WAAW,YAAY,GAAG,SAAS;EACvC;CACF;CAEA,eAAe,YAAY,WAAmB,MAAc,QAAuE;EACjI,MAAM,oBAAoB,WAAW,YAAY,iBAAiB,WAAW,MAAM,CAAC;EACpF,UAAU;GAAE,MAAM;GAAoB,IAAI;GAAU;EAAU,CAAC;CACjE;CAEA,eAAe,iBAAiB,WAAmB,QAAuE;EACxH,MAAM,QAAQ,IAAI;EAClB,IAAI;EACJ,IAAI,MAAM,aACR,SAAS,MAAM,MAAM,YAAY,WAAW,MAAM;OAE/C;GACH,MAAM,OAAO,MAAM,MAAM,KAAK,SAAS;GACvC,MAAM,OAAO,OAAO,OAAO,KAAK,KAAK,IAAI;GACzC,SAAS,CAAC,OAAO,eAAe,SAAS,OAAO,cAAc;GAC9D,IAAI,QAAQ,SAAS,MACnB,MAAM,MAAM,KAAK;IAAE,GAAG;IAAM,OAAO;IAAM,WAAW,KAAK,IAAI;GAAE,CAAC;EACpE;EACA,IAAI,WAAW,cACb,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;CACvD;CAoLA,OAAO;EAAE;EAAgB,SAAA;GAjLvB,cAAa,WAAUC,YAAkB,IAAI,OAAO;IAAE,GAAG;IAAQ,SAAS,aAAa;GAAE,CAAC;GAE1F,MAAM,WAAW,WAAW,QAAQ;IAClC,MAAM,YAAY,WAAW,oBAAoB,UAAU;KAEzD,MAAM,OAAO,iBAAiB,OAAO,MAAM;KAC3C,IAAI,SAAS,MACX,MAAM,IAAI,MAAM,SAAS,OAAO,0BAA0B,UAAU,GAAG;KACzE,OAAO;IACT,CAAC;GACH;GAEA,MAAM,aAAa,WAAW,QAAQ,MAAM;IAC1C,MAAM,YAAY,WAAW,kBAAkB,UAAU;KACvD,MAAM,OAAO,sBAAsB,OAAO,QAAQ,IAAI;KACtD,IAAI,SAAS,MACX,MAAM,IAAI,MAAM,SAAS,OAAO,+BAA+B;KACjE,OAAO;IACT,CAAC;GACH;GAEA,MAAM,iBAAiB,WAAW,WAAW;IAC3C,MAAM,SAAS,MAAM,IAAI,MAAM,KAAK,SAAS;IAC7C,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;IAErD,MAAM,OAAO,uBAAuB,OAAO,QAAQ,CAAC,CAAC;IACrD,MAAM,YAAY,cAAc,MAAM,iBAAiB,IAAI,MAAM;IAEjE,MAAM,MAAM,aAAa,MAAM,KAAK,CAAC,CAAC,aAAa,WAAW,IAAI,EAAA,CAAG,MAAM,IAAI,UAAU,YAAY,SAAS;IAC9G,IAAI,OAAO,CAAC,cAAc,CAAC,WAAW,GAAG,KAAK,CAAC,SAAS,KAAK,EAAE,gBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,IACnG,MAAM,IAAI,MAAM,WAAW,IAAI,oDAAoD;IACrF,IAAI,OAAO,cAAc,OAAO,QAAQ,GACtC,MAAM,IAAI,MAAM,+CAA+C;IAGjE,MAAM,oBAAoB,WAAW,MAAM,oBAAoB,qBAAqB,YAAY;KAG9F,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;KAC3C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;KAErD,MAAM,EAAE,aAAa,WAAW,GAAG,SAAS;KAC5C,MAAM,OAAoB;MACxB,GAAG;MACH,UAAU;OAAE,GAAG,KAAK;OAAU;MAAI;MAClC,GAAI,MAAM,EAAE,aAAa,YAAY,MAAM,cAAc,GAAG,EAAE,IAAI,CAAC;MACnE,WAAW,KAAK,IAAI;KACtB;KACA,OAAO,IAAI,MAAM,WAAW,IAAI,MAAM,SAAS,IAAI,IAAI,IAAI,MAAM,KAAK,IAAI;IAC5E,CAAC;IACD,UAAU;KAAE,MAAM;KAAoB,IAAI;KAAU;IAAU,CAAC;GACjE;GAEA,MAAM,YAAY,WAAW,OAAO;IAClC,MAAM,OAAO,OAAO,IAAI,SAAS,CAAC,EAAE,MAAM;IAC1C,IAAI,MACF,MAAM,KAAK,YAAY,KAAK;SAEzB;KAGH,IAAI,CAAE,MAAM,eAAe,IAAI,OAAO,SAAS,GAC7C,MAAM,IAAI,MAAM,eAAe,UAAU,gBAAgB;KAC3D,MAAM,IAAI,MAAM,YAAY,WAAW,KAAK;IAC9C;IACA,UAAU;KAAE,MAAM;KAAoB,IAAI;KAAU;IAAU,CAAC;GACjE;GAEA,MAAM,WAAW,WAAW,QAAQ;IAClC,IAAI,OAAO,WAAW,GACpB,OAAO;IAGT,IAAI,CAAC,OAAO,IAAI,SAAS,GACvB,MAAM,cAAc,IAAI,SAAS,CAAC,EAAE,YAAY,KAAA,CAAS;IAC3D,MAAM,MAAM,OAAO,IAAI,SAAS;IAChC,IAAI,KAAK,MAAM,SAAS;KACtB,MAAM,eAAe,KAAK,MAAM;KAChC,OAAO;IACT;IACA,MAAM,OAAoB;KAAE,IAAI,WAAW;KAAG,MAAM;KAAW,WAAW,KAAK,IAAI;KAAG,SAAS,uBAAuB,MAAM;IAAE;IAC9H,IAAI;KACF,MAAM,iBAAiB,YAAW,UAAS,CAAC,GAAG,OAAO,IAAI,CAAC;IAC7D,QACM;KACJ,OAAO;IACT;IACA,KAAK,MAAM,SAAS,QAClB,UAAU;KAAE,MAAM;KAAS;KAAW,OAAO;MAAE,GAAG,oBAAoB,KAAK;MAAG,QAAQ,KAAK;KAAG;IAAE,CAAC;IACnG,OAAO;GACT;;;;;;;;;;;;;GAcA,MAAM,qBAAqB,WAAW,OAAO;IAC3C,MAAM,QAAQ,OAAO,IAAI,SAAS;IAClC,MAAM,UAAU,OAAO,MAAM;IAC7B,IAAI,CAAC,SACH,OAAO;IACT,MAAO,aAAa,KAAK,IAAI;IAC7B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,QAAQ,QAAQ,KAAK,KAAK;IAC5B,MAAM,QAAQ,KAAK;IACnB,OAAO;GACT;GAEA,MAAM,iBAAiB,WAAW,OAAO,OAAO,CAAC,GAAG;IAClD,IAAI,MAAM,KAAK,CAAC,CAAC,qBAAqB,WAAW,KAAK,GACpD;IAQF,MAAM,OAAO,MAAM,IAAI,MAAM,KAAK,SAAS;IAC3C,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;IACrD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAI,UAAU,KAAA,GACZ,OAAO,KAAK,SAAS;SAErB,KAAK,SAAS,OAAO;IAEzB,IAAI,KAAK,kBAAkB,OACzB,KAAK,YAAY,KAAK,IAAI;IAC5B,IAAI,IAAI,MAAM,UACZ,MAAM,IAAI,MAAM,SAAS,IAAI;SAE7B,MAAM,IAAI,MAAM,KAAK,IAAI;GAC7B;GAEA,MAAM,gBAAgB,WAAW,MAAM;IAOrC,MAAM,KAAK,CAAC,CAAC,iBAAiB,WAAW;KACvC,aAAa,KAAK;KAClB,SAAS,KAAK;KACd,YAAY,mBAAmB,KAAK,aAAa,KAAK,SAAS,KAAK,SAAS;KAC7E,QAAQ,KAAK;KACb,cAAc,KAAK,gBAAgB,OAAO,KAAK,KAAK,YAAY,CAAC,CAAC,SAAS,IACvE,oBAAoB,KAAK,YAAY,IACrC,KAAA;IACN,CAAC;IACD,uBAAuB,SAAS;GAClC;GAEA,MAAM,sBAAsB,WAAW,SAAS;IAC9C,MAAM,QAAQ,OAAO,IAAI,SAAS;IAClC,MAAM,UAAU,OAAO,MAAM;IAC7B,IAAI,CAAC,SACH,OAAO;IACT,MAAO,aAAa,KAAK,IAAI;IAC7B,QAAQ,WAAW,OAAO;IAC1B,MAAM,QAAQ,KAAK;IACnB,OAAO;GACT;EAI6B;CAAE;AACnC;;;ACzRA,eAAsB,yBACpB,MAKA,WACA,OAAyB,CAAC,GACT;CACjB,MAAM,OAAO,MAAM,KAAK,IAAI,MAAM,KAAK,SAAS;CAChD,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,YAAY,UAAU,aAAa;CAErD,IAAI,cAAc,KAAK,QAAQ,GAC7B,MAAM,IAAI,MAAM,kCAAkC;CACpD,MAAM,MAAM,OAAO,KAAK,UAAU,QAAQ,WAAW,KAAK,SAAS,MAAM;CACzE,MAAM,EAAE,cAAc,MAAM,KAAK,IAAI,cAAc,gBAAgB,uBAAuB,KAAK,QAAQ,CAAC,CAAC,MAAM,KAAK,KAAK,IAAI,YAAY,CAAC,CAAC;CAE3I,MAAM,EAAE,aAAa,YAAY,KAAK,gBAAgB,KAAA,KAAa,OAAO,OAAO,WAAW,KAAK,WAAW,IACxG,aAAa,WAAW,KAAK,aAA4B,KAAK,KAAK,MACjE,EAAE,aAAa,aAAa;EAAE;EAAa,SAAS;CAAM,GAAA,CAAI,oBAAoB,KAAK,UAAU,SAAS,CAAC;CACjH,MAAM,QAAQ,MAAM,qBAAqB;EAAE,UAAU,KAAK,cAAc,WAAW,WAAW;EAAG,OAAO;EAAS,OAAO,KAAK;CAAM,CAAC;CAEpI,MAAM,KAAK,iBAAiB,WAAW,EAAE,MAAM,GAAG,EAAE,eAAe,MAAM,CAAC;CAC1E,OAAO;AACT;;;ACvCA,SAAgB,eAAe,EAAE,KAAK,MAAM,cAAc,WAAW,OAAO,QAAQ,WAAW,iBAU3E;CAClB,MAAM,EAAE,QAAQ,eAAe,YAAY,eAAe,WAAW,gBAAgB,cAAc;CACnG,MAAM,EAAE,gBAAgB,cAAc;CACtC,IAAI;CAEJ,OAAO;;;;;;EAML,eAAe,WAAW;GACxB,aAAa,aAAa,SAAS;GACnC,UAAU,QAAQ,SAAS;GAC3B,eAAe,OAAO,SAAS;GAC/B,MAAM,UAAU,SAAS;GAOzB,cAAc,OAAO,SAAS;GAE9B,OAAO,oBAAoB,SAAS;GAIpC,UAAU,eAAe,QAAQ,SAAS,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;GAElE,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,CAAC,OACH;GAEF,OAAO,mBAAmB,WAAW,KAAK;EAC5C;;;;;;EAOA,QAAQ;GACN,IAAI,CAAC,cAAc;IACjB,UAAU,SAAS;IACnB,UAAU,cAAc;IAExB,KAAK,CAAC,CAAC,SAAS,MAAM;IACtB,MAAM,cAAc,CAAC,GAAG,OAAO,OAAO,CAAC,CAAC,CAAC,SAAQ,UAAS,MAAM,aAAa,CAAC,MAAM,UAAU,IAAI,CAAC,CAAC;IACpG,KAAK,CAAC,CAAC,SAAS;IAChB,gBAAgB,YAAY;KAC1B,MAAM,QAAQ,WAAW,WAAW;KACpC,OAAO,WAAW,OAAO,KAAK,cAAc,OAAO,GACjD,MAAM,QAAQ,WAAW,CAAC,GAAG,WAAW,OAAO,GAAG,GAAG,aAAa,CAAC;KAKrE,MAAM,OAAO,eAAe,SAAS;KAErC,MAAM,UAAU,SAAS;KACzB,MAAM,eAAe,WAAW;KAChC,MAAM,QAAQ,WAAW,KAAK,KAAI,OAAM,UAAU,mBAAmB,EAAE,CAAC,CAAC;IAC3E,EAAA,CAAG;GACL;GACA,OAAO;EACT;EAEA,WAAW;GACT,eAAe,MAAM;GAOrB,cAAc,MAAM;GACpB,MAAM,cAAc;GAKpB,UAAU,sBAAsB;GAChC,cAAc,MAAM;GAEpB,UAAU,QAAQ;GAElB,KAAK,MAAM,CAAC,WAAW,UAAU,QAAQ;IACvC,OAAO,YAAY,KAAK;IACxB,aAAa,aAAa,SAAS;GACrC;GACA,OAAO,MAAM;GACb,OAAO,wBAAwB;EACjC;CACF;AACF;;;;;;;;;;AChEA,SAAgB,eAAe,KAAoC;CACjE,MAAM,EAAE,WAAW,iBAAiB,mBAAmB,oBAAoB,GAAG;CAC9E,MAAM,MAAM,kBAAkB,KAAK,SAAS;CAC5C,MAAM,EAAE,QAAQ,YAAY,eAAe,iBAAiB,oBAAoB,kBAAkB;CAClG,MAAM,eAAe,qBAAqB;EACxC;EACA,OAAO,IAAI;EACX,oBAAoB,IAAI,aAAa;EAGrC,iBAAgB,cAAa,QAAQ,CAAC,CAAC,UAAU,SAAS;CAC5D,CAAC;CACD,MAAM,YAAY,kBAAkB;EAClC;EACA,aAAa,IAAI;EACjB,GAAI,IAAI,uBAAuB,EAAE,aAAa,IAAI,qBAAqB,IAAI,CAAC;CAC9E,CAAC;CACD,MAAM,cAAc,kBAAkB,KAAK;EAAE;EAAW;CAAa,CAAC;CACtE,MAAM,UAAU,iBAAiB,EAAE,UAAU,CAAC;CAE9C,MAAM,EAAE,kBAAkB,uBAAuB,uBAAuB;CACxE,MAAM,YAAY,gBAAgB;EAAE;EAAK,MAAM;EAAS;EAAY;EAAkB;CAAiB,CAAC;CACxG,MAAM,EAAE,gBAAgB,cAAc;CAEtC,MAAM,YAAmE,CAAC;CAC1E,MAAM,EAAE,UAAU,UAAU,QAAQ,kBAAkB,eAAe;EAAE;EAAK,cAAc,UAAU,QAAQ;EAAc,YAAW,cAAa,YAAY,UAAU,SAAS;EAAG,UAAS,cAAa,KAAK,UAAU,SAAS,uBAAuB,SAAS;CAAE,CAAC;CACrQ,MAAM,UAAU,qBAAqB;EAAE;EAAU,cAAc,UAAU,QAAQ;EAAc,WAAW,IAAI;EAAW,eAAe,IAAI,YAAY;CAAE,CAAC;CAE3J,MAAM,gBAAgB,oBAAoB;EACxC,OAAO,IAAI;EACX;EACA,oBAAoB,IAAI,aAAa;EACrC,aAAY,SAAQ,WAAW,IAAI;EACnC,MAAM;EACN,OAAO,YAAY;EACnB,WAAW,YAAY;EACvB,cAAa,cAAa,OAAO,IAAI,SAAS,CAAC,EAAE,MAAM,WAAW,KAAA;EAClE,WAAW;EACX,eAAe,UAAU;CAC3B,CAAC;CACD,eAAe,aAAa;CAE5B,MAAM,gBAAgB,sBAAsB,GAAG;CAC/C,MAAM,gBAAgB,oBAAoB;CAO1C,MAAM,WAAW,oBAAoB;EACnC,KAAK;GACH,GAAG;GACH,eAAe,OAAO,QAAQ;IAC5B,MAAM,aAAa,mBAAmB;IACtC,MAAM,SAAS,MAAM,IAAI,cAAc,GAAG;IAC1C,mBAAmB,UAAU;IAC7B,OAAO;GACT;EACF;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,MAAM,eAAe,mBAAmB;EACtC;EACA;EACA;EACA;EACA,YAAY,IAAI;EAChB,cAAc,IAAI;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;EACA,kBAAkB,UAAU;EAC5B,mBAAmB,UAAU;EAC7B;EACA;EACA;CACF,CAAC;CACD,MAAM,SAAS,UAAU,UAAU,qBAAqB;EACtD;EACA;EACA;EACA;EACA;EACA,oBAAoB,UAAU;EAC9B,gBAAgB,aAAa;EAC7B;CACF,CAAC;CACD,MAAM,aAAa,iBAAiB;EAClC;EACA,MAAM;EACN,kBAAkB,OAAO;EACzB,qBAAqB,OAAO;EAC5B,wBAAwB,OAAO;EAC/B;CACF,CAAC;CACD,MAAM,OAAO,WAAW;EACtB;EACA;EACA,aAAa,OAAO;EACpB;EACA;EACA,qBAAqB,OAAO;EAC5B,iBAAiB,OAAO;EACxB;EACA,gBAAgB,WAAW;CAC7B,CAAC;CACD,MAAM,QAAQ,YAAY;EAAE;EAAK,YAAY,KAAK;EAAY,iBAAgB,cAAa,UAAU,aAAa,IAAI,SAAS;CAAE,CAAC;CAClI,MAAM,WAAW,eAAe;EAAE;EAAK,MAAM;EAAS;EAAc;EAAW;EAAO;EAAQ;EAAW;CAAc,CAAC;CAExH,MAAM,OAAiB;EACrB;EACA;EACA;EACA;EACA,YAAY,KAAK;EACjB,WAAW,IAAI;EACf;EACA,GAAG,QAAQ;EACX,cAAc,OAAO,KAAK,SAAS,SAAS,aAAa,QAAQ,aAAa,KAAK,IAAI,CAAC;EACxF,qBAAqB,OAAO,KAAK,MAAM,YAAY,SAAS,SAAS,oBAAoB,QAAQ,aAAa,KAAK,IAAI,GAAG,MAAM,UAAU;EAC1I,GAAG;EACH,GAAG,MAAM;EAET,iBAAiB,WAAW;GAC1B,MAAM,QAAQ,OAAO,IAAI,SAAS;GAClC,IAAI,OACF,MAAM,aAAa,KAAK,IAAI;GAC9B,OAAO,cAAc,SAAS;EAChC;EAEA,mBAAmB;GACjB,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,GAAG,GAAG,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAI,eAAc;IAC9E;IACA,SAAS,cAAc,SAAS;GAClC,EAAE;EACJ;EAEA,aAAa,WAAW;GACtB,OAAO,OAAO,IAAI,SAAS,CAAC,EAAE,MAAM,SAAS,SAAS;EACxD;EAEA,eAAe,WAAW;GACxB,OAAO,OAAO,IAAI,SAAS,CAAC,EAAE,MAAM,WAAW;EACjD;EAEA,gBAAgB;GACd,IAAI,WAAW,OAAO,KAAK,cAAc,OAAO,GAC9C,OAAO;GAET,IAAI,UAAU,gBAAgB,GAC5B,OAAO;GACT,KAAK,MAAM,SAAS,OAAO,OAAO,GAIhC,IAAI,MAAM,MAAM,aAAa,MAAM,cAAc,MAAM,iBAAiB,KAAA,KAAa,MAAM,KAAK,OAAO,GACrG,OAAO;GAEX,OAAO;EACT;EAEA,GAAG,kBAAkB,MAAM;EAC3B,GAAG,kBAAkB;GAAE;GAAQ;EAAU,CAAC;EAC1C,GAAG,UAAU;EACb,GAAG,WAAW;EACd;EACA,GAAG,oBAAoB;GAAE;GAAK;GAAQ,aAAa,OAAO;EAAY,CAAC;EACvE,GAAG,OAAO;EAEV,uBAAuB,WAAW;GAChC,OAAO,uBAAuB,SAAS;EACzC;EAEA,oBAAoB,4BAA4B;GAAE;GAAiB;GAAQ,wBAAwB,OAAO;GAAwB,WAAW,EAAE,cAAa,QAAO,QAAQ,QAAQ,GAAG,CAAC,CAAC,IAAI;EAAE,CAAC;EAC/L,mBAAmB,QAAQ,MAAM;GAE/B,MAAM,mBAAmB;IADH;IAAY;IAAiB;GACf,CAAC,CAAC,MAAK,QAAQ,OAAO,SAAS,WAAY,KAAK,SAAS,MAAM;GAOnG,IAAI,EANiB,oBAChB,QAAQ,OAAO,cAAc,MAAM,QAAQ,KAAK,cAAc,KAE9D,QAAQ,OAAO,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAEjD,OAAO,oBAAoB,gBAAiB,KAAK,oBAAoB,cAEzE;GACF,IAAI,oBAAoB,KAAK,aAAa,OACxC,UAAe,mBAAmB;GACpC,KAAU,iBAAiB;EAC7B;EAEA,mBAAmB,wBAAwB;GAAE;GAAQ;GAAW,OAAO,IAAI;GAAO,aAAa,OAAO;EAAY,CAAC;EACnH,uBAAuB,WAAW,SAAS,yBAAyB;GAAE;GAAK;GAAe,mBAAmB,GAAG,SAAS,KAAK,iBAAiB,GAAG,IAAI;EAAE,GAAG,WAAW,IAAI;EAC1K,GAAG;CACL;CAIA,QAAQ,2BAA2B,KAAK,KAAK,iBAAiB,CAAC;CAC/D,UAAU,qBAAqB,KAAK,KAAK,iBAAiB,CAAC;CAC3D,UAAU,kBAAkB,KAAK,gBAAgB;CAEjD,OAAO;CAKP,SAAS,UAAoB;EAC3B,OAAO;CACT;CACA,SAAS,YAAY,WAAuC;EAC1D,OAAO,OAAO,YAAY,SAAS;CACrC;CACA,SAAS,iBAAiB,WAAyB;EACjD,OAAO,iBAAiB,SAAS;CACnC;CACA,SAAS,WAAW,MAA+C;EACjE,OAAO,KAAK,WAAW,IAAI;CAC7B;CACA,SAAS,WAAW,WAAyB;EAC3C,MAAM,WAAW,SAAS;CAC5B;CACA,SAAS,UAAU,WAAyB;EAC1C,MAAM,UAAU,SAAS;CAC3B;CACA,SAAS,QAAQ,WAAkC;EACjD,OAAO,MAAM,QAAQ,SAAS;CAChC;AACF;;;;ACzQA,MAAM,aAAa;CAAC;CAAgB;CAAU;CAAU;AAAM;;;;;AAM9D,SAAgB,eAAe,WAAuC,UAA8C;CAClH,MAAM,yBAAS,IAAI,IAA+B;CAClD,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,OAAO,OAAO,IAAI,SAAS,IAAI,KAAK,CAAC;EAC3C,KAAK,KAAK;GAAE;GAAU,KAAK,kBAAkB,UAAU,QAAQ;EAAE,CAAC;EAClE,OAAO,IAAI,SAAS,MAAM,IAAI;CAChC;CAQA,OAPc,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM;EAC9C,MAAM,KAAK,WAAW,QAAQ,CAAC;EAC/B,MAAM,KAAK,WAAW,QAAQ,CAAC;EAC/B,IAAI,OAAO,MAAM,OAAO,IACtB,QAAQ,OAAO,KAAK,WAAW,SAAS,OAAO,OAAO,KAAK,WAAW,SAAS;EACjF,OAAO,EAAE,cAAc,CAAC;CAC1B,CACW,CAAC,CAAC,KAAI,UAAS;EAAE;EAAM,OAAO,kBAAkB,MAAM,QAAQ;EAAG,MAAM,OAAO,IAAI,IAAI;CAAG,EAAE;AACxG;;AAGA,SAAgB,wBAAwB,WAAuC,UAAiC;CAC9G,OAAO,eAAe,WAAW,QAAQ,CAAC,CACvC,KAAI,MAAK,GAAG,EAAE,KAAK,OAAO,GAAG,cAAc,EAAE,OAAO,EAAE,KAAK,MAAM,GAAG,CAAC,CACrE,KAAK,KAAK;AACf;AAEA,SAAS,cAAc,OAAe,OAAuB;CAC3D,MAAM,QAAQ,MAAM,YAAY;CAChC,IAAI,UAAU,GACZ,OAAO;CACT,OAAO,iBAAiB,KAAK,KAAK,IAAI,GAAG,MAAM,MAAM,GAAG,MAAM;AAChE;;;;AC9DA,SAAgB,YAAY,MAAyB,MAAyB,QAAQ,KAAc;CAClG,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,IAAI,IAAI;EACd,IAAI,MAAM,KAAA,KAAa,MAAM,MAAM,MAAM,OAAO,EAAE,YAAY,MAAM,SAClE,OAAO;CACX;CACA,OAAO;AACT;;;AC0IA,MAAMC,iBAAe;CAAC;CAAoB;CAAsB;AAAI;AAEpE,SAAS,WAAW,MAAyB,QAAQ,KAAc;CACjE,OAAO,YAAYA,gBAAc,GAAG;AACtC;AAeA,SAAgB,YAAY,OAA6F;CACvH,MAAM,IAAI,uDAAuD,KAAK,MAAM,KAAK,CAAC;CAClF,IAAI,CAAC,GACH,OAAO;CACT,OAAO;EACL,OAAO,OAAO,EAAE,EAAE;EAClB,OAAO,OAAO,EAAE,EAAE;EAClB,OAAO,OAAO,EAAE,EAAE;EAClB,YAAY,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC;CACxC;AACF;;AAGA,SAAgB,cAAc,GAAW,GAAuB;CAC9D,MAAM,IAAI,YAAY,CAAC;CACvB,MAAM,IAAI,YAAY,CAAC;CACvB,IAAI,CAAC,KAAK,CAAC,GACT,OAAO;CACT,KAAK,MAAM,KAAK;EAAC;EAAS;EAAS;CAAO,GACxC,IAAI,EAAE,OAAO,EAAE,IACb,OAAO,EAAE,KAAK,EAAE,KAAK,KAAK;CAG9B,IAAI,EAAE,WAAW,WAAW,KAAK,EAAE,WAAW,SAAS,GACrD,OAAO;CACT,IAAI,EAAE,WAAW,SAAS,KAAK,EAAE,WAAW,WAAW,GACrD,OAAO;CACT,MAAM,MAAM,KAAK,IAAI,EAAE,WAAW,QAAQ,EAAE,WAAW,MAAM;CAC7D,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,KAAK;EAC5B,MAAM,KAAK,EAAE,WAAW;EACxB,MAAM,KAAK,EAAE,WAAW;EACxB,IAAI,OAAO,KAAA,GACT,OAAO;EACT,IAAI,OAAO,KAAA,GACT,OAAO;EACT,MAAM,KAAK,QAAQ,KAAK,EAAE,IAAI,OAAO,EAAE,IAAI;EAC3C,MAAM,KAAK,QAAQ,KAAK,EAAE,IAAI,OAAO,EAAE,IAAI;EAC3C,IAAI,OAAO,QAAQ,OAAO,MACpB;OAAA,OAAO,IACT,OAAO,KAAK,KAAK,KAAK;EAAA,OAErB,IAAI,OAAO,MACd,OAAO;OAEJ,IAAI,OAAO,MACd,OAAO;OAEJ,IAAI,OAAO,IACd,OAAO,KAAK,KAAK,KAAK;CAE1B;CACA,OAAO;AACT;AAeA,SAAS,cAAc,UAAkB,aAAqB,SAAyB;CAGrF,MAAM,OAAO,GAAG,YAAY,WAAW,KAAK,IAAI,EAAE,GAAG;CACrD,OAAO,QAAQ,UAAU,gBAAgB,KAAK,MAAM;AACtD;AAEA,SAAS,UAAU,MAAsC;CACvD,IAAI;EACF,MAAM,MAAM,aAAa,MAAM,MAAM;EACrC,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,cAAc,UACnE,OAAO;EACT,OAAO;CACT,QACM;EACJ,OAAO;CACT;AACF;AAEA,SAAS,WAAW,MAAc,OAA8B;CAC9D,IAAI;EACF,UAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EAG5C,cAAc,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,EAAE,GAAG;CAC3D,QACM,CAEN;AACF;;AAOA,SAAS,UAAU,GAAmB;CACpC,OAAO,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,IAAI;AAC5C;AAOA,eAAe,mBAAmB,MAON;CAK1B,MAAM,MAAM,GAAG,UAAU,KAAK,QAAQ,EAAE,GAAG,mBAAmB,KAAK,WAAW,EAAE,GAAG,mBAAmB,KAAK,OAAO;CAClH,MAAM,UAAkC;EACtC,UAAU;EACV,cAAc;CAChB;CACA,IAAI,KAAK,MACP,QAAQ,mBAAmB,KAAK;CAClC,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK;EAAE;EAAS,QAAQ,KAAK;EAAQ,UAAU;CAAS,CAAC;CACxF,IAAI,IAAI,WAAW,KAGjB,MAAM,IAAI,iBAAiB;CAE7B,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,MAAM,qBAAqB,IAAI,QAAQ;CACnD,MAAM,OAAO,MAAM,IAAI,KAAK;CAC5B,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MAAM,oCAAoC;CACtD,OAAO;EAAE,QAAQ,KAAK;EAAS,MAAM,IAAI,QAAQ,IAAI,MAAM;CAAE;AAC/D;AAEA,IAAM,mBAAN,cAA+B,MAAM;CACnC,cAAc;EAAE,MAAM,cAAc;CAAE;AACxC;;;;;;;;;;AAeA,eAAsB,eAAe,SAAuD;CAC1F,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,MAAM,QAAQ,OAAO,KAAK;CAChC,MAAM,UAAU,QAAQ,WAAW,WAAW;CAC9C,MAAM,MAAM,QAAQ,cAAc;CAClC,MAAM,YAAY,QAAQ,aAAa;CAEvC,IAAI,CAAC,QAAQ,SAAS,WAAW,GAC/B,OAAO,QAAQ,QAAQ,gBAAgB,OAAO;CAEhD,MAAM,YAAY,QAAQ,WACtB,cAAc,QAAQ,UAAU,QAAQ,aAAa,OAAO,IAC5D;CAQJ,MAAM,SAAS,YAAY,UAAU,SAAS,IAAI;CAClD,IAAI,CAAC,QAAQ,SAAS,UAAU,OAAO,gBAAgB,QAAQ,eAAe,OAAO,YAAY,SACjF;MAAA,MAAM,KAAM,IAAI,IAAI,OAAO,YAAa,KAC3C;GACT,MAAM,YAAY,cAAc,OAAO,QAAQ,QAAQ,cAAc,IAAI;GACzE,OAAO;IACL,SAAS,QAAQ;IACjB,QAAQ,OAAO;IACf;IACA,QAAQ;IACR,WAAW,OAAO;IAClB;GACF;EACF;;CAMF,IAAI,OAAO,YAAY,YAAY;EACjC,IAAI,QACF,OAAO;GACL,SAAS,QAAQ;GACjB,QAAQ,OAAO;GACf,WAAW,cAAc,OAAO,QAAQ,QAAQ,cAAc,IAAI;GAClE,QAAQ;GACR,WAAW,OAAO;GAClB;EACF;EAEF,OAAO,QAAQ,QAAQ,gBAAgB,OAAO;CAChD;CAIA,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,QAAQ,iBAAiB,WAAW,sBAAM,IAAI,MAAM,SAAS,CAAC,GAAG,SAAS;CAChF,IAAI,QAAQ,QAAQ;EAClB,IAAI,QAAQ,OAAO,SACjB,WAAW,MAAM,QAAQ,OAAO,MAAe;OAE/C,QAAQ,OAAO,iBAAiB,eAAe,WAAW,MAAM,QAAQ,OAAQ,MAAe,GAAG,EAAE,MAAM,KAAK,CAAC;CACpH;CAEA,IAAI;EACF,MAAM,UAAU,MAAM,mBAAmB;GACvC,UAAU,QAAQ,YAAY;GAC9B,aAAa,QAAQ;GACrB;GACA,MAAM,QAAQ;GACd;GACA,QAAQ,WAAW;EACrB,CAAC;EACD,MAAM,YAAY,IAAI;EACtB,IAAI,WACF,WAAW,WAAW;GACpB,aAAa,QAAQ;GACrB;GACA,QAAQ,QAAQ;GAChB;GACA,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;EAC/C,CAAC;EAEH,OAAO;GACL,SAAS,QAAQ;GACjB,QAAQ,QAAQ;GAChB,WAAW,cAAc,QAAQ,QAAQ,QAAQ,cAAc,IAAI;GACnE,QAAQ;GACR;GACA;EACF;CACF,SACO,KAAK;EACV,IAAI,eAAe,oBAAoB,QAAQ;GAG7C,MAAM,YAAY,IAAI;GACtB,IAAI,WACF,WAAW,WAAW;IACpB,GAAG;IACH;GACF,CAAC;GAEH,OAAO;IACL,SAAS,QAAQ;IACjB,QAAQ,OAAO;IACf,WAAW,cAAc,OAAO,QAAQ,QAAQ,cAAc,IAAI;IAClE,QAAQ;IACR;IACA;GACF;EACF;EACA,IAAI,QAGF,OAAO;GACL,SAAS,QAAQ;GACjB,QAAQ,OAAO;GACf,WAAW,cAAc,OAAO,QAAQ,QAAQ,cAAc,IAAI;GAClE,QAAQ;GACR,WAAW,OAAO;GAClB;EACF;EAEF,OAAO;GACL,SAAS,QAAQ;GACjB,QAAQ;GACR,WAAW;GACX,QAAQ;GACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GACtD,WAAW;GACX;EACF;CACF,UACQ;EACN,aAAa,KAAK;CACpB;AACF;AAEA,SAAS,QAAQ,SAAiB,SAA+B;CAC/D,OAAO;EAAE;EAAS,QAAQ;EAAM,WAAW;EAAO,QAAQ;EAAW,WAAW;EAAM;CAAQ;AAChG;AAsBA,SAAS,cAAc,MAAsB;CAI3C,IAAI;EACF,OAAO,aAAa,IAAI;CAC1B,QACM;EACJ,OAAO;CACT;AACF;;;;;;AAOA,SAAgB,cAAc,SAAgC,aAAqB,SAAyB;CAC1G,MAAM,MAAM,QAAQ,KAAK,KAAK,GAAG;CACjC,OAAO,QAAQ,OAAO,UAAU,mBAAmB,YAAY,oBAAoB,YAAY,GAAG,YAAY;AAChH;AAEA,SAAgB,qBAAqB,OAAoC,CAAC,GAA0B;CAClG,MAAM,MAAM,KAAK,OAAO,QAAQ;CAChC,MAAM,OAAO,KAAK,QAAQ,QAAQ;CACjB,KAAK,YAAY,QAAQ;CAC1C,MAAM,UAAU,KAAK,WAAW;CAChC,MAAM,cAAc,KAAK,eAAe;CACxC,MAAM,aAAa,KAAK,cAAc,QAAQ;CAC9C,MAAM,iBAAiB,cAAc,UAAU;CAC/C,MAAM,YAAY,KAAK,aAAa,IAAI;CAOxC,MAAM,SAAS,GAAG,YAAY,GAAG;CAQjC,MAAM,mBAAmB,MAAc,YAAoB;EAGzD,MAAM,OAAO,GAAG,UAAU;EAC1B,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,OAAO;CACrD;CACA,MAAM,UAAU,YACd,gBAAgB,gBAAgB,OAAO,KAAK,gBAAgB,YAAY,OAAO;CACjF,MAAM,WAAW,SAAiB,GAAG,OAAO,MAAM;CAIlD,IAAI,OAAO,QAAQ,QAAQ,CAAC,GAC1B,OAAO;EACL,IAAI;EACJ,MAAM;GAAC;GAAS;GAAW;EAAM;EACjC,MAAM;CACR;CAEF,IAAI,OAAO,QAAQ,MAAM,CAAC,GACxB,OAAO;EACL,IAAI;EACJ,MAAM;GAAC;GAAO;GAAO;GAAY;EAAM;EACvC,MAAM;CACR;CAEF,IACE,OAAO,QAAQ,mBAAmB,CAAC,KAChC,OAAO,QAAQ,cAAc,CAAC,KAC9B,eAAe,SAAS,GAAG,IAAI,MAAM,KAAK,GAE7C,OAAO;EACL,IAAI;EACJ,MAAM;GAAC;GAAQ;GAAO;GAAY;EAAM;EACxC,MAAM;CACR;CAEF,IAAI,OAAO,QAAQ,OAAO,CAAC,GACzB,OAAO;EACL,IAAI;EACJ,MAAM;GAAC;GAAQ;GAAU;GAAO;EAAM;EACtC,MAAM;CACR;CAQF,IAAI,WAAW;EACb,MAAM,KAAK,UAAU,YAAY;EACjC,IAAI,GAAG,WAAW,OAAO,GACvB,OAAO;GAAE,IAAI;GAAQ,MAAM;IAAC;IAAQ;IAAO;IAAY;GAAM;EAAE;EACjE,IAAI,GAAG,WAAW,OAAO,GACvB,OAAO;GAAE,IAAI;GAAQ,MAAM;IAAC;IAAQ;IAAU;IAAO;GAAM;EAAE;EAC/D,IAAI,GAAG,WAAW,MAAM,GACtB,OAAO;GAAE,IAAI;GAAO,MAAM;IAAC;IAAO;IAAO;IAAY;GAAM;EAAE;EAC/D,IAAI,GAAG,WAAW,MAAM,GACtB,OAAO;GAAE,IAAI;GAAO,MAAM;IAAC;IAAO;IAAW;IAAY;GAAM;EAAE;CACrE;CAOA,IAAI,IAAI,YACN,OAAO;EAAE,IAAI;EAAS,MAAM;GAAC;GAAS;GAAW;EAAM;EAAG,MAAM;CAA6G;CAC/K,IAAI,IAAI,aACN,OAAO;EAAE,IAAI;EAAO,MAAM;GAAC;GAAO;GAAO;GAAY;EAAM;CAAE;CAC/D,IAAI,IAAI,WACN,OAAO;EAAE,IAAI;EAAQ,MAAM;GAAC;GAAQ;GAAO;GAAY;EAAM;CAAE;CAKjE,OAAO;EACL,IAAI;EACJ,MAAM;GAAC;GAAO;GAAW;GAAY;EAAM;CAC7C;AACF;;;;;;;;;;;;;AA2BA,eAAsB,sBAAsB,MAAyE;CACnH,MAAM,UAAU,KAAK,WAAW,WAAW;CAC3C,MAAM,WAAW,UAAU,KAAK,YAAY,4BAA4B;CACxE,MAAM,KAAK,IAAI,gBAAgB;CAC/B,MAAM,QAAQ,iBAAiB,GAAG,MAAM,GAAG,KAAK,aAAa,GAAI;CACjE,IAAI;EACF,MAAM,WAAW,MAAM,QACrB,GAAG,SAAS,GAAG,mBAAmB,KAAK,WAAW,EAAE,GAAG,mBAAmB,KAAK,OAAO,KACtF;GAAE,SAAS;IAAE,UAAU;IAAoB,cAAc;GAAwB;GAAG,QAAQ,GAAG;GAAQ,UAAU;EAAS,CAC5H;EACA,IAAI,SAAS,WAAW,KACtB,OAAO;EACT,IAAI,CAAC,SAAS,IACZ,OAAO;EAET,MAAM,WAAU,MADG,SAAS,KAAK,EAAA,CACZ,MAAM;EAC3B,IAAI,CAAC,SACH,OAAO;EACT,MAAM,OAAO,MAAM,QAAQ,SAAS;GAAE,QAAQ;GAAQ,QAAQ,GAAG;GAAQ,UAAU;EAAS,CAAC;EAC7F,IAAI,KAAK,WAAW,KAClB,OAAO;EACT,OAAO,KAAK,KAAK,OAAO;CAC1B,QACM;EACJ,OAAO;CACT,UACQ;EACN,aAAa,KAAK;CACpB;AACF;;;;;;;AAwCA,eAAsB,kBAAkB,SAA8D;CACpG,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,UAAU,QAAQ,kBAAkB,QAAQ,mBAAmB,SACjE,gBAAgB,QAAQ,gBAAgB,QAAQ,aAAa,QAAQ,WAAW,QAAQ,IACxF,OAAO;EAAE,aAAa,QAAQ;EAAa,SAAS,QAAQ,WAAW;CAAS,CAAC;CAErF,IAAI,QAAQ,QACV,OAAO;EAAE;EAAS,UAAU;CAAK;CAEnC,MAAM,WAAW,QAAQ,SAAS;CAClC,OAAO,MAAM,IAAI,SAA2B,aAAa;EACvD,MAAM,CAAC,KAAK,GAAG,QAAQ,QAAQ;EAC/B,MAAM,QAAQ,SAAS,KAAM,MAAM;GACjC,OAAO,QAAQ,UAAU,QAAQ,SAC7B;IAAC;IAAU;IAAQ;GAAM,IACzB;GACJ,KAAK;IAAE,GAAG,QAAQ;IAAK,GAAG,QAAQ;GAAI;EACxC,CAAC;EACD,IAAI,QAAQ,UAAU,MAAM,QAC1B,MAAM,OAAO,KAAK,QAAQ,MAAM;EAClC,IAAI,QAAQ,UAAU,MAAM,QAC1B,MAAM,OAAO,KAAK,QAAQ,MAAM;EAClC,MAAM,GAAG,UAAU,QAAQ;GAGzB,SAAS;IAAE;IAAS,UAAU;IAAM,YAAY,IAAI;GAAQ,CAAC;EAC/D,CAAC;EACD,MAAM,GAAG,SAAS,SAAS;GACzB,SAAS;IAAE;IAAS,UAAU;GAAK,CAAC;EACtC,CAAC;EACD,IAAI,QAAQ,QAAQ;GAClB,MAAM,gBAAgB,MAAM,KAAK;GACjC,IAAI,QAAQ,OAAO,SACjB,QAAQ;QAER,QAAQ,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EACpE;CACF,CAAC;AACH;;AAGA,SAAgB,gBAAgB,IAAsB,aAAqB,SAAwC;CACjH,MAAM,SAAS,GAAG,YAAY,GAAG;CACjC,QAAQ,IAAR;EACE,KAAK,QAAQ,OAAO;GAAE;GAAI,MAAM;IAAC;IAAQ;IAAO;IAAY;GAAM;EAAE;EACpE,KAAK,QAAQ,OAAO;GAAE;GAAI,MAAM;IAAC;IAAQ;IAAU;IAAO;GAAM;EAAE;EAClE,KAAK,OAAO,OAAO;GAAE;GAAI,MAAM;IAAC;IAAO;IAAO;IAAY;GAAM;EAAE;EAClE,KAAK,SAAS,OAAO;GAAE;GAAI,MAAM;IAAC;IAAS;IAAW;GAAM;EAAE;EAE9D,SAAS,OAAO;GAAE,IAAI;GAAO,MAAM;IAAC;IAAO;IAAW;IAAY;GAAM;EAAE;CAC5E;AACF;;;;;;;AAuDA,eAAsB,yBAAyB,SAAoE;CACjH,IAAI,QAAQ,aAAa,SACvB,OAAO;EAAE,QAAQ;EAAW,QAAQ;CAA0E;CAEhH,MAAM,aAAa,QAAQ,cAAc,QAAQ;CACjD,MAAM,WAAW,cAAc,UAAU;CAEzC,IADgB,QAAQ,qBACX,MAAK,MAAK,SAAS,WAAW,CAAC,CAAC,GAC3C,OAAO;EAAE,QAAQ;EAAW,QAAQ,aAAa,SAAS;CAA0F;CAItJ,IAAI,SAAS,SAAS,GAAG,QAAQ,IAAI,IAAI,QAAQ,KAAK,GACpD,OAAO;EAAE,QAAQ;EAAW,QAAQ;CAAuF;CAG7H,MAAM,UAAU,QAAQ,WAAW,WAAW;CAC9C,IAAI,OAAO,YAAY,YACrB,OAAO;EAAE,QAAQ;EAAU,QAAQ;CAA2D;CAEhG,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,YAAY,QAAQ,aAAa;CAGvC,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,QAAQ,iBAAiB,WAAW,sBAAM,IAAI,MAAM,SAAS,CAAC,GAAG,SAAS;CAChF,IAAI,QAAQ,QAAQ;EAClB,IAAI,QAAQ,OAAO,SACjB,WAAW,MAAM,QAAQ,OAAO,MAAe;OAE/C,QAAQ,OAAO,iBAAiB,eAAe,WAAW,MAAM,QAAQ,OAAQ,MAAe,GAAG,EAAE,MAAM,KAAK,CAAC;CACpH;CAEA,IAAI;EAEF,MAAM,UAAU,MAAM,QAAQ,GADX,UAAU,QAAQ,EAAE,GAAG,mBAAmB,QAAQ,WAAW,EAAE,GAAG,mBAAmB,OAAO,KACxE;GACrC,SAAS;IAAE,UAAU;IAAoB,cAAc;GAAwB;GAC/E,QAAQ,WAAW;EACrB,CAAC;EACD,IAAI,CAAC,QAAQ,IACX,OAAO;GAAE,QAAQ;GAAU,QAAQ,qBAAqB,QAAQ,OAAO,OAAO,QAAQ,YAAY,GAAG;EAAU;EACjH,MAAM,OAAO,MAAM,QAAQ,KAAK;EAIhC,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,MAAM,SAC/B,OAAO;GAAE,QAAQ;GAAU,QAAQ,mDAAmD,QAAQ,YAAY,GAAG;EAAU;EAKzH,IAAI,CAAC,KAAK,KAAK,aAAa,CAAC,KAAK,KAAK,QACrC,OAAO;GAAE,QAAQ;GAAU,QAAQ,mDAAmD,QAAQ,YAAY,GAAG,QAAQ;EAAqC;EAM5J,MAAM,YAAY,QAAQ,UAAU;EACpC,IAAI;EACJ,IAAI;GACF,aAAa,YAAY,KAAK,WAAW,iBAAiB,CAAC;EAC7D,QACM;GACJ,aAAa,YAAY,KAAK,OAAO,GAAG,gBAAgB,CAAC;EAC3D;EACA,MAAM,cAAc,KAAK,YAAY,aAAa;EAElD,IAAI;GACF,MAAM,SAAS,MAAM,QAAQ,KAAK,KAAK,SAAS;IAC9C,SAAS,EAAE,cAAc,wBAAwB;IACjD,QAAQ,WAAW;GACrB,CAAC;GACD,IAAI,CAAC,OAAO,MAAM,CAAC,OAAO,MACxB,OAAO;IAAE,QAAQ;IAAU,QAAQ,4BAA4B,OAAO;GAAS;GACjF,MAAM,UAAU,MAAM,aAAa,OAAO,MAAM,WAAW;GAM3D,MAAM,iBAAiB,gBAAgB,KAAK,MAAM,OAAO;GACzD,IAAI,CAAC,eAAe,IAClB,OAAO;IAAE,QAAQ;IAAU,QAAQ,2BAA2B,eAAe;GAAS;GAGxF,MAAM,oBAAoB,QAAQ,qBAC7B,OAAO,eAAe,UAAU;GACrC,MAAM,gBAAgB,MAAM,wBAAwB,aAAa,mBAAmB,UAAU;GAC9F,IAAI,CAAC,eACH,OAAO;IAAE,QAAQ;IAAU,QAAQ,2BAA2B;GAAoB;GAEpF,IAAI,QAAQ,QACV,OAAO;IAAE,QAAQ;IAAW,kBAAkB,KAAK;IAAS,YAAY;GAAc;GAIxF,UAAU,eAAe,GAAK;GAC9B,MAAM,gBAAgB;GACtB,IAAI;IACF,WAAW,eAAe,aAAa;GACzC,SACO,KAAK;IACV,OAAO;KAAE,QAAQ;KAAU,QAAQ,mBAAmB,cAAc,IAAI,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IAAI;GAC7H;GACA,OAAO;IAAE,QAAQ;IAAW,kBAAkB,KAAK;IAAS,YAAY;GAAc;EACxF,UACQ;GACN,IAAI;IAAE,OAAO,YAAY;KAAE,WAAW;KAAM,OAAO;IAAK,CAAC;GAAE,QACrD,CAAoB;EAC5B;CACF,SACO,KAAK;EACV,OAAO;GAAE,QAAQ;GAAU,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAAE;CACtF,UACQ;EACN,aAAa,KAAK;CACpB;AACF;AAEA,SAAS,eAAe,MAAsB;CAC5C,MAAM,OAAO,KAAK,MAAM,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK;CAC3C,OAAO,KAAK,SAAS,MAAM,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AACrD;;;;;;;AAcA,eAAe,aAAa,MAAkC,MAAsC;CAClG,MAAM,OAAO,kBAAkB,IAAI;CACnC,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,SAAS,WAAW,QAAQ;CAClC,IAAI,OAAO;CACX,MAAM,SAAS,KAAK,UAAU;CAC9B,IAAI;EACF,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAC1C,IAAI,MACF;GACF,IAAI,SAAS,MAAM,aAAa,GAAG;IACjC,KAAK,OAAO,KAAK;IACjB,OAAO,OAAO,KAAK;IACnB,QAAQ,MAAM;IACd,MAAM,IAAI,SAAe,KAAK,QAAQ,KAAK,MAAM,QAAO,QAAO,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC;GACxF;EACF;CACF,UACQ;EACN,MAAM,IAAI,SAAc,QAAO,KAAK,UAAU,IAAI,CAAC,CAAC;CACtD;CACA,OAAO;EACL,MAAM,KAAK,OAAO,KAAK;EACvB,cAAc,OAAO,OAAO,QAAQ;EACpC;CACF;AACF;;;;;;;;AASA,SAAS,gBACP,MACA,SAC8C;CAC9C,IAAI,KAAK,WAAW;EAElB,MAAM,UAAU,KAAK,UAAU,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;EAC1D,KAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,IAAI,8BAA8B,KAAK,KAAK;GAClD,IAAI,CAAC,GACH;GACF,MAAM,OAAO,EAAE;GACf,MAAM,WAAW,EAAE;GACnB,IAAI,SAAS,YAAY,QAAQ,iBAAiB,UAChD,OAAO,EAAE,IAAI,KAAK;GAIpB,IAAI,SAAS,UACX,OAAO;IAAE,IAAI;IAAO,QAAQ,+BAA+B,KAAK;GAAsC;EAC1G;EACA,OAAO;GAAE,IAAI;GAAO,QAAQ;EAAyE;CACvG;CACA,IAAI,KAAK,QAAQ;EACf,IAAI,QAAQ,SAAS,KAAK,OAAO,YAAY,GAC3C,OAAO,EAAE,IAAI,KAAK;EACpB,OAAO;GAAE,IAAI;GAAO,QAAQ;EAAwE;CACtG;CACA,OAAO;EAAE,IAAI;EAAO,QAAQ;CAA8C;AAC5E;AASA,eAAe,wBACb,aACA,cACA,QACwB;CACxB,MAAM,cAAc,IAAI;CACxB,MAAM,MAAM,KAAK,QAAQ,YAAY;CAIrC,MAAM,SAAuB,CAAC;CAC9B,MAAM,SAAS,aAAa;CAC5B,MAAM,QAAQ,iBAAiB,WAAW;CAC1C,MAAM,IAAI,SAAe,KAAK,QAAQ;EACpC,OAAO,GAAG,SAAS,MAAc,OAAO,KAAK,CAAC,CAAC;EAC/C,OAAO,GAAG,aAAa,IAAI,CAAC;EAC5B,OAAO,GAAG,SAAS,GAAG;EACtB,MAAM,GAAG,SAAS,GAAG;EACrB,MAAM,KAAK,MAAM;CACnB,CAAC;CACD,MAAM,MAAM,aAAa,MAAM;CAC/B,IAAI,SAAS;CACb,OAAO,SAAS,OAAO,IAAI,QAAQ;EACjC,MAAM,SAAS,IAAI,SAAS,QAAQ,SAAS,GAAG;EAChD,IAAI,OAAO,OAAM,MAAK,MAAM,CAAC,GAC3B;EACF,MAAM,OAAO,cAAc,QAAQ,GAAG,GAAG;EACzC,MAAM,UAAU,cAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,KAAK;EACpD,MAAM,OAAO,YAAY,KAAK,IAAI,OAAO,SAAS,SAAS,CAAC;EAC5D,MAAM,YAAY,SAAS;EAC3B,MAAM,UAAU,YAAY;EAC5B,IAAI,SAAS,SAAS,gBAAgB,KAAK,SAAS,WAAW,IAAI;GACjE,cAAc,KAAK,IAAI,SAAS,WAAW,OAAO,CAAC;GACnD,OAAO;EACT;EAEA,SAAS,WAAY,MAAO,OAAO,OAAQ;CAC7C;CACA,OAAO;AACT;AAEA,SAAS,cAAc,KAAiB,OAAe,KAAqB;CAC1E,MAAM,MAAM,QAAQ;CACpB,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,KAC3B,IAAI,IAAI,OAAO,GAAG;EAAE,OAAO;EAAG;CAAM;CAEtC,OAAO,IAAI,YAAY,MAAM,CAAC,CAAC,OAAO,IAAI,SAAS,OAAO,IAAI,CAAC;AACjE;AAEA,SAAS,aAAa,QAAkC;CACtD,IAAI,QAAQ;CACZ,KAAK,MAAM,KAAK,QAAQ,SAAS,EAAE;CACnC,MAAM,MAAM,IAAI,WAAW,KAAK;CAChC,IAAI,SAAS;CACb,KAAK,MAAM,KAAK,QAAQ;EACtB,IAAI,IAAI,GAAG,MAAM;EACjB,UAAU,EAAE;CACd;CACA,OAAO;AACT;AAqBA,SAAgB,uBAAuB,OAA+B,CAAC,GAAkB;CACvF,MAAM,WAAW,KAAK,YAAY,QAAQ;CAC1C,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAClC,MAAM,OAAO,KAAK,QAAQ,WAAW;CACrC,MAAM,SAAS,KAAK,UAAU;CAC9B,IAAI,aAAa,UAAU;EACzB,IAAI,SAAS,SACX,OAAO,GAAG,OAAO;EACnB,IAAI,SAAS,OACX,OAAO,GAAG,OAAO;EACnB,OAAO;CACT;CACA,IAAI,aAAa,SAAS;EACxB,IAAI,SAAS,SACX,OAAO;EACT,IAAI,SAAS,SACX,OAAO,GAAG,OAAO;EACnB,IAAI,SAAS,OACX,OAAO,GAAG,OAAO;EACnB,OAAO;CACT;CACA,OAAO;AACT;;AAGA,SAAgB,aAA+B;CAC7C,IAAI,QAAQ,aAAa,SACvB,OAAO;CACT,IAAI;EAEF,MAAM,EAAE,aAAA,UAAqB,oBAAoB;EAEjD,OADY,SAAS,sBAAsB;GAAE,UAAU;GAAQ,OAAO;IAAC;IAAU;IAAQ;GAAM;EAAE,CACxF,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI,SAAS;CACvD,QACM;EACJ,OAAO;CACT;AACF;;;;;;;AC7kCA,SAAgB,uBAAuB,MAAqB,OAA6B,CAAC,GAA8B;CACtH,MAAM,MAAM,KAAK,OAAO,QAAQ;CAChC,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAClC,MAAM,WAAW,KAAK,YAAY,QAAQ;CAG1C,MAAM,aAAa,WAFH,KAAK,WAAW,KAAK,aAEE,IAAI,QAAQ,IAAI,QAAQ;CAC/D,IAAI,CAAC,YACH,OAAO;CAET,MAAM,aAAa,kBAAkB,KAAK,aAAa,YAAY,IAAI;CACvE,IAAI,CAAC,YACH,OAAO;CAET,MAAM,UAAU,mBAAmB,YAAY,KAAK,WAAW;CAC/D,IAAI,CAAC,SACH,OAAO;CAET,OAAO;EAAE,aAAa,KAAK;EAAa;EAAS;EAAY;CAAW;AAC1E;AAEA,SAAS,WAAW,SAAiB,SAAiB,UAA0C;CAC9F,MAAM,aAAa,aAAa,UAAU;EAAC;EAAS,GAAG,QAAQ;EAAO,GAAG,QAAQ;CAAK,IAAI,CAAC,OAAO;CAClG,KAAK,MAAM,OAAO,QAAQ,MAAM,SAAS,GAAG;EAC1C,IAAI,CAAC,KACH;EACF,KAAK,MAAM,QAAQ,YAAY;GAC7B,MAAM,OAAO,KAAK,KAAK,IAAI;GAC3B,IAAI;IACF,IAAI,SAAS,IAAI,CAAC,CAAC,OAAO,GACxB,OAAO;GACX,QACM,CAEN;EACF;CACF;CACA,OAAO;AACT;;;;;;;;;;AAWA,SAAS,kBAAkB,aAAqB,YAAoB,MAA6B;CAC/F,IAAI,WAAW;CACf,IAAI;EACF,WAAW,aAAa,UAAU;CACpC,QACM,CAEN;CAEA,MAAM,UAAU,eAAe,QAAQ,QAAQ,GAAG,WAAW;CAC7D,IAAI,SACF,OAAO;CAET,MAAM,YAAY,aAAa,YAAY,UAAU,IAAI;CACzD,IAAI,WAAW;EACb,MAAM,MAAM,KAAK,WAAW,SAAS,SAAS,YAAY,aAAa,OAAO,gBAAgB,WAAW;EACzG,IAAI,WAAW,KAAK,KAAK,cAAc,CAAC,GACtC,OAAO;CACX;CACA,OAAO;AACT;AAEA,SAAS,eAAe,OAAe,aAAoC;CACzE,IAAI,MAAM;CACV,KAAK,IAAI,QAAQ,GAAG,QAAQ,GAAG,SAAS;EACtC,IAAI,mBAAmB,KAAK,WAAW,GACrC,OAAO;EACT,MAAM,SAAS,QAAQ,GAAG;EAC1B,IAAI,WAAW,KACb;EACF,MAAM;CACR;CACA,OAAO;AACT;AAEA,SAAS,aAAa,YAAoB,UAAkB,MAA6B;CACvF,MAAM,SAAS,GAAG,IAAI,QAAQ;CAC9B,KAAK,MAAM,KAAK,CAAC,YAAY,QAAQ,GAAG;EACtC,MAAM,MAAM,EAAE,QAAQ,MAAM;EAC5B,IAAI,QAAQ,IACV,OAAO,EAAE,MAAM,GAAG,MAAM,OAAO,SAAS,CAAC;CAC7C;CACA,MAAM,WAAW,KAAK,MAAM,QAAQ;CACpC,OAAO,WAAW,QAAQ,IAAI,WAAW;AAC3C;AAEA,SAAS,mBAAmB,KAAa,aAAoC;CAC3E,IAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,KAAK,KAAK,cAAc,GAAG,MAAM,CAAC;EACtE,IAAI,IAAI,SAAS,eAAe,OAAO,IAAI,YAAY,UACrD,OAAO;EACT,OAAO,IAAI;CACb,QACM;EACJ,OAAO;CACT;AACF;;;AC5HA,MAAa,wBAAwB;AASrC,SAAgB,wBAAwB,UAA0B;CAChE,OAAO,KAAK,UAAU,qBAAqB;AAC7C;;;;;AAMA,SAAgB,yBAAyB,UAAkB,QAAsC;CAC/F,IAAI;EACF,UAAU,UAAU,EAAE,WAAW,KAAK,CAAC;EACvC,cAAc,wBAAwB,QAAQ,GAAG,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,GAAG;EACvF,OAAO;CACT,QACM;EACJ,OAAO;CACT;AACF;AAEA,SAAgB,wBAAwB,UAA8C;CACpF,IAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,wBAAwB,QAAQ,GAAG,MAAM,CAAC;EAC9E,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB,OAAO;EACT,MAAM,EAAE,IAAI,aAAa;EACzB,IAAI,OAAO,OAAO,YAAY,CAAC,MAAM,QAAQ,QAAQ,GACnD,OAAO;EACT,OAAO;GACL;GACA,UAAU,SAAS,QAAO,MAAK,KAAK,OAAO,EAAE,gBAAgB,YAAY,OAAO,EAAE,YAAY,QAAQ;EACxG;CACF,QACM;EACJ,OAAO;CACT;AACF;;;;;;AAgDA,SAAgB,sBACd,MACA,gBACA,QAA+C,wBAC/C,MAAoB,KAAK,KACF;CACvB,MAAM,YAAY,iBAAiB,MAAM,IAAI,CAAC,EAAE,WAAW,OAAO;CAClE,OAAO;EACL,SAAS;EACT;EACA,iBAAiB,cAAc,QAAQ,cAAc,WAAW,cAAc,IAAI;EAClF,WAAW,IAAI;CACjB;AACF;AAEA,SAAgB,sBAAsB,SAAgE;CACpG,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,MAAM,QAAQ,OAAO,KAAK;CAChC,MAAM,UAAU,QAAQ,eAAe,SAAS;CAChD,IAAI,QAAQ,sBAAsB,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,GAAG;CAClF,IAAI,SAAS;CAEb,MAAM,WAAW,SAAgC;EAC/C,MAAM,UAAU,KAAK,cAAc,MAAM,aAAa,KAAK,oBAAoB,MAAM;EACrF,QAAQ;EACR,IAAI,WAAW,CAAC,QACd,QAAQ,SAAS,IAAI;CACzB;CACA,MAAM,cAAqC;EACzC,IAAI,CAAC,WAAW,QACd,OAAO;EACT,QAAQ,sBAAsB,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,GAAG,CAAC;EAC/E,OAAO;CACT;CAEA,IAAI,UAA4B;CAChC,IAAI,WAAiD;CACrD,IAAI,OAA8C;CAElD,IAAI,SAAS;EACX,IAAI,QAAQ,UAGV,IAAI;GACF,UAAU,QAAQ,UAAU,EAAE,WAAW,KAAK,CAAC;GAC/C,UAAU,MAAM,QAAQ,WAAW,QAAQ,aAAa;IACtD,IAAI,YAAY,SAAS,SAAS,MAAA,uBAChC;IACF,IAAI,UACF,aAAa,QAAQ;IACvB,WAAW,iBAAiB;KAC1B,WAAW;KACX,MAAM;IACR,GAAG,QAAQ,cAAc,GAAG;GAC9B,CAAC;GACD,QAAQ,GAAG,eAAe;IAGxB,SAAS,MAAM;IACf,UAAU;GACZ,CAAC;EACH,QACM;GACJ,UAAU;EACZ;EAEF,MAAM,SAAS,QAAQ,UAAU;EACjC,IAAI,SAAS,GAAG;GACd,OAAO,YAAY,OAAO,MAAM;GAEhC,IAAI,OAAO,SAAS,YAAY,WAAW,MACzC,KAAK,MAAM;EACf;CACF;CAEA,OAAO;EACL;EACA,eAAe;EACf,aAAa;GACX,SAAS;GACT,SAAS,MAAM;GACf,IAAI,UACF,aAAa,QAAQ;GACvB,IAAI,MACF,cAAc,IAAI;EACtB;CACF;AACF;;AAGA,SAAgB,uBAAuB,UAA2B;CAChE,OAAO,WAAW,wBAAwB,QAAQ,CAAC;AACrD;;;;;;AAqBA,SAAgB,mBAAmB,SAAkE;CACnG,MAAM,CAAC,OAAO,YAAY,SAAuC,IAAI;CACrE,MAAM,EAAE,MAAM,gBAAgB,UAAU,SAAS,WAAW;CAC5D,MAAM,cAAc,MAAM;CAC1B,MAAM,UAAU,MAAM;CAEtB,gBAAgB;EACd,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,gBAAgB;GAC/C,SAAS,IAAI;GACb;EACF;EACA,MAAM,UAAU,sBAAsB;GACpC,MAAM,UAAU;IAAE;IAAa;GAAQ,IAAI,EAAE,YAAY;GACzD;GACA;GACA;GACA,UAAU;EACZ,CAAC;EACD,SAAS,QAAQ,QAAQ,CAAC;EAC1B,aAAa,QAAQ,MAAM;CAC7B,GAAG;EAAC;EAAS;EAAa;EAAS;EAAgB;EAAU;CAAM,CAAC;CAEpE,OAAO;AACT;;;ACvKA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCrB,eAAsB,iBAAiB,SAAmE;CACxG,MAAM,MAAM,QAAQ,UAAU,QAAQ;CACtC,MAAM,MAAM,QAAQ,UAAU,QAAQ;CACtC,MAAM,SAAS,UAAU,QAAQ,IAAI;CACrC,IAAI,OAAO,SAAS,SAAS;EAC3B,IAAI,MAAM,mBAAmB,OAAO,QAAQ,GAAG;EAC/C,IAAI,MAAM,YAAY;EACtB,OAAO,EAAE,UAAU,EAAE;CACvB;CACA,IAAI,OAAO,MAAM;EACf,IAAI,MAAM,YAAY;EACtB,OAAO,EAAE,UAAU,EAAE;CACvB;CACA,MAAM,QAAqB;CAE3B,MAAM,UAAU,MAAM,WAAW,QAAQ,kBAAkB;CAC3D,MAAM,WAAW,MAAM,YAAY,QAAQ;CAC3C,MAAM,mBAAmB,QAAQ,yBAAyB;CAC1D,MAAM,UAAU,QAAQ,qBAAqB;CAI7C,MAAM,SAAS,MAAM,eAAe;EAClC,aAAa,QAAQ;EACrB,gBAAgB,QAAQ;EACxB;EACA;EACA,UAAU,QAAQ;EAClB,OAAO;EACP,WAAW;CACb,CAAC;CACD,MAAM,OAAc;EAClB,MAAM,QAAQ;EACd,SAAS,QAAQ;EACjB;EACA,UAAU,OAAO,WAAW,QAAQ,cAAc,OAAO,QAAQ,QAAQ,cAAc,IAAI;CAC7F;CAKA,MAAM,aAAa,MAAM,UAAU,CAAC,IAAI,MAAM,kBAAkB,SAAS,SAAS,QAAQ;CAC1F,MAAM,UAAmB,CAAC,MAAM,GAAG,UAAU;CAC7C,MAAM,SAAS,SAAiB,KAAK,OAAO,KAAK,IAAI,GAAG,QAAQ,KAAI,MAAK,EAAE,KAAK,MAAM,CAAC,CAAC;CAKxF,IAAI,MAAM,OAAO;EACf,KAAK,MAAM,KAAK,SACd,IAAI,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,WAAW,CAAC,EAAE,GAAG;EAClD,OAAO,EAAE,UAAU,EAAE;CACvB;CAKA,IAAI,OAAO,WAAW,SAAS;EAC7B,IAAI,MAAM,GAAG,KAAK,KAAK,2BAA2B,OAAO,SAAS,gBAAgB,GAAG;EACrF,IAAI,CAAC,MAAM,OAAO;GAChB,IAAI,MAAM,kCAAkC;GAC5C,OAAO,EAAE,UAAU,EAAE;EACvB;CACF;CACA,KAAK,MAAM,KAAK,WAAW,QAAO,MAAK,EAAE,OAAO,WAAW,WAAW,CAAC,MAAM,KAAK,GAChF,IAAI,MAAM,GAAG,EAAE,KAAK,2BAA2B,EAAE,OAAO,SAAS,gBAAgB,GAAG;CAEtF,MAAM,cAAc,MAAM,SAAS,KAAK;CACxC,MAAM,oBAAoB,WAAW,QAAO,MAAK,MAAM,SAAS,EAAE,QAAQ;CAC1E,KAAK,MAAM,KAAK,QAAQ,QAAO,MAAK,CAAC,EAAE,YAAY,EAAE,OAAO,WAAW,OAAO,GAC5E,IAAI,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,WAAW,CAAC,EAAE,GAAG;CAClD,IAAI,CAAC,eAAe,kBAAkB,WAAW,GAC/C,OAAO,EAAE,UAAU,EAAE;CAKvB,IAAI,WAAW;CACf,MAAM,UAA2C,CAAC;CAClD,IAAI,aAAa;EACf,WAAW,MAAM,YAAY;EAC7B,IAAI,aAAa,KAAK,CAAC,MAAM,UAAU,OAAO,QAC5C,QAAQ,KAAK;GAAE,aAAa,KAAK;GAAM,SAAS,OAAO;EAAO,CAAC;CACnE;CACA,KAAK,MAAM,KAAK,mBAAmB;EACjC,MAAM,OAAO,MAAM,iBAAiB,CAAC;EACrC,IAAI,SAAS,KAAK,CAAC,MAAM,UAAU,EAAE,OAAO,QAC1C,QAAQ,KAAK;GAAE,aAAa,EAAE;GAAM,SAAS,EAAE,OAAO;EAAO,CAAC;EAChE,IAAI,aAAa,GACf,WAAW;CACf;CAEA,IAAI,QAAQ,SAAS,KAAK,QAAQ,UAChC,CAAC,QAAQ,eAAe,yBAAA,CAA0B,QAAQ,UAAU;EAAE,IAAI,KAAK,IAAI;EAAG,UAAU;CAAQ,CAAC;CAC3G,OAAO,EAAE,SAAS;;;;;;;CAQlB,eAAe,MAAM,aAAqB,SAAmC;EAC3E,IAAI,MAAM,SAAS,MAAM,QACvB,OAAO;EAET,IAAI,MADuB,iBAAiB;GAAE;GAAa;GAAS;EAAS,CAAC,MACzD,WACnB,OAAO;EACT,IAAI,MAAM,GAAG,YAAY,GAAG,QAAQ,sEAAsE;EAC1G,OAAO;CACT;CAEA,eAAe,cAA+B;EAC5C,MAAM,SAAS,OAAO,UAAU;EAChC,IAAI,MAAM,GAAG,MAAM,KAAK,IAAI,EAAE,IAAI,KAAK,QAAQ,KAAK,OAAO,GAAG;EAE9D,IAAI,MAAM,SAAS;GACjB,MAAM,cAAc,uBAAuB,EACzC,QAAQ,QAAQ,yBAAyB,GAAG,QAAQ,YAAY,GAClE,CAAC;GACD,IAAI,CAAC,aAAa;IAChB,IAAI,MAAM,GAAG,KAAK,KAAK,2BAA2B,QAAQ,SAAS,GAAG,QAAQ,KAAK,sCAAsC;IACzH,OAAO;GACT;GACA,IAAI,OAAO,UAAU,CAAC,MAAM,MAAM,aAAa,OAAO,MAAM,GAC1D,OAAO;GACT,MAAM,SAAS,MAAM,yBAAyB;IAAE,aAAa;IAAa;IAAS;IAAU,QAAQ,MAAM;GAAO,CAAC;GACnH,IAAI,OAAO,WAAW,WAAW;IAC/B,IAAI,MAAM,GAAG,MAAM,KAAK,IAAI,EAAE,IAAI,OAAO,iBAAiB,GAAG,MAAM,SAAS,kBAAkB,KAAK,GAAG;IACtG,OAAO;GACT;GACA,IAAI,MAAM,GAAG,KAAK,KAAK,4BAA4B,OAAO,UAAU,gBAAgB,GAAG;GACvF,IAAI,OAAO,WAAW,WACpB,IAAI,MAAM,sDAAsD;GAClE,OAAO;EACT;EAIA,MAAM,cAAc,uBAAuB,EAAE,QAAQ,QAAQ,yBAAyB,GAAG,QAAQ,YAAY,GAAG,CAAC;EACjH,IAAI,OAAO,UAAU,CAAC,MAAM,MAAM,eAAe,QAAQ,aAAa,OAAO,MAAM,GACjF,OAAO;EAET,MAAM,UAAU,MAAM,iBAClB,gBAAgB,MAAM,gBAAgB,QAAQ,aAAa,OAAO,IAClE,qBAAqB;GAAE,aAAa,QAAQ;GAAa;EAAQ,CAAC;EACtE,IAAI,MAAM,KAAK,QAAQ,KAAK,KAAK,GAAG,EAAE,GAAG;EACzC,IAAI,MAAM,QACR,OAAO;EACT,MAAM,SAAS,MAAM,QAAQ;GAAE,aAAa,QAAQ;GAAa;GAAS,gBAAgB,MAAM,kBAAkB;EAAO,CAAC;EAC1H,IAAI,OAAO,YAAY;GACrB,IAAI,MAAM,GAAG,KAAK,KAAK,kBAAkB,OAAO,QAAQ,KAAK,GAAG,IAAI,OAAO,WAAW,GAAG;GACzF,OAAO;EACT;EACA,IAAI,OAAO,aAAa,GAAG;GACzB,IAAI,MAAM,GAAG,KAAK,KAAK,IAAI,OAAO,QAAQ,KAAK,GAAG,eAAe,OAAO,YAAY,UAAU,GAAG;GACjG,OAAO,OAAO,YAAY;EAC5B;EACA,OAAO,OAAO,KAAK,MAAM,OAAO,QAAQ,QAAQ,kBAAkB,QAAQ,WAAW,GAAG,OAAO,OAAO;CACxG;CAEA,eAAe,iBAAiB,GAAoC;EAClE,MAAM,SAAS,EAAE,OAAO,UAAU;EAClC,IAAI,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,KAAK,OAAO,GAAG;EACxD,IAAI,EAAE,OAAO,UAAU,CAAC,MAAM,MAAM,EAAE,MAAM,EAAE,OAAO,MAAM,GACzD,OAAO;EAGT,MAAM,UAAU,MAAM,iBAAiB,gBAAgB,MAAM,gBAAgB,EAAE,MAAM,OAAO,IAAI,EAAE;EAClG,IAAI,MAAM,KAAK,QAAQ,KAAK,KAAK,GAAG,EAAE,GAAG;EACzC,IAAI,MAAM,QACR,OAAO;EACT,MAAM,SAAS,MAAM,QAAQ;GAAE,aAAa,EAAE;GAAM;GAAS,gBAAgB,MAAM,kBAAkB,EAAE,QAAQ;EAAG,CAAC;EACnH,IAAI,OAAO,YAAY;GACrB,IAAI,MAAM,GAAG,EAAE,KAAK,kBAAkB,OAAO,QAAQ,KAAK,GAAG,IAAI,OAAO,WAAW,GAAG;GACtF,OAAO;EACT;EACA,IAAI,OAAO,aAAa,GAAG;GACzB,IAAI,MAAM,GAAG,EAAE,KAAK,IAAI,OAAO,QAAQ,KAAK,GAAG,eAAe,OAAO,YAAY,UAAU,GAAG;GAC9F,OAAO;EACT;EACA,MAAM,OAAO,QAAQ,iBAAiB;EACtC,OAAO,OAAO,EAAE,MAAM,EAAE,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS,OAAO,OAAO;CAC9E;;;;;;CAOA,SAAS,OAAO,MAAc,UAAyB,QAAmC,SAAwC;EAChI,IAAI,CAAC,YAAY,WAAW,KAAA,GAAW;GACrC,IAAI,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,YAAY,QAAQ,MAAM;GACvD,OAAO;EACT;EACA,IAAI,WAAW,QAAQ,cAAc,QAAQ,QAAQ,KAAK,GAAG;GAC3D,IAAI,MAAM,GAAG,MAAM,IAAI,EAAE,IAAI,OAAO,MAAM;GAC1C,OAAO;EACT;EACA,IAAI,MAAM,GAAG,KAAK,yBAAyB,UAAU,UAAU,wBAAwB,SAAS,IAAI;EACpG,IAAI,MAAM,cAAc,cAAc,SAAS,MAAM,OAAO,EAAE,GAAG;EACjE,OAAO;CACT;AACF;AAEA,SAAS,WAAW,GAAkB;CACpC,IAAI,EAAE,OAAO,WAAW,SACtB,OAAO,GAAG,EAAE,QAAQ,kBAAkB,EAAE,OAAO,SAAS,gBAAgB;CAC1E,IAAI,CAAC,EAAE,OAAO,QACZ,OAAO,GAAG,EAAE,QAAQ;CACtB,OAAO,EAAE,WAAW,GAAG,EAAE,QAAQ,KAAK,EAAE,OAAO,OAAO,cAAc,GAAG,EAAE,QAAQ;AACnF;AAsBA,eAAe,kBACb,SACA,SACA,UAC2B;CAC3B,MAAM,OAAO,QAAQ,iBAAiB;CACtC,MAAM,SAAS,QAAQ,cAAc,CAAC,EAAA,CACnC,KAAI,UAAS;EAAE;EAAM,WAAW,KAAK,IAAI;CAAE,EAAE,CAAC,CAC9C,QAAQ,MAAmE,EAAE,cAAc,IAAI;CAClG,OAAO,MAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,EAAE,MAAM,gBAAgB;EAChE,MAAM,SAAS,MAAM,eAAe;GAClC,aAAa,UAAU;GACvB,gBAAgB,UAAU;GAC1B;GACA;GACA,UAAU,QAAQ;GAClB,OAAO;GACP,WAAW;EACb,CAAC;EACD,OAAO;GACL;GACA;GACA,MAAM,UAAU;GAChB,SAAS,UAAU;GACnB;GACA,UAAU,OAAO,WAAW,QAAQ,cAAc,OAAO,QAAQ,UAAU,OAAO,IAAI;GACtF,SAAS,qBAAqB;IAAE,aAAa,UAAU;IAAa;IAAS,YAAY,UAAU;GAAW,CAAC;EACjH;CACF,CAAC,CAAC;AACJ;AAwBA,SAAS,UAAU,MAAsC;CACvD,IAAI,QAAQ;CACZ,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,QAAQ;CACZ,IAAI,OAAO;CACX,IAAI,UAAU;CACd,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,IAAI,KAAK;EACf,QAAQ,GAAR;GACE,KAAK;IAAW,QAAQ;IAAM;GAC9B,KAAK;GACL,KAAK;IAAa,UAAU;IAAM;GAClC,KAAK;GACL,KAAK;IAAY,SAAS;IAAM;GAChC,KAAK;IAAW,QAAQ;IAAM;GAC9B,KAAK;IAAc,UAAU;IAAM;GACnC,KAAK;GACL,KAAK;IAAU,OAAO;IAAM;GAC5B,KAAK;IACH,UAAU,KAAK,EAAE;IACjB,IAAI,CAAC,SACH,OAAO;KAAE,MAAM;KAAS,SAAS;IAA6B;IAChE;GACF,KAAK;IACH,WAAW,KAAK,EAAE;IAClB,IAAI,CAAC,UACH,OAAO;KAAE,MAAM;KAAS,SAAS;IAA8B;IACjE;GACF,KAAK;GACL,KAAK,QAAQ;IACX,MAAM,IAAI,KAAK,EAAE;IACjB,IAAI,CAAC,GACH,OAAO;KAAE,MAAM;KAAS,SAAS;IAAqC;IACxE,IAAI,MAAM,SAAS,MAAM,UAAU,MAAM,UAAU,MAAM,SAAS,MAAM,SACtE,OAAO;KAAE,MAAM;KAAS,SAAS,4BAA4B;IAAI;IACnE,iBAAiB;IACjB;GACF;GACA,SACE,OAAO;IAAE,MAAM;IAAS,SAAS,qBAAqB;GAAI;EAC9D;CACF;CAEA,OAAO;EAAE,MAAM;EAAM;EAAO;EAAS;EAAQ;EAAO;EAAM;EAAS;EAAS;EAAU;CAAe;AACvG;;;;;;;;;;;;;;;;;AC1YA,SAAgB,eAAe,SAAqD;CAClF,MAAM,CAAC,QAAQ,aAAa,SAA8B,IAAI;CAG9D,MAAM,UAAU,OAAO,OAAO;CAC9B,QAAQ,UAAU;CAElB,gBAAgB;EACd,IAAI,CAAC,QAAQ,WAAW,CAAC,QAAQ,gBAAgB;GAK/C,UAAU,IAAI;GACd;EACF;EACA,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,QAAQ,iBAAiB;GAC7B,eAAoB;IAClB,aAAa,QAAQ,QAAQ;IAC7B,gBAAgB,QAAQ,QAAQ;IAChC,UAAU,QAAQ,QAAQ;IAC1B,UAAU,QAAQ,QAAQ;IAC1B,SAAS,QAAQ,QAAQ;IAEzB,YAAY,QAAQ,QAAQ,cAAc;IAC1C,QAAQ,WAAW;IACnB,KAAK,QAAQ,QAAQ;IACrB,SAAS,QAAQ,QAAQ;GAC3B,CAAC,CAAC,CAAC,MAAM,MAAM;IACb,IAAI,CAAC,WAAW,OAAO,SACrB,UAAU,CAAC;GACf,CAAC;EACH,GAAG,QAAQ,WAAW,IAAI;EAC1B,aAAa;GACX,aAAa,KAAK;GAClB,WAAW,MAAM;EACnB;CAKF,GAAG;EAAC,QAAQ;EAAS,QAAQ;EAAa,QAAQ;CAAc,CAAC;CAEjE,OAAO;AACT;AA2BA,SAAgB,gBAAgB,QAA6B,SAA8C;CACzG,IAAI,CAAC,QAAQ,aAAa,CAAC,OAAO,QAChC,OAAO;CACT,MAAM,QAAQ,QAAQ,gBAAgB,QAClC,WACA,IAAI,aAAa,OAAO,MAAM;CAClC,OAAO;EACL,KAAK,QAAQ,SAAS;EACtB,UAAU,QAAQ;EAClB;EACA,YAAY,QAAQ;CACtB;AACF;;;;;;;AAQA,SAAgB,iBACd,OACA,SACa;CACb,IAAI,CAAC,OAAO,mBAAmB,CAAC,MAAM,WACpC,OAAO;CACT,OAAO;EACL,KAAK,QAAQ,SAAS;EACtB,UAAU,QAAQ;EAClB,OAAO,QAAQ,gBAAgB,QAAQ,YAAY,IAAI,aAAa,MAAM,SAAS;EACnF,YAAY,QAAQ;CACtB;AACF;AAEA,SAAS,aAAa,GAAmB;CACvC,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,MAAM,CAAC,IAAI;AAC1C;;;AC9FA,eAAsB,yBAAyB,SAAkE;CAC/G,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,OAAO,QAAQ,iBAAiB;CACtC,MAAM,QAAQ,QAAQ,kBAAkB;CACxC,MAAM,YAAY,QAAQ,yBAAyB;CACnD,MAAM,UAAU,QAAQ,qBAAqB;CAC7C,MAAM,SAAS,QAAQ,wBAAwB;CAC/C,MAAM,WAAW,QAAQ,qBAAqB,CAAC;CAE/C,MAAM,UAAkC,CAAC;CACzC,KAAK,MAAM,QAAQ,QAAQ,SAAS;EAClC,IAAI,QAAQ,QAAQ,SAClB;EACF,MAAM,YAAY,KAAK,IAAI;EAC3B,IAAI,CAAC,WAAW;GACd,QAAQ,KAAK;IAAE,aAAa,KAAK;IAAa,MAAM;IAAM,IAAI;IAAM,QAAQ;GAAgB,CAAC;GAC7F;EACF;EACA,SAAS;GAAE,MAAM;GAAS,aAAa,KAAK;EAAY,CAAC;EAWzD,MAAM,SAAS,MAAM,WAAW,WAAW,MAVtB,MAAM;GACzB,aAAa,UAAU;GACvB,gBAAgB,UAAU;GAC1B;GACA,UAAU,QAAQ;GAClB,UAAU,QAAQ;GAClB,OAAO;GACP,WAAW;GACX,QAAQ,QAAQ;EAClB,CAAC,CACgD;EACjD,SAAS;GAAE,MAAM;GAAQ;EAAO,CAAC;EACjC,QAAQ,KAAK,MAAM;CACrB;CAEA,MAAM,eAAe,QAAQ,MAAK,MAAK,EAAE,WAAW,SAAS;CAC7D,IAAI,gBAAgB,QAAQ,UAE1B,CADoB,QAAQ,eAAe,yBAAA,CAC/B,QAAQ,UAAU;EAC5B,KAAK,QAAQ,OAAO,KAAK,IAAA,CAAK;EAC9B,UAAU,QACP,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,EAAE,CAAC,CAC3C,KAAI,OAAM;GAAE,aAAa,EAAE;GAAa,SAAS,EAAE;EAAI,EAAE;CAC9D,CAAC;CAEH,OAAO;EACL;EACA,IAAI,QAAQ,OAAM,MAAK,EAAE,WAAW,YAAY,EAAE,WAAW,aAAa;EAC1E;CACF;CAEA,eAAe,WAAW,WAA+B,QAAqD;EAC5G,MAAM,OAAO;GAAE,aAAa,UAAU;GAAa,MAAM,UAAU;GAAS,IAAI,OAAO;EAAO;EAC9F,IAAI,OAAO,WAAW,WAAW,CAAC,QAAQ,OACxC,OAAO;GAAE,GAAG;GAAM,QAAQ;GAAU,OAAO,0BAA0B,OAAO,SAAS;EAAkB;EAEzG,IAAI,EADa,OAAO,WAAW,QAAQ,cAAc,OAAO,QAAQ,UAAU,OAAO,IAAI,MAC5E,CAAC,QAAQ,OACxB,OAAO;GAAE,GAAG;GAAM,QAAQ;EAAa;EACzC,IAAI,OAAO,UAAU,CAAC,QAAQ,OAExB;OAAA,MADuB,UAAU;IAAE,aAAa,UAAU;IAAa,SAAS,OAAO;IAAQ,UAAU,QAAQ;GAAS,CAAC,MAC1G,WACnB,OAAO;IAAE,GAAG;IAAM,QAAQ;IAAe,OAAO,GAAG,UAAU,YAAY,GAAG,OAAO,OAAO;GAAqE;EAAA;EAGnK,MAAM,UAAiC,OAAO;GAAE,aAAa,UAAU;GAAa;GAAS,YAAY,UAAU;EAAW,CAAC;EAC/H,SAAS;GAAE,MAAM;GAAW,aAAa,UAAU;GAAa,MAAM,UAAU;GAAS,IAAI,OAAO,UAAU;GAAS,SAAS,QAAQ;EAAK,CAAC;EAE9I,MAAM,UAAU,MAAM,QAAQ;GAC5B,aAAa,UAAU;GACvB;GACA,gBAAgB,QAAQ;GACxB,QAAQ,QAAQ;GAChB,QAAQ,SAAS,UAAU,aAAa,QAAQ;GAChD,QAAQ,SAAS,UAAU,aAAa,QAAQ;GAEhD,KAAK;IAAE,qBAAqB;IAAS,qBAAqB;GAAQ;EACpE,CAAC;EACD,IAAI,QAAQ,YACV,OAAO;GAAE,GAAG;GAAM,QAAQ;GAAU,SAAS,QAAQ;GAAM,OAAO,iBAAiB,QAAQ,KAAK,GAAG,IAAI,QAAQ;EAAa;EAC9H,IAAI,QAAQ,aAAa,GACvB,OAAO;GAAE,GAAG;GAAM,QAAQ;GAAU,SAAS,QAAQ;GAAM,OAAO,GAAG,QAAQ,KAAK,GAAG,eAAe,QAAQ,YAAY;EAAY;EAGtI,MAAM,QAAQ,KAAK,SAAS;EAC5B,IAAI,OAAO,UAAU,SAAS,cAAc,MAAM,SAAS,OAAO,MAAM,IAAI,GAC1E,OAAO;GACL,GAAG;GACH,QAAQ;GACR,SAAS,QAAQ;GACjB,OAAO,wBAAwB,MAAM,QAAQ,wBAAwB,OAAO,OAAO,eAAe,cAAc,SAAS,UAAU,aAAa,OAAO;EACzJ;EAEF,OAAO;GAAE,GAAG;GAAM,IAAI,OAAO,WAAW,OAAO;GAAQ,QAAQ;GAAW,SAAS,QAAQ;EAAK;CAClG;;CAGA,SAAS,SAAS,aAAqB,QAAoD;EACzF,IAAI,SAAS;EACb,MAAM,SAAS,UAAmB;GAChC,MAAM,QAAQ,OAAO,MAAM,OAAO;GAClC,SAAS,QAAQ,KAAK,MAAM,IAAI,KAAK;GACrC,KAAK,MAAM,QAAQ,OAAO;IACxB,MAAM,OAAO,KAAK,KAAK;IACvB,IAAI,MACF,SAAS;KAAE,MAAM;KAAO;KAAa;KAAQ;IAAK,CAAC;GACvD;EACF;EACA,OAAO,IAAI,SAAS;GAClB,MAAM,OAA4B,MAAM,IAAI;IAC1C,UAAU,MAAM,SAAS;IACzB,MAAM,KAAK;IACX,GAAG;GACL;GACA,MAAM,IAAI;IACR,MAAM,IAAI;IACV,GAAG;GACL;EACF,CAAC;CACH;AACF;;;ACrLA,MAAM,UAAU,CAAC,CAAC,QAAQ,IAAI;;;;;;;;AAQ9B,MAAM,QAAQ,YAAY,IAAI;AAC9B,IAAI,OAAO;;;;;;;;;;AAWX,SAAgB,SAAS,OAAqB;CAC5C,IAAI,CAAC,SACH;CACF,MAAM,MAAM,YAAY,IAAI;CAC5B,MAAM,QAAQ,MAAM;CACpB,MAAM,QAAQ,MAAM;CACpB,OAAO;CAIP,QAAQ,OAAO,MACb,WAAW,MAAM,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,aAAa,MAAM,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,OAAO,MAAM,GACjG;AACF;;;;;;AAOA,SAAgB,qBAA8B;CAC5C,OAAO;AACT;;;;;;;;;;;;;;;;;;;AC5CA,SAAgB,eAAe,KAAmB;CAChD,MAAM,CAAC,KAAK,GAAG,eAAe;EAC5B,IAAI,QAAQ,aAAa,UACvB,OAAO,CAAC,QAAQ,GAAG;EACrB,IAAI,QAAQ,aAAa,SACvB,OAAO;GAAC;GAAO;GAAM;GAAS;GAAI;EAAG;EACvC,OAAO,CAAC,YAAY,GAAG;CACzB,EAAA,CAAG;CACH,IAAI;EACF,MAAM,QAAQ,MAAM,KAAK,MAAM;GAAE,OAAO;GAAU,UAAU;EAAK,CAAC;EAClE,MAAM,GAAG,eAAe,CAAC,CAAC;EAC1B,MAAM,MAAM;CACd,QACM,CAEN;AACF;;;;;;;AAQA,SAAgB,cAAc,MAAc,cAAc,OAAa;CACrE,MAAM,SAAS,KAAK,QAAQ,cAAc,EAAE;CAC5C,MAAM,CAAC,KAAK,GAAG,eAAe;EAC5B,IAAI,QAAQ,aAAa,UACvB,OAAO,cAAc,CAAC,QAAQ,MAAM,IAAI;GAAC;GAAQ;GAAM;EAAM;EAC/D,IAAI,QAAQ,aAAa,SACvB,OAAO,cAAc,CAAC,YAAY,MAAM,IAAI,CAAC,YAAY,WAAW,QAAQ;EAC9E,OAAO,CAAC,YAAY,cAAc,SAAS,QAAQ,MAAM,CAAC;CAC5D,EAAA,CAAG;CACH,IAAI;EACF,MAAM,QAAQ,MAAM,KAAK,MAAM;GAAE,OAAO;GAAU,UAAU;EAAK,CAAC;EAClE,MAAM,GAAG,eAAe,CAAC,CAAC;EAC1B,MAAM,MAAM;CACd,QACM,CAEN;AACF;;;;;;;;;AC5BA,SAAgB,cAAc,OAAuB,MAAiE;CACpH,MAAM,UAAU,MAAM,UAAU,UAAA,CAAW,QAAQ,OAAO,EAAE;CAO5D,MAAM,SANa,iBAAiB;EAClC,SAAS;EACT,GAAI,MAAM,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;EACrC,GAAI,MAAM,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;EACxC,GAAI,MAAM,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;CAChD,CACwB,CAAC,CAAC,MAAK,MAAK,EAAE,WAAW,SAAS,EAAE,KAAK,SAAS,IAAI,QAAQ,CAAC;CACvF,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,MAAM,MAAM,0BAA0B;CACxD,OAAO,OAAO;AAChB;;;;;;;;AAgBA,SAAgB,gBAAgB,UAAkB,OAAyC;CACzF,IAAI,CAAC,WAAW,QAAQ,GAAG;EACzB,UAAU,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;EAChD,cAAc,UAAU,GAAG,KAAK,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,EAAE,GAAG;EAC/D,OAAO;GAAE,MAAM;GAAU,QAAQ;EAAQ;CAC3C;CAKA,MAAM,MAAe,kBAAkB,aAAa,UAAU,MAAM,CAAC;CAGrE,IAAI,MAAM,QAAQ,GAAG,GAAG;EACtB,MAAM,MAAM,IAAI,WAAU,MAAK,SAAS,CAAC,KAAK,EAAE,SAAS,MAAM,IAAI;EACnE,MAAM,OAAO,CAAC,GAAG,GAAG;EACpB,MAAM,SAAS,OAAO,IAAI,YAAqB;EAC/C,IAAI,OAAO,GACT,KAAK,OAAO;OAEZ,KAAK,KAAK,KAAK;EACjB,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;EAC5D,OAAO;GAAE,MAAM;GAAU;EAAO;CAClC;CAEA,IAAI,SAAS,GAAG,GAAG;EAEjB,IAAI,SAAS,IAAI,UAAU,GAAG;GAC5B,MAAM,MAAM,IAAI;GAChB,MAAM,SAAS,MAAM,QAAQ,MAAM,YAAqB;GACxD,MAAM,OAAO;IAAE,GAAG;IAAK,YAAY;KAAE,GAAG;MAAM,MAAM,OAAO,UAAU,KAAK;IAAE;GAAE;GAC9E,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;GAC5D,OAAO;IAAE,MAAM;IAAU;GAAO;EAClC;EAEA,MAAM,SAAS,MAAM,QAAQ,MAAM,YAAqB;EACxD,MAAM,OAAO;GAAE,GAAG;IAAM,MAAM,OAAO,UAAU,KAAK;EAAE;EACtD,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;EAC5D,OAAO;GAAE,MAAM;GAAU;EAAO;CAClC;CAEA,MAAM,IAAI,MAAM,GAAG,SAAS,yEAAyE;AACvG;;;;;;;;;AAeA,SAAgB,gBAAgB,UAAkB,MAA+B;CAC/E,IAAI,CAAC,WAAW,QAAQ,GACtB,MAAM,IAAI,MAAM,GAAG,SAAS,iBAAiB;CAG/C,MAAM,MAAe,kBAAkB,aAAa,UAAU,MAAM,CAAC;CAErE,IAAI,MAAM,QAAQ,GAAG,GAAG;EACtB,MAAM,OAAO,IAAI,QAAO,MAAK,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,KAAK;EAC9D,IAAI,KAAK,WAAW,IAAI,QACtB,MAAM,IAAI,MAAM,mBAAmB,KAAK,OAAO,SAAS,EAAE;EAC5D,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;EAC5D,OAAO,EAAE,MAAM,SAAS;CAC1B;CAEA,IAAI,SAAS,GAAG,GAAG;EACjB,IAAI,SAAS,IAAI,UAAU,GAAG;GAC5B,IAAI,EAAE,QAAQ,IAAI,aAChB,MAAM,IAAI,MAAM,mBAAmB,KAAK,OAAO,SAAS,EAAE;GAC5D,MAAM,GAAG,OAAO,UAAU,GAAG,SAAS,IAAI;GAC1C,MAAM,OAAO;IAAE,GAAG;IAAK,YAAY;GAAK;GACxC,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;GAC5D,OAAO,EAAE,MAAM,SAAS;EAC1B;EACA,IAAI,EAAE,QAAQ,MACZ,MAAM,IAAI,MAAM,mBAAmB,KAAK,OAAO,SAAS,EAAE;EAC5D,MAAM,GAAG,OAAO,UAAU,GAAG,SAAS;EACtC,cAAc,UAAU,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,GAAG;EAC5D,OAAO,EAAE,MAAM,SAAS;CAC1B;CAEA,MAAM,IAAI,MAAM,GAAG,SAAS,yEAAyE;AACvG;;AAGA,SAAS,UAAU,OAAuD;CACxE,MAAM,EAAE,MAAM,OAAO,GAAG,SAAS;CACjC,OAAO;AACT;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;AC3GA,SAAS,MAAM,MAAkE;CAC/E,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;CACpC,OAAO;EACL,aAAaC,cAAY,GAAG,KAAK;EACjC,MAAM,KAAK,QAAQ,QAAQ;CAC7B;AACF;;AAGA,SAAgB,mBAAmB,OAA4B,CAAC,GAAY;CAC1E,OAAO,WAAW,QAAQ,MAAM,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC;AACxD;;;;;;;AAYA,SAAgB,kBAAkB,MAAsB;CACtD,OAAO,KAAK,QAAQ,eAAe,GAAG;AACxC;;;;;;;;;;;;;;;AAsBA,SAAgB,uBAAuB,OAA4B,CAAC,GAAwB;CAC1F,MAAM,MAA2B,CAAC;CAClC,uBAAuB,MAAM,KAAK,eAC9B,SAAQ,IAAI,KAAK,IAAI,KACpB,MAAM,WAAW;EAChB,IAAI,OAAO,GACT,IAAI,KAAK,IAAI;CACjB,CAAC;CACL,OAAO;AACT;;;;;;;;AASA,SAAgB,wBAAwB,OAA4B,CAAC,GAAqC;CACxG,IAAI,UAAU;CACd,IAAI,MAAM;CACV,uBAAuB;EAAE,GAAG;EAAM,aAAa;CAAM,IAAI,OAAO,WAAW;EACzE;EACA,IAAI,OAAO,GACT;CACJ,GAAsB,IAAI;CAC1B,OAAO;EAAE;EAAS;CAAI;AACxB;;;;;;;;;AAUA,SAAS,uBACP,MACA,OACA,eAAe,OACT;CACN,MAAM,EAAE,aAAa,SAAS,MAAM,IAAI;CACxC,MAAM,cAAc,QAAQ,MAAM,kBAAkB;CACpD,IAAI,CAAC,WAAW,WAAW,GACzB;CACF,MAAM,QAAQ,CAAC,kBAAkB,WAAW,GAAG,kBAAkB,WAAW,WAAW,CAAC,CAAC;CACzF,MAAM,QAAQ,IAAI,IAAI,KAAK;CAC3B,MAAM,WAAW,CAAC,GAAG,IAAI,IAAI,MAAM,KAAI,MAAK,GAAG,EAAE,EAAE,CAAC,CAAC;CACrD,MAAM,8BAAc,IAAI,IAAI,CAAC,aAAa,WAAW,WAAW,CAAC,CAAC;CAClE,KAAK,MAAM,SAAS,YAAY,aAAa,EAAE,eAAe,KAAK,CAAC,GAAG;EACrE,IAAI,CAAC,MAAM,YAAY,GACrB;EACF,MAAM,aAAa,MAAM,IAAI,MAAM,IAAI;EACvC,MAAM,YAAY,cAAc,SAAS,MAAK,MAAK,MAAM,KAAK,WAAW,CAAC,CAAC;EAC3E,IAAI,CAAC,KAAK,eAAe,CAAC,gBAAgB,CAAC,WACzC;EACF,MAAM,aAAa,KAAK,aAAa,MAAM,IAAI;EAC/C,KAAK,MAAM,QAAQ,YAAY,UAAU,GAAG;GAC1C,IAAI,CAAC,KAAK,SAAS,QAAQ,GACzB;GACF,MAAM,OAAO,KAAK,YAAY,IAAI;GAMlC,MAAM,eAAwB;IAC5B,IAAI,CAAC,WACH,OAAO;IACT,MAAM,OAAO,sBAAsB,IAAI;IACvC,OAAO,SAAS,OAAO,aAAa,YAAY,IAAI,IAAI,KAAK,YAAY,IAAI,WAAW,IAAI,CAAC;GAC/F;GACA,MAAM;IAAE;IAAM;GAAW,GAAG,MAAM;EACpC;CACF;AACF;;;;;;;;;;AAWA,SAAS,sBAAsB,MAA6B;CAC1D,IAAI;CACJ,IAAI,YAAY;CAChB,IAAI;EACF,MAAM,KAAK,SAAS,MAAM,GAAG;EAC7B,IAAI;GACF,MAAM,MAAM,OAAO,MAAM,MAAU;GACnC,MAAM,IAAI,SAAS,IAAI,KAAK,GAAG,IAAI,QAAQ,CAAC;GAC5C,OAAO,IAAI,SAAS,GAAG,CAAC,CAAC,CAAC,SAAS,MAAM;GACzC,YAAY,MAAM,IAAI;EACxB,UACQ;GACN,UAAU,EAAE;EACd;CACF,QACM;EACJ,OAAO;CACT;CACA,MAAM,YAAY,WAAW,IAAI;CACjC,IAAI,cAAc,QAAQ,CAAC,WACzB,OAAO;CACT,IAAI;EACF,OAAO,WAAW,aAAa,MAAM,MAAM,CAAC;CAC9C,QACM;EACJ,OAAO;CACT;AACF;AAEA,SAAS,WAAW,MAA6B;CAC/C,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,IAAI,CAAC,KAAK,KAAK,GACb;EACF,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,IAAI;GAC9B,IAAI,OAAO,OAAO,QAAQ,UACxB,OAAOA,cAAY,OAAO,GAAG,KAAK,OAAO;EAC7C,QACM;GACJ;EACF;CACF;CACA,OAAO;AACT;AAEA,SAAS,WAAW,MAAsB;CACxC,IAAI;EACF,OAAO,aAAa,IAAI;CAC1B,QACM;EACJ,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;AAkDA,SAAgB,qBAAqB,OAAe,OAAgC,CAAC,GAAkC;CACrH,MAAM,QAAuB,CAAC;CAC9B,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,KAAK,MAAM,QAAQ,MAAM,MAAM,IAAI,GAAG;EACpC,IAAI,CAAC,KAAK,KAAK,GACb;EACF,IAAI;EACJ,IAAI;GACF,SAAS,KAAK,MAAM,IAAI;EAC1B,QACM;GACJ;EACF;EACA,IAAI,OAAO,SAAS,kBAAkB,OAAO,OAAO,gBAAgB,UAAU;GAC5E,QAAQ,OAAO;GACf;EACF;EACA,IAAI,OAAO,SAAS,aAAa,OAAO,OAAO,YAAY,UAAU;GACnE,UAAU,OAAO;GACjB;EACF;EACA,IAAI,OAAO,SAAS,UAAU,OAAO,SAAS,aAC5C;EACF,IAAI,OAAO,eAAe,OAAO,UAAU,CAAC,OAAO,SACjD;EACF,oBAAoB,OAAO;EAC3B,QAAQ,OAAO;EAGf,MAAM,WAAW,OAAO,YAAY,KAAK,MAAM,OAAO,SAAS,IAAI;EACnE,MAAM,YAAY,OAAO,MAAM,QAAQ,IAAI,KAAK,IAAI,IAAI;EAExD,IAAI,OAAO,SAAS,aAAa;GAC/B,MAAM,UAAU,sBAAsB,OAAO,QAAQ,OAAO;GAC5D,IAAI,QAAQ,WAAW,GACrB;GACF,MAAM,YAAY,OAAO,QAAQ;GACjC,MAAM,WAAW,MAAM,MAAM,SAAS;GAKtC,IAAI,aAAa,cAAc,0BAA0B,UAAU,SAAS,aAAa;IACvF,SAAS,QAAQ,KAAK,GAAG,OAAO;IAChC,MAAM,QAAQ,YAAY,OAAO,QAAQ,OAAO,OAAO,QAAQ,KAAK;IACpE,IAAI,OACF,SAAS,QAAQ;IACnB;GACF;GACA,yBAAyB;GACzB,MAAM,QAAQ,YAAY,OAAO,QAAQ,OAAO,OAAO,QAAQ,KAAK;GACpE,MAAM,KAAK;IACT,IAAI,OAAO,QAAQ,OAAO,WAAW;IACrC,MAAM;IACN;IACA;IACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAC3B,CAAC;GACD;EACF;EAEA,yBAAyB,KAAA;EACzB,MAAM,UAAU,sBAAsB,OAAO,QAAQ,OAAO;EAC5D,IAAI,QAAQ,WAAW,GACrB;EAGF,MAAM,WAAW,MAAM,MAAM,SAAS;EACtC,IAAI,UAAU,SAAS,UAAU,iBAAiB,OAAO,KAAK,iBAAiB,SAAS,OAAO,GAAG;GAChG,SAAS,QAAQ,KAAK,GAAG,OAAO;GAChC;EACF;EACA,MAAM,KAAK;GAAE,IAAI,OAAO,QAAQ,OAAO,WAAW;GAAG,MAAM;GAAQ;GAAS;EAAU,CAAC;CACzF;CAEA,IAAI,MAAM,WAAW,GACnB,OAAO;CAOT,MAAM,KAAK,KAAK,cAAc,mBAAmB,OAAO,WAAW;CAGnE,MAAM,cAAc,MAAM,cAAc,GAAG,IAAI,KAAA;CAkB/C,OAAO;EAAE,SAAA;GAhBP;GACA,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;GACrC;GACA,MAAM,CAAC;GACP,QAAQ;GACR,UAAU;IACR,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;IACzB,cAAc;IACd,iBAAiB;IAGjB,GAAI,mBAAmB,oBAAoB,KAAK,EAAE,iBAAiB,gBAAgB,IAAI,CAAC;GAC1F;GACA,WAAW,MAAM,EAAE,CAAE;GACrB,WAAW,MAAM,MAAM,SAAS,EAAE,CAAE;EAEvB;EAAG,iBAAiB;CAAG;AACxC;;AAGA,SAAS,sBAAsB,SAAyC;CACtE,IAAI,OAAO,YAAY,UACrB,OAAO,QAAQ,KAAK,IAAI,CAAC;EAAE,MAAM;EAAQ,MAAM;CAAQ,CAAC,IAAI,CAAC;CAC/D,IAAI,CAAC,MAAM,QAAQ,OAAO,GACxB,OAAO,CAAC;CACV,MAAM,MAA6B,CAAC;CACpC,KAAK,MAAM,OAAO,SAAS;EACzB,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB;EACF,MAAM,QAAQ;EACd,QAAQ,MAAM,MAAd;GACE,KAAK;IACH,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,GACpD,IAAI,KAAK;KAAE,MAAM;KAAQ,MAAM,MAAM;IAAK,CAAC;IAC7C;GACF,KAAK;IACH,IAAI,OAAO,MAAM,OAAO,YAAY,OAAO,MAAM,SAAS,UAAU;KAClE,MAAM,QAAQ,MAAM,SAAS,OAAO,MAAM,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,KAAK,IACtF,MAAM,QACN,CAAC;KACL,IAAI,KAAK;MAAE,MAAM;MAAa,IAAI,MAAM;MAAI,MAAM,MAAM;MAAM;KAAM,CAAC;IACvE;IACA;GACF,KAAK;IACH,IAAI,OAAO,MAAM,gBAAgB,UAC/B,IAAI,KAAK;KACP,MAAM;KACN,QAAQ,MAAM;KACd,QAAQ,uBAAuB,MAAM,OAAO;KAC5C,GAAI,MAAM,aAAa,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;IACrD,CAAC;IAEH;GACF,KAAK,SAAS;IACZ,MAAM,QAAQ,YAAY,KAAK;IAC/B,IAAI,OACF,IAAI,KAAK,KAAK;IAChB;GACF;EAEF;CACF;CACA,OAAO;AACT;AAEA,SAAS,YAAY,OAA4D;CAC/E,MAAM,SAAS,MAAM;CACrB,IAAI,CAAC,UAAU,OAAO,SAAS,YAAY,OAAO,OAAO,eAAe,YAAY,OAAO,OAAO,SAAS,UACzG,OAAO;CACT,OAAO;EAAE,MAAM;EAAS,WAAW,OAAO;EAAY,MAAM,OAAO;CAAK;AAC1E;AAEA,SAAS,uBAAuB,SAAgD;CAC9E,IAAI,OAAO,YAAY,UACrB,OAAO;CACT,IAAI,CAAC,MAAM,QAAQ,OAAO,GACxB,OAAO;CACT,MAAM,QAA6B,CAAC;CACpC,KAAK,MAAM,OAAO,SAAS;EACzB,IAAI,CAAC,OAAO,OAAO,QAAQ,UACzB;EACF,MAAM,QAAQ;EACd,IAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,UACjD,MAAM,KAAK;GAAE,MAAM;GAAQ,MAAM,MAAM;EAAK,CAAC;OAE1C,IAAI,MAAM,SAAS,SAAS;GAC/B,MAAM,QAAQ,YAAY,KAAK;GAC/B,IAAI,OAAO,SAAS,WAAW,MAAM,MACnC,MAAM,KAAK;IAAE,MAAM;IAAS,WAAW,MAAM;IAAW,MAAM,MAAM;GAAK,CAAC;EAC9E;CACF;CAEA,IAAI,MAAM,OAAM,MAAK,EAAE,SAAS,MAAM,GACpC,OAAO,MAAM,KAAI,MAAM,EAAuB,IAAI,CAAC,CAAC,KAAK,IAAI;CAC/D,OAAO;AACT;AAIA,SAAS,YAAY,OAAgC,OAAuC;CAC1F,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO,KAAA;CACT,OAAO;EACL,OAAO,MAAM,gBAAgB;EAC7B,QAAQ,MAAM,iBAAiB;EAC/B,GAAI,MAAM,8BAA8B,EAAE,eAAe,MAAM,4BAA4B,IAAI,CAAC;EAChG,GAAI,MAAM,0BAA0B,EAAE,WAAW,MAAM,wBAAwB,IAAI,CAAC;EACpF,GAAI,QAAQ,EAAE,SAAS,MAAM,IAAI,CAAC;CACpC;AACF;AAEA,SAAS,iBAAiB,QAAiD;CACzE,OAAO,OAAO,SAAS,KAAK,OAAO,OAAM,MAAK,EAAE,SAAS,aAAa;AACxE;;AAaA,eAAsB,qBAAqB,OAAqB,OAA4B,CAAC,GAAuC;CAClI,MAAM,SAAoC;EAAE,UAAU;EAAG,SAAS;EAAG,OAAO;EAAG,QAAQ,CAAC;CAAE;CAC1F,KAAK,MAAM,QAAQ,uBAAuB,IAAI,GAC5C,IAAI;EAKF,MAAM,aAAa,SAAS,KAAK,MAAM,QAAQ;EAK/C,IAAI,MAAM,MAAM,KAAK,UAAU,GAAG;GAChC,OAAO;GACP;EACF;EACA,MAAM,YAAY,qBAAqB,aAAa,KAAK,MAAM,MAAM,GAAG,EAAE,WAAW,CAAC;EACtF,IAAI,CAAC,WAAW;GACd,OAAO;GACP;EACF;EACA,MAAM,MAAM,KAAK,UAAU,OAAO;EAClC,OAAO;CACT,SACO,KAAK;EACV,OAAO,OAAO,KAAK;GAAE,MAAM,KAAK;GAAM,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAAE,CAAC;CACjG;CAEF,OAAO;AACT;;;;;;;;;;;;;AAiCA,SAAgB,iBAAiB,OAA4B,CAAC,GAAqB;CACjF,MAAM,EAAE,aAAa,SAAS,MAAM,IAAI;CACxC,MAAM,SAA2B;EAAE,QAAQ,CAAC;EAAG,SAAS,CAAC;EAAG,QAAQ,CAAC;EAAG,YAAY,CAAC;CAAE;CASvF,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,aAAa,uBAAuB;EAAE,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;EAAI;EAAM,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;CAAG,CAAC,GAAG;EACjJ,IAAI,CAAC,WAAW,UAAU,IAAI,GAC5B;EACF,KAAK,MAAM,QAAQ,YAAY,aAAa,UAAU,MAAM,MAAM,CAAC,GACjE,YAAY,IAAI,IAAI;CACxB;CAEA,MAAM,UAAuE,CAAC;CAC9E,MAAM,UAAU,QAAQ,aAAa,WAAW;CAChD,IAAI,WAAW,OAAO,GACpB,IAAI;EACF,QAAQ,KAAK;GAAE,SAAS,cAAc,aAAa,SAAS,MAAM,CAAC;GAAG,OAAO;EAAU,CAAC;CAC1F,SACO,KAAK;EACV,OAAO,OAAO,KAAK;GAAE,MAAM;GAAS,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAAE,CAAC;CAC/F;CAEF,MAAM,cAAc,QAAQ,MAAM,cAAc;CAChD,IAAI,WAAW,WAAW,GACxB,IAAI;EACF,MAAM,QAAiB,KAAK,MAAM,aAAa,aAAa,MAAM,CAAC;EAEnE,QAAQ,KAAK;GAAE,SAAS,iBAAiB,OAAO,wBAAwB,WAAW;GAAG,OAAO;EAAO,CAAC;EACrG,QAAQ,KAAK;GAAE,SAAS,iBAAiB,OAAO,mBAAmB;GAAG,OAAO;EAAO,CAAC;CACvF,SACO,KAAK;EACV,OAAO,OAAO,KAAK;GAAE,MAAM;GAAa,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;EAAE,CAAC;CACnG;CAGF,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,EAAE,SAAS,WAAW,SAC/B,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,KAAK,IAAI,OAAO,IAAI,GAAG;GAGzB,OAAO,WAAY,KAAK,OAAO,IAAI;GACnC;EACF;EACA,KAAK,IAAI,OAAO,IAAI;EACpB,IAAI,YAAY,IAAI,OAAO,IAAI,GAAG;GAChC,OAAO,QAAQ,KAAK,OAAO,IAAI;GAC/B;EACF;EACA,IAAI;GACF,MAAM,SAAS,cAAc,OAAO;IAAE,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;IAAI;IAAM,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;GAAG,CAAC;GACrI,MAAM,EAAE,WAAW,gBAAgB,QAAQ,MAAM;GACjD,IAAI,WAAW,WAAW;IAKxB,OAAO,OAAO,KAAK;KAAE,MAAM,OAAO;KAAM,OAAO,kCAAkC,OAAO;IAAiD,CAAC;IAC1I;GACF;GACA,OAAO,OAAO,KAAK,OAAO,IAAI;EAChC,SACO,KAAK;GACV,OAAO,OAAO,KAAK;IAAE,MAAM,OAAO;IAAM,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAAE,CAAC;EACnG;CACF;CAEF,OAAO;AACT;;;;;;;;AASA,SAAS,YAAY,MAAwB;CAC3C,IAAI;CACJ,IAAI;EACF,MAAM,kBAAkB,IAAI;CAC9B,QACM;EACJ,OAAO,CAAC;CACV;CACA,IAAI,MAAM,QAAQ,GAAG,GACnB,OAAO,IAAI,SAAQ,UACjB,SAAS,OAAO,UAAU,YAAY,OAAQ,MAA6B,SAAS,WAChF,CAAE,MAA2B,IAAI,IACjC,CAAC,CAAC;CAEV,IAAI,OAAO,OAAO,QAAQ,UAAU;EAClC,MAAM,SAAS;EACf,MAAM,MAAM,OAAO,cAAc,OAAO,OAAO,eAAe,YAAY,CAAC,MAAM,QAAQ,OAAO,UAAU,IACtG,OAAO,aACP;EACJ,OAAO,OAAO,KAAK,GAAG;CACxB;CACA,OAAO,CAAC;AACV;;;;;;;AAYA,SAAgB,mBAAmB,OAA4B,CAAC,GAAqB;CACnF,MAAM,EAAE,aAAa,SAAS,MAAM,IAAI;CACxC,MAAM,UAAU,KAAK,UAAU,UAAA,CAAW,QAAQ,OAAO,EAAE;CAC3D,MAAM,SAA2B;EAAE,QAAQ,CAAC;EAAG,SAAS,CAAC;EAAG,QAAQ,CAAC;CAAE;CAEvE,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,QAAQ,iBAAiB;EAAE,SAAS;EAAU,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;EAAI;EAAM,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;CAAG,CAAC,GAAG;EACzJ,IAAI,CAAC,WAAW,KAAK,IAAI,GACvB;EACF,KAAK,MAAM,SAAS,YAAY,KAAK,MAAM,EAAE,eAAe,KAAK,CAAC,GAChE,IAAI,MAAM,YAAY,GACpB,YAAY,IAAI,MAAM,IAAI;CAEhC;CAEA,MAAM,QAAwC,CAC5C;EAAE,MAAM,QAAQ,aAAa,gBAAgB;EAAG,IAAI,QAAQ,aAAa,IAAI,OAAO,QAAQ;CAAE,GAC9F;EAAE,MAAM,QAAQ,MAAM,gBAAgB;EAAG,IAAI,QAAQ,MAAM,IAAI,OAAO,QAAQ;CAAE,CAClF;CACA,KAAK,MAAM,EAAE,MAAM,QAAQ,OAAO;EAChC,IAAI,CAAC,WAAW,IAAI,GAClB;EACF,KAAK,MAAM,SAAS,YAAY,MAAM,EAAE,eAAe,KAAK,CAAC,GAAG;GAC9D,IAAI,CAAC,MAAM,YAAY,GACrB;GACF,IAAI,CAAC,WAAW,KAAK,MAAM,MAAM,MAAM,UAAU,CAAC,GAChD;GACF,IAAI,YAAY,IAAI,MAAM,IAAI,GAAG;IAC/B,OAAO,QAAQ,KAAK,MAAM,IAAI;IAC9B;GACF;GACA,IAAI;IACF,OAAO,KAAK,MAAM,MAAM,IAAI,GAAG,KAAK,IAAI,MAAM,IAAI,GAAG;KAAE,WAAW;KAAM,cAAc;KAAM,OAAO;IAAM,CAAC;IAC1G,YAAY,IAAI,MAAM,IAAI;IAC1B,OAAO,OAAO,KAAK,MAAM,IAAI;GAC/B,SACO,KAAK;IACV,OAAO,OAAO,KAAK;KAAE,MAAM,MAAM;KAAM,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;IAAE,CAAC;GAClG;EACF;CACF;CACA,OAAO;AACT;;;;;;;;AAaA,SAAgB,yBAAyB,MAA6B,OAA4B,CAAC,GAAqB;CACtH,MAAM,EAAE,aAAa,SAAS,MAAM,IAAI;CACxC,MAAM,UAAU,KAAK,UAAU,UAAA,CAAW,QAAQ,OAAO,EAAE;CAC3D,MAAM,SAA2B;EAAE,QAAQ,CAAC;EAAG,SAAS,CAAC;EAAG,QAAQ,CAAC;CAAE;CACvE,MAAM,SAAS,iBAAiB;EAAE;EAAM,GAAI,KAAK,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;EAAI;EAAM,QAAQ,IAAI;EAAU,gBAAgB;CAAM,CAAC;CACnI,MAAM,cAAc,IAAI,IAAI,qBAAqB,MAAM,CAAC,CAAC,KAAI,SAAQ,KAAK,IAAI,CAAC;CAE/E,MAAM,QAAoE,CACxE;EAAE,MAAM,QAAQ,aAAa,WAAW,MAAM;EAAG,IAAI,QAAQ,aAAa,IAAI,OAAO,GAAG,MAAM;EAAG,QAAQ;CAAU,GACnH;EAAE,MAAM,QAAQ,MAAM,WAAW,MAAM;EAAG,IAAI,QAAQ,MAAM,IAAI,OAAO,GAAG,MAAM;EAAG,QAAQ;CAAO,CACpG;CACA,KAAK,MAAM,EAAE,MAAM,IAAI,YAAY,OACjC,KAAK,MAAM,QAAQ,qBAAqB,CAAC;EAAE,MAAM;EAAM;EAAQ,SAAS;CAAK,CAAC,CAAC,GAAG;EAChF,IAAI,YAAY,IAAI,KAAK,IAAI,GAAG;GAC9B,OAAO,QAAQ,KAAK,KAAK,IAAI;GAC7B;EACF;EACA,IAAI;GACF,MAAM,SAAS,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,CAAC;GACjD,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;GAC9C,OAAO,KAAK,MAAM,QAAQ;IAAE,cAAc;IAAM,OAAO;GAAM,CAAC;GAC9D,YAAY,IAAI,KAAK,IAAI;GACzB,OAAO,OAAO,KAAK,KAAK,IAAI;EAC9B,SACO,KAAK;GACV,OAAO,OAAO,KAAK;IAAE,MAAM,KAAK;IAAM,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAAE,CAAC;EACjG;CACF;CAEF,OAAO;AACT;;;;;;AAiCA,SAAgB,qBAAqB,YAAsE;CACzG,IAAI,YAAY,SAAS,UACvB,OAAO;CACT,OAAO,qCAAqC,WAAW,KAAK;AAC9D;;;;;;;AAQA,eAAsB,qBACpB,OACA,OAAyK,CAAC,GAC5I;CAC9B,MAAM,WAAW,qBAAqB,KAAK,UAAU;CACrD,MAAM,UAA+B;EACnC,QAAQ;EACR,OAAO;GACL,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAC;GAC7B;GACA;EACF;CACF;CACA,IAAI,KAAK,aAAa,OACpB,QAAQ,WAAW,MAAM,qBAAqB,OAAO,IAAI;CAC3D,IAAI,KAAK,SAAS,OAChB,QAAQ,OAAO,iBAAiB,IAAI;CACtC,IAAI,KAAK,WAAW,OAClB,QAAQ,SAAS,mBAAmB,IAAI;CAC1C,IAAI,KAAK,aAAa,OACpB,QAAQ,WAAW,yBAAyB,YAAY,IAAI;CAC9D,IAAI,KAAK,WAAW,OAClB,QAAQ,SAAS,yBAAyB,UAAU,IAAI;CAC1D,OAAO;AACT;;;;;;;;ACnyBA,MAAM,aAAsD,OAAO,OAAO,CAAC,CAAC;;;;;;;;;;;;;AA0C5E,SAAgB,cACd,OACA,WACA,UAAuC,CAAC,GAChB;CACxB,MAAM,EAAE,MAAM,WAAW;CAIzB,MAAM,EAAE,mBAAmB;CAS3B,MAAM,CAAC,uBAAuB,4BAA4B,SAAwB,IAAI;CAEtF,MAAM,aAAa,cACX,mBAAmB,MAAM,QAAQ,WAAW,EAAE,eAAe,CAAC,GACpE;EAAC;EAAM;EAAQ;EAAW;CAAc,CAC1C;CAEA,MAAM,cAAc,cAAc;EAChC,IAAI,CAAC,YACH,OAAO;EACT,IAAI,WAAW,KAAK,UAAU,uBAC5B,OAAO;EACT,OAAO;CACT,GAAG,CAAC,YAAY,qBAAqB,CAAC;CAKtC,MAAM,SAAS,cACP,cACF;EAAE,UAAU,YAAY,UAAU;EAAI,OAAO,YAAY;EAAO,MAAM,YAAY;CAAK,IACvF,MACJ,CAAC,WAAW,CACd;CAMA,gBAAgB;EACd,IAAI,CAAC,YACH,yBAAyB,IAAI;CACjC,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,CAAC,OAAO,YAAY,SAA2C,CAAC,CAAC;CACvE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,CAAC,eAAe,oBAAoB,SAAS,CAAC;CAGpD,MAAM,WAAW,OAA+B,IAAI;CAEpD,gBAAgB;EACd,SAAS,SAAS,MAAM;EACxB,IAAI,CAAC,aAAa;GAChB,SAAS,CAAC,CAAC;GACX,WAAW,KAAK;GAChB,iBAAiB,CAAC;GAClB;EACF;EACA,MAAM,aAAa,IAAI,gBAAgB;EACvC,SAAS,UAAU;EACnB,MAAM,MAAyB;GAAE;GAAM;EAAO;EAC9C,IAAI,YAAY;EAChB,MAAM,OAAO,YAAY,UAAU,KAAI,cAAa;GAClD;GACA,KAAK,SAAS,QAAQ,YAAY,OAAO,KAAK,WAAW,MAAM;EACjE,EAAE;EAGF,IAAI,KAAK,OAAM,MAAK,MAAM,QAAQ,EAAE,GAAG,CAAC,GAAG;GACzC,SAAS,iBAAiB,KAAK,KAAI,OAAM;IAAE,UAAU,EAAE;IAAU,OAAO,EAAE;GAA+B,EAAE,GAAG,YAAY,UAAU,MAAM,CAAC;GAC3I,iBAAiB,CAAC;GAClB,WAAW,KAAK;GAChB;EACF;EACA,WAAW,IAAI;EAKf,QAAa,WAAW,KAAK,IAAI,OAAM,OAAM;GAAE,UAAU,EAAE;GAAU,OAAO,MAAM,EAAE;EAAI,EAAE,CAAC,CAAC,CAAC,MAC1F,YAAY;GACX,IAAI,WACF;GACF,SAAS,iBAAiB,QAAQ,SAAQ,MAAK,EAAE,WAAW,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,GAAG,YAAY,UAAU,MAAM,CAAC;GACxH,iBAAiB,CAAC;GAClB,WAAW,KAAK;EAClB,CACF;EACA,aAAa;GACX,YAAY;GACZ,WAAW,MAAM;EACnB;CACF,GAAG;EAAC;EAAa;EAAM;CAAM,CAAC;CAc9B,MAAM,aAAa,cACX;EACJ,MAAM,OAAO,kBAAkB,MAAM,WAAW,MAAM;EACtD,OAAO,KAAK,WAAW,IAAK,aAAuD;CACrF,GACA,CAAC,MAAM,SAAS,CAClB;CAEA,MAAM,aAAa,kBAAkB;EACnC,kBAAiB,MAAM,MAAM,WAAW,IAAI,KAAK,IAAI,KAAK,MAAM,MAAO;CACzE,GAAG,CAAC,MAAM,MAAM,CAAC;CACjB,MAAM,aAAa,kBAAkB;EACnC,kBAAiB,MAAM,MAAM,WAAW,IAAI,KAAK,IAAI,IAAI,MAAM,UAAU,MAAM,MAAO;CACxF,GAAG,CAAC,MAAM,MAAM,CAAC;CACjB,MAAM,UAAU,kBAAkB;EAGhC,IAAI,YACF,yBAAyB,WAAW,KAAK,KAAK;CAClD,GAAG,CAAC,UAAU,CAAC;CACf,MAAM,SAAS,kBAA2D;EACxE,IAAI,CAAC,UAAU,MAAM,WAAW,GAC9B,OAAO;EACT,MAAM,OAAO,MAAM,KAAK,IAAI,eAAe,MAAM,SAAS,CAAC;EAC3D,OAAO,YAAY,MAAM,OAAO,MAAM,KAAK,UAAU;CACvD,GAAG;EAAC;EAAQ;EAAO;EAAe;CAAI,CAAC;CAKvC,OAAO,eACE;EAAE;EAAQ;EAAO;EAAS;EAAe;EAAY;EAAY;EAAQ;EAAS;CAAW,IACpG;EAAC;EAAQ;EAAO;EAAS;EAAe;EAAY;EAAY;EAAQ;EAAS;CAAU,CAC7F;AACF;;;AClNA,MAAa,mCAAmC;AAgBhD,MAAM,uBAAuB;;AAG7B,MAAM,eAAkD;CACtD,cAAc;EAAC;EAAM;EAAQ;CAAI;CACjC,QAAQ,CAAC,UAAU,IAAI;CACvB,QAAQ,CAAC,UAAU,KAAK;CACxB,MAAM,CAAC,QAAQ,MAAM;AACvB;AAEA,SAAS,WAAW,OAAuC;CACzD,OAAO,MAAM,IAAI,QAAQ,MAAM,SAAS;AAC1C;AAEA,SAAS,SAAS,OAAuC;CACvD,MAAM,UAAU,aAAa,MAAM,SAAS,SAAS,CAAC,MAAM,SAAS,IAAI;CACzE,OAAO;EAAC,MAAM,IAAI;EAAO,MAAM,IAAI,YAAY;EAAI,MAAM,SAAS;EAAO,MAAM;EAAW,GAAG;CAAO,CAAC,CAAC,KAAK,GAAG;AAChH;AAEA,SAAS,eAAe,OAAuC;CAC7D,MAAM,OAAO,CAAC,MAAM,SAAS;CAC7B,IAAI,MAAM,IAAI,QACZ,KAAK,KAAK,MAAM,IAAI,MAAM;CAC5B,KAAK,KAAK,UAAU,MAAM,SAAS,SAAS,CAAC;CAC7C,MAAM,MAAM,WAAW,KAAK;CAC5B,IAAI,QAAQ,MAAM,IAAI,OACpB,KAAK,KAAK,GAAG;CACf,OAAO,KAAK,KAAK,KAAK;AACxB;AAEA,SAAgB,eACd,SACA,OACA,QAAQ,sBACiC;CACzC,MAAM,IAAI,MAAM,KAAK,CAAC,CAAC,YAAY;CACnC,MAAM,QAAQ,EAAE,SAAS,IACrB,IAAI,IAAI,IAAI,IAAI,SAAS;EAAE,UAAU;EAAU,QAAQ;CAAmB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,IAAI,CAAC,IACrG;CACJ,MAAM,SAA4D,CAAC;CACnE,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,EAAE,WAAW,GAAG;GAClB,OAAO,KAAK;IAAE;IAAO,MAAM;GAAE,CAAC;GAC9B;EACF;EACA,MAAM,QAAQ,MAAM,IAAI,MAAM,YAAY;EAC1C,MAAM,WAAW,aAAa,MAAM,SAAS,SAAS,CAAC,MAAM,SAAS,IAAI,EAAA,CAAG,KAAI,MAAK,EAAE,YAAY,CAAC;EACrG,MAAM,YAAY,MAAM,UAAU,YAAY;EAC9C,IAAI,QAAQ,MAAK,MAAK,MAAM,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,UAAU,WAAW,CAAC,GAAG;GAC5E,OAAO,KAAK;IAAE;IAAO,MAAM;GAAE,CAAC;GAC9B;EACF;EACA,IAAI,MAAM,WAAW,CAAC,GAAG;GACvB,OAAO,KAAK;IAAE;IAAO,MAAM;GAAE,CAAC;GAC9B;EACF;EACA,IAAI,MAAM,SAAS,CAAC,KAAK,WAAW,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG;GACpE,OAAO,KAAK;IAAE;IAAO,MAAM;GAAE,CAAC;GAC9B;EACF;EACA,IAAI,OAAO,IAAI,KAAK,GAClB,OAAO,KAAK;GAAE;GAAO,MAAM;EAAE,CAAC;CAClC;CACA,OAAO,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,YAAY,EAAE,MAAM,SAAS,SAAS;CAChG,OAAO,OAAO,MAAM,GAAG,KAAK,CAAC,CAAC,KAA4C,EAAE,YAAY;EACtF,MAAM,UAAU,WAAW,KAAK;EAChC,OAAO;GACL,IAAI,YAAY,MAAM,SAAS;GAC/B,OAAO,MAAM,IAAI;GACjB,aAAa,eAAe,KAAK;GACjC,YAAY,GAAG,QAAQ;GACvB,MAAM;IAAE;IAAO;GAAQ;EACzB;CACF,CAAC;AACH;AAEA,SAAgB,kCAAkC,MAIJ;CAC5C,MAAM,QAAQ,KAAK,SAAS;CAC5B,OAAO;EACL,IAAI;EACJ,SAAS;EACT,OAAO;EACP,QAAQ,OAAO;GACb,MAAM,UAAU,KAAK,WAAW;GAChC,IAAI,QAAQ,SAAS,KAAK,CAAC,KAAK,eAC9B,OAAO,eAAe,SAAS,OAAO,KAAK;GAC7C,OAAO,KAAK,cAAc,CAAC,CAAC,MAAK,WAAU,eAAe,QAAQ,OAAO,KAAK,CAAC;EACjF;EAEA,uBAAuB,CAAC;CAC1B;AACF;;;;;;;;;;;;;;;;;;;;AChGA,SAAgB,eAAe,SAAyB;CACtD,OAAO,QAAQ,SAAS,aAAa;AACvC;;;;;;AAOA,SAAgB,eAAe,SAA6B;CAC1D,MAAM,OAAO,eAAe,OAAO;CACnC,IAAI,CAAC,WAAW,IAAI,GAClB,OAAO,CAAC;CACV,IAAI;EACF,MAAM,MAAM,aAAa,MAAM,MAAM;EACrC,MAAM,SAAS,KAAK,MAAM,GAAG;EAC7B,IAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAC/D,OAAO,CAAC;EACV,OAAO,oBAAoB,MAAiC;CAC9D,SACO,KAAK;EACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,8CAA8C,KAAK,KAAKC,eAAa,GAAG,EAAE,GAAG;EACpG,OAAO,CAAC;CACV;AACF;;;;;;AAOA,SAAS,oBAAoB,KAA0C;CACrE,MAAM,MAAkB,CAAC;CACzB,IAAI,OAAO,IAAI,cAAc,WAC3B,IAAI,YAAY,IAAI;CACtB,OAAO;AACT;;;;;;;;;;;;AC6ZA,SAAgB,cAAc,SAAsC;CAClE,MAAM,SAAS,QAAQ,UAAU,QAAQ,IAAI,iBAAiB;CAM9D,MAAM,qBAAqB,QAAQ,cAAc,QAAQ,IAAI;CAC7D,MAAM,aAAa,sBAAsB,QAAQ;CACjD,MAAM,QAAQ,oBAAoB;EAChC;EACA,GAAI,uBAAuB,KAAA,IAAY,EAAE,YAAY,mBAAmB,IAAI,CAAC;EAC7E,KAAK,QAAQ,OAAO,QAAQ,IAAI;EAChC,WAAW,QAAQ;CACrB,CAAC;CAQD,MAAM,YAAY,2BAA2B,EAAE,SAAS,MAAM,SAAS,CAAC;CACxE,IAAI,QAAQ,IAAI,iBAAiB,UAAU,QAAQ,KAAK,UAAU,SAAS,IACzE,QAAQ,OAAO,MACb,8CAA8C,UAAU,MAAM,YAAY,UAAU,QAAQ,WAAW,UAAU,OAAO,GAC1H;CAQF,IAAI,CAAC,QAAQ,OACX,MAAM,IAAI,MAAM,yJAAyJ;CAC3K,MAAM,QAAsB,OAAO,QAAQ,UAAU,aACjD,QAAQ,MAAM,KAAK,IACnB,QAAQ;CACZ,MAAM,aAAa,iBAAiB,MAAM,KAAK;CAC/C,MAAM,eAAe,WAAW,KAAK;CAMrC,MAAM,aAAgC,QAAQ,qBAAqB;CAOnE,MAAM,gBAAkC,QAAQ,aAAa;CAI7D,MAAM,YAA8B,qCAHM,OAAO,KAAK,WAAW,SAAS,CAAC,CAAC,WAAW,IACnF,gBACA;EAAE,GAAG,WAAW;EAAW,GAAG;CAAc,GAC0C,UAAU;CASpG,IAAI,QAAQ,UAAU,QAAQ,QAC5B,MAAM,IAAI,MACR,mLAGF;CAEF,MAAM,aAA4B,QAAQ,WACpC,QAAQ,SAAS,oBAAoB,QAAQ,MAAM,IAAI;CAG7D,MAAM,SAAwB,OAAO,KAAK,WAAW,MAAM,CAAC,CAAC,WAAW,IACpE,aACA;EAAE,GAAG,WAAW;EAAQ,GAAG;CAAW;CAC1C,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GACjC,MAAM,IAAI,MAAM,sEAAsE;CAUxF,QAAQ,IAAI,0BAA0B,gBAAgB,MAAM,OAAO;CACnE,eAAe,MAAM,SAAS,SAAS;CAEvC,MAAM,YAAY,mBAAmB,SAAS;CAE9C,MAAM,iBAAiB,QAAQ,SAC3B,sBAAsB,QAAQ,OAAO,UAAU,WAAW,MAAM,OAAO,IACvE;CACJ,MAAM,iBAAiB,QAAQ,SAC3B,iBACA,sBAAsB,cAAc,WAAW,MAAM,OAAO;CAChE,MAAM,gBAAgB,iBAClB,YAAY,gBAAgB,WAAW,cAAc;EACnD,OAAO,QAAQ,QAAQ;EACvB,UAAU,QAAQ,QAAQ;CAC5B,CAAC,IACD,iBACE,YAAY,gBAAgB,WAAW,YAAY,IACnD;CAQN,MAAM,iBAAiB,eACrB,QACA,KAAA,GACA,QAAQ,gBAAA,OACV;CACA,IAAI,CAAC,gBAEH,MAAM,IAAI,MAAM,iFAAiF;CAQnG,MAAM,iBAAiB,mBAAmB,MAAM,OAAO;CACvD,MAAM,cAAc,iBAAiB,cAAc;CACnD,MAAM,uBAAuB,WAAW,iBAAiB,YAAY,WAAW,IAC5E,CAAC,IACD,4BACE,WAAW,iBAAiB,aAC5B,cACF;CAEJ,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,iBAAiB,sBAAsB,aAAa,YAAY,CAAC,CAAC;EAClE;EACA;EACA;EACA;EACA,YAAY,QAAQ,cAAc;EAClC;EACA,oBAAoB,QAAQ,sBAAsB,CAAC;EACnD,iBAAiB,QAAQ,mBAAmB,CAAC;EAC7C,iBAAiB,qBAAqB,UAAU;EAChD,0BAA0B,WAAW;EACrC,oBAAoB,WAAW;EAC/B,4BAA4B,WAAW;EACvC,2BAA2B,WAAW;EACtC,sBAAsB,WAAW;EACjC,wBAAwB,QAAQ,0BAC1B,QAAQ,IAAI,oCAAoC;EACtD;EACA,QAAQ,QAAQ,UAAU;CAC5B;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAgB,oBAAoB,MAOlB;CAChB,MAAM,OAAO,mBAAmB;EAC9B,QAAQ,KAAK;EACb,GAAI,KAAK,eAAe,KAAA,IAAY,EAAE,YAAY,KAAK,WAAW,IAAI,CAAC;CACzE,CAAC;CAMD,MAAM,aAAa,eAAe,KAAK,SAAS;CAChD,MAAM,UAAU,aAAa,QAAQ,IAAI,iBAAiB;CAQ1D,MAAM,UAPmB,KAAK,aACzB,WACA,WAAW,aACX,QAI8B,gBAAgB,KAAK,GAAG,IAAI;CAM/D,MAAM,aAAa,UAAU,QAAQ,SAAS,KAAK,MAAM,IAAI;CAE7D,IAAI,cAAc,CAAC,WAAW,UAAU,GAAG;EACzC,IAAI;GACF,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;EAC3C,SACO,KAAK;GAIV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,oCAAoC,WAAW,YAAYC,eAAa,GAAG,EAAE,GAAG;GACvG,OAAO,cAAc,IAAI;EAC3B;EAOA,IAAI;GACF,cAAc,QAAQ,YAAY,YAAY,GAAG,KAAK;EACxD,SACO,KAAK;GACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,sCAAsC,WAAW,uBAAuBA,eAAa,GAAG,EAAE,GAAG;EACtH;CACF;CAEA,IAAI,YACF,OAAO;EACL,KAAK;EACL,SAAS,KAAK;EACd;EACA,IAAI,QAAQ,YAAY,aAAa;EACrC,OAAO,QAAQ,YAAY,YAAY;EACvC,WAAW,KAAK;EAChB,SAAS,KAAK;EACd,UAAU,KAAK;EACf,UAAU,KAAK;EACf,aAAa,KAAK;CACpB;CAEF,OAAO,cAAc,IAAI;AAC3B;AAEA,SAAS,cAAc,MAML;CAChB,OAAO;EACL,KAAK,KAAK;EACV,SAAS,KAAK;EACd,YAAY;EACZ,IAAI,QAAQ,KAAK,SAAS,aAAa;EACvC,OAAO,QAAQ,KAAK,UAAU,YAAY;EAC1C,WAAW,KAAK;EAChB,SAAS,KAAK;EACd,UAAU,KAAK;EACf,UAAU,KAAK;EACf,aAAa,KAAK;CACpB;AACF;;AAGA,SAAS,sBAAsB,QAAwE;CACrG,MAAM,WAAoC,EAAE,GAAG,OAAO;CAEtD,IAAI,sBAAsB,YAAY,EAAE,qBAAqB,WAC3D,SAAS,kBAAkB,SAAS,qBAAqB,QAAQ,aAAa;CAChF,OAAO,SAAS;CAEhB,IAAI,mBAAmB,YAAY,EAAE,qBAAqB,WACxD,SAAS,kBAAkB,SAAS,kBAAkB,QAAQ,WAAW;CAC3E,OAAO,SAAS;CAEhB,OAAO;AACT;;AAGA,SAAS,aAAa,KAA8C;CAClE,IAAI,QAAQ,KAAA,GACV,OAAO,KAAA;CACT,MAAM,IAAI,IAAI,KAAK,CAAC,CAAC,YAAY;CACjC,IAAI,MAAM,OAAO,MAAM,WAAW,MAAM,SAAS,MAAM,MACrD,OAAO;CACT,IAAI,MAAM,OAAO,MAAM,UAAU,MAAM,QAAQ,MAAM,OACnD,OAAO;CACT,QAAQ,OAAO,MAAM,oCAAoC,IAAI,oFAAoF;AAEnJ;AAEA,SAAS,mBAAmB,UAAwE;CAClG,QAAQ,QAAQ;EACd,MAAM,aAAa,SAAS;EAC5B,OAAO,aAAa,oBAAoB,UAAU,IAAI,CAAC;CACzD;AACF;AAEA,SAAS,qCACP,WACA,YACkB;CAClB,IAAI,WAAW,oBAAoB,WAAW,GAC5C,OAAO;CACT,MAAM,MAA0C,CAAC;CACjD,KAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,SAAS,GACtD,IAAI,OAAO;EACT,GAAG;EACH,eAAe;GACb,IAAI,WAAW,WAAW,QAAQ;GAClC,KAAK,MAAM,SAAS,WAAW,qBAC7B,IAAI;IACF,MAAM,OAAO,MAAM,MAAM,UAAU;KACjC,eAAe,MAAM;KACrB,QAAQ,MAAM;KACd;IACF,CAAC;IAID,IAAI,eAAe,IAAI,GACrB,WAAW;GACf,SACO,KAAK;IACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,uBAAuB,MAAM,cAAc,+BAA+BA,eAAa,GAAG,EAAE,GAAG;GACxH;GAEF,OAAO;EACT;CACF;CAEF,OAAO;AACT;AAEA,SAAS,eAAe,OAAmC;CACzD,IAAI,CAAC,SAAS,OAAO,UAAU,UAC7B,OAAO;CACT,MAAM,WAAW;CACjB,OAAO,OAAO,SAAS,SAAS,YAC3B,CAAC,CAAC,SAAS,QACX,OAAO,SAAS,SAAS,YACzB,OAAO,SAAS,gBAAgB,cAChC,OAAO,SAAS,gBAAgB,cAChC,OAAO,SAAS,qBAAqB,cACrC,OAAO,SAAS,uBAAuB,cACvC,OAAO,SAAS,WAAW;AAClC;AAEA,SAAS,sBACP,OACA,WACA,YACqB;CAQrB,IAAI,CAAC,MAAM,cAAc;EACvB,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,uFAAuF,WAAW,gDAAgD;EACzK,OAAO;CACT;CACA,IAAI,CAAC,UAAU,MAAM,eAAe;EAClC,IAAI,QAAQ,IAAI,cAAc;GAC5B,MAAM,QAAQ,OAAO,KAAK,SAAS,CAAC,CAAC,KAAK,IAAI,KAAK;GACnD,QAAQ,OAAO,MAAM,+CAA+C,MAAM,aAAa,+CAA+C,MAAM,IAAI;EAClJ;EACA,OAAO;CACT;CACA,MAAM,WAAW,WAAW,YAAY,SAAS;CACjD,MAAM,QAAQ,SAAS,MAAK,MAAK,EAAE,QAAQ,MAAM,gBAAgB,EAAE,SAAS;CAC5E,IAAI,CAAC,SAAS,QAAQ,IAAI,cAAc;EACtC,MAAM,QAAQ,SAAS,MAAK,MAAK,EAAE,QAAQ,MAAM,YAAY;EAC7D,QAAQ,OAAO,MAAM,2BAA2B,MAAM,aAAa,4FAA4F,QAAQ,KAAK,UAAU,MAAM,OAAO,IAAI,oCAAoC,IAAI;CACjP;CACA,OAAO,SAAS;AAClB;AAEA,SAAS,sBACP,KACA,WACA,YACqB;CACrB,IAAI,CAAC,UAAU,MACb,OAAO;CACT,OAAO,WAAW,YAAY,SAAS,CAAC,CAAC,MAAK,MAAK,EAAE,QAAQ,OAAO,EAAE,SAAS,KAAK;AACtF;AAEA,SAAS,YACP,MACA,WACA,OACA,YAA6D,CAAC,GAC/C;CACf,MAAM,aAAa,UAAU,KAAK;CAClC,IAAI,CAAC,YACH,OAAO;CACT,MAAM,aAAa,MAAM,sBAAsB,KAAK;CAIpD,MAAM,QAAQ,UAAU,SAAS,cAAc,WAAW,gBAAgB,mBAAmB,UAAU;CACvG,IAAI,CAAC,OACH,OAAO;CAIT,MAAM,SAAS,UAAU,aAAa,uBAAuB,YAAY,KAAK,IACzE,MAAM,oBAAoB,UAAU,WACrC,KAAA;CACJ,MAAM,eAAe,oBAAoB,YAAY,OAAO,MAAM,uBAAuB;CAIzF,MAAM,YAAY,sBAChB,MAAM,gBACN;EAAE,UAAU,KAAK;EAAK;CAAM,IAC5B,MAAK,UAAU,OAAO,KAAA,CACxB;CACA,OAAO;EACL,UAAU;EACV;EACA,GAAI,UAAU,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;EAC5C,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAC3B,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;CACzC;AACF;AAEA,SAAS,mBAAmB,YAAoD;CAC9E,IAAI;EACF,OAAO,WAAW,QAAQ,CAAC,CAAC,KAAK;CACnC,QACM;EACJ;CACF;AACF;;;ACz7BA,MAAM,gBAAgB,cAAqC,IAAI;AAE/D,SAAgB,eAAe,EAAE,QAAQ,YAA6D;CACpG,OAAO,oBAAC,cAAc,UAAf;EAAwB,OAAO;EAAS;CAAiC,CAAA;AAClF;AAEA,SAAgB,YAA4B;CAC1C,MAAM,MAAM,WAAW,aAAa;CACpC,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,gDAAgD;CAClE,OAAO;AACT;;;AC6DA,MAAM,mBAAmB,cAA4C,IAAI;AAEzE,SAAgB,kBAAkB,EAChC,OACA,YAIC;CACD,OACE,oBAAC,iBAAiB,UAAlB;EAAkC;EAC/B;CACwB,CAAA;AAE/B;;;;;;;;AASA,SAAgB,eAAsC;CACpD,MAAM,MAAM,WAAW,gBAAgB;CACvC,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,sDAAsD;CACxE,OAAO;AACT;;;;;;;;AASA,SAAgB,uBAAqD;CACnE,OAAO,WAAW,gBAAgB;AACpC;;;ACtDA,SAAgB,oBAAuB,SAAoD;CACzF,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,YAAY,IAAI,gBAAgB;CACtC,IAAI,YAA0C;CAC9C,IAAI,aAAmC;CACvC,IAAI,gBAAgB;CACpB,IAAI,UAAU;CAEd,MAAM,eAAe,KAAc,UAA0C;EAC3E,QAAQ,UAAU,KAAK,KAAK;CAC9B;CAEA,MAAM,qBAAoC;EACxC,gBAAgB,KAAK,IAAI;EACzB,MAAM,MAAM,QAAQ,KAAK,UAAU,MAAM,CAAC,CACvC,MAAM,UAAU;GACf,IAAI,SACF;GACF,QAAQ,OAAO,KAAK;EACtB,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,IAAI,SACF;GACF,YAAY,KAAK,SAAS;EAC5B,CAAC,CAAC,CACD,cAAc;GACb,IAAI,eAAe,KACjB,aAAa;EACjB,CAAC;EACH,aAAa;EACb,OAAO;CACT;CAEA,MAAM,OAAyB;EAC7B,SAAS;GACP,IAAI,SACF,OAAO,QAAQ,QAAQ,CAAC,CAAiB;GAC3C,IAAI,CAAC,WAAW;IACd,gBAAgB,KAAK,IAAI;IACzB,YAAY,QAAQ,KAAK,UAAU,MAAM,CAAC,CACvC,MAAM,UAAU;KACf,IAAI,SACF,OAAO,CAAC;KACV,QAAQ,OAAO,KAAK;KACpB,OAAO;IACT,CAAC,CAAC,CACD,OAAO,QAAQ;KACd,IAAI,CAAC,SACH,YAAY,KAAK,YAAY;KAC/B,OAAO,CAAC;IACV,CAAC;IACH,OAAO;GACT;GAEA,IAAI,CAAC,cAAc,KAAK,IAAI,IAAI,iBAAiB,YAC/C,aAAkB;GACpB,OAAO;EACT;EACA,UAAU;GACR,IAAI,SACF,OAAO,QAAQ,QAAQ;GACzB,IAAI,YACF,OAAO;GAKT,IAAI,CAAC,WACH,OAAO,KAAK,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC;GACpC,OAAO,aAAa;EACtB;EACA,eAAe;GACb,OAAO,eAAe;EACxB;EACA,QAAQ;GACN,IAAI,SACF;GACF,UAAU;GACV,UAAU,MAAM;EAClB;CACF;CACA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7HA,SAAgB,mBAAmB,MAAwB;CACzD,MAAM,SAAmB,CAAC;CAC1B,IAAI,UAAU;CAGd,IAAI,QAA2B;CAG/B,IAAI,SAAS;CAEb,KAAK,MAAM,MAAM,MAAM;EACrB,IAAI,OAAO;GACT,IAAI,OAAO,OACT,QAAQ;QAER,WAAW;GACb;EACF;EACA,IAAI,OAAO,QAAO,OAAO,KAAM;GAC7B,QAAQ;GACR,SAAS;GACT;EACF;EACA,IAAI,OAAO,OAAO,OAAO,OAAQ,OAAO,QAAQ,OAAO,MAAM;GAC3D,IAAI,YAAY,MAAM,QAAQ;IAC5B,OAAO,KAAK,OAAO;IACnB,UAAU;IACV,SAAS;GACX;GACA;EACF;EACA,WAAW;CACb;CACA,IAAI,YAAY,MAAM,QACpB,OAAO,KAAK,OAAO;CACrB,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,cAAc,OAAuB;CACnD,IAAI,UAAU,IACZ,OAAO;CACT,IAAI,CAAC,iBAAiB,KAAK,KAAK,GAC9B,OAAO;CACT,OAAO,IAAI,MAAM,QAAQ,MAAM,MAAI,EAAE;AACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvDA,SAAgB,oBAAuB,MAYlB;CACnB,MAAM,EAAE,UAAU,eAAe,YAAY;CAC7C,MAAM,EAAE,SAAS,OAAO,YAAY,WAAW;CAC/C,MAAM,YAAY,SAAS;CAE3B,MAAM,aAAa,cAAmC;EACpD,IAAI,cAAc,KAAA,GAChB,OAAO,IAAI,IAAI,QAAQ,IAAI,KAAK,CAAC;EACnC,OAAO,IAAI,IAAI,SAAS;CAC1B,GAAG;EAAC;EAAW;EAAS;CAAK,CAAC;CAS9B,MAAM,cAAc,cACZ,IAAI,IAAI,UAAU,QAAQ,IAAI,KAAK,CAAC,GAC1C;EAAC;EAAQ;EAAS;CAAK,CACzB;CAoBA,OAAO;EAAE;EAAY,QAlBN,aAAa,SAAiB;GAO3C,MAAM,OAAO,IAAI,IAAI,UAAU;GAC/B,IAAI,KAAK,IAAI,IAAI,GACf,KAAK,OAAO,IAAI;QAEhB,KAAK,IAAI,IAAI;GACf,MAAM,YAAY,CAAC,GAAG,IAAI,CAAC,CACxB,QAAO,MAAK,YAAY,IAAI,CAAC,CAAC,CAAC,CAC/B,KAAK;GACR,WAAW,YAAY,SAAS;EAClC,GAAG;GAAC;GAAY;GAAa;GAAY;EAAU,CAEzB;CAAE;AAC9B;;;AChDA,SAAS,KAAK,QAAiD;CAC7D,OAAO;EACL,MAAM,OAAO;EACb,WAAW,OAAO;EAClB,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;EACxC,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EACpD,YAAY,OAAO,OAAO,KAAK;CACjC;AACF;AAEA,SAAgB,uBAAuB,SAA0D;CAC/F,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,uBAAO,IAAI,IAAuB;CACxC,MAAM,yBAAS,IAAI,IAAwD;CAC3E,MAAM,UAAU,QAAQ,aAAa,SAAS,SAAS,kBAAkB,SAAS,KAAA,GAAW,KAAA,GAAW,IAAI;CAE5G,SAAS,WAAW,KAAgC;EAClD,MAAM,MAAM,OAAO,IAAI,GAAG;EAC1B,IAAI,OAAO,KAAK,IAAI,IAAI,IAAI,KAAK,cAC/B,OAAO,IAAI;EACb,MAAM,WAAY,QAAQ,aAAa,KAAK,CAAC;EAC7C,MAAM,UAAU,0BAA0B,KAAK,QAAQ,QAAQ,QAAQ,CAAC,CAAC,QAAO,MAAK,EAAE,UAAU,SAAS;EAC1G,OAAO,IAAI,KAAK;GAAE,IAAI,KAAK,IAAI;GAAG;EAAQ,CAAC;EAC3C,OAAO;CACT;CAEA,SAAS,QAAQ,KAAa,OAAwB;EACpD,MAAM;EACN,IAAI,MAAM,OAAO,GACf;EACF,MAAM,QAAQ,iBAAiB;GAC7B,IAAI,KAAK,IAAI,GAAG,MAAM,OACpB;GACF,KAAK,OAAO,GAAG;GACf,MAAM,WAAW,MAAK,MAAK,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAC7D,GAAG,MAAM;EAET,MAAM,MAAM,QAAQ;CACtB;CAEA,SAAS,QAAQ,KAAa,QAA4D;EACxF,MAAM,MAAM,GAAG,IAAI,QAAQ,KAAK,UAAU,MAAM;EAChD,IAAI,QAAQ,KAAK,IAAI,GAAG;EACxB,IAAI,CAAC,OAAO;GACV,MAAM,QAAQ,QAAQ;GACtB,MAAM,aAAa,QAAQ,oBAAoB,CAAC,MAAM,GAAG,GAAG,GAAG,EAC7D,GAAI,QAAQ,EAAE,oBAAoB,MAAuB,IAAI,iBAAiB;IAAE,MAAM,EAAE;IAAM,OAAO,MAAM;GAAE,CAAC,EAAE,IAAI,CAAC,EACvH,CAAC;GACD,QAAQ;IAAE;IAAY,MAAM;GAAE;GAC9B,KAAK,IAAI,KAAK,KAAK;GAEnB,WAAW,YAAY;IACrB,IAAI,KAAK,IAAI,GAAG,MAAM,OACpB,KAAK,OAAO,GAAG;GACnB,CAAC;EACH;EACA,IAAI,MAAM,OACR,aAAa,MAAM,KAAK;EAC1B,MAAM;EACN,OAAO;GAAE;GAAK;EAAM;CACtB;CAEA,OAAO;EACL,SAAS,OAAM,QAAO,WAAW,GAAG,CAAC,CAAC,IAAI,IAAI;EAC9C,UAAU,OAAO,KAAK,QAAQ,MAAM,MAAM,SAAS;GACjD,MAAM,SAAS,WAAW,GAAG,CAAC,CAAC,MAAK,MAAK,EAAE,SAAS,MAAM;GAC1D,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,eAAe,OAAO,kCAAkC;GAC1E,MAAM,EAAE,KAAK,UAAU,QAAQ,KAAK,MAAM;GAC1C,IAAI;IACF,MAAM,aAAa,MAAM,MAAM;IAC/B,MAAM,SAAS,OAAO,OAAO,KAAK;IAClC,MAAM,MAAM,WAAW,MAAM,GAAG,SAAS;IACzC,IAAI,CAAC,KAAK;KAGR,IAAI,CAAC,OAAO,KAAK,WAAW,KAAK,CAAC,CAAC,MAAK,SAAQ,KAAK,WAAW,MAAM,CAAC,KAAK,KAAK,IAAI,GAAG,MAAM,OAAO;MACnG,KAAK,OAAO,GAAG;MACf,WAAW,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS;KAC1C;KACA,MAAM,IAAI,MAAM,eAAe,OAAO,oBAAoB,KAAK,sDAAsD;IACvH;IACA,MAAM,SAAS,KAAK,UAAU,YAAY,IAAI,CAAC,YAAY,QAAQ,KAAK,OAAO,GAAG,GAAI,KAAK,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAE,CAAC,IAAI,KAAK;IAGjI,MAAM,MAAM;KAAE,QAAQ;KAAa,QAAQ,OAAO,WAAW;KAAG,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAAG;IAC9F,IAAI;KACF,OAAO;MAAE,MAAM,iBAAiB,MAAM,IAAI,QAAQ,MAAM,GAAG,CAAC;MAAG,SAAS;KAAM;IAChF,SACO,KAAK;KAEV,OAAO;MAAE,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;MAAG,SAAS;KAAK;IACjF;GACF,UACQ;IACN,QAAQ,KAAK,KAAK;GACpB;EACF;EACA,SAAS,YAAY;GACnB,MAAM,UAAU,CAAC,GAAG,KAAK,OAAO,CAAC;GACjC,KAAK,MAAM;GACX,OAAO,MAAM;GACb,MAAM,QAAQ,IAAI,QAAQ,IAAI,OAAO,MAAM;IACzC,IAAI,EAAE,OACJ,aAAa,EAAE,KAAK;IACtB,MAAM,EAAE,WAAW,MAAK,MAAK,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;GAC/D,CAAC,CAAC;EACJ;CACF;AACF;;;;;;;;;ACnHA,MAAM,oBAAoB;;;;;;;AAQ1B,MAAM,+BAAe,IAAI,IAAY;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;;;;;;;AA2BD,eAAsB,iBAAiB,OAAgC,CAAC,GAAyB;CAC/F,MAAM,MAAM,QAAQ,KAAK,OAAO,QAAQ,IAAI,CAAC;CAC7C,MAAM,WAAW,KAAK,YAAY;CAClC,MAAM,SAAS,KAAK;CAEpB,IAAI;EAEF,OAAO,UAAU,MADG,WAAW,KAAK,MAAM,GAClB,OAAO,QAAQ;CACzC,SACO,KAAK;EACV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,sCAAsCC,eAAa,GAAG,EAAE,qCAAqC;EACpH,IAAI;GAEF,OAAO,UAAU,MADG,UAAU,KAAK,UAAU,MAAM,GAC3B,MAAM,QAAQ;EACxC,SACO,OAAO;GACZ,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,iCAAiCA,eAAa,KAAK,EAAE,GAAG;GAC/E,OAAO,CAAC;EACV;CACF;AACF;;;;;;;;;;;;AAaA,eAAe,WAAW,KAAa,QAAoD;CACzF,OAAO,IAAI,SAAmB,UAAU,YAAY;EAClD,MAAM,QAAQ,MAAM,OAAO;GAAC;GAAY;GAAY;GAAY;GAAsB;EAAI,GAAG;GAC3F;GACA,OAAO;IAAC;IAAU;IAAQ;GAAM;EAClC,CAAC;EAKD,MAAM,eAAyB,CAAC;EAChC,MAAM,eAAyB,CAAC;EAChC,MAAM,gBAAgB,MAAM,KAAK,SAAS;EAC1C,IAAI,QAAQ;GACV,IAAI,OAAO,SAAS;IAClB,MAAM,KAAK,SAAS;IACpB,wBAAQ,IAAI,MAAM,SAAS,CAAC;IAC5B;GACF;GACA,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;EAC1D;EACA,MAAM,OAAO,YAAY,MAAM;EAC/B,MAAM,OAAO,YAAY,MAAM;EAC/B,MAAM,OAAO,GAAG,SAAQ,UAAS,aAAa,KAAK,KAAK,CAAC;EACzD,MAAM,OAAO,GAAG,SAAQ,UAAS,aAAa,KAAK,KAAK,CAAC;EACzD,MAAM,GAAG,UAAU,QAAQ;GACzB,QAAQ,oBAAoB,SAAS,OAAO;GAC5C,QAAQ,GAAG;EACb,CAAC;EACD,MAAM,GAAG,UAAU,SAAS;GAC1B,QAAQ,oBAAoB,SAAS,OAAO;GAC5C,IAAI,QAAQ,SAAS;IACnB,wBAAQ,IAAI,MAAM,SAAS,CAAC;IAC5B;GACF;GACA,IAAI,SAAS,GAAG;IACd,wBAAQ,IAAI,MAAM,uBAAuB,KAAK,IAAI,aAAa,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC;IACjF;GACF;GAGA,SADc,aAAa,KAAK,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,CAC1D,CAAC;EAChB,CAAC;CACH,CAAC;AACH;;;;;;AAOA,eAAe,UACb,KACA,UACA,QACmB;CACnB,MAAM,MAAgB,CAAC;CACvB,MAAM,QAAkB,CAAC,GAAG;CAC5B,OAAO,MAAM,SAAS,GAAG;EACvB,IAAI,QAAQ,SACV,MAAM,IAAI,MAAM,SAAS;EAC3B,MAAM,MAAM,MAAM,IAAI;EACtB,MAAM,MAAM,QAAQ,MAAM,MAAM,QAAQ,KAAK,GAAG;EAChD,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;EACtD,QACM;GAGJ;EACF;EACA,KAAK,MAAM,KAAK,SAAS;GACvB,IAAI,aAAa,IAAI,EAAE,IAAI,GACzB;GACF,MAAM,WAAW,QAAQ,MAAM,EAAE,OAAO,GAAG,MAAM,MAAM,EAAE;GACzD,IAAI,EAAE,YAAY,GAChB,MAAM,KAAK,QAAQ;QAEhB,IAAI,EAAE,OAAO,GAAG;IACnB,IAAI,KAAK,eAAe,QAAQ,CAAC;IACjC,IAAI,IAAI,UAAU,UAChB,OAAO;GACX,OACK,IAAI,EAAE,eAAe,GAAG;IAI3B,IAAI;IACJ,IAAI;KACF,KAAK,MAAM,KAAK,QAAQ,KAAK,EAAE,IAAI,CAAC;IACtC,QACM;KACJ;IACF;IACA,IAAI,GAAG,OAAO,GAAG;KACf,IAAI,KAAK,eAAe,QAAQ,CAAC;KACjC,IAAI,IAAI,UAAU,UAChB,OAAO;IACX;GACF;EACF;CACF;CACA,OAAO;AACT;AAEA,SAAS,eAAe,GAAmB;CACzC,OAAO,QAAQ,MAAM,IAAI,EAAE,WAAW,KAAK,GAAG;AAChD;;;;;;AAOA,SAAgB,qBAAqB,OAA0B,SAAuB,OAAO,WAAW,mBAAgC;CACtI,OAAO,UAAU,OAAO,QAAQ,QAAQ;AAC1C;AAEA,SAAS,UAAU,OAA0B,QAAsB,UAA+B;CAChG,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAmB,CAAC;CAC1B,KAAK,MAAM,OAAO,OAAO;EACvB,MAAM,OAAO,eAAe,GAAG;EAC/B,IAAI,KAAK,WAAW,KAAK,KAAK,IAAI,IAAI,GACpC;EACF,KAAK,IAAI,IAAI;EACb,MAAM,YAAY,KAAK,YAAY,GAAG;EACtC,MAAM,OAAO,aAAa,IAAI,KAAK,MAAM,YAAY,CAAC,IAAI;EAC1D,IAAI,KAAK;GAAE;GAAM;GAAM;GAAQ,MAAM;EAAO,CAAC;EAC7C,IAAI,IAAI,UAAU,UAChB;CACJ;CAMA,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,SAAS,KAAK;EACvB,IAAI,IAAI,MAAM;EACd,KAAK,IAAI,MAAM,EAAE,YAAY,GAAG,GAAG,MAAM,GAAG,MAAM,EAAE,YAAY,GAAG,GAAG;GACpE,IAAI,EAAE,MAAM,GAAG,GAAG;GAClB,IAAI,KAAK,IAAI,CAAC,GACZ;GACF,KAAK,IAAI,CAAC;EACZ;CACF;CACA,IAAI,WAAW;CACf,KAAK,MAAM,QAAQ,MAAM;EACvB,MAAM,YAAY,KAAK,YAAY,GAAG;EACtC,MAAM,OAAO,aAAa,IAAI,KAAK,MAAM,YAAY,CAAC,IAAI;EAC1D,IAAI,KAAK;GAAE;GAAM;GAAM;GAAQ,MAAM;EAAM,CAAC;EAC5C,IAAI,EAAE,YAAY,UAChB;CACJ;CACA,OAAO;AACT;;;;;;;;;;;;AC3JA,SAAgB,WAAW,SAAoC;CAC7D,MAAM,EACJ,QACA,MACA,SACA,wBACA,2BACA,gBACA,mBACA,QACA,YACA,YACA,aACA,aACA,gBACA,mBACA,YACA,YACA,aACA,mBACA,kBACA,iBACA,cACA,YACA,iBAAiB,MACjB,qBACE;CAYJ,MAAM,YAAyB,iBAAiB,OAC5C;EAAE,KAAK,YAAY;EAAW,OAAO,GAAG,aAAa;CAAQ,IAC7D;CACJ,MAAM,aAAa,UAA0B,YAAY,CAAC,GAAG,OAAO,SAAS,IAAI;CAKjF,IAAI,SACF,OAAO,UAAU;EAAC;GAAE,KAAK;GAAM,OAAO;EAAW;EAAG;GAAE,KAAK;GAAK,OAAO;EAAS;EAAG;GAAE,KAAK,wBAAwB,YAAY,QAAQ;GAAG,OAAO;EAAY;CAAC,CAAC;CAChK,IAAI,wBACF,OAAO,UAAU;EAAC;GAAE,KAAK;GAAM,OAAO;EAAW;EAAG;GAAE,KAAK;GAAK,OAAO;EAAS;EAAG;GAAE,KAAK,wBAAwB,YAAY,QAAQ;GAAG,OAAO;EAAY;CAAC,CAAC;CAChK,IAAI,2BACF,OAAO,UAAU;EAAC;GAAE,KAAK;GAAM,OAAO;EAAW;EAAG;GAAE,KAAK;GAAK,OAAO;EAAS;EAAG;GAAE,KAAK;GAAO,OAAO;EAAkB;CAAC,CAAC;CAC9H,IAAI,MAAM;EAKR,MAAM,gBAAwB,CAAC;EAC/B,IAAI,oBAAoB,GACtB,cAAc,KAAK;GACjB,KAAK,YAAY;GACjB,OAAO,sBAAsB,IAAI,WAAW,WAAW,kBAAkB;EAC3E,CAAC;EAEH,cAAc,KAAK;GAAE,KAAK,wBAAwB,YAAY,QAAQ;GAAG,OAAO;EAAQ,CAAC;EACzF,cAAc,KAAK;GAAE,KAAK;GAAO,OAAO;EAAW,CAAC;EAGpD,IAAI,YACF,cAAc,KAAK;GAAE,KAAK;GAAI,OAAO;GAAY,YAAY;EAAW,CAAC;EAC3E,OAAO,UAAU,aAAa;CAChC;CACA,IAAI,WAAW,QACb,OAAO;EAAC;GAAE,KAAK;GAAM,OAAO;EAAW;EAAG;GAAE,KAAK;GAAK,OAAO;EAAS;EAAG;GAAE,KAAK;GAAO,OAAO;EAAO;CAAC;CACxG,IAAI,WAAW,YACb,OAAO;EACL;GAAE,KAAK;GAAM,OAAO;EAAW;EAC/B;GAAE,KAAK;GAAK,OAAO;EAAO;EAC1B;GAAE,KAAK;GAAO,OAAO,mBAAmB,oBAAoB;EAAe;EAC3E;GAAE,KAAK,YAAY;GAAoB,OAAO;EAAU;EACxD;GAAE,KAAK,YAAY;GAAc,OAAO;EAAW;EACnD;GAAE,KAAK;GAAO,OAAO,iBAAiB,SAAS;EAAO;CACxD;CA0BF,MAAM,aAAa,CAAC,aAAa,iBAAiB,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK;CACjF,MAAM,YAAyB,aAC3B;EACE,KAAK,YAAY;EACjB,OAAO;EACP,YAAY;EACZ,GAAI,aACA,EAAE,OAAO;GAAE,KAAK,WAAW,YAAY,gBAAgB;GAAG,SAAS,YAAY;GAAkB,UAAU;GAAgB,OAAO;GAAY,YAAY;EAAY,EAAE,IACxK,CAAC;CACP,IACA;CAMJ,MAAM,aAA0B,mBAAmB,IAC/C;EACE,KAAK;EACL,UAAU;EACV,OAAO,qBAAqB,IAAI,YAAY,GAAG,iBAAiB;EAChE,YAAY;CACd,IACA;CAMJ,MAAM,iBAA8B,oBAAoB,IACpD;EACE,KAAK,YAAY;EACjB,OAAO,sBAAsB,IAAI,gBAAgB,gBAAgB,kBAAkB;CACrF,IACA;CAMJ,IAAI,WAAW,WACb,OAAO;EACL,GAAI,oBAAoB,CAAC;GAAE,KAAK,YAAY;GAAY,OAAO;GAAY,YAAY;EAAW,CAAC,IAAI,CAAC;EACxG,GAAI,YAAY,CAAC,SAAS,IAAI,CAAC;EAC/B;GAAE,KAAK,YAAY;GAAc,OAAO;EAAW;CACrD;CAEF,OAAO;EACL,GAAI,oBAAoB,CAAC;GAAE,KAAK,YAAY;GAAY,OAAO;GAAY,YAAY;EAAW,CAAC,IAAI,CAAC;EACxG,GAAI,YAAY,CAAC,SAAS,IAAI,CAAC;EAC/B,GAAI,aAAa,CAAC,UAAU,IAAI,CAAC;EACjC,GAAI,YAAY,CAAC,SAAS,IAAI,CAAC;EAC/B,GAAI,iBAAiB,CAAC,cAAc,IAAI,CAAC;EACzC,GAAI,iBAAiB,CAAC;GAAE,KAAK,YAAY;GAAoB,OAAO;EAAU,CAAC,IAAI,CAAC;EACpF;GAAE,KAAK,YAAY;GAAc,OAAO;EAAW;EACnD;GAAE,KAAK;GAAO,OAAO;EAAW;EAIhC,GAAI,iBAAiB,CAAC,cAAc,IAAI,CAAC;EACzC,GAAI,aAAa,CAAC,UAAU,IAAI,CAAC;CACnC;AACF;;;;;;;;;AAUA,SAAgB,WAAW,MAAsB;CAC/C,OAAO,KAAK,WAAW,OAAO,IAAI,IAAI,KAAK,MAAM,CAAc,MAAM;AACvE;;;;;;;;;;;;;AClQA,SAAgB,iBAAiB,MAAc,KAAqB;CAClE,IAAI,OAAO,GACT,OAAO;CACT,IAAI,KAAK,UAAU,KACjB,OAAO;CACT,IAAI,QAAQ,GACV,OAAO;CACT,OAAO,GAAG,KAAK,MAAM,GAAG,MAAM,CAAC,EAAE;AACnC;;;;;;;AAiBA,SAAgB,YAAY,OAAgC;CAC1D,IAAI,MAAM,WAAW,GACnB,OAAO;CACT,OAAO,MAAM,QAAQ,KAAK,GAAG,MAAM,MAAM,WAAW,CAAC,KAAK,IAAI,IAAI,IAAI,IAAI,CAAC;AAC7E;;AAGA,SAAS,WAAW,GAAiB;CAGnC,OAFa,EAAE,IAAI,SAAS,IAAI,EAAE,MAAM,UAC1B,EAAE,QAAQ,EAAE,MAAM,IAAI,SAAS,IAAI,EAAE,MAAM,MAAM,SAAS;AAE1E;;;;;;;;;AAUA,MAAa,cAA+B,OAAO,OAAO,CAAC,CAAC;;;;;;;;;;;;AAa5D,SAAgB,iBAAiB,OAAwB,QAAiC;CACxF,IAAI,UAAU,KAAK,MAAM,WAAW,GAClC,OAAO;CACT,MAAM,MAAc,CAAC;CACrB,IAAI,OAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,IAAI,MAAM;EAChB,MAAM,QAAQ,IAAI,IAAI,IAAI,KAAK,WAAW,CAAC;EAC3C,IAAI,OAAO,OAAO,QAChB;EACF,IAAI,KAAK,CAAC;EACV,QAAQ;CACV;CACA,IAAI,IAAI,WAAW,GACjB,OAAO;CACT,OAAO,IAAI,WAAW,MAAM,SAAS,QAAQ;AAC/C;;;ACzGA,MAAM,eAAe,cAA+B,CAAC,CAAC;AACtD,MAAM,kBAAkB,cAAsD,IAAI;;;;;AAMlF,SAAgB,gBAAgB,EAAE,YAAqC;CACrE,MAAM,CAAC,OAAO,YAAY,SAA0B,CAAC,CAAC;CACtD,MAAM,WAAW,aAAa,UAAwB;EACpD,UAAS,SAAQ,cAAc,MAAM,KAAK,CAAC;CAC7C,GAAG,CAAC,CAAC;CACL,OACE,oBAAC,aAAa,UAAd;EAAuB,OAAO;EAC5B,UAAA,oBAAC,gBAAgB,UAAjB;GAA0B,OAAO;GAC9B;EACuB,CAAA;CACL,CAAA;AAE3B;AAEA,SAAgB,kBAAmC;CACjD,OAAO,WAAW,YAAY;AAChC;AAEA,SAAgB,qBAAoD;CAClE,MAAM,WAAW,WAAW,eAAe;CAC3C,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,0DAA0D;CAC5E,OAAO;AACT;;;;;;;;;;;;;;;;;ACRA,SAAgB,oBACd,SACA,UACA,eACiB;CACjB,MAAM,MAAuB,CAAC;CAC9B,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,KAAK;GAAE,MAAM;GAAU;EAAM,CAAC;EAClC,IAAI,CAAC,SAAS,IAAI,MAAM,OAAO,IAAI,GACjC;EACF,MAAM,QAAQ,cAAc,MAAM,OAAO,SAAS,CAAC;EACnD,IAAI,MAAM,WAAW,GAAG;GACtB,IAAI,KAAK;IAAE,MAAM;IAAc,YAAY,MAAM,OAAO;GAAK,CAAC;GAC9D;EACF;EACA,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK;GAAE,MAAM;GAAQ,YAAY,MAAM,OAAO;GAAM;EAAK,CAAC;CAClE;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,KAA4B;CAC3D,OAAO,IAAI,SAAS,WAAW,IAAI,MAAM,OAAO,OAAO,IAAI;AAC7D;;;;;;;;AASA,SAAgB,iBAAiB,MAAgC,YAA4B;CAC3F,OAAO,KAAK,WACV,MAAK,EAAE,SAAS,YAAY,EAAE,MAAM,OAAO,SAAS,UACtD;AACF;;;;;;;;;;;;;ACxCA,SAAgB,oBAAoB,MAGf;CACnB,MAAM,EAAE,UAAU,eAAe,YAAY;CAC7C,MAAM,cAAc,aACjB,SAAuC,WAAW,oBAAoB,IAAI,GAC3E,CAAC,UAAU,CACb;CAEA,MAAM,eAAe,cAAc,KAAK,QAAQ,KAAI,MAAK,EAAE,IAAI,GAAG,CAAC,KAAK,OAAO,CAAC;CAChF,MAAM,mBAAmB,SAAS;CAElC,OAAO,cACC,gBAAgB;EACpB,YAAY,KAAK;EACjB;EACA;EACA,qBAAqB;CACvB,CAAC,GACD;EAAC,KAAK;EAAY;EAAc;EAAkB;CAAW,CAC/D;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,oBAAoB,MAEC;CACnC,MAAM,EAAE,UAAU,eAAe,YAAY;CAC7C,MAAM,cAAc,aACjB,SAAuC,WAAW,oBAAoB,IAAI,GAC3E,CAAC,UAAU,CACb;CACA,MAAM,mBAAmB,SAAS;CAElC,OAAO,cAAc;EACnB,MAAM,MAAwC,CAAC;EAC/C,KAAK,MAAM,CAAC,YAAY,YAAY,OAAO,QAAQ,KAAK,eAAe,GACrE,IAAI,cAAc,gBAAgB;GAChC;GACA,cAAc,QAAQ,KAAI,MAAK,EAAE,IAAI;GACrC;GACA,qBAAqB;EACvB,CAAC;EAEH,OAAO;CACT,GAAG;EAAC,KAAK;EAAiB;EAAkB;CAAW,CAAC;AAC1D;;;;;;;;;;;AAYA,SAAgB,gBAAgB,MAKX;CACnB,MAAM,EAAE,YAAY,cAAc,kBAAkB,wBAAwB;CAC5E,MAAM,gBAAgB,mBAAmB;CACzC,MAAM,aAAa,IAAI,IAAI,YAAY;CAEvC,MAAM,oBAAyC;EAC7C,IAAI,CAAC,iBAAiB,cAAc,WAAW,GAC7C,OAAO,IAAI,IAAI,YAAY;EAC7B,MAAM,OAAO,IAAI,IAAI,aAAa;EAClC,OAAO,IAAI,IAAI,aAAa,QAAO,SAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;CAC7D,EAAA,CAAG;CAEH,MAAM,UAAU,aAA2B;EAMzC,MAAM,cAAc,IAAI,IAAI,iBAAiB,CAAC,CAAC;EAC/C,IAAI,YAAY,IAAI,QAAQ,GAC1B,YAAY,OAAO,QAAQ;OAE3B,YAAY,IAAI,QAAQ;EAE1B,MAAM,gBAAgB,CAAC,GAAG,WAAW,CAAC,CACnC,QAAO,MAAK,WAAW,IAAI,CAAC,CAAC,CAAC,CAC9B,KAAK;EAGR,MAAM,UAA6C,EAAE,GADrC,oBAAoB,CAAC,EAC2B;EAChE,IAAI,cAAc,WAAW,GAI3B,OAAO,QAAQ;OAGf,QAAQ,cAAc;EAMxB,MAAM,OACF,OAAO,KAAK,OAAO,CAAC,CAAC,WAAW,IAAI,KAAA,IAAY;EACpD,oBAAoB,IAAI;CAC1B;CAEA,OAAO;EAAE;EAAY;CAAO;AAC9B;;;AC9JA,SAAgB,cAAc,YAAyC;CACrE,OAAO,WAAW,kBAAkB,KAAA;AACtC;;AAGA,SAAgB,yBAAyB,YAAyC;CAChF,OAAO,WAAW,eAAe,uBAAuB;AAC1D;;;;;;;;AAiDA,eAAsB,cACpB,YACA,SAC2B;CAC3B,IAAI,CAAC,WAAW,eACd,MAAM,IAAI,MACR,2BAA2B,WAAW,MAAM,IAAI,WAAW,IAAI,2BACjE;CASF,IAAI,mBAAmB;CAEvB,MAAM,YAAiC;EACrC,SAAS,SAAS;GAChB,IAAI,kBACF;GACF,QAAQ,MAAM,KAAK,KAAK,KAAK,YAAY;GAIzC,IAAI,QAAQ,gBAAgB,OAC1B,eAAoB,KAAK,GAAG;EAChC;EACA,eAAe,SAAS;GACtB,mBAAmB;GACnB,IAAI,QAAQ,cAAc;IACxB,QAAQ,aAAa,IAAI;IACzB;GACF;GAOA,QAAQ,MAAM,KAAK,iBAAiB,cAAc,KAAK,SAAS,eAAe;GAC/E,QAAQ,aACN,gBAAgB,KAAK,SAAS,SAAS,KAAK,iBAC9C;GACA,IAAI,QAAQ,gBAAgB,OAC1B,eAAoB,KAAK,eAAe;EAC5C;EACA,UAAU,OAAO,WAAW;GAC1B,IAAI,CAAC,QAAQ,UACX,MAAM,IAAI,MACR,mBAAmB,WAAW,MAAM,2BAA2B,OAAO,QAAQ,qCAChF;GAEF,OAAO,QAAQ,SAAS,MAAM;EAChC;EACA,UAAU,OAAO,WAAW;GAC1B,IAAI,QAAQ,UACV,OAAO,QAAQ,SAAS,MAAM;GAGhC,OAAO,OAAO,QAAQ,EAAE,EAAE;EAC5B;EACA,YAAY,QAAQ;EACpB,QAAQ,QAAQ;EAChB,GAAI,QAAQ,oBAAoB,EAAE,mBAAmB,QAAQ,kBAAkB,IAAI,CAAC;CACtF;CACA,IAAI,QAAQ,mBAAmB,OAC7B,UAAyC,iBAAiB;CAE5D,OAAO,WAAW,cAAc,MAAM,SAAS;AACjD;;;;;;;;;;;;;;;;;;;;;;;ACrIA,MAAM,iCAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAO;AAAO,CAAC;;;;;;;;;;;;AAazE,SAAgB,uBAAuB,SAA6B;CAClE,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,OAAO;CAC1B,QACM;EACJ,OAAO;CACT;CACA,MAAM,WAAW,OAAO,aAAa,IAAI,cAAc;CACvD,IAAI,CAAC,UACH,OAAO;CACT,IAAI;EACF,OAAO,IAAI,IAAI,QAAQ;CACzB,QACM;EACJ,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,SAAgB,uBAAuB,QAAgB,SAA0B;CAC/E,MAAM,UAAU,OAAO,KAAK;CAC5B,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,2CAA2C;CAI7D,IAAI,2BAA2B,KAAK,OAAO,GACzC,OAAO;CAET,MAAM,WAAW,UAAU,uBAAuB,OAAO,IAAI;CAC7D,IAAI,CAAC,UACH,MAAM,IAAI,MACR,oHACF;CAQF,IAAI,QAAQ,WAAW,GAAG,GAAG;EAC3B,MAAM,SAAS,IAAI,IAAI,SAAS,QAAQ;EACxC,IAAI,CAAC,OAAO,aAAa,IAAI,MAAM,KAAK,CAAC,OAAO,aAAa,IAAI,OAAO,GACtE,MAAM,IAAI,MAAM,0FAAyF;EAC3G,OAAO,OAAO,SAAS;CACzB;CAEA,MAAM,SAAS,IAAI,IAAI,SAAS,SAAS,CAAC;CAC1C,MAAM,QAAQ,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;CAQ3D,IAAI,CADa,cAAc,KAAK,KACxB,KAAK,MAAM,SAAS,GAAG,GAAG;EACpC,MAAM,SAAS,IAAI,gBAAgB,KAAK;EACxC,IAAI,CAAC,OAAO,IAAI,MAAM,KAAK,CAAC,OAAO,IAAI,OAAO,GAC5C,MAAM,IAAI,MAAM,sGAAoG;EACtH,KAAK,MAAM,CAAC,KAAK,UAAU,QACzB,OAAO,aAAa,IAAI,KAAK,KAAK;EACpC,OAAO,OAAO,SAAS;CACzB;CAMA,IAAI,KAAK,KAAK,KAAK,GACjB,MAAM,IAAI,MAAM,kHAAmH;CACrI,OAAO,aAAa,IAAI,QAAQ,KAAK;CACrC,MAAM,QAAQ,IAAI,IAAI,OAAQ,CAAC,CAAC,aAAa,IAAI,OAAO;CACxD,IAAI,OACF,OAAO,aAAa,IAAI,SAAS,KAAK;CACxC,OAAO,OAAO,SAAS;AACzB;;;;;;;;;;;;;;;;;;AA0BA,eAAsB,mBACpB,QACA,UAA0E,CAAC,GACxC;CACnC,MAAM,UAAU,uBAAuB,QAAQ,QAAQ,OAAO;CAE9D,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,OAAO;CACvB,QACM;EACJ,MAAM,IAAI,MAAM,yEAA0E;CAC5F;CAIA,MAAM,OAAO,IAAI,SAAS,QAAQ,YAAY,EAAE;CAChD,IAAI,CAAC,eAAe,IAAI,IAAI,GAC1B,MAAM,IAAI,MACR,yDAAyD,IAAI,SAAS,8DACxE;CAKF,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,KAAK,IAAI,gBAAgB;CAC/B,MAAM,QAAQ,iBAAiB,GAAG,MAAM,GAAG,SAAS;CACpD,QAAQ,QAAQ,iBAAiB,eAAe,GAAG,MAAM,GAAG,EAAE,MAAM,KAAK,CAAC;CAE1E,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC9D,SACO,KAAK;EACV,IAAK,IAAc,SAAS,cAC1B,MAAM,IAAI,MAAM,sEAAsE;EACxF,MAAM,IAAI,MAAM,8CAA+C,IAAc,SAAS;CACxF,UACQ;EACN,aAAa,KAAK;CACpB;CAEA,MAAM,WAAW,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,EAAE;CACrD,OAAO;EAAE,QAAQ,SAAS;EAAQ,SAAS,eAAe,QAAQ;CAAE;AACtE;;;;;;AAOA,SAAS,eAAe,MAAkC;CACxD,IAAI,CAAC,MACH,OAAO,KAAA;CACT,MAAM,KAAK,6BAA6B,KAAK,IAAI,CAAC,GAAG;CACrD,IAAI,IACF,OAAO,UAAU,EAAE,CAAC,CAAC,KAAK,KAAK,KAAA;CACjC,MAAM,IAAI,2BAA2B,KAAK,IAAI,CAAC,GAAG;CAClD,IAAI,GACF,OAAO,UAAU,CAAC,CAAC,CAAC,KAAK,KAAK,KAAA;AAElC;AAEA,SAAS,UAAU,GAAmB;CACpC,OAAO,EAAE,QAAQ,YAAY,EAAE,CAAC,CAAC,QAAQ,UAAU,GAAG,CAAC,CAAC,QAAQ,SAAS,GAAG,CAAC,CAAC,QAAQ,SAAS,GAAG,CAAC,CAAC,QAAQ,WAAW,IAAG,CAAC,CAAC,QAAQ,UAAU,GAAI;AACpJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClLA,SAAgB,iBACd,qBACA,aACA,KACQ;CACR,IAAI,oBAAoB,WAAW,GACjC,OAAO;CACT,IAAI,WAAW,mBAAmB,GAChC,OAAO;CACT,MAAM,SAAS,QAAQ,aAAa,mBAAmB;CACvD,MAAM,OAAO,QAAQ,GAAG;CACxB,IAAI,WAAW,MACb,OAAO;CACT,MAAM,MAAM,SAAS,MAAM,MAAM;CACjC,IAAI,IAAI,WAAW,GACjB,OAAO;CACT,OAAO,QAAQ,MAAM,MAAM,IAAI,MAAM,GAAG,CAAC,CAAC,KAAK,MAAM,GAAG;AAC1D;;;;ACjBA,MAAM,mBAAmB;;AAGzB,MAAa,qBAAqB;;AAElC,MAAM,qBAAqB;;;;;;AAU3B,MAAM,2BAAkE;CACtE,aAAa;CACb,gBAAgB;CAChB,aAAa;CACb,cAAc;AAChB;;AAGA,MAAM,mBAA8E;CAClF,QAAQ;CACR,OAAO;CACP,MAAM;CACN,YAAY;AACd;;AAGA,SAAgB,eAAe,YAAoD;CACjF,OAAO,yBAAyB,UAAU,UAAU,MAAM;AAC5D;;AAGA,SAAgB,uBAAuB,YAAyC;CAC9E,OAAO,eAAe,UAAU,MAAM;AACxC;;AAYA,MAAM,wBAAQ,IAAI,IAAwB;;AAE1C,MAAM,2BAAW,IAAI,IAA4C;;;;;;;;;;AAUjE,MAAM,8BAAc,IAAI,IAAoB;AAC5C,IAAI,cAAc;;;;;;;AAQlB,SAAgB,0BAAgC;CAC9C,MAAM,MAAM;CACZ,SAAS,MAAM;CACf,YAAY,MAAM;AACpB;AAeA,MAAM,eAAe,CAAC,yBAAyB,IAAI;;AAGnD,SAAgB,oBAAoB,MAAyB,QAAQ,KAAc;CACjF,OAAO,YAAY,cAAc,GAAG;AACtC;;;;;;;;;;;;AA2BA,eAAsB,mBACpB,SACA,YACA,OAAkC,CAAC,GACI;CACvC,MAAM,SAAS,eAAe,UAAU;CACxC,IAAI,CAAC,UAAU,oBAAoB,GACjC,OAAO;CACT,MAAM,CAAC,aAAa,wBAAwB,SAAS,YAAY,MAAM;CACvE,IAAI,CAAC,WACH,OAAO;CACT,OAAO,aAAa,SAAS,QAAQ,YAAY,WAAW,IAAI;AAClE;;;;;;AAOA,eAAsB,2BACpB,SACA,YACA,OAAkC,CAAC,GACQ;CAC3C,MAAM,SAAS,eAAe,UAAU;CACxC,IAAI,CAAC,UAAU,oBAAoB,GACjC,OAAO,CAAC;CACV,MAAM,cAAc,wBAAwB,SAAS,YAAY,MAAM;CACvE,OAAO,QAAQ,IAAI,YAAY,KAAI,MAAK,aAAa,SAAS,QAAQ,YAAY,GAAG,IAAI,CAAC,CAAC;AAC7F;;;;;;AAOA,SAAS,aACP,SACA,QACA,YACA,YACA,MACgC;CAChC,IAAI,CAAC,aAAa,WAAW,IAAI,GAC/B,OAAO,YAAY,QAAQ,YAAY,YAAY,IAAI;CACzD,OAAO,aAAa,SAAS,YAAY,UAAU,CAAC,CAAC,MAAK,YACxD,YAAY,UACR,cAAc,SAAS,YAAY,UAAU,IAC7C,YAAY,QAAQ,YAAY,SAAS,IAAI,CAAC;AACtD;;;;;AAMA,SAAS,aAAa,MAAmC;CACvD,OAAO,KAAK,SAAS,WAAW,OAAO,KAAK,YAAY,YAAY,KAAK,WAAW,KAAK,IAAI,KAAK,CAAC,CAAC,KAAK;AAC3G;;;;;;AAOA,eAAe,aACb,SACA,YACA,YACkD;CAClD,IAAI;EACF,MAAM,mBAAmB;GACvB,UAAU,WAAW;GACrB,YAAY,UAAU,UAAU;GAChC,eAAe,WAAW;GAC1B,iBAAiB,gBAAgB,OAAO;GACxC,cAAc;GACd,eAAc,WAAU;EAC1B,CAAC;CACH,QACM;EAGJ,OAAO,SACL;GAAE,aAAa,WAAW;GAAK,OAAO,WAAW;EAAM,GACvD;GAAE,QAAQ;GAAgB,OAAO;EAAiB,CACpD;CACF;CAIA,MAAM,SAAS,gBAAgB,OAAO,CAAC,CAAC,WAAW;CACnD,OAAO,QAAQ,SAAS,UAAU;EAAE,GAAG;EAAY,MAAM;CAAO,IAAI;AACtE;;AAGA,SAAS,YACP,QACA,YACA,YACA,MACgC;CAIhC,MAAM,WAAW,GAAG,WAAW,IAAI,IAAI,WAAW,KAAK,SAAS,UAAU,WAAW,KAAK,SAAS,WAAW,KAAK;CAInH,MAAM,YAAY,aAA2D,cAAc,UAAU,YAAY,UAAU;CAE3H,IAAI,CAAC,KAAK,SAAS;EACjB,MAAM,SAAS,MAAM,IAAI,QAAQ;EACjC,IAAI,UAAU,OAAO,YAAY,KAAK,IAAI,GACxC,OAAO,QAAQ,QAAQ,SAAS,OAAO,QAAQ,CAAC;EAClD,MAAM,UAAU,SAAS,IAAI,QAAQ;EACrC,IAAI,SACF,OAAO,QAAQ,KAAK,QAAQ;CAChC;CAEA,MAAM,SAAS,EAAE;CACjB,YAAY,IAAI,UAAU,MAAM;CAChC,MAAM,WAAW,MAAM,IAAI,QAAQ,CAAC,EAAE;CACtC,MAAM,QAAQ,SAAS,QAAQ,YAAY,WAAW,IAAI,CAAC,CACxD,MAAM,UAAU;EAMf,MAAM,eAAe,MAAM,WAAW,iBAAiB,UAAU,WAAW;EAC5E,MAAM,WAAW,eAAe,WAAW;EAC3C,IAAI,YAAY,IAAI,QAAQ,MAAM,QAChC,MAAM,IAAI,UAAU;GAAE,WAAW,KAAK,IAAI,KAAK,eAAe,qBAAqB;GAAqB;EAAS,CAAC;EACpH,OAAO;CACT,CAAC,CAAC,CACD,cAAc;EACb,IAAI,SAAS,IAAI,QAAQ,MAAM,OAC7B,SAAS,OAAO,QAAQ;CAC5B,CAAC;CACH,SAAS,IAAI,UAAU,KAAK;CAC5B,OAAO,MAAM,KAAK,QAAQ;AAC5B;;AAGA,SAAS,cAAc,UAAiC,YAAgC,YAAoD;CAC1I,OAAO;EACL,GAAG;EACH,aAAa,WAAW;EACxB,OAAO,WAAW;EAClB,eAAe,WAAW;EAC1B,SAAS,WAAW,KAAK,SAAS,UAAU,kBAAkB,WAAW,IAAI,IAAI;EACjF,kBAAkB,WAAW;CAC/B;AACF;;;;;;;;;;;;;AAcA,SAAS,wBACP,SACA,YACA,QACmB;CACnB,MAAM,OAAO,iBAAiB;CAC9B,MAAM,UAAU,UAAU,UAAU;CAIpC,MAAM,SAAS,oBAAoB,gBAAgB,OAAO,GAAG,OAAO,CAAC,CAClE,QAAO,MAAK,EAAE,WAAW,SAAS,SAAS,EAAE,WAAW,SAAS,YAAY,EAAE,WAAW,MAAM,CAAC,CACjG,KAAI,OAAM;EAAE,KAAK,EAAE;EAAK,MAAM,EAAE;EAAY,QAAQ,EAAE;CAAO,EAAE;CAClE,IAAI,OAAO,SAAS,GAClB,OAAO;CACT,IAAI,SAAS,YAAY,WAAW,QAAQ;EAC1C,MAAM,UAAU,QAAQ,IAAI,WAAW;EACvC,IAAI,SACF,OAAO,CAAC;GAAE,KAAK;GAAS,MAAM;IAAE,MAAM;IAAU,OAAO;GAAQ;GAAG,QAAQ;EAAK,CAAC;CACpF;CACA,OAAO,CAAC;AACV;;;;;AAMA,eAAsB,sBACpB,SACA,UACA,OAAkC,CAAC,GACQ;CAC3C,MAAM,aAAa,OAAO,OAAO,QAAQ,CAAC,CAAC,OAAO,sBAAsB;CAIxE,QAAO,MAHe,QAAQ,IAC5B,WAAW,KAAI,eAAc,2BAA2B,SAAS,YAAY,IAAI,CAAC,CACpF,EAAA,CACe,KAAK;AACtB;AAMA,eAAe,SACb,QACA,YACA,MACgC;CAChC,MAAM,OAAO;EAAE,aAAa,WAAW;EAAK,OAAO,WAAW;CAAM;CACpE,IAAI;EACF,QAAQ,QAAR;GACE,KAAK,UACH,OAAO,MAAM,iBAAiB,MAAM,IAAI;GAC1C,KAAK,SACH,OAAO,MAAM,gBAAgB,MAAM,IAAI;GACzC,KAAK,QACH,OAAO,MAAM,eAAe,MAAM,IAAI;GACxC,KAAK,cACH,OAAO,MAAM,qBAAqB,MAAM,IAAI;EAChD;CACF,SACO,KAAK;EAGV,OAAO,SAAS,MAAM,EAAE,OAAO,eAAe,QAAQ,IAAI,UAAU,iBAAiB,CAAC;CACxF;AACF;;;;;;AAUA,SAAS,SAAS,MAAoB,UAA0C,CAAC,GAA0B;CACzG,OAAO;EACL,GAAG;EACH,eAAe,KAAK;EACpB,SAAS;EACT,kBAAkB;EAClB,QAAQ;EACR,MAAM;EACN,SAAS,CAAC;EACV,SAAS;EACT,WAAW,KAAK,IAAI;EACpB,OAAO;EACP,GAAG;CACL;AACF;;;;;;AAOA,SAAS,cACP,MACA,MACqD;CACrD,IAAI,KAAK,SAAS,WAAW,CAAC,KAAK,QACjC,OAAO,EAAE,MAAM,SAAS,MAAM;EAAE,QAAQ;EAAgB,OAAO;CAAgB,CAAC,EAAE;CACpF,IAAI,OAAO,KAAK,YAAY,YAAY,KAAK,WAAW,KAAK,IAAI,GAC/D,OAAO,EAAE,MAAM,SAAS,MAAM;EAAE,QAAQ;EAAgB,OAAO;CAAgB,CAAC,EAAE;CACpF,OAAO,EAAE,OAAO,KAAK,OAAO;AAC9B;;;;;;;;;;AAWA,SAAS,YAAY,MAAoB,KAA6C;CACpF,IAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KACvC,OAAO,SAAS,MAAM;EAAE,QAAQ;EAAgB,OAAO;CAAiB,CAAC;CAC3E,IAAI,CAAC,IAAI,IACP,OAAO,SAAS,MAAM,EAAE,OAAO,QAAQ,IAAI,SAAS,CAAC;CACvD,OAAO;AACT;AAMA,MAAM,iBAAwE;CAC5E;EAAE,KAAK;EAAa,IAAI;EAAa,OAAO;CAAK;CACjD;EAAE,KAAK;EAAa,IAAI;EAAa,OAAO;CAAS;CACrD;EAAE,KAAK;EAAkB,IAAI;EAAkB,OAAO;CAAc;CACpE;EAAE,KAAK;EAAoB,IAAI;EAAoB,OAAO;CAAgB;AAC5E;AAEA,eAAe,iBAAiB,MAAoB,MAA0D;CAC5G,MAAM,OAAO,cAAc,MAAM,IAAI;CACrC,IAAI,UAAU,MACZ,OAAO,KAAK;CAEd,MAAM,MAAM,MAAM,MAAM,6CAA6C;EACnE,SAAS;GACP,iBAAiB,UAAU,KAAK;GAChC,kBAAkB;GAClB,UAAU;EACZ;EACA,QAAQ,YAAY,QAAQ,gBAAgB;CAC9C,CAAC;CACD,MAAM,UAAU,YAAY,MAAM,GAAG;CACrC,IAAI,SACF,OAAO;CAET,MAAM,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;CAC9C,IAAI,CAAC,MACH,OAAO,SAAS,MAAM,EAAE,OAAO,mBAAmB,CAAC;CAErD,MAAM,UAAiC,CAAC;CACxC,KAAK,MAAM,EAAE,KAAK,IAAI,WAAW,gBAAgB;EAC/C,MAAM,MAAM,KAAK;EACjB,IAAI,OAAO,OAAO,IAAI,gBAAgB,UACpC,QAAQ,KAAK;GACX;GACA;GACA,aAAa,aAAa,IAAI,WAAW;GACzC,UAAU,WAAW,IAAI,SAAS;EACpC,CAAC;CAEL;CACA,IAAI,QAAQ,WAAW,GACrB,OAAO,SAAS,MAAM,EAAE,OAAO,gBAAgB,CAAC;CAClD,OAAO,SAAS,MAAM;EAAE,QAAQ;EAAM;CAAQ,CAAC;AACjD;;AAOA,SAAS,iBAAiB,KAAkB,UAA0B;CACpE,MAAM,UAAU,IAAI;CACpB,IAAI,CAAC,SACH,OAAO;CACT,IAAI,UAAU,OACZ,OAAO,GAAG,KAAK,MAAM,UAAU,IAAI,EAAE;CACvC,MAAM,OAAO,KAAK,MAAM,UAAU,KAAM;CACxC,OAAO,SAAS,IAAI,WAAW,GAAG,KAAK;AACzC;AAEA,eAAe,gBAAgB,MAAoB,MAA0D;CAC3G,MAAM,OAAO,cAAc,MAAM,IAAI;CACrC,IAAI,UAAU,MACZ,OAAO,KAAK;CACd,MAAM,YAAY,KAAK,SAAS,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;CAEjG,MAAM,MAAM,MAAM,MAAM,8CAA8C;EACpE,SAAS;GACP,iBAAiB,UAAU,KAAK;GAChC,GAAI,YAAY,EAAE,sBAAsB,UAAU,IAAI,CAAC;GACvD,cAAc;GACd,UAAU;EACZ;EACA,QAAQ,YAAY,QAAQ,gBAAgB;CAC9C,CAAC;CACD,MAAM,UAAU,YAAY,MAAM,GAAG;CACrC,IAAI,SACF,OAAO;CAET,MAAM,OAAO,MAAM,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI;CAO9C,IAAI,CAAC,MACH,OAAO,SAAS,MAAM,EAAE,OAAO,mBAAmB,CAAC;CAErD,MAAM,YAAY,KAAK,cAAc,KAAK;CAC1C,MAAM,UAAiC,CAAC;CACxC,MAAM,QAAQ,KAA8B,IAAY,kBAA0B;EAChF,IAAI,OAAO,OAAO,IAAI,iBAAiB,UACrC,QAAQ,KAAK;GACX;GACA,OAAO,iBAAiB,KAAK,aAAa;GAC1C,aAAa,aAAa,IAAI,YAAY;GAC1C,UAAU,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW,MAAO;EACrE,CAAC;CAEL;CACA,KAAK,WAAW,gBAAgB,WAAW,IAAI;CAC/C,KAAK,WAAW,kBAAkB,aAAa,QAAQ;CAEvD,MAAM,UAAU,KAAK,WAAW,OAAO,KAAK,QAAQ,YAAY,YAAY,CAAC,KAAK,QAAQ,YACtF;EAAE,WAAW,KAAK,QAAQ;EAAS,OAAO;CAAK,IAC/C;CAEJ,IAAI,QAAQ,WAAW,KAAK,CAAC,SAC3B,OAAO,SAAS,MAAM,EAAE,OAAO,gBAAgB,CAAC;CAClD,OAAO,SAAS,MAAM;EACpB,QAAQ;EACR,MAAM,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;EAC5D;EACA;CACF,CAAC;AACH;AAIA,eAAe,qBAAqB,MAAoB,MAA0D;CAChH,IAAI,KAAK,SAAS,YAAY,CAAC,KAAK,OAClC,OAAO,SAAS,MAAM;EAAE,QAAQ;EAAgB,OAAO;CAAoB,CAAC;CAE9E,MAAM,MAAM,MAAM,MAAM,wCAAwC;EAC9D,SAAS;GAAE,eAAe,UAAU,KAAK;GAAS,QAAQ;EAAmB;EAC7E,QAAQ,YAAY,QAAQ,gBAAgB;CAC9C,CAAC;CACD,MAAM,UAAU,YAAY,MAAM,GAAG;CACrC,IAAI,SACF,OAAO;CAGT,MAAM,UAAS,MADI,IAAI,KAAK,CAAC,CAAC,YAAY,IAAI,EAAA,EACzB;CACrB,IAAI,CAAC,UAAU,OAAO,OAAO,kBAAkB,YAAY,OAAO,OAAO,gBAAgB,UACvF,OAAO,SAAS,MAAM,EAAE,OAAO,mBAAmB,CAAC;CAKrD,OAAO,SAAS,MAAM;EACpB,QAAQ;EACR,SAAS,CAAC;GAAE,IAAI;GAAW,OAAO;GAAW,aAL3B,OAAO,gBAAgB,IACvC,aAAc,OAAO,cAAc,OAAO,gBAAiB,GAAG,IAC9D;GAGwD,UAAU;EAAK,CAAC;EAC1E,SAAS;GAAE,WAAW,OAAO,gBAAgB,OAAO;GAAa,OAAO,OAAO;EAAc;CAC/F,CAAC;AACH;AAIA,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;AAE7B,eAAe,eAAe,MAAoB,MAA0D;CAC1G,MAAM,OAAO,cAAc,MAAM,IAAI;CACrC,IAAI,UAAU,MACZ,OAAO,KAAK;CAEd,MAAM,MAAM,MAAM,MAAM,kBAAkB;EACxC,QAAQ;EACR,SAAS;GACP,iBAAiB,UAAU,KAAK;GAChC,gBAAgB;GAChB,cAAc;GACd,gBAAgB;GAChB,UAAU;GACV,WAAW;GACX,UAAU;EACZ;EAEA,MAAM,IAAI,WAAW;GAAC;GAAG;GAAG;GAAG;GAAG;EAAC,CAAC;EACpC,QAAQ,YAAY,QAAQ,gBAAgB;CAC9C,CAAC;CACD,MAAM,UAAU,YAAY,MAAM,GAAG;CACrC,IAAI,SACF,OAAO;CAIT,MAAM,aAAa,IAAI,QAAQ,IAAI,aAAa;CAChD,IAAI,cAAc,eAAe,KAAK;EACpC,MAAM,UAAU,IAAI,QAAQ,IAAI,cAAc,KAAK;EAKnD,OAJqB,eAAe,QAAS,eAAe,OAAO,qBAAqB,KAAK,OAAO,IAKhG,SAAS,MAAM;GAAE,QAAQ;GAAgB,OAAO;EAAqB,CAAC,IACtE,SAAS,MAAM,EAAE,OAAO,QAAQ,aAAa,UAAU,KAAK,YAAY,KAAK,CAAC;CACpF;CAEA,MAAM,SAAS,yBAAyB,IAAI,WAAW,MAAM,IAAI,YAAY,CAAC,CAAC;CAC/E,IAAI,CAAC,QACH,OAAO,SAAS,MAAM,EAAE,OAAO,sBAAsB,CAAC;CACxD,OAAO,SAAS,MAAM;EACpB,QAAQ;EACR,SAAS,CAAC;GACR,IAAI;GACJ,OAAO;GACP,aAAa,aAAa,OAAO,WAAW;GAC5C,UAAU,OAAO,WAAW,OAAO,SAAS,QAAQ,IAAI;EAC1D,CAAC;CACH,CAAC;AACH;;AAeA,SAAgB,kBAAkB,OAAiC;CACjE,MAAM,SAAuB,CAAC;CAC9B,IAAI,QAAQ;CACZ,OAAO,QAAQ,MAAM,QAAQ;EAC3B,IAAI,QAAQ,IAAI,MAAM,QACpB,OAAO,CAAC;EACV,MAAM,QAAQ,MAAM;EACpB,MAAM,SAAU,MAAM,QAAQ,MAAO,KAAO,MAAM,QAAQ,MAAO,KAAO,MAAM,QAAQ,MAAO,IAAK,MAAM,QAAQ;EAChH,MAAM,QAAQ,QAAQ;EACtB,MAAM,MAAM,QAAQ;EACpB,IAAI,SAAS,KAAK,MAAM,MAAM,QAC5B,OAAO,CAAC;EACV,KAAK,QAAQ,SAAU,GACrB,OAAO,KAAK,MAAM,SAAS,OAAO,GAAG,CAAC;EACxC,QAAQ;CACV;CACA,OAAO;AACT;AAEA,SAAS,kBAAkB,OAA4B;CACrD,IAAI,MAAM,WAAW,GACnB,OAAO;CACT,MAAM,cAAc,MAAM,MAAO;CACjC,MAAM,WAAW,MAAM,KAAM;CAC7B,OAAO,cAAc,MAAM,aAAa,KAAK,aAAa,KAAK,aAAa,KAAK,aAAa;AAChG;AAEA,SAAS,WAAW,OAAmB,QAAwD;CAC7F,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,OAAO,QAAQ,MAAM,UAAU,QAAQ,IAAI;EACzC,MAAM,OAAO,MAAM;EAGnB,UAAU,OAAO,OAAQ,KAAK;EAC9B,SAAS;EACT,KAAK,OAAO,SAAU,GACpB,OAAO;GAAE;GAAO,MAAM;EAAM;EAC9B,SAAS;CACX;CACA,OAAO;AACT;AAEA,SAAS,aAAa,OAAmB,MAAgB,MAAoB,UAAyB,OAAqB;CACzH,IAAI,QAAQ,GACV;CACF,IAAI,QAAQ;CACZ,OAAO,QAAQ,MAAM,QAAQ;EAC3B,MAAM,MAAM,WAAW,OAAO,KAAK;EACnC,IAAI,CAAC,KACH;EACF,MAAM,cAAc,KAAK,MAAM,IAAI,QAAQ,CAAC;EAC5C,MAAM,WAAW,IAAI,QAAQ;EAC7B,IAAI,gBAAgB,GAClB;EACF,QAAQ,IAAI;EACZ,MAAM,YAAY,CAAC,GAAG,MAAM,WAAW;EACvC,QAAQ,UAAR;GACE,KAAK,GAAG;IACN,MAAM,IAAI,WAAW,OAAO,KAAK;IACjC,IAAI,CAAC,GACH;IACF,KAAK,OAAO,KAAK;KAAE,MAAM;KAAW,OAAO,SAAS;KAAK,OAAO,EAAE;IAAM,CAAC;IACzE,QAAQ,EAAE;IACV;GACF;GACA,KAAK;IACH,IAAI,QAAQ,IAAI,MAAM,QACpB;IACF,SAAS;IACT;GAEF,KAAK,GAAG;IACN,IAAI,QAAQ,IAAI,MAAM,QACpB;IACF,MAAM,OAAO,IAAI,SAAS,MAAM,QAAQ,MAAM,aAAa,OAAO,CAAC;IACnE,KAAK,QAAQ,KAAK;KAAE,MAAM;KAAW,OAAO,SAAS;KAAK,OAAO,KAAK,WAAW,GAAG,IAAI;IAAE,CAAC;IAC3F,SAAS;IACT;GACF;GACA,KAAK,GAAG;IACN,MAAM,MAAM,WAAW,OAAO,KAAK;IACnC,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,QAAQ,MAAM,QACvC;IACF,MAAM,MAAM,MAAM,SAAS,IAAI,MAAM,IAAI,OAAO,IAAI,KAAK;IACzD,IAAI,kBAAkB,GAAG,GACvB,aAAa,KAAK,WAAW,MAAM,UAAU,QAAQ,CAAC;IACxD,QAAQ,IAAI,OAAO,IAAI;IACvB;GACF;GACA,SACE;EACJ;CACF;AACF;;;;;;;AAQA,SAAgB,yBACd,OACA,sBAAM,IAAI,KAAK,GACwC;CACvD,IAAI,SAAS,kBAAkB,KAAK;CACpC,IAAI,OAAO,WAAW,KAAK,kBAAkB,KAAK,GAChD,SAAS,CAAC,KAAK;CACjB,IAAI,OAAO,WAAW,GACpB,OAAO;CAET,MAAM,OAAqB;EAAE,SAAS,CAAC;EAAG,QAAQ,CAAC;CAAE;CACrD,MAAM,WAAW,EAAE,GAAG,EAAE;CACxB,KAAK,MAAM,SAAS,QAClB,aAAa,OAAO,CAAC,GAAG,MAAM,UAAU,CAAC;CAE3C,MAAM,eAAe,KAAK,QACvB,QAAO,MAAK,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,OAAO,SAAS,EAAE,KAAK,KAAK,EAAE,SAAS,KAAK,EAAE,SAAS,GAAG,CAAC,CAC9F,MAAM,GAAG,MAAM,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,MAAM,CAAC,CAAC;CAEvG,MAAM,cAAc,KAAK,OACtB,QAAO,MAAK,EAAE,SAAS,QAAiB,EAAE,SAAS,IAAa,CAAC,CACjE,KAAI,OAAM;EAAE,MAAM,EAAE;EAAM,sBAAM,IAAI,KAAK,EAAE,QAAQ,GAAI;CAAE,EAAE,CAAC,CAC5D,QAAO,MAAK,EAAE,OAAO,GAAG;CAC3B,MAAM,YAAY,YAAY,QAC5B,MAAK,EAAE,KAAK,WAAW,KAAK,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,CAClF;CACA,MAAM,YAAY,UAAU,SAAS,IAAI,YAAY,YAAA,CAClD,KAAI,MAAK,EAAE,IAAI,CAAC,CAChB,MAAM,GAAG,MAAM,EAAE,QAAQ,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM;CAInD,MAAM,iBAAiB,KAAK,OAAO,MAAK,MACrC,EAAE,KAAK,UAAU,KAAK,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,KACpD,EAAE,KAAK,WAAW,KAAK,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,KAAK,EAAE,KAAK,OAAO,MAAM,EAAE,UAAU,KAAK,EAAE,UAAU,EACpH;CACA,IAAI,CAAC,cAAc;EACjB,IAAI,KAAK,QAAQ,WAAW,KAAK,YAAY,gBAC3C,OAAO;GAAE,aAAa;GAAG;EAAS;EACpC,OAAO;CACT;CACA,OAAO;EAAE,aAAa,aAAa;EAAO;CAAS;AACrD;AAMA,SAAS,aAAa,OAAuB;CAC3C,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,OAAO;CACT,OAAO,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC/D;AAEA,SAAS,WAAW,OAAiD;CACnE,IAAI,OAAO,UAAU,UACnB,OAAO;CACT,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC,CAAC,QAAQ;CACnC,OAAO,OAAO,SAAS,EAAE,IAAI,KAAK;AACpC;;;ACpvBA,MAAM,uBAAuB,cAA0C,CAAC,CAAC;AACzE,MAAM,yBAAyB,cAAsC,IAAI;AAEzE,IAAI,oBAAoB;AACxB,SAAS,iBAAyB;CAIhC,qBAAqB;CACrB,OAAO,YAAY;AACrB;;;;;AAMA,SAAgB,iBAAiB,EAAE,YAAqC;CACtE,MAAM,CAAC,OAAO,YAAY,SAAqC,CAAC,CAAC;CAIjE,MAAM,WAAW,OAAmC,CAAC,CAAC;CACtD,SAAS,UAAU;CAMnB,sBAAsB;EACpB,KAAK,MAAM,KAAK,SAAS,SACvB,EAAE,QAAQ,MAAM;CACpB,GAAG,CAAC,CAAC;CAKL,MAAM,kBAAkB,aACrB,MAAM,OAAO,YAAY,kBAAkB,IAAI,SAA2B,YAAY;EACrF,UAAS,SAAQ,CACf,GAAG,MACH;GACE,IAAI,eAAe;GACnB;GACA;GACA;GACA,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;GACnC,GAAI,gBAAgB,EAAE,cAAc,IAAI,CAAC;EAC3C,CACF,CAAC;CACH,CAAC,GACD,CAAC,CACH;CAEA,MAAM,cAAc,aAAa,aAA+B;EAC9D,UAAU,SAAS;GACjB,MAAM,CAAC,MAAM,GAAG,QAAQ;GACxB,IAAI,MACF,KAAK,QAAQ,QAAQ;GACvB,OAAO;EACT,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,UAAU,kBAAkB;EAChC,UAAU,SAAS;GACjB,KAAK,MAAM,KAAK,MAAM,EAAE,QAAQ,MAAM;GACtC,OAAO,CAAC;EACV,CAAC;CACH,GAAG,CAAC,CAAC;CAEL,MAAM,oBAAoB,aAAa,kBAA0B;EAI/D,UAAS,SAAQ,KAAK,QAAO,MAAK,EAAE,kBAAkB,aAAa,CAAC;CACtE,GAAG,CAAC,CAAC;CAML,MAAM,aAAa,OAA+B,IAAI;CACtD,IAAI,CAAC,WAAW,SACd,WAAW,UAAU;EAAE;EAAiB;EAAa;EAAS;CAAkB;CAElF,OACE,oBAAC,uBAAuB,UAAxB;EAAiC,OAAO,WAAW;EACjD,UAAA,oBAAC,qBAAqB,UAAtB;GAA+B,OAAO;GACnC;EAC4B,CAAA;CACA,CAAA;AAErC;AAEA,SAAgB,mBAA+C;CAC7D,OAAO,WAAW,oBAAoB;AACxC;AAEA,SAAgB,qBAAsC;CACpD,MAAM,MAAM,WAAW,sBAAsB;CAC7C,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,2DAA2D;CAC7E,OAAO;AACT;;;AC7HA,MAAM,iBAAiB;;;;;;;;;;;;;;;AAgBvB,SAAgB,2BAA2B,MAGF;CACvC,MAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;CACpC,MAAM,OAAO,KAAK,QAAQ,QAAQ;CAClC,MAAM,SAAS,gBAAgB,KAAK,MAAM;CAC1C,MAAM,WAAW,eAAe,KAAK,WAAW,KAAK,MAAM;CAE3D,MAAM,WAAW,YAAY,GAAG;CAChC,MAAM,SAA8B,WAAW,YAAY;CAC3D,MAAM,MAAM,WACR,QAAQ,UAAU,IAAI,UAAU,UAAU,IAC1C,QAAQ,KAAK,WAAW,mBAAmB;EAAE,QAAQ,IAAI;EAAU;CAAK,CAAC,CAAC,CAAC,SAAS,UAAU;CAClG,OAAO;EAAE;EAAK,UAAU,KAAK,KAAK,QAAQ;EAAG;CAAO;AACtD;;;;;;;;;;;;;;;;AAiBA,SAAgB,cAAc,SAAsB,QAAqC;CACvF,IAAI,WAAW,QACb,OAAO,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE;CAC7C,OAAO,eAAe,OAAO;AAC/B;;;;;;;AAQA,eAAsB,mBACpB,MAC8B;CAC9B,MAAM,SAAS,2BAA2B;EACxC,WAAW,KAAK,QAAQ;EACxB,QAAQ,KAAK;EACb,KAAK,KAAK;EACV,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,SAAS,KAAK;CAChB,CAAC;CACD,MAAM,OAAO,cAAc,KAAK,SAAS,KAAK,MAAM;CAIpD,UAAU,OAAO,KAAK,EAAE,WAAW,KAAK,CAAC;CACzC,MAAM,UAAU,OAAO,UAAU,MAAM,MAAM;CAC7C,OAAO;AACT;;;;;;;AAYA,SAAS,eAAe,SAA8B;CACpD,MAAM,QAAQ,mBAAmB,QAAQ,OAAO,QAAQ,QAAQ;CAChE,MAAM,YAAY,QAAQ,MAAM,QAAO,MAAK,EAAE,SAAS,MAAM,CAAC,CAAC;CAC/D,MAAM,iBAAiB,QAAQ,MAAM,QAAO,MAAK,EAAE,SAAS,WAAW,CAAC,CAAC;CACzE,MAAM,QAAQ,eAAe,QAAQ,IAAI;CACzC,MAAM,QAAkB,CAAC;CACzB,MAAM,KAAK,KAAK,aAAa,KAAK,GAAG;CACrC,MAAM,KAAK,EAAE;CACb,MAAM,KAAK,eAAe,QAAQ,QAAQ,EAAE,EAAE,OAAO,QAAQ,MAAM,OAAO,OAAO,QAAQ,MAAM,WAAW,IAAI,KAAK,IAAI,KAAK,QAAQ,KAAK,OAAO,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,KAAK;CAC5L,MAAM,KAAK,EAAE;CACb,MAAM,KAAK,aAAa;CACxB,MAAM,KAAK,EAAE;CACb,MAAM,KAAK,eAAe,QAAQ,GAAG,GAAG;CACxC,MAAM,KAAK,kBAAkB,IAAI,KAAK,QAAQ,SAAS,CAAC,CAAC,YAAY,GAAG;CACxE,MAAM,KAAK,kBAAkB,IAAI,KAAK,QAAQ,SAAS,CAAC,CAAC,YAAY,GAAG;CACxE,MAAM,KAAK,iBAAiB,QAAQ,QAAQ;CAC5C,MAAM,KAAK,gBAAgB,QAAQ,MAAM,OAAO,IAAI,UAAU,UAAU,eAAe,YAAY;CACnG,MAAM,KAAK,eAAe,QAAQ,KAAK,QAAQ;CAC/C,IAAI,MAAM,QAAQ,GAAG;EACnB,MAAM,YAAsB,CAC1B,MAAM,UAAU,MAAM,KAAK,KAC3B,OAAO,UAAU,MAAM,MAAM,GAC/B;EACA,IAAI,MAAM,YAAY,GACpB,UAAU,KAAK,UAAU,UAAU,MAAM,SAAS,GAAG;EACvD,MAAM,KAAK,iBAAiB,UAAU,MAAM,KAAK,EAAE,IAAI,UAAU,KAAK,KAAK,EAAE,EAAE;EAC/E,IAAI,MAAM,OAAO,GACf,MAAM,KAAK,gBAAgB,MAAM,KAAK,QAAQ,MAAM,OAAO,MAAO,IAAI,CAAC,GAAG;CAC9E;CACA,MAAM,KAAK,EAAE;CACb,MAAM,KAAK,iBAAiB;CAC5B,MAAM,KAAK,EAAE;CAEb,IAAI,QAAQ,MAAM,WAAW,GAAG;EAC9B,MAAM,KAAK,0BAA0B;EACrC,MAAM,KAAK,EAAE;EACb,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE;CAC7B;CAEA,QAAQ,MAAM,SAAS,MAAM,QAAQ;EACnC,MAAM,KAAK,iBAAiB,MAAM,MAAM,CAAC,CAAC;EAC1C,MAAM,KAAK,EAAE;EACb,MAAM,OAAO,eAAe,IAAI;EAChC,IAAI,MAAM;GACR,MAAM,KAAK,IAAI;GACf,MAAM,KAAK,EAAE;EACf;CACF,CAAC;CAED,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,QAAQ,QAAQ,IAAI,EAAE;AACnD;;AAGA,SAAS,iBAAiB,MAAmB,OAAuB;CAClE,MAAM,OAAO,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,YAAY;CAClD,MAAM,cAAc,KAAK,QAAQ,QAAQ,KAAK,MAAM,MAAM;CAC1D,MAAM,gBAAgB,KAAK,QAAQ,MAAM,gBAAgB,KAAK,KAAK,MAAM;CACzE,OAAO,OAAO,MAAM,IAAI,KAAK,OAAO,YAAY,KAAK,OAAO;AAC9D;;AAGA,SAAS,gBAAgB,OAA0B;CACjD,MAAM,QAAkB,CAAC;CACzB,IAAI,MAAM,QAAQ,GAChB,MAAM,KAAK,MAAM,UAAU,MAAM,KAAK,GAAG;CAC3C,IAAI,MAAM,SAAS,GACjB,MAAM,KAAK,OAAO,UAAU,MAAM,MAAM,GAAG;CAC7C,KAAK,MAAM,aAAa,KAAK,GAC3B,MAAM,KAAK,UAAU,UAAU,MAAM,aAAa,CAAC,GAAG;CACxD,OAAO,MAAM,KAAK,KAAK;AACzB;;;;;;;AAQA,SAAS,eAAe,MAA2B;CACjD,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,SAAS,KAAK,SAAS;EAChC,MAAM,QAAQ,YAAY,KAAK;EAC/B,IAAI,OACF,MAAM,KAAK,KAAK;CACpB;CACA,OAAO,MAAM,KAAK,MAAM;AAC1B;AAEA,SAAS,YAAY,OAAoC;CACvD,QAAQ,MAAM,MAAd;EACE,KAAK,QACH,OAAO,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,KAAK,IAAI;EACjD,KAAK,YAAY;GACf,MAAM,OAAO,MAAM,KAAK,KAAK;GAC7B,IAAI,CAAC,MACH,OAAO;GAIT,OAAO,sBADQ,KAAK,MAAM,IAAI,CAAC,CAAC,KAAI,MAAK,KAAK,GAAG,CAAC,CAAC,KAAK,IACtB;EACpC;EACA,KAAK,aAAa;GAChB,MAAM,OAAO,KAAK,UAAU,MAAM,OAAO,MAAM,CAAC;GAChD,OAAO;IACL,mBAAmB,MAAM,KAAK,YAAY,MAAM,GAAG;IACnD;IACA;IACA;IACA;GACF,CAAC,CAAC,KAAK,IAAI;EACb;EACA,KAAK,eAKH,OAAO;GAJQ,MAAM,UACjB,kCAAkC,MAAM,OAAO,MAC/C,0BAA0B,MAAM,OAAO;GAE3B;GADD,iBAAiB,MAAM,MACb;EAAC,CAAC,CAAC,KAAK,IAAI;EAEvC,KAAK,SAIH,OAAO,aAAa,MAAM,UAAU;EACtC,KAAK,SACH,OAAO,aAAa,MAAM,OAAO,GAAG,MAAM,KAAK,OAAO,KAAK,MAAM,UAAU;EAC7E,KAAK,SACH,OAAO,aAAa,MAAM,OAAO,GAAG,MAAM,KAAK,OAAO,KAAK,MAAM,UAAU;EAC7E,KAAK,YACH,OAAO,gBAAgB,MAAM,OAAO,GAAG,MAAM,KAAK,OAAO,KAAK,MAAM,UAAU;EAChF,KAAK,mBAAmB;GAMtB,MAAM,QAAQ,MAAM,gBAAgB;GACpC,OAAO;IACL,4BAA4B,MAAM,OAAO,UAAU,IAAI,KAAK,IAAI,uBAAuB,MAAM,MAAM;IACnG;IACA,MAAM,QAAQ,KAAK;GACrB,CAAC,CAAC,KAAK,IAAI;EACb;EACA,SACE,OAAO;CACX;AACF;;;;;;;AAQA,SAAS,iBAAiB,QAA8C;CACtE,IAAI,OAAO,WAAW,UAAU;EAC9B,MAAM,QAAQ,UAAU,MAAM;EAC9B,OAAO,GAAG,MAAM,IAAI,OAAO,IAAI;CACjC;CACA,MAAM,WAAqB,CAAC;CAC5B,KAAK,MAAM,SAAS,QAClB,IAAI,MAAM,SAAS,QAAQ;EACzB,MAAM,QAAQ,UAAU,MAAM,IAAI;EAClC,SAAS,KAAK,GAAG,MAAM,IAAI,MAAM,KAAK,IAAI,OAAO;CACnD,OACK,IAAI,MAAM,SAAS,SACtB,SAAS,KAAK,aAAa,MAAM,UAAU,GAAG;MAE3C,IAAI,MAAM,SAAS,SACtB,SAAS,KAAK,aAAa,MAAM,UAAU,GAAG;MAE3C,IAAI,MAAM,SAAS,SACtB,SAAS,KAAK,aAAa,MAAM,UAAU,GAAG;MAG9C,SAAS,KAAK,gBAAgB,MAAM,OAAO,GAAG,MAAM,KAAK,OAAO,KAAK,MAAM,UAAU,GAAG;CAG5F,OAAO,SAAS,KAAK,MAAM;AAC7B;;;;;;;;AASA,SAAS,UAAU,SAAyB;CAC1C,IAAI,aAAa;CACjB,IAAI,UAAU;CACd,KAAK,MAAM,MAAM,SACf,IAAI,OAAO,KAAK;EACd;EACA,IAAI,UAAU,YACZ,aAAa;CACjB,OAEE,UAAU;CAGd,MAAM,MAAM,KAAK,IAAI,GAAG,aAAa,CAAC;CACtC,OAAO,IAAI,OAAO,GAAG;AACvB;;AAGA,SAAS,aAAa,GAAmB;CACvC,OAAO,EAAE,QAAQ,YAAY,GAAG,CAAC,CAAC,KAAK;AACzC;;;;;;AAWA,SAAS,YAAY,OAA8B;CACjD,IAAI,MAAM,QAAQ,KAAK;CAIvB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,IAAI,WAAW,KAAK,KAAK,MAAM,CAAC,GAC9B,OAAO;EACT,MAAM,SAAS,QAAQ,GAAG;EAC1B,IAAI,WAAW,KACb,OAAO;EACT,MAAM;CACR;CACA,OAAO;AACT;;AAGA,SAAS,gBAAgB,QAAoC;CAC3D,QAAQ,UAAU,eAAA,CAAgB,QAAQ,OAAO,EAAE;AACrD;;;;;;AAOA,SAAS,eAAe,WAAmB,QAAqC;CAC9E,MAAM,MAAM,WAAW,SAAS,SAAS;CACzC,MAAM,UAAU,UAAU,KAAK;CAC/B,IAAI,CAAC,WAAW,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,IAAI,KAAK,YAAY,OAAO,YAAY,MAChG,MAAM,IAAI,WAAW,sCAAsC,UAAU,EAAE;CACzE,OAAO,GAAG,QAAQ,GAAG;AACvB;;;;;;;;;;AAuBA,SAAgB,eAAe,MAA8C;CAC3E,MAAM,MAAM;EAAE,OAAO;EAAG,QAAQ;EAAG,WAAW;EAAG,MAAM;CAAE;CACzD,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,IAAI,YAAY;GAClB,IAAI,SAAS,IAAI,WAAW,SAAS;GACrC,IAAI,UAAU,IAAI,WAAW,UAAU;GACvC,IAAI,aAAa,IAAI,WAAW,aAAa;EAC/C,OACK,IAAI,IAAI,WACX,KAAK,MAAM,KAAK,IAAI,WAAW;GAC7B,IAAI,SAAS,EAAE,SAAS;GACxB,IAAI,UAAU,EAAE,UAAU;GAC1B,IAAI,aAAa,EAAE,aAAa;EAClC;EAEF,IAAI,IAAI,MACN,IAAI,QAAQ,IAAI;CACpB;CACA,OAAO;EAAE,GAAG;EAAK,OAAO,IAAI,QAAQ,IAAI;CAAO;AACjD;;;;;;;;;ACjbA,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;AA0BzB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,6BAA6B;AACnC,MAAM,iBAAiB;AACvB,MAAM,2BAA2B;;;;;;;;;;AAWjC,MAAa,0BAA0B;AAEvC,MAAM,eAAsB;AAoB5B,SAAS,YAAY,OAAc,OAA4B;CAC7D,OAAO;EAAE,UAAU;EAAI,UAAU;EAAI;EAAO;EAAO,aAAa;CAAE;AACpE;AAEA,SAAS,YAAY,MAAqB,QAAoC;CAC5E,IAAI,SAAS;CACb,IAAI,OAAO,UACT,SAAS,oBAAoB,QAAQ,OAAO,UAAU,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;CACjG,IAAI,OAAO,UACT,SAAS,oBAAoB,QAAQ,OAAO,UAAU,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM;CACjG,OAAO;AACT;;;;;;;;;;;;AA2GA,SAAgB,oBAAoB,SAAyB;CAC3D,IAAI,WAAW,GACb,OAAO;CACT,IAAI,WAAW,0BACb,OAAO;CACT,IAAI,WAAW,4BAA4B;EACzC,MAAM,IAAI,UAAU;EACpB,OAAO,kBAAkB,IAAK;CAChC;CACA,MAAM,KAAK,UAAU,8BAChB;CACL,OAAO,mBAAmB,IAAK;AACjC;;;;;;;;;;;;AAaA,SAAS,mBACP,SACA,OACA,MACiC;CACjC,IAAI,WAAW,GACb,OAAO;EAAE,MAAM;EAAG,OAAO;CAAE;CAE7B,MAAM,OADM,oBAAoB,OACjB,IAAI,OAAO,MAAO;CACjC,MAAM,OAAO,KAAK,MAAM,IAAI;CAC5B,IAAI,QAAQ,GACV,OAAO;EAAE,MAAM;EAAG,OAAO;CAAK;CAChC,IAAI,QAAQ,SAGV,OAAO;EAAE,MAAM;EAAS,OAAO;CAAE;CAMnC,OAAO;EAAE;EAAM,OAAO,OAAO;CAAK;AACpC;;;;;;;AAQA,SAAS,UAAU,KAAa,GAA4C;CAC1E,IAAI,IAAI,UAAU,GAChB,OAAO;EAAE,OAAO;EAAK,MAAM;CAAG;CAChC,IAAI,MAAM;CACV,MAAM,OAAO,IAAI,WAAW,MAAM,CAAC;CAInC,IAAI,QAAQ,SAAU,QAAQ,SAAU,MAAM,IAAI,QAChD;CACF,OAAO;EAAE,OAAO,IAAI,MAAM,GAAG,GAAG;EAAG,MAAM,IAAI,MAAM,GAAG;CAAE;AAC1D;;;;;;AAOA,SAAS,iBACP,SACA,QACA,MACuD;CACvD,MAAM,WAA0B,CAAC;CACjC,IAAI,kBAAkB;CACtB,KAAK,MAAM,UAAU,QAAQ,OAAO,GAAG;EACrC,MAAM,WAAW,OAAO;EACxB,OAAO,WAAW;EAElB,IAAI,QAAQ;EACZ,IAAI,OAAO,SAAS,SAAS,GAAG;GAC9B,IAAI,QAAQ;IACV,MAAM,EAAE,MAAM,UAAU,mBACtB,OAAO,SAAS,QAChB,OAAO,aACP,IACF;IACA,OAAO,cAAc;IACrB,IAAI,OAAO,GAAG;KACZ,MAAM,SAAS,UAAU,OAAO,UAAU,IAAI;KAC9C,QAAQ,OAAO;KACf,OAAO,WAAW,OAAO;KACzB,IAAI,OAAO,SAAS,WAAW,GAC7B,OAAO,cAAc;IACzB;GACF,OACK;IACH,QAAQ,OAAO;IACf,OAAO,WAAW;IAClB,OAAO,cAAc;GACvB;EACF;EAEA,IAAI,SAAS,UACX,SAAS,KAAK;GACZ,UAAU;GACV;GACA,OAAO,OAAO;GACd,OAAO,OAAO;GACd,QAAQ,OAAO;GACf,aAAa;EACf,CAAC;EAEH,IAAI,OAAO,SAAS,SAAS,GAC3B,kBAAkB;CACtB;CACA,OAAO;EAAE;EAAU;CAAgB;AACrC;;AAGA,SAAS,WAAW,SAAkC,iBAAkC;CACtF,IAAI,OAAO,oBAAoB;CAC/B,IAAI,MACG;OAAA,MAAM,UAAU,QAAQ,OAAO,GAClC,IAAI,OAAO,SAAS,SAAS,KAAK,OAAO,SAAS,SAAS,GAAG;GAC5D,OAAO;GACP;EACF;;CAGJ,OAAO;AACT;;AAKA,SAAS,eACP,SACA,kBACA,iBACA,WACM;CAQN,IAAI,eAAe,iBAAiB;CACpC,MAAM,SAAS;EACb;EACA,OAAO,KAAA;CACT;CACA,MAAM,YAA2C,iBAAiB;EAChE,IAAI,iBAAiB,YAAY,cAAc;GAC7C,eAAe,iBAAiB;GAChC,OAAO,QAAQ,IAAI;GACnB;EACF;EACA,gBAAgB,UAAU,gBAAgB,QAAQ,QAAO,MAAK,MAAM,MAAM;EAC1E,QAAQ;CACV,GAAG,SAAS;CACZ,OAAO,QAAQ,IAAI;CACnB,gBAAgB,QAAQ,KAAK,MAAM;AACrC;AAEA,SAAgB,gBACd,WACA,SACc;CACd,MAAM,aAAa,uBAAgC,IAAI,IAAI,CAAC;CAC5D,MAAM,YAAY,OAA8C,IAAI;CAMpE,MAAM,gBAAgB,OAAe,CAAC;CAGtC,MAAM,eAAe,OAAoC,SAAS,SAAS;CAC3E,aAAa,UAAU,SAAS;;CAEhC,MAAM,eAAe,OAAkC,SAAS,mBAAmB;CACnF,aAAa,UAAU,SAAS;CAChC,MAAM,kBAAkB,OAAO,SAAS,sBAAsB;CAC9D,gBAAgB,UAAU,SAAS;CACnC,MAAM,eAAe,aAAa,WAAyC;EACzE,MAAM,MAAM,gBAAgB,UAAU,gBAAgB,QAAQ,IAAI,aAAa;EAC/E,OAAO,QAAQ,OAAO,SAAS,oBAAoB,QAAQ,OAAO,KAAA,CAAS;CAC7E,GAAG,CAAC,CAAC;;;;;;;;;;;;;CAcL,MAAM,qBAAqB,OAAqD,CAAC,CAAC;;;;;;CAOlF,MAAM,kBAAkB,OAAsB,CAAC,CAAC;;;;;;CAOhD,MAAM,mBAAmB,OAAO,CAAC;CAEjC,MAAM,sBAAsB,kBAAkB;EAC5C,IAAI,gBAAgB,QAAQ,WAAW,GACrC;EACF,MAAM,UAAU,gBAAgB;EAChC,gBAAgB,UAAU,CAAC;EAC3B,KAAK,MAAM,UAAU,SAAS;GAC5B,aAAa,OAAO,KAAK;GACzB,OAAO,QAAQ;EACjB;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,kBAAkB;EACnC,IAAI,UAAU,SAAS;GACrB,cAAc,UAAU,OAAO;GAC/B,UAAU,UAAU;EACtB;EAIA,cAAc,UAAU;CAC1B,GAAG,CAAC,CAAC;;;;;;;;;CAUL,MAAM,qBAAqB,kBAA2B;EACpD,KAAK,MAAM,UAAU,WAAW,QAAQ,OAAO,GAC7C,IAAI,OAAO,SAAS,SAAS,GAC3B,OAAO;EAEX,OAAO;CACT,GAAG,CAAC,CAAC;;;;;;;;CASL,MAAM,WAAW,aAAa,YAAuD;EACnF,WAAW;EACX,MAAM,UAAU,MAAM,KAAK,WAAW,QAAQ,OAAO,CAAC;EACtD,WAAW,QAAQ,MAAM;EACzB,MAAM,SAAS,mBAAmB;EAClC,mBAAmB,UAAU,CAAC;EAE9B,IAAI,CADc,QAAQ,MAAK,MAAK,EAAE,SAAS,SAAS,KAAK,EAAE,SAAS,SAAS,CACpE,KAAK,CAAC,WAAW,OAAO,WAAW,GAAG;GACjD,oBAAoB;GACpB;EACF;EACA,WAAW,SAAS;GAClB,IAAI,SAAS;GACb,KAAK,MAAM,UAAU,SACnB,SAAS,YAAY,QAAQ,MAAM;GACrC,KAAK,MAAM,KAAK,QACd,SAAS,EAAE,MAAM;GACnB,IAAI,SACF,SAAS,QAAQ,MAAM;GAGzB,OAAO,aAAa,MAAM;EAC5B,CAAC;EACD,oBAAoB;CACtB,GAAG;EAAC;EAAc;EAAqB;EAAW;CAAU,CAAC;;;;;;;;;;;;CAa7D,MAAM,OAAO,kBAAkB;EAC7B,MAAM,SAAS,aAAa,UAAU,KAAK;EAC3C,MAAM,UAAU,WAAW;EAM3B,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,OAAO,cAAc,YAAY,IACnC,mBACA,KAAK,IAAI,IAAsB,KAAK,IAAI,GAAG,MAAM,cAAc,OAAO,CAAC;EAC3E,cAAc,UAAU;EAExB,MAAM,EAAE,UAAU,oBAAoB,iBAAiB,SAAS,QAAQ,IAAI;EAO5E,MAAM,SADc,CAAC,mBAAmB,mBAAmB,QAAQ,SAAS,IAExE,mBAAmB,QAAQ,OAAO,GAAG,mBAAmB,QAAQ,MAAM,IACtE,CAAC;EAEL,IAAI,SAAS,SAAS,KAAK,OAAO,SAAS,GAAG;GAC5C,iBAAiB,WAAW;GAC5B,WAAW,SAAS;IAClB,IAAI,OAAO;IACX,KAAK,MAAM,WAAW,UACpB,OAAO,YAAY,MAAM,OAAO;IAClC,KAAK,MAAM,KAAK,QACd,OAAO,EAAE,IAAI;IAIf,OAAO,aAAa,IAAI;GAC1B,CAAC;EACH;EAEA,IAAI,CAAC,iBAAiB;GACpB,WAAW;GAGX,oBAAoB;EACtB;CACF,GAAG;EAAC;EAAc;EAAqB;EAAW;CAAU,CAAC;CAE7D,MAAM,eAAe,kBAAkB;EACrC,IAAI,UAAU,SACZ;EACF,UAAU,UAAU,YAAY,MAAM,gBAAgB;CACxD,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;CAWT,MAAM,eAAe,aAAa,YAAsD;EAEtF,KADe,aAAa,UAAU,KAAK,SAC7B,mBAAmB,GAAG;GAClC,mBAAmB,QAAQ,KAAK,OAAO;GACvC,aAAa;GACb;EACF;EACA,SAAS,OAAO;CAClB,GAAG;EAAC;EAAU;EAAc;CAAkB,CAAC;CAE/C,MAAM,QAAQ,kBAAkB;EAM9B,KADe,aAAa,UAAU,KAAK,SAC7B,mBAAmB,GAAG;GAClC,aAAa;GACb;EACF;EACA,SAAS;CACX,GAAG;EAAC;EAAU;EAAc;CAAkB,CAAC;CAE/C,MAAM,iBAAiB,aACpB,WAAqD,aAAa,MAAM,GACzE,CAAC,YAAY,CACf;CAEA,MAAM,kBAAkB,aACrB,QAAqB,cAAa,WAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,GAC7D,CAAC,YAAY,CACf;CAEA,MAAM,mBAAmB,aACvB,MACA,OACA,WACG;EACH,IAAI,CAAC,OACH;EACF,MAAM,QAAe,QAAQ,WAAW;EACxC,MAAM,QAAQ,QAAQ,SAAS;EAC/B,IAAI,SAAS,WAAW,QAAQ,IAAI,KAAK;EACzC,IAAI,CAAC,QAAQ;GACX,SAAS,YAAY,OAAO,KAAK;GACjC,WAAW,QAAQ,IAAI,OAAO,MAAM;EACtC;EACA,OAAO,SAAS;EAKhB,IAAI,QAAQ,QACV,OAAO,SAAS,OAAO;EACzB,aAAa;CACf,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,QAAQ,kBAAkB;EAC9B,WAAW;EACX,WAAW,QAAQ,MAAM;EACzB,mBAAmB,UAAU,CAAC;EAG9B,oBAAoB;CACtB,GAAG,CAAC,qBAAqB,UAAU,CAAC;CAEpC,MAAM,cAAc,aAAa,YAAoB,4BAA2C;EAC9F,IAAI,WAAW,WAAW,SAAS,mBAAmB,QAAQ,MAAM,GAClE,OAAO,QAAQ,QAAQ;EACzB,OAAO,IAAI,SAAQ,YAAW,eAAe,SAAS,kBAAkB,iBAAiB,SAAS,CAAC;CACrG,GAAG,CAAC,CAAC;CAML,gBAAgB,OAAO,CAAC,KAAK,CAAC;CAO9B,OAAO,eACE;EAAE;EAAkB;EAAiB;EAAgB;EAAO;EAAO;CAAY,IACtF;EAAC;EAAkB;EAAiB;EAAgB;EAAO;EAAO;CAAW,CAC/E;AACF;;;AC7nBA,MAAM,eAAe,cAAqB,aAAa;AAEvD,SAAgB,cAAc,EAAE,OAAO,YAAmD;CACxF,OAAO,oBAAC,aAAa,UAAd;EAAuB,OAAO;EAAQ;CAAgC,CAAA;AAC/E;AAEA,SAAgB,WAAkB;CAChC,OAAO,WAAW,YAAY;AAChC;;AAGA,SAAgB,YAAyB;CACvC,OAAO,WAAW,YAAY,CAAC,CAAC;AAClC;;AAGA,SAAgB,iBAA8B;CAC5C,OAAO,WAAW,YAAY,CAAC,CAAC;AAClC;;AAGA,SAAgB,cAA6B;CAC3C,OAAO,WAAW,YAAY,CAAC,CAAC;AAClC;;AAGA,SAAgB,kBAAgC;CAC9C,OAAO,WAAW,YAAY,CAAC,CAAC;AAClC;;;ACpCA,SAAgB,uBACd,OACA,UAAmC,CAAC,GAC5B;CACR,IAAI,QAAQ,YAAY,SAAS,MAAM,WAAW,GAChD,OAAO;CACT,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,YAAY,CAAC,CAAC;CAC9D,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,UAAU,MAAM,MAAM,GAAG,QAAQ;CACvC,MAAM,QAAQ,CAAC,KAAK,WAAW,gBAAgB;CAC/C,KAAK,MAAM,QAAQ,SACjB,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,SAAS;CACjD,IAAI,MAAM,SAAS,QAAQ,QACzB,MAAM,KAAK,SAAS,MAAM,SAAS,QAAQ,OAAO,MAAM;CAC1D,MAAM,KAAK,iBAAiB;CAC5B,OAAO,MAAM,KAAK,IAAI;AACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,4BAA4B,UAAmC,CAAC,GAAiB;CAC/F,OAAO,EACL,qBAAqB,QAAQ;EAE3B,MAAM,SAAS,uBADD,kBAAkB,IAAI,OACM,CAAC,CAAC,OAAO,OAAO;EAE1D,IAAI,QACF,IAAI,SAAS,qBAAqB,IAAI,QAAQ,MAAM;CACxD,EACF;AACF;;;;;;;;;;;;;;;;;;;;;ACZA,SAAgB,mBAAmB,OAIjC;CACA,MAAM,2BAAW,IAAI,IAAoB;CACzC,IAAI;CACJ,MAAM,OAAO,WAAmD;EAC9D,IAAI,CAAC,QACH,OAAO,KAAA;EACT,aAAa;EACb,IAAI,SAAS,IAAI,MAAM,GACrB,OAAO,KAAA;EACT,MAAM,KAAK,eAAe;EAC1B,SAAS,IAAI,QAAQ,EAAE;EACvB,OAAO;CACT;CACA,MAAM,MAAgC,CAAC;CACvC,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,SAChB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,MAAM,CAAC,CAAC;MAEjC,IAAI,KAAK,KAAK,OAAO,KAAI,MAAK,IAAI,EAAE,MAAM,CAAC,CAAC;CAEhD,OAAO;EAAE;EAAU;EAAK;CAAW;AACrC"}
|