zidane 9.1.1 → 9.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-Di9WvMDF.js → acp-CeCavNlg.js} +7 -7
- package/dist/{acp-Di9WvMDF.js.map → acp-CeCavNlg.js.map} +1 -1
- package/dist/acp-cli.js +5 -5
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-DJhpTS-B.js → agent-Dh_XZ7fj.js} +74 -19
- package/dist/agent-Dh_XZ7fj.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{auth-store-port-DFgf22oo.js → auth-store-port-BKpjlJ8a.js} +2 -2
- package/dist/{auth-store-port-DFgf22oo.js.map → auth-store-port-BKpjlJ8a.js.map} +1 -1
- package/dist/{auto-update-restart-BFB7Ek87.js → auto-update-restart-CQJtndMG.js} +277 -41
- package/dist/auto-update-restart-CQJtndMG.js.map +1 -0
- package/dist/{browser-BcoCCB_n.js → browser-BkdeKnxO.js} +56 -2
- package/dist/browser-BkdeKnxO.js.map +1 -0
- package/dist/{browser-entry-ypi8CyE-.d.ts → browser-entry-BCwruqNa.d.ts} +10 -10
- package/dist/{browser-entry-ypi8CyE-.d.ts.map → browser-entry-BCwruqNa.d.ts.map} +1 -1
- package/dist/channels.d.ts +5 -5
- package/dist/chat/browser.d.ts +4 -4
- package/dist/chat/browser.js +6 -6
- package/dist/chat/pure.d.ts +5 -5
- package/dist/chat/pure.js +8 -8
- package/dist/chat.d.ts +5 -5
- package/dist/chat.js +55 -55
- package/dist/chat.js.map +1 -1
- package/dist/{cli-shared-CabruH8Z.js → cli-shared-DeRHgYvl.js} +4 -4
- package/dist/{cli-shared-CabruH8Z.js.map → cli-shared-DeRHgYvl.js.map} +1 -1
- package/dist/cli-style-DBEm6CyT.js +105 -0
- package/dist/cli-style-DBEm6CyT.js.map +1 -0
- package/dist/{client-core-CIixwznM.d.ts → client-core-C_4m_oL6.d.ts} +4 -4
- package/dist/{client-core-CIixwznM.d.ts.map → client-core-C_4m_oL6.d.ts.map} +1 -1
- package/dist/{client-CCaIXWue.d.ts → client-ygTASGis.d.ts} +2 -2
- package/dist/{client-CCaIXWue.d.ts.map → client-ygTASGis.d.ts.map} +1 -1
- package/dist/codemode-worker.js +8 -5
- package/dist/codemode-worker.js.map +1 -1
- package/dist/codemode.d.ts +16 -0
- package/dist/codemode.d.ts.map +1 -1
- package/dist/codemode.js +2 -2
- package/dist/{connection-loop-QmWL-fJf.d.ts → connection-loop-D_pRONCr.d.ts} +4 -4
- package/dist/{connection-loop-QmWL-fJf.d.ts.map → connection-loop-D_pRONCr.d.ts.map} +1 -1
- package/dist/contexts/daytona.d.ts +3 -3
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +2 -2
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/{contexts-C72b0mMa.js → contexts-DLZTSRHU.js} +17 -106
- package/dist/contexts-DLZTSRHU.js.map +1 -0
- package/dist/contexts.d.ts +4 -4
- package/dist/contexts.js +2 -2
- package/dist/{credentials-wwETW8rI.js → credentials-Bqg-qNBM.js} +2 -2
- package/dist/{credentials-wwETW8rI.js.map → credentials-Bqg-qNBM.js.map} +1 -1
- package/dist/{cwd-picker-CcekODCt.js → cwd-picker-BsHA6HKv.js} +4 -4
- package/dist/{cwd-picker-CcekODCt.js.map → cwd-picker-BsHA6HKv.js.map} +1 -1
- package/dist/daemon-cli.js +4 -3
- package/dist/daemon-cli.js.map +1 -1
- package/dist/{decisions-CXmK0nz9.js → decisions-hsw5XS2g.js} +3 -1
- package/dist/decisions-hsw5XS2g.js.map +1 -0
- package/dist/{discovery-DycXFxdA.js → discovery-CX7nbMCn.js} +4 -4
- package/dist/{discovery-DycXFxdA.js.map → discovery-CX7nbMCn.js.map} +1 -1
- package/dist/durable/sqlite.d.ts +2 -2
- package/dist/durable.d.ts +1 -1
- package/dist/{engine-VQ86XGdG.js → engine-CxBGgU94.js} +6 -6
- package/dist/{engine-VQ86XGdG.js.map → engine-CxBGgU94.js.map} +1 -1
- package/dist/{eval-Bod0I1W_.js → eval-CfGUDAkN.js} +3 -3
- package/dist/{eval-Bod0I1W_.js.map → eval-CfGUDAkN.js.map} +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/{executor-C7RQrkEq.js → executor-j_LFRBwS.js} +4 -4
- package/dist/{executor-C7RQrkEq.js.map → executor-j_LFRBwS.js.map} +1 -1
- package/dist/{extension-mark-BqKdEZwF.js → extension-mark-_rhkDWL5.js} +9 -6
- package/dist/extension-mark-_rhkDWL5.js.map +1 -0
- package/dist/extensions/testing.d.ts +1 -1
- package/dist/extensions/testing.js +2 -2
- package/dist/{extensions-BCx4QuGB.js → extensions-ADlhBQ_1.js} +8 -8
- package/dist/{extensions-BCx4QuGB.js.map → extensions-ADlhBQ_1.js.map} +1 -1
- package/dist/{extensions-client-D8tEAcMw.d.ts → extensions-client-D4Q2XRKV.d.ts} +31 -5
- package/dist/extensions-client-D4Q2XRKV.d.ts.map +1 -0
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +6 -6
- package/dist/{fold-rules-DvLK8pbf.d.ts → fold-rules-1DpDwG9h.d.ts} +2 -2
- package/dist/{fold-rules-DvLK8pbf.d.ts.map → fold-rules-1DpDwG9h.d.ts.map} +1 -1
- package/dist/{google-Crva32sk.js → google-B-Dhmzzf.js} +2 -2
- package/dist/{google-Crva32sk.js.map → google-B-Dhmzzf.js.map} +1 -1
- package/dist/{headless-CCm-jLLT.js → headless-CQm19BL0.js} +4 -4
- package/dist/{headless-CCm-jLLT.js.map → headless-CQm19BL0.js.map} +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/history-worker.js +1 -1
- package/dist/{host-wO_6GW0y.js → host-C61ntFBC.js} +276 -103
- package/dist/host-C61ntFBC.js.map +1 -0
- package/dist/{host-BHMs9jsN.js → host-DEoEzQal.js} +13 -4
- package/dist/host-DEoEzQal.js.map +1 -0
- package/dist/{host-scoped-settings-CrbcqOkP.js → host-scoped-settings-WBYaCork.js} +2 -2
- package/dist/{host-scoped-settings-CrbcqOkP.js.map → host-scoped-settings-WBYaCork.js.map} +1 -1
- package/dist/{host-signals-Jsjd_-4g.js → host-signals-Cb2TlGtN.js} +5 -5
- package/dist/{host-signals-Jsjd_-4g.js.map → host-signals-Cb2TlGtN.js.map} +1 -1
- package/dist/{host-version-CNAr9pov.js → host-version-BIx4CuBM.js} +2 -2
- package/dist/{host-version-CNAr9pov.js.map → host-version-BIx4CuBM.js.map} +1 -1
- package/dist/{index-C6nnKu32.d.ts → index-B0PLo9jn.d.ts} +4 -4
- package/dist/{index-C6nnKu32.d.ts.map → index-B0PLo9jn.d.ts.map} +1 -1
- package/dist/{index-Djnc8Peh.d.ts → index-De4x-s76.d.ts} +14 -14
- package/dist/{index-Djnc8Peh.d.ts.map → index-De4x-s76.d.ts.map} +1 -1
- package/dist/{index-CGbOWa7y.d.ts → index-WlE93Q6d.d.ts} +411 -3
- package/dist/index-WlE93Q6d.d.ts.map +1 -0
- package/dist/{index-CCf_WeTQ.d.ts → index-f-XWIoYo.d.ts} +2 -2
- package/dist/{index-CCf_WeTQ.d.ts.map → index-f-XWIoYo.d.ts.map} +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +17 -17
- package/dist/ipc/browser-types.d.ts +304 -7
- package/dist/ipc/browser-types.d.ts.map +1 -1
- package/dist/ipc/browser.d.ts +4 -4
- package/dist/ipc/browser.js +2 -2
- package/dist/ipc/remote.d.ts +6 -6
- package/dist/ipc/remote.js +3 -3
- package/dist/{ipc-BzWhIybr.js → ipc-DiH_P-wr.js} +4 -4
- package/dist/{ipc-BzWhIybr.js.map → ipc-DiH_P-wr.js.map} +1 -1
- package/dist/ipc.d.ts +10 -10
- package/dist/ipc.js +8 -8
- package/dist/{json-Dj-YATkZ.js → json-BjClr43H.js} +2 -20
- package/dist/json-BjClr43H.js.map +1 -0
- package/dist/{links-CJG_rFvf.js → links-BbC_lOnn.js} +9 -9
- package/dist/{links-CJG_rFvf.js.map → links-BbC_lOnn.js.map} +1 -1
- package/dist/{loaded-entry-DTURJo_R.js → loaded-entry-C0vkCVNQ.js} +2 -2
- package/dist/{loaded-entry-DTURJo_R.js.map → loaded-entry-C0vkCVNQ.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{media-type-BtA0cbfI.d.ts → media-type-ZSmAGHvg.d.ts} +188 -7
- package/dist/media-type-ZSmAGHvg.d.ts.map +1 -0
- package/dist/{memory-DuVGrzbl.js → memory-C3w8nO8f.js} +132 -31
- package/dist/memory-C3w8nO8f.js.map +1 -0
- package/dist/model-test-CAtJ76kM.js.map +1 -1
- package/dist/{move-session-kylExJ5H.js → move-session-D7ILECs-.js} +4 -4
- package/dist/{move-session-kylExJ5H.js.map → move-session-D7ILECs-.js.map} +1 -1
- package/dist/{nested-call-record-DlzPeTB7.js → nested-call-record-OayszZBQ.js} +4 -3
- package/dist/nested-call-record-OayszZBQ.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/{path-display-COVV71Yu.js → path-display-DRAEpKOU.js} +3 -3
- package/dist/{path-display-COVV71Yu.js.map → path-display-DRAEpKOU.js.map} +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/{prelude-CVKoUzV8.js → prelude-BwiSR1uA.js} +16 -5
- package/dist/prelude-BwiSR1uA.js.map +1 -0
- package/dist/{presets-CBt6rFfS.js → presets-CMY43nUP.js} +3 -3
- package/dist/{presets-CBt6rFfS.js.map → presets-CMY43nUP.js.map} +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{protocol-CEVqBO-q.d.ts → protocol-C2lqKuMd.d.ts} +50 -7
- package/dist/protocol-C2lqKuMd.d.ts.map +1 -0
- package/dist/protocol-DOGyHgLQ.js.map +1 -1
- package/dist/protocol-NSllElLw.js.map +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/google.d.ts +1 -1
- package/dist/providers/google.js +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/neuralwatt.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/{providers-Z0TaBp1O.js → providers-CpXV_uLE.js} +5 -5
- package/dist/providers-CpXV_uLE.js.map +1 -0
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/{readonly-db-D7Z-k0pQ.js → readonly-db-DrbT8tX6.js} +2 -2
- package/dist/{readonly-db-D7Z-k0pQ.js.map → readonly-db-DrbT8tX6.js.map} +1 -1
- package/dist/{registry-BKjeBnoy.js → registry-CJHvmvaP.js} +2 -2
- package/dist/{registry-BKjeBnoy.js.map → registry-CJHvmvaP.js.map} +1 -1
- package/dist/{registry-B6Ww76iW.js → registry-CN6JlZKj.js} +2 -2
- package/dist/{registry-B6Ww76iW.js.map → registry-CN6JlZKj.js.map} +1 -1
- package/dist/{registry-B9INJwJR.js → registry-CnnKaY9s.js} +324 -39
- package/dist/registry-CnnKaY9s.js.map +1 -0
- package/dist/{remote-hosts-BMWoHCWO.js → remote-hosts-DoO9CJUQ.js} +4 -4
- package/dist/{remote-hosts-BMWoHCWO.js.map → remote-hosts-DoO9CJUQ.js.map} +1 -1
- package/dist/{repo-url-D4Dr8NfZ.js → repo-url-DLjjuVk_.js} +169 -2
- package/dist/repo-url-DLjjuVk_.js.map +1 -0
- package/dist/restate.d.ts +2 -2
- package/dist/{sandbox-BwiPGKF7.d.ts → sandbox-B4OW6oNx.d.ts} +2 -2
- package/dist/{sandbox-BwiPGKF7.d.ts.map → sandbox-B4OW6oNx.d.ts.map} +1 -1
- package/dist/script-progress-CrZ507Qq.js +900 -0
- package/dist/script-progress-CrZ507Qq.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/{setting-BQBSyUq0.js → setting-D_FpKFMw.js} +6 -6
- package/dist/{setting-BQBSyUq0.js.map → setting-D_FpKFMw.js.map} +1 -1
- package/dist/{settings-catalog-4IU2i_jG.js → settings-catalog-DEZlXP51.js} +14 -2
- package/dist/settings-catalog-DEZlXP51.js.map +1 -0
- package/dist/{settings-keys-iI_Y-7MC.js → settings-keys-CW2UgHgb.js} +3 -3
- package/dist/{settings-keys-iI_Y-7MC.js.map → settings-keys-CW2UgHgb.js.map} +1 -1
- package/dist/{skills-CFXRItJ6.js → skills-CEbosUlM.js} +2 -2
- package/dist/{skills-CFXRItJ6.js.map → skills-CEbosUlM.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +1 -1
- package/dist/{source-Bl1Z501r.js → source-3ZnEPOSa.js} +3 -2
- package/dist/source-3ZnEPOSa.js.map +1 -0
- package/dist/{sqlite-runtime-BZ2L4RaG.d.ts → sqlite-runtime-CS_LBaAN.d.ts} +2 -2
- package/dist/sqlite-runtime-CS_LBaAN.d.ts.map +1 -0
- package/dist/{src-BY_ND2xn.js → src-BmTXDta8.js} +2 -2
- package/dist/{src-BY_ND2xn.js.map → src-BmTXDta8.js.map} +1 -1
- package/dist/{store-C6gI7FfZ.js → store-ByCDaKgJ.js} +14 -3
- package/dist/store-ByCDaKgJ.js.map +1 -0
- package/dist/{system-freeze-m5o1sGIM.js → system-freeze-XgDPIwQS.js} +3 -3
- package/dist/{system-freeze-m5o1sGIM.js.map → system-freeze-XgDPIwQS.js.map} +1 -1
- package/dist/{todo-edits-CbukbjyV.js → todo-edits-Dyj32ds6.js} +4 -3
- package/dist/todo-edits-Dyj32ds6.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/{tools-CVTGhggj.js → tools-BsrGQ8K4.js} +2 -2
- package/dist/{tools-CVTGhggj.js.map → tools-BsrGQ8K4.js.map} +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +3 -3
- package/dist/{transcript-anchors-CiSi_UBn.js → transcript-anchors-DMjvyUjk.js} +3 -3
- package/dist/{transcript-anchors-CiSi_UBn.js.map → transcript-anchors-DMjvyUjk.js.map} +1 -1
- package/dist/{transcript-reconcile-jbSBjLq2.js → transcript-reconcile-DpQO85wl.js} +3 -3
- package/dist/{transcript-reconcile-jbSBjLq2.js.map → transcript-reconcile-DpQO85wl.js.map} +1 -1
- package/dist/tui.d.ts +9 -9
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +289 -38
- package/dist/tui.js.map +1 -1
- package/dist/{types-bDQagoiL.d.ts → types-2HrgolQz.d.ts} +20 -8
- package/dist/types-2HrgolQz.d.ts.map +1 -0
- package/dist/types-4q1bFG53.js +122 -0
- package/dist/types-4q1bFG53.js.map +1 -0
- package/dist/{types-DnRd9_cA.d.ts → types-SXqk6hLD.d.ts} +3 -3
- package/dist/{types-DnRd9_cA.d.ts.map → types-SXqk6hLD.d.ts.map} +1 -1
- package/dist/types-myxheQkw.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/{usage-summary-BfcXjiSM.js → usage-summary-BM7B3JdI.js} +2 -2
- package/dist/{usage-summary-BfcXjiSM.js.map → usage-summary-BM7B3JdI.js.map} +1 -1
- package/dist/{version-DqqqvHDP.js → version-szdW1Od9.js} +2 -2
- package/dist/{version-DqqqvHDP.js.map → version-szdW1Od9.js.map} +1 -1
- package/dist/{wait-task-BX4NcOOm.js → wait-task-BiI5UaZQ.js} +13 -3
- package/dist/wait-task-BiI5UaZQ.js.map +1 -0
- package/dist/{wire-CLm2rMK0.js → wire-C3l9jl9x.js} +2 -2
- package/dist/{wire-CLm2rMK0.js.map → wire-C3l9jl9x.js.map} +1 -1
- package/dist/{write-file-0E6TUJ9A.js → write-file-Dquu7MzB.js} +5 -3
- package/dist/write-file-Dquu7MzB.js.map +1 -0
- package/dist/{ws-DfGGYQ4W.js → ws-CEHi0CiB.js} +4 -4
- package/dist/{ws-DfGGYQ4W.js.map → ws-CEHi0CiB.js.map} +1 -1
- package/dist/{ws-client-CFMbhsNq.js → ws-client-t8XNWxcq.js} +2 -2
- package/dist/{ws-client-CFMbhsNq.js.map → ws-client-t8XNWxcq.js.map} +1 -1
- package/docs/CHAT.md +55 -0
- package/docs/CODEMODE.md +37 -0
- package/docs/EXTENSIONS.md +8 -6
- package/docs/RELEASE-NOTES-NEXT.md +48 -1
- package/docs/RELEASE.md +9 -1
- package/package.json +2 -3
- package/dist/agent-DJhpTS-B.js.map +0 -1
- package/dist/auto-update-restart-BFB7Ek87.js.map +0 -1
- package/dist/browser-BcoCCB_n.js.map +0 -1
- package/dist/contexts-C72b0mMa.js.map +0 -1
- package/dist/decisions-CXmK0nz9.js.map +0 -1
- package/dist/extension-mark-BqKdEZwF.js.map +0 -1
- package/dist/extensions-client-D8tEAcMw.d.ts.map +0 -1
- package/dist/host-BHMs9jsN.js.map +0 -1
- package/dist/host-wO_6GW0y.js.map +0 -1
- package/dist/index-CGbOWa7y.d.ts.map +0 -1
- package/dist/json-Dj-YATkZ.js.map +0 -1
- package/dist/media-type-BtA0cbfI.d.ts.map +0 -1
- package/dist/memory-DuVGrzbl.js.map +0 -1
- package/dist/nested-call-events-BYk8XvGX.js +0 -182
- package/dist/nested-call-events-BYk8XvGX.js.map +0 -1
- package/dist/nested-call-record-DlzPeTB7.js.map +0 -1
- package/dist/prelude-CVKoUzV8.js.map +0 -1
- package/dist/protocol-CEVqBO-q.d.ts.map +0 -1
- package/dist/providers-Z0TaBp1O.js.map +0 -1
- package/dist/registry-B9INJwJR.js.map +0 -1
- package/dist/repo-url-D4Dr8NfZ.js.map +0 -1
- package/dist/settings-catalog-4IU2i_jG.js.map +0 -1
- package/dist/source-Bl1Z501r.js.map +0 -1
- package/dist/sqlite-runtime-BZ2L4RaG.d.ts.map +0 -1
- package/dist/store-C6gI7FfZ.js.map +0 -1
- package/dist/todo-edits-CbukbjyV.js.map +0 -1
- package/dist/types-DTMEhKJO.js +0 -14
- package/dist/types-DTMEhKJO.js.map +0 -1
- package/dist/types-bDQagoiL.d.ts.map +0 -1
- package/dist/wait-task-BX4NcOOm.js.map +0 -1
- package/dist/write-file-0E6TUJ9A.js.map +0 -1
- package/scripts/eval.ts +0 -179
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"write-file-0E6TUJ9A.js","names":["entryPath"],"sources":["../src/behaviors/read-file-defaults.ts","../src/tools/spawn-bubble.ts","../src/tools/spawn-child.ts","../src/tools/spawn-run.ts","../src/tools/spawn.ts","../src/tools/record-artifact.ts","../src/tools/path-suggest.ts","../src/tools/whole-read-guard.ts","../src/tools/edit.ts","../src/tools/list-files.ts","../src/tools/multi-edit.ts","../src/tools/binary-read.ts","../src/tools/read-file.ts","../src/tools/write-file.ts"],"sourcesContent":["import type { AgentBehavior } from '../types'\n\nexport interface ReadFileDefaultFallbacks {\n lineLimit: number\n textMaxBytes: number\n attachmentMaxBytes: number\n}\n\n// Resolved defaults are structurally the fallbacks with every field filled in.\nexport type ResolvedReadFileDefaults = ReadFileDefaultFallbacks\n\nexport function normalizeReadFileInteger(value: unknown, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value))\n return fallback\n // Validation auto-coerces strings to numbers, so by the time we get here\n // a non-finite value means the caller passed something garbled.\n if (value < 0)\n return fallback\n return Math.floor(value)\n}\n\nexport function resolveReadFileDefaults(\n behavior: AgentBehavior | undefined,\n fallbacks: ReadFileDefaultFallbacks,\n): ResolvedReadFileDefaults {\n return {\n lineLimit: normalizeReadFileInteger(behavior?.readFileDefaults?.limit, fallbacks.lineLimit),\n textMaxBytes: normalizeReadFileInteger(behavior?.readFileDefaults?.maxBytes, fallbacks.textMaxBytes),\n // Text only: attachments (images, PDFs) are a different scale (MiB, not\n // KiB), and a text-sized cap would refuse ordinary screenshots.\n attachmentMaxBytes: fallbacks.attachmentMaxBytes,\n }\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\n\n// ---------------------------------------------------------------------------\n// Events to bubble from child → parent. Keep these lists small: the goal is\n// to give the parent a usable live-tail (and a place to gate child calls)\n// without drowning it in telemetry.\n//\n// Three tables (how each is forwarded: see `bubbleHooks`):\n// - `BUBBLED_EVENTS` — observational. Forwarded as a spread copy so the\n// parent's listeners can't accidentally mutate the child's ctx.\n// - `BUBBLED_MUTABLE_EVENTS` — gates and rewrites. Forwarded with the SAME\n// ctx reference so parent listeners can set `block` / `reason` /\n// `result` / `data` and have those mutations land on what the child's\n// loop is awaiting on.\n// - `CHILD_SPAWN_EVENT_NAME` — the child's own spawn lifecycle.\n// ---------------------------------------------------------------------------\n\nconst BUBBLED_EVENTS = [\n 'stream:text',\n 'stream:thinking',\n 'stream:end',\n 'stream:error',\n 'stream:server_tool_use',\n 'stream:server_tool_result',\n 'stream:retry',\n 'tool:dispatched',\n 'tool:before',\n 'tool:after',\n 'tool:error',\n 'tool:cancelled',\n 'validation:reject',\n 'repeat-guard:exceeded',\n 'background:start',\n 'background:exit',\n 'background:reassign',\n 'turn:after',\n 'artifact:recorded',\n] as const\n\n// Same-ref bubble — parent listener mutations propagate back into the\n// child's loop. Content-ref resolution (`data`), gate hooks (`block` /\n// `result`), and `tool:transform` (`result` rewrite) need this so parent\n// policy lands on the child's wire-level request/result.\nconst BUBBLED_MUTABLE_EVENTS = [\n 'content-ref:resolve',\n 'tool:gate',\n 'mcp:tool:gate',\n 'tool:transform',\n] as const\n\ntype BubbledEvent = typeof BUBBLED_EVENTS[number]\ntype BubbledMutableEvent = typeof BUBBLED_MUTABLE_EVENTS[number]\n\n// Mapping from a bubbled event to its corresponding `child:*` event. Kept as\n// an explicit table (rather than a computed `child:${evt}` template literal)\n// so AgentHooks can type each entry independently.\nconst CHILD_EVENT_NAME: Record<BubbledEvent, keyof AgentHooks> = {\n 'stream:text': 'child:stream:text',\n 'stream:thinking': 'child:stream:thinking',\n 'stream:end': 'child:stream:end',\n 'stream:error': 'child:stream:error',\n 'stream:server_tool_use': 'child:stream:server_tool_use',\n 'stream:server_tool_result': 'child:stream:server_tool_result',\n 'stream:retry': 'child:stream:retry',\n 'tool:dispatched': 'child:tool:dispatched',\n 'tool:before': 'child:tool:before',\n 'tool:after': 'child:tool:after',\n 'tool:error': 'child:tool:error',\n 'validation:reject': 'child:validation:reject',\n 'repeat-guard:exceeded': 'child:repeat-guard:exceeded',\n 'tool:cancelled': 'child:tool:cancelled',\n 'background:start': 'child:background:start',\n 'background:exit': 'child:background:exit',\n 'background:reassign': 'child:background:reassign',\n 'turn:after': 'child:turn:after',\n 'artifact:recorded': 'child:artifact:recorded',\n}\n\nconst CHILD_MUTABLE_EVENT_NAME: Record<BubbledMutableEvent, keyof AgentHooks> = {\n 'content-ref:resolve': 'content-ref:resolve',\n 'tool:gate': 'child:tool:gate',\n 'mcp:tool:gate': 'child:mcp:tool:gate',\n 'tool:transform': 'child:tool:transform',\n}\n\n// Spawn lifecycle of a spawn the CHILD ran (its own `spawn` tool fires these\n// on its bus). Re-emitted as `child:spawn:*` — not as `child:*`-tagged copies\n// of `spawn:*`, because the payload's `id` / `depth` already name the spawned\n// agent; the spawner travels as `parentChildId` (see `ChildSpawnIdentity`).\nconst CHILD_SPAWN_EVENT_NAME = {\n 'spawn:before': 'child:spawn:before',\n 'spawn:complete': 'child:spawn:complete',\n 'spawn:error': 'child:spawn:error',\n} as const satisfies Partial<Record<keyof AgentHooks, keyof AgentHooks>>\n\n/**\n * Surface a thrown observational-bubble listener without killing the\n * process. Observational events (`child:stream:text`, `child:tool:after`,\n * `child:turn:after`, …) are fire-and-forget — a rejected promise here\n * has no caller. Without this handler, a buggy parent listener bubbles\n * up to an unhandled-rejection, and Node/Bun under\n * `--unhandled-rejections=strict` terminates the host.\n *\n * Gated on `ZIDANE_DEBUG` so production logs stay quiet; debug builds\n * still get the tagged line.\n */\nfunction swallowBubbleError(eventName: string, err: unknown): void {\n if (!process.env.ZIDANE_DEBUG)\n return\n const message = err instanceof Error ? (err.stack ?? err.message) : String(err)\n process.stderr.write(`[zidane/spawn] parent listener for \"${eventName}\" rejected: ${message}\\n`)\n}\n\n/**\n * Wire child's hooks to bubble into `parentHooks` as `child:*` events.\n *\n * Four kinds of forwarding:\n *\n * 1. **Originating observational events** (`stream:text`, `tool:before`, …)\n * → rewrite to the matching `child:*` event, inject `{ childId, depth }`,\n * fire on the parent's hook bus as a **spread copy** (so parent listeners\n * can't accidentally mutate the child's ctx).\n * 2. **Originating same-ref events** (`tool:gate`, `mcp:tool:gate`,\n * `tool:transform`, `content-ref:resolve`) → forward the **same ctx\n * reference**, augmented with `childId` / `depth`, so a parent listener\n * writing `ctx.block = true` (or a `result` / `data`) lands on what the\n * child's loop is awaiting on. The bubble itself `await`s the parent's\n * callHook so any async approval (e.g. a TUI picker) completes before\n * the child's loop sees the decision.\n * 3. **Re-bubbled `child:*` events** from a grandchild already carry the\n * originating `childId` + `depth`. Forward verbatim so a top-level\n * listener sees true ancestry, not the immediate parent's.\n * 4. **Spawn lifecycle** of a spawn the child itself ran (`spawn:before` /\n * `spawn:complete` / `spawn:error`) → `child:spawn:*`, a spread copy of\n * the spawned agent's record + `parentChildId` (this child), minus\n * `tracingContext`. Already-tagged `child:spawn:*` from deeper levels\n * chain through verbatim (kind 3).\n *\n * Returns a function that unregisters every listener registered here.\n * Called before `agent.run()` starts, torn down in a finally block — so\n * nothing leaks even if the child throws mid-run.\n */\nexport function bubbleHooks(\n childHooks: Hookable<AgentHooks>,\n parentHooks: Hookable<AgentHooks>,\n childId: string,\n depth: number,\n): () => void {\n const unregisters: Array<() => void> = []\n\n // Cast the callHook surface once — it accepts any (name, ctx) at runtime\n // but the typed overload is too narrow to satisfy across the map.\n const fire = parentHooks.callHook as unknown as (\n name: keyof AgentHooks,\n ctx: Record<string, unknown>,\n ) => Promise<unknown>\n\n // Observational events — fire-and-forget so a slow parent listener never\n // backpressures child emission (the child has already moved on by then).\n // `Promise.resolve(...).catch(swallowBubbleError)` instead of `void` so a\n // rejected listener surfaces as a tagged stderr line rather than an\n // unhandled rejection — which would terminate the process under\n // `--unhandled-rejections=strict`. `Promise.resolve` because hookable's\n // `callHook` returns `undefined` when no listeners are registered (rather\n // than a resolved promise), and we still want a uniform `.catch` surface.\n for (const evt of BUBBLED_EVENTS) {\n const parentEvt = CHILD_EVENT_NAME[evt]\n const unregister = childHooks.hook(evt, (ctx: object) => {\n Promise.resolve(fire(parentEvt, { ...(ctx as Record<string, unknown>), childId, depth }))\n .catch(err => swallowBubbleError(parentEvt, err))\n })\n unregisters.push(unregister)\n }\n\n // Same-ref bubble — `await` so the parent's decision lands before the\n // child's loop reads back the mutable slot (`ctx.block` / `ctx.result`\n // for gates, `ctx.result` for `tool:transform`). The bubble only adds\n // `childId` + `depth` for routing; the ctx reference itself is the\n // one the child's loop is awaiting on.\n const tagOnCtx = (ctx: Record<string, unknown>) => {\n ctx.childId ??= childId\n ctx.depth ??= depth\n }\n for (const evt of BUBBLED_MUTABLE_EVENTS) {\n const parentEvt = CHILD_MUTABLE_EVENT_NAME[evt]\n const unregister = childHooks.hook(evt, async (ctx: object) => {\n tagOnCtx(ctx as Record<string, unknown>)\n await fire(parentEvt, ctx as Record<string, unknown>)\n })\n unregisters.push(unregister)\n }\n\n // Nested spawn lifecycle — observational spread copy (like BUBBLED_EVENTS)\n // tagged with the spawner. `tracingContext` is dropped: the carrier is the\n // spawner's to fill (its own tracer knows the active span); a parent\n // writing into the same ref would re-parent the grandchild's trace.\n for (const [evt, parentEvt] of Object.entries(CHILD_SPAWN_EVENT_NAME) as Array<[keyof typeof CHILD_SPAWN_EVENT_NAME, keyof AgentHooks]>) {\n unregisters.push(childHooks.hook(evt, (ctx: object) => {\n const { tracingContext: _carrier, ...record } = ctx as Record<string, unknown>\n Promise.resolve(fire(parentEvt, { ...record, parentChildId: childId }))\n .catch(err => swallowBubbleError(parentEvt, err))\n }))\n }\n\n // Chain bubbling: forward already-tagged `child:*` events from a grandchild\n // through to the parent, preserving the originating spawn's `childId` +\n // `depth`. Without this, only direct children would surface.\n const chainHook = childHooks.hook as unknown as (\n name: keyof AgentHooks,\n handler: (ctx: object) => void | Promise<void>,\n ) => () => void\n const chained: Array<keyof AgentHooks> = [\n ...BUBBLED_EVENTS.map(evt => CHILD_EVENT_NAME[evt]),\n // Already carry the originating spawner's `parentChildId` — verbatim.\n ...Object.values(CHILD_SPAWN_EVENT_NAME),\n ]\n for (const parentEvt of chained) {\n unregisters.push(chainHook(parentEvt, (ctx) => {\n Promise.resolve(fire(parentEvt, ctx as Record<string, unknown>))\n .catch(err => swallowBubbleError(parentEvt, err))\n }))\n }\n for (const evt of BUBBLED_MUTABLE_EVENTS) {\n const parentEvt = CHILD_MUTABLE_EVENT_NAME[evt]\n // Self-mapped events (parentEvt === evt, e.g. `content-ref:resolve`) already\n // have an originating-bubble listener on this same event (registered above).\n // A second listener here would fire the parent twice for a direct child.\n // Grandchild propagation still works without it: the child→grandchild\n // bubble fires the child's own `content-ref:resolve`, which this child's\n // originating listener forwards upward.\n if (parentEvt === evt)\n continue\n unregisters.push(chainHook(parentEvt, async (ctx) => {\n // Same-ref forwards need the await chain to remain serial up to\n // the top-level listener — otherwise the deepest child's loop\n // resumes before the root's decision / result mutation lands.\n await fire(parentEvt, ctx as Record<string, unknown>)\n }))\n }\n\n return () => {\n for (const u of unregisters) u()\n }\n}\n","import type { Agent } from '../agent'\nimport type { Preset } from '../presets'\nimport type { Session, SessionRun } from '../session'\nimport type { AgentStats, ChildRunStats, TurnUsage } from '../types'\nimport type { ChildAgent, SpawnTaskOutcome } from './spawn'\nimport type { SpawnRequest, SpawnToolEnv } from './spawn-run'\nimport type { DurableToolContext, ToolContext } from './types'\nimport { agentExtensionWiringOf, childExtensionOptions } from '../agent-extension-wiring'\nimport { RunSuspendedError, suspensionOf } from '../durable/errors'\nimport { flattenTurns, formatTokenUsage } from '../stats'\nimport { resolveReadStateMap } from './read-state'\nimport { bubbleHooks } from './spawn-bubble'\nimport { extractText, filterToolsForSubagent, inheritedMcpForSubagent, raceWithTimeout, SpawnTimeoutError } from './spawn-helpers'\n\nlet agentModule: Promise<typeof import('../agent')> | undefined\n\n/**\n * The agent module, loaded on first use. Not a static import: that would put\n * the whole agent loop behind every import of the spawn tool (`zidane/tools`,\n * presets, extensions) and close the agent → extensions → spawn → agent cycle.\n * `createSpawnTool` starts the load, so a child's first run doesn't wait on it.\n */\nexport function loadAgentModule(): Promise<typeof import('../agent')> {\n agentModule ??= import('../agent')\n return agentModule\n}\n\n/**\n * Mutable outcome of one reserved child run. Lives on an object (not\n * closure `let`s) so the lifecycle phases below — and the hook listeners\n * they register — read and write the same live values.\n */\nexport interface SpawnRunState {\n /** Error from `agent.destroy()`, reported via `spawn:error` without masking the run outcome. */\n destroyError: Error | undefined\n /** Terminal status of the child run. */\n childRunStatus: NonNullable<ChildRunStats['status']>\n /** Cumulative stats of the child run, once it settled. */\n finalStats: AgentStats | undefined\n /** Model-facing result string. */\n result: string\n /** The child's bare final response text. */\n responseText: string\n /** Removes the hook bubbling and the edit-tool enricher, when `forwardHooks` is set. */\n unbubble: (() => void) | undefined\n /** Stats captured from the child's `agent:done` hook, a spend fallback for rejected runs. */\n reportedStats: AgentStats | undefined\n /** Set when the replay-safe deadline aborted the child at a turn boundary. */\n deadlineExceeded: boolean\n}\n\n/** Clock-sampling timing shared by the run and its result formatting. */\ninterface ChildTiming {\n /** Current time from the parent's clock, or `Date.now()` without one. */\n nowMs: () => number | Promise<number>\n /** Clock sample taken before the child run. */\n spawnStartedMs: number\n /** Timeout enforced at turn boundaries in a replaying run, else `undefined`. */\n journaledDeadlineMs: number | undefined\n}\n\n/**\n * Build the child agent and wire its listeners: spend capture, the\n * replay-safe deadline, and (with `forwardHooks`) the edit-tool enricher +\n * hook bubbling — in that registration order.\n */\nasync function prepareChildAgent(\n env: SpawnToolEnv,\n ctx: ToolContext,\n req: SpawnRequest,\n id: string,\n run: SpawnRunState,\n): Promise<{ agent: Agent } & ChildTiming> {\n const { createAgent } = await loadAgentModule()\n const { options, forwardHooks } = env\n const { subagentDef, childProvider, childDepth } = req\n // Apply the subagent-type tool filter on top of the parent's\n // tool registry. `tools` wins over `readonly` when both are\n // set (explicit beats implicit). The filter is a strict subset\n // — a subagent can never gain tools the parent doesn't have.\n const filteredTools = subagentDef\n ? filterToolsForSubagent(ctx.tools, subagentDef)\n : ctx.tools\n\n // MCP inheritance honors the subagent tool policy — see\n // `inheritedMcpForSubagent`. The connector is NOT part of the\n // preset (Preset omits `mcpConnector` by design); it's passed\n // straight to `createAgent` below.\n const inheritedMcp = inheritedMcpForSubagent(ctx, subagentDef)\n const parentPreset: Preset = {\n ...(ctx.name !== undefined ? { name: ctx.name } : {}),\n ...(ctx.system !== undefined ? { system: ctx.system } : {}),\n tools: filteredTools,\n ...(ctx.toolAliases !== undefined ? { toolAliases: ctx.toolAliases } : {}),\n ...(ctx.toolDescriptions !== undefined ? { toolDescriptions: ctx.toolDescriptions } : {}),\n ...(inheritedMcp.mcpServers !== undefined ? { mcpServers: inheritedMcp.mcpServers } : {}),\n ...(ctx.skills !== undefined ? { skills: ctx.skills } : {}),\n ...(ctx.behavior !== undefined ? { behavior: ctx.behavior } : {}),\n }\n // Resolve the parent's read-state map for cross-context\n // sharing. `shareReadState: true` forwards it to the child via\n // `AgentOptions.readState`, which tools resolve through\n // `resolveReadStateMap(ctx)`. Skips when the parent has\n // nothing to share (no session, no explicit map). Orthogonal\n // to `persist` — turn-history and read-state are independent.\n // Reading via `resolveReadStateMap` here ensures we forward\n // the same map a grandparent might already have forwarded\n // into us (chained `shareReadState` across the tree).\n const sharedReadState = options.shareReadState\n ? resolveReadStateMap(ctx)\n : undefined\n // Replay-safe child deadline. Racing the child against a wall-clock\n // `setTimeout` is a non-deterministic branch: in a replaying run the\n // same child can time out on the live attempt and not on the replay\n // (or the reverse), diverging control flow inside a journaled region,\n // and the abort itself can land mid-stream, tearing down a provider\n // call from INSIDE its recorded step. So when replaying, don't arm the\n // timer: compare the run clock at the child's turn boundaries instead\n // (see the `turn:after` listener below).\n //\n // NOT via `behavior.maxWallMs`, which looks like the natural fit and\n // isn't: the loop derives the provider stream watchdogs from it\n // (`providerWatchdogTimeouts` clamps start / total / idle by the wall\n // budget), so borrowing it would shrink the child's TTFT ceiling to the\n // spawn timeout and abort a live provider stream inside its recorded\n // step. Verified against a real replay runtime: that path fails the\n // attempt with a concurrent journal operation and then a journal\n // mismatch on the retry.\n //\n // Tradeoff of the turn-boundary check: no mid-turn interruption (a\n // child stuck inside ONE long tool call runs that call to completion);\n // hosts needing a hard cut use the runtime's own invocation timeout.\n // The parent's extension runtime covers the child's calls too: its\n // interceptors (a `tool.call` safety policy among them), tools catalog and\n // approval flow. Absent when the parent has no extension runtime.\n const parentExtensions = agentExtensionWiringOf(ctx.hooks)\n const childExtensions = parentExtensions\n ? childExtensionOptions(parentExtensions, {\n childId: id,\n ...(ctx.runId !== undefined ? { parentRunId: ctx.runId } : {}),\n narrowed: filteredTools !== ctx.tools,\n })\n : undefined\n const replaying = ctx.durable?.mode === 'replay'\n const journaledDeadlineMs = replaying\n && options.timeoutMs !== undefined\n && options.timeoutMs > 0\n ? options.timeoutMs\n : undefined\n const agent = createAgent({\n ...parentPreset,\n ...options.preset,\n // Reuse the parent's live MCP connection instead of re-bootstrapping\n // every server per spawn — see `nonOwningMcpConnector`. Suppressed\n // when the embedder preset pins its OWN `mcpServers`: the agent\n // invokes whatever connector it has for ANY non-empty server list,\n // so injecting the parent's here would hand the child the parent's\n // live toolset and silently ignore the embedder's explicit config —\n // those servers must bootstrap from their config instead.\n ...(inheritedMcp.mcpConnector !== undefined && options.preset?.mcpServers === undefined\n ? { mcpConnector: inheritedMcp.mcpConnector }\n : {}),\n provider: childProvider,\n execution: ctx.execution,\n // A replaying parent's child records its steps on the same runtime, so a\n // replay answers them from the parent's journal.\n ...(replaying && ctx.durable ? { durable: ctx.durable.runtime } : {}),\n // A checkpointing parent's child sharing its session is its own\n // checkpoint run, with its own steps: a resumed parent reattaches to it\n // (`SpawnRequest.reattach`).\n ...(ctx.durable?.checkpoint && options.persist && ctx.session ? { durable: ctx.durable.runtime } : {}),\n // Same time/UUID source as the parent, so persisted metadata (turn\n // `createdAt`, run start/end, fallback turn ids) the child writes\n // into the SHARED session comes from one clock. A replaying child\n // takes the runtime's clock instead, which keeps it byte-identical\n // across replays.\n ...(ctx.clock ? { clock: ctx.clock } : {}),\n // Opt-in: run on the parent's handle instead of minting one per\n // child. `AgentOptions.handle` also means the child never destroys\n // it — the parent owns the lifecycle.\n ...(options.shareHandle && ctx.handle ? { handle: ctx.handle } : {}),\n // Share the parent's session on opt-in. Child turns get appended to\n // the same session.turns stream with the child's runId; the child\n // run itself is tagged with parentRunId below, via AgentRunOptions.\n ...(options.persist && ctx.session ? { session: ctx.session } : {}),\n ...(sharedReadState ? { readState: sharedReadState } : {}),\n ...childExtensions,\n })\n // Every exit path of `agent.run()` fires `agent:done` with the loop's\n // real usage mirror BEFORE the throwing paths re-throw (budget breach,\n // hard failure). Capturing it here is the only way a REJECTED child run\n // can still report true spend: `await runPromise` on an\n // already-rejected promise just re-throws, leaving nothing to read.\n // Matters most for the replay-safe deadline: that timeout arrives as a\n // rejection, and zeroed tokens/cost would land in `spawn:complete`,\n // `AgentStats.children` and the parent's aggregation on exactly the\n // runtime where cost accounting matters.\n agent.hooks.hook('agent:done', (stats) => {\n run.reportedStats = stats\n })\n\n // Replay-safe deadline (see `journaledDeadlineMs` above): ONE clock\n // sample before the run, then a synchronous comparison against each\n // assistant turn's `createdAt` — which the loop already minted from\n // this same clock. Aborting AT a turn boundary is the safe moment:\n // nothing is in flight, so no journal entry gets torn down mid-body.\n //\n // The listener must not do journal I/O of its own. `turn:after` is\n // dispatched through `settledHook`, which abandons a handler that\n // hasn't settled within `hookTimeoutMs` and continues to the next turn\n // — an awaited `clock.now()` in here could still be in flight when the\n // loop opens the next provider call, which is the concurrent-ctx-op\n // condition that fails the attempt live and with a journal mismatch on\n // the retry. Reusing `createdAt` also saves one journaled `now()` per\n // child turn, the runtime's biggest suspension-count lever.\n //\n // The same sample anchors the elapsed figure in the model-visible\n // result string. That string lands in the PARENT's transcript, and a\n // durable host persists the transcript through a journaled state write\n // whose payload is compared across attempts — so a live `Date.now()`\n // delta (`finalStats.elapsed`, deliberately live for measurement\n // accuracy) differs by a millisecond on the replay and fails the\n // invocation with a journal mismatch at the state write. Verified against\n // a real server: an attempt that fails AFTER the child completed retries\n // forever. Rule of thumb: anything that reaches the transcript has to\n // come from `ctx.clock`.\n const nowMs = (): number | Promise<number> => ctx.clock ? ctx.clock.now() : Date.now()\n const spawnStartedMs = await nowMs()\n if (journaledDeadlineMs !== undefined) {\n agent.hooks.hook('turn:after', (turnCtx) => {\n if (run.deadlineExceeded)\n return\n if (turnCtx.message.createdAt - spawnStartedMs < journaledDeadlineMs)\n return\n run.deadlineExceeded = true\n agent.abort()\n })\n }\n if (forwardHooks) {\n // Enrich `tool:before` ctx with `priorContent` for the three\n // edit tools BEFORE bubbleHooks fires the parent's\n // `child:tool:before`. Hookable runs listeners serially in\n // registration order, so registering this enricher first\n // guarantees the bubble's ctx-spread captures the field.\n // Hosts that listen on `child:tool:before` (the TUI's\n // edit-diff feature) read `priorContent` to:\n // - render a true `old → new` diff for `write_file` instead\n // of an all-add view, and\n // - paint real-file line numbers in the gutter / compact\n // summary for all three edit tools (via the renderer's\n // `buildContextualDiff` path).\n //\n // Note: `tool:before` is awaited by the child's loop, so this\n // pre-read blocks the child's tool execution by the read\n // latency. Acceptable — edit calls are cheap relative to the\n // model round-trip, and the read is skipped entirely for\n // non-edit tools.\n const unregisterEnricher = agent.hooks.hook('tool:before', async (toolCtx) => {\n if (toolCtx.name !== 'write_file' && toolCtx.name !== 'edit' && toolCtx.name !== 'multi_edit')\n return\n if (!agent.handle)\n return\n const inputPath = toolCtx.input?.path\n if (typeof inputPath !== 'string')\n return\n try {\n toolCtx.priorContent = await agent.execution.readFile(agent.handle, inputPath)\n }\n catch {\n // File doesn't exist (fresh create for `write_file`, or\n // a model-side mistake for `edit` / `multi_edit`) — leave\n // priorContent unset; downstream renderers treat the\n // absence as \"no real-file positions available\" and fall\n // back to synthetic line numbers.\n }\n })\n const unbubbleInner = bubbleHooks(agent.hooks, ctx.hooks, id, childDepth)\n run.unbubble = () => {\n unregisterEnricher()\n unbubbleInner()\n }\n }\n\n return { agent, nowMs, spawnStartedMs, journaledDeadlineMs }\n}\n\n/** Run a child whose slot + id are already reserved; returns the outcome. */\nexport async function runReservedChild(\n env: SpawnToolEnv,\n ctx: ToolContext,\n req: SpawnRequest,\n child: ChildAgent,\n run: SpawnRunState,\n): Promise<SpawnTaskOutcome> {\n const { options } = env\n const localStats = env.state.stats\n const { task, systemOverride, subagentDef, childProvider, childModel, announcedModel, resumeRun, resumeLabel, childDepth } = req\n const { id } = child\n const { agent, nowMs, spawnStartedMs, journaledDeadlineMs } = await prepareChildAgent(env, ctx, req, id, run)\n\n options.onSpawn?.(child)\n // Mutable tracingContext carrier — empty by default; parent tracer\n // listeners on `spawn:before` write a W3C `traceparent` (plus\n // optional `tracestate`) into it. We forward whatever it contains\n // to the child's `agent.run()` so the child tracer can re-parent\n // its root span. Empty / absent for parents that don't run a\n // tracer (no-op, no key gets set, child sees `undefined`).\n const spawnHookCtx: { id: string, task: string, callId?: string, depth: number, model: string, provider: string, tracingContext: Record<string, string>, resumesChildId?: string } = {\n id,\n task,\n // This spawn's own call id, so a host learns `childId` -> callId at\n // spawn time — needed for children that never dispatch a tool (no\n // `child:tool:*` carries the mapping) and under parallel spawns\n // (where `task` is the only other thing to match on).\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n // Which prior child this run continues — hosts render it next to\n // the spawn-start marker (e.g. “child-4 (resumes child-2)”).\n ...(resumeLabel !== undefined ? { resumesChildId: resumeLabel } : {}),\n depth: childDepth,\n // What the child actually runs on — hosts surface it next to the\n // spawn-start marker so cost-tiered delegation is visible.\n model: announcedModel,\n provider: childProvider.name,\n tracingContext: {},\n }\n await ctx.hooks.callHook('spawn:before', spawnHookCtx)\n\n // `agent.run()` is started here and we hold onto its promise so we\n // can always `await` it before destroying. Even on a timeout we\n // re-await the run — that lets the child's internal `finally`\n // (session.abortRun, finalizeSession, hooks) flush its state to the\n // store before the parent hands the outcome back to the LLM.\n const propagatedTracing = Object.keys(spawnHookCtx.tracingContext).length > 0\n ? Object.freeze({ ...spawnHookCtx.tracingContext })\n : undefined\n // System prompt precedence (highest first):\n // 1. per-call `input.system` — model-supplied specialization.\n // 2. `subagents[type].system` — host preset for this type.\n // 3. `options.system` — spawn-tool default.\n // Subagent-type system overrides matter for Plan/Explore-style\n // presets where the type IS the contract (e.g. \"you are a research\n // subagent…\").\n const effectiveSystem\n = systemOverride\n ?? subagentDef?.system\n ?? options.system\n // Model precedence: per-call `input.model` (catalog-validated) >\n // `subagents[type].model` > spawn-tool `options.model` > parent\n // run's resolved model > provider default (inside `agent.run`).\n // Without the `ctx.model` fallback, a parent running on a per-run\n // model would silently spawn children on `provider.meta.defaultModel`\n // (e.g. a sonnet run spawning opus subagents). `childModel` is\n // resolved above, before the `spawn:before` hook announced it.\n const runOptions = {\n ...(childModel !== undefined ? { model: childModel } : {}),\n system: effectiveSystem,\n thinking: subagentDef?.thinking ?? options.thinking,\n depth: childDepth,\n ...(options.persist && ctx.runId ? { parentRunId: ctx.runId } : {}),\n // The spawn call's own id, forwarded so every tool call inside the\n // child (and every bubbled `child:tool:*` the parent sees) can be\n // attributed to the call that created it. Unconditional — unlike\n // `parentRunId`, which needs a shared session. Guarded only for\n // hand-built tool contexts that omit `callId`.\n ...(ctx.callId ? { parentCallId: ctx.callId } : {}),\n // Persist the reserved label onto the child's SessionRun so\n // `resume` resolution and transcript numbering read a stored\n // fact instead of a positional guess.\n ...(options.persist && ctx.session ? { runLabel: id } : {}),\n ...(propagatedTracing ? { tracingContext: propagatedTracing } : {}),\n }\n // A resumed parent's call reattaches to the child run it started before\n // the process died: that run continues from its own steps.\n const runPromise = req.reattach\n ? agent.resume({ runId: req.reattach.id, signal: ctx.signal, run: runOptions }).then(stats => stats ?? Promise.reject(new Error(`Child run \"${req.reattach!.id}\" has nothing left to resume.`)))\n : agent.run({ prompt: task, signal: ctx.signal, ...runOptions, ...(resumeRun ? { resumeRunId: resumeRun.id } : {}) })\n // The parent's suspension suspends the child: it keeps its resumable mark,\n // and the parent's resume reattaches to it (`SpawnRequest.reattach`).\n const suspendChild = (): void => {\n agent.suspend().catch(() => undefined)\n }\n const { suspendSignal } = ctx as DurableToolContext\n if (suspendSignal?.aborted)\n suspendChild()\n else\n suspendSignal?.addEventListener('abort', suspendChild, { once: true })\n try {\n run.finalStats = await raceWithTimeout(\n runPromise,\n journaledDeadlineMs === undefined ? options.timeoutMs : undefined,\n )\n // Not an outcome: the call stays pending, to continue on the parent's resume.\n if (run.finalStats.suspended)\n throw suspensionOf(suspendSignal) ?? new RunSuspendedError()\n\n // Tree-wide turn count keeps the model-facing line internally\n // consistent with the cumulative token numbers — otherwise a\n // 2-turn child that spawned a 50-turn grandchild would print\n // \"2 turns ... 5000 tokens\" and look broken. Equals\n // `finalStats.turns` when the child has no descendants of its own.\n const treeTurns = flattenTurns(run.finalStats).length\n // `formatTokenUsage` reports the effective input (including\n // cached reads / cache creations) with the cached portion broken\n // out — see the helper's docstring.\n const usage = formatTokenUsage(run.finalStats)\n // Clock-sourced, not `finalStats.elapsed` — see `spawnStartedMs`.\n const elapsedMs = (await nowMs()) - spawnStartedMs\n if (run.deadlineExceeded) {\n // The journaled deadline aborted the child at a turn boundary, so\n // the run resolved cleanly and `finalStats` is the child's REAL\n // spend — no fabrication needed on this path.\n run.childRunStatus = 'timeout'\n run.result = `[sub-agent ${id}] Timed out after ${journaledDeadlineMs}ms`\n }\n else if (ctx.signal.aborted) {\n run.childRunStatus = 'aborted'\n run.result = [\n `[sub-agent ${id}] Aborted after ${treeTurns} turns (${elapsedMs}ms)`,\n `Tokens: ${usage}`,\n ].join('\\n')\n }\n else {\n const response = extractText(agent.turns.at(-1))\n run.responseText = response ?? ''\n run.result = [\n `[sub-agent ${id}] Completed in ${treeTurns} turns (${elapsedMs}ms)`,\n `Tokens: ${usage}`,\n '',\n response || '(no text response)',\n ].join('\\n')\n }\n }\n catch (err) {\n if (err instanceof RunSuspendedError)\n throw err\n // Both deadline mechanisms land here as one `timeout` outcome, so\n // the model-visible result and `ChildRunStats.status` don't depend on\n // which clock the host installed: the wall timer rejects with\n // `SpawnTimeoutError`, while a journaled-deadline abort can surface\n // as the child's own abort rejection.\n const timedOutAfterMs = err instanceof SpawnTimeoutError\n ? err.timeoutMs\n : run.deadlineExceeded\n ? journaledDeadlineMs\n : undefined\n if (timedOutAfterMs !== undefined) {\n run.childRunStatus = 'timeout'\n agent.abort() // triggers child's internal abort path\n // Await the run so its finally block persists aborted state\n // before we move on. Swallow any error from the awaited promise\n // — we've already classified the outcome as 'timeout'.\n try {\n run.finalStats = await runPromise\n }\n catch {\n // Rejected — the wall-clock path resolves through the abort\n // branch, the journaled deadline arrives here. Fall back to the\n // spend `agent:done` reported, and only fabricate zeros when the\n // run never got far enough to report any.\n run.finalStats = run.reportedStats ?? {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: timedOutAfterMs,\n }\n }\n run.result = `[sub-agent ${id}] Timed out after ${timedOutAfterMs}ms`\n }\n else {\n const error = err instanceof Error ? err : new Error(String(err))\n run.childRunStatus = 'error'\n // Same reasoning as the timeout branch: a child that burned tokens\n // and then failed should report them, not zeros.\n run.finalStats = run.reportedStats ?? {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: 0,\n }\n run.result = `[sub-agent ${id}] Error: ${error.message}`\n await ctx.hooks.callHook('spawn:error', { id, task, ...(ctx.callId ? { callId: ctx.callId } : {}), depth: childDepth, model: announcedModel, provider: childProvider.name, error })\n }\n }\n finally {\n suspendSignal?.removeEventListener('abort', suspendChild)\n await teardownChildAgent(ctx, agent, id, run)\n }\n\n // Aggregate after run finalization so in-flight totalIn/Out/turns\n // counters are stable.\n if (run.finalStats) {\n localStats.totalIn += run.finalStats.totalIn\n localStats.totalOut += run.finalStats.totalOut\n localStats.totalCacheRead += run.finalStats.totalCacheRead\n localStats.totalCacheCreation += run.finalStats.totalCacheCreation\n localStats.turns += run.finalStats.turns\n // `elapsed` is a cumulative sum across children — documented as such.\n // Over-counts when children run in parallel; reflects \"total CPU-ish\n // time burned on children\" rather than wall-clock parallelism.\n localStats.elapsed += run.finalStats.elapsed\n }\n\n // Build ChildRunStats + emit completion hook. Emitted for every\n // terminal state (success/abort/timeout/error) so consumers can\n // reconcile local state without also listening on spawn:error.\n const childRunStats: ChildRunStats = {\n id,\n task,\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n stats: run.finalStats!,\n depth: childDepth,\n status: run.childRunStatus,\n ...(run.finalStats!.output ? { output: run.finalStats!.output } : {}),\n }\n options.onComplete?.(child, run.finalStats!, run.childRunStatus)\n await ctx.hooks.callHook('spawn:complete', childRunStats)\n\n if (run.destroyError) {\n // Non-fatal but worth surfacing: a destroy failure leaves an\n // execution-handle / MCP connection in a weird state.\n await ctx.hooks.callHook('spawn:error', {\n id,\n task,\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n depth: childDepth,\n model: announcedModel,\n provider: childProvider.name,\n error: run.destroyError,\n })\n }\n\n return { id, status: run.childRunStatus, text: run.responseText, message: run.result, ...(run.finalStats ? { stats: run.finalStats } : {}) }\n}\n\n/**\n * The outcome of a spawn call whose child run ended in a process that died\n * before the parent saved the call's result (`SpawnRequest.reattach` on a\n * run no longer resumable): rebuilt from the child's run record and saved\n * turns, without running it again. Elapsed time is the run's own, from its\n * record.\n */\nexport async function finishedChildOutcome(env: SpawnToolEnv, ctx: ToolContext, session: Session, req: SpawnRequest, childRun: SessionRun): Promise<SpawnTaskOutcome> {\n const { options } = env\n const id = childRun.label ?? childRun.id\n const stats = storedRunStats(session, childRun)\n const status = storedRunStatus(childRun)\n const usage = formatTokenUsage(stats)\n const treeTurns = flattenTurns(stats).length\n let text = ''\n let message: string\n if (status === 'completed') {\n text = extractText(session.turns.findLast(t => t.runId === childRun.id && t.role === 'assistant' && !t.aborted))\n message = [`[sub-agent ${id}] Completed in ${treeTurns} turns (${stats.elapsed}ms)`, `Tokens: ${usage}`, '', text || '(no text response)'].join('\\n')\n }\n else if (status === 'aborted') {\n message = [`[sub-agent ${id}] Aborted after ${treeTurns} turns (${stats.elapsed}ms)`, `Tokens: ${usage}`].join('\\n')\n }\n else {\n message = `[sub-agent ${id}] Error: ${childRun.error ?? 'the child run failed'}`\n }\n const localStats = env.state.stats\n localStats.totalIn += stats.totalIn\n localStats.totalOut += stats.totalOut\n localStats.totalCacheRead += stats.totalCacheRead\n localStats.totalCacheCreation += stats.totalCacheCreation\n localStats.turns += stats.turns\n localStats.elapsed += stats.elapsed\n options.onComplete?.({ id, task: req.task, startedAt: childRun.startedAt, depth: req.childDepth }, stats, status)\n await ctx.hooks.callHook('spawn:complete', {\n id,\n task: req.task,\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n stats,\n depth: req.childDepth,\n status,\n })\n return { id, status, text, message, stats }\n}\n\nfunction storedRunStatus(run: SessionRun): NonNullable<ChildRunStats['status']> {\n return run.status === 'completed' ? 'completed' : run.status === 'error' ? 'error' : 'aborted'\n}\n\n/** A finished run's {@link AgentStats} from its record, with its own children's (the run's subtree, like a live child's). */\nfunction storedRunStats(session: Session, run: SessionRun): AgentStats {\n const turnUsage: TurnUsage[] = run.turnUsage ?? []\n const sum = (pick: (u: TurnUsage) => number | undefined): number => turnUsage.reduce((n, u) => n + (pick(u) ?? 0), 0)\n const children: ChildRunStats[] = session.runs\n .filter(r => r.parentRunId === run.id)\n .map(r => ({\n id: r.label ?? r.id,\n task: r.prompt,\n ...(r.parentCallId ? { callId: r.parentCallId } : {}),\n stats: storedRunStats(session, r),\n ...(r.depth !== undefined ? { depth: r.depth } : {}),\n status: storedRunStatus(r),\n }))\n const fold = (own: number, pick: (s: AgentStats) => number): number => children.reduce((n, c) => n + pick(c.stats), own)\n const cost = fold(run.cost ?? 0, s => s.cost ?? 0)\n return {\n totalIn: fold(run.tokensIn ?? sum(u => u.input), s => s.totalIn),\n totalOut: fold(run.tokensOut ?? sum(u => u.output), s => s.totalOut),\n totalCacheRead: fold(sum(u => u.cacheRead), s => s.totalCacheRead),\n totalCacheCreation: fold(sum(u => u.cacheCreation), s => s.totalCacheCreation),\n turns: run.turns ?? turnUsage.length,\n elapsed: Math.max(0, (run.endedAt ?? run.startedAt) - run.startedAt),\n ...(turnUsage.length > 0 ? { turnUsage } : {}),\n ...(cost > 0 ? { cost } : {}),\n ...(children.length > 0 ? { children } : {}),\n }\n}\n\n/**\n * Teardown after the child settled: promote its background tasks to the\n * parent's handle, then destroy it (capturing any destroy error).\n */\nasync function teardownChildAgent(ctx: ToolContext, agent: Agent, id: string, run: SpawnRunState): Promise<void> {\n // Promote the subagent's still-running background tasks up\n // to the parent's handle BEFORE destroying the child.\n // Without this, `agent.destroy()` would SIGTERM every task\n // the subagent started (per-handle scoping is what makes\n // sibling subagents isolated, but it also kills `&`-shell\n // semantics where backgrounded work outlives the spawning\n // process). With it, the user can `ctrl+k` a long-running\n // task the subagent started even after the subagent returns,\n // and `killBackgroundTask` from the parent agent actually\n // finds it.\n //\n // The reassignment also REPLACES the task's `onExit`\n // callback — the original closed over the child's hook bus,\n // which is about to be torn down. The new callback fires\n // `background:exit` on the PARENT's bus so the TUI's\n // existing listener drains the entry when the task\n // eventually terminates.\n //\n // Optional in the contract — sandboxes that don't expose\n // `reassignBackgroundTasks` fall through: destroy kills the\n // subagent's tasks. Same for\n // a child agent that minted no execution handle (no runs\n // ever executed).\n // Skipped outright under `shareHandle`: the child ran ON the parent's\n // handle, so there is nothing to promote. Guarding here rather than\n // relying on a same-id no-op keeps us inside the documented contract\n // — `reassignBackgroundTasks` is specified to REPLACE each task's\n // `onExit`, so a context without that no-op would rewrite the\n // PARENT's own still-running tasks and we'd emit `background:reassign`\n // with `fromHandleId === toHandleId` for tasks no child started.\n const childHandle = agent.handle\n if (childHandle && childHandle.id !== ctx.handle.id && ctx.execution.reassignBackgroundTasks) {\n try {\n const reassigned = await ctx.execution.reassignBackgroundTasks(\n childHandle,\n ctx.handle,\n (info) => {\n void Promise.resolve(ctx.hooks.callHook('background:exit', info)).catch(() => {})\n },\n )\n for (const entry of reassigned) {\n await ctx.hooks.callHook('background:reassign', {\n taskId: entry.taskId,\n fromHandleId: childHandle.id,\n toHandleId: ctx.handle.id,\n childId: id,\n pid: entry.pid,\n command: entry.command,\n outputPath: entry.outputPath,\n startedAt: entry.startedAt,\n })\n }\n }\n catch (err) {\n // Non-fatal — destroy will still kill the tasks. Log\n // under ZIDANE_DEBUG so a misconfigured sandbox surfaces\n // visibly. We don't promote this into `spawn:error`\n // because it doesn't affect the subagent's own outcome.\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/spawn] reassignBackgroundTasks failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n }\n }\n\n // Always attempt to destroy. Capture any destroy error so it can be\n // surfaced via spawn:error without masking the primary outcome.\n try {\n await agent.destroy()\n }\n catch (err) {\n run.destroyError = err instanceof Error ? err : new Error(String(err))\n }\n}\n","import type { Provider } from '../providers'\nimport type { SessionRun } from '../session'\nimport type { AgentStats } from '../types'\nimport type { SpawnModelEntry } from './model-search'\nimport type { ChildAgent, SpawnTaskInput, SpawnTaskOutcome, SpawnToolOptions, SubagentDef, SubagentRegistry } from './spawn'\nimport type { SpawnRunState } from './spawn-child'\nimport type { ToolContext } from './types'\nimport { resumeChainRunIds } from '../session'\nimport { matchModelEntries } from './model-search'\nimport { finishedChildOutcome, runReservedChild } from './spawn-child'\nimport { childRunsOf, describeChildRuns, EMBEDDED_CATALOG_MAX, reserveChildLabel, resolveProviderByName } from './spawn-helpers'\n\n/**\n * Mutable per-instance state shared across {@link SpawnTool.withSubagents}\n * rebuilds. Threading the SAME object into a rebuilt instance keeps the\n * concurrency counter, the cumulative child-stats accumulator, and the\n * sessionless child-label counter alive across a rebuild.\n */\nexport interface SpawnInstanceState {\n /** Currently running children by label. */\n children: Map<string, ChildAgent>\n /** Cumulative stats of completed direct children. */\n stats: AgentStats\n /** Sessionless child-label fallback counter (see `reserveChildLabel`). */\n counter: number\n /** Concurrency counter — taken synchronously in `runSpawnTask`, or handed over by `releaseSlot`. */\n activeCount: number\n /**\n * Top-level spawn calls waiting for a slot, first come first served. A\n * finishing child hands its slot straight to the first one (see\n * `releaseSlot`), so a newer call never takes it first.\n */\n waiters: Array<() => void>\n}\n\n/** What one built spawn-tool instance hands its per-call lifecycle. */\nexport interface SpawnToolEnv {\n /** Options the tool was built with. */\n options: SpawnToolOptions\n /** Per-instance mutable state. */\n state: SpawnInstanceState\n /** Cap on simultaneous children. */\n maxConcurrent: number\n /** Cap on subagent depth. */\n maxDepth: number\n /** Whether child hook events bubble to the parent. */\n forwardHooks: boolean\n /** Registry of named subagent presets, when one is configured. */\n subagentRegistry: SubagentRegistry | undefined\n /** Model catalog children may run on, when one is configured. */\n modelCatalog: readonly SpawnModelEntry[] | undefined\n}\n\n/** Everything {@link resolveSpawnRequest} settles before a slot is reserved. */\nexport interface SpawnRequest {\n /** Task prompt for the child. */\n task: string\n /** Per-call system prompt override. */\n systemOverride: string | undefined\n /** The selected subagent preset, if any. */\n subagentDef: SubagentDef | undefined\n /** Provider the child runs on. */\n childProvider: Provider\n /** Model id pinned for the child, or `undefined` to use the provider default. */\n childModel: string | undefined\n /** Model id announced to hosts in `spawn:before`. */\n announcedModel: string\n /** Prior child run being resumed, if any. */\n resumeRun: SessionRun | undefined\n /** Label of the resumed child, if any. */\n resumeLabel: string | undefined\n /** Depth of the new child: parent depth plus one. */\n childDepth: number\n /**\n * The child run this call started in a process that died, when the\n * parent's checkpoint run was resumed: the call reattaches to it instead\n * of starting a new child. Still resumable: it continues (`Agent.resume`).\n * Ended: its outcome is rebuilt from its record, it does not run again.\n */\n reattach?: SessionRun\n}\n\n/**\n * Validate a spawn call and resolve its child config. Returns the resolved\n * request, or a rejected or aborted outcome when no child should run. Synchronous on purpose:\n * the caller reserves the concurrency slot right after, and nothing may\n * `await` between the cap check and the reservation.\n */\nexport function resolveSpawnRequest(env: SpawnToolEnv, input: SpawnTaskInput, ctx: ToolContext): SpawnRequest | { outcome: SpawnTaskOutcome } {\n const { options, maxDepth, subagentRegistry, modelCatalog } = env\n const task = input.task\n const systemOverride = input.system\n const requestedSubagentType = typeof input.subagent_type === 'string'\n ? input.subagent_type\n : undefined\n // Resolve the subagent preset. Unknown types degrade to\n // `general-purpose` (i.e. no overlay) so Claude-Code-trained\n // models that emit `subagent_type: 'Verification'` against hosts\n // that never wired that type don't get silently broken — the\n // call still runs, just with the parent's default config.\n const subagentDef = requestedSubagentType && subagentRegistry && Object.hasOwn(subagentRegistry, requestedSubagentType)\n ? subagentRegistry[requestedSubagentType]\n : undefined\n\n // Model selection. Only honored when a catalog is configured —\n // without one the `model` field isn't in the schema, and an\n // unvalidated id would fail deep inside the child's first stream\n // instead of here where the model can self-correct.\n // Precedence: per-call `input.model` > `subagents[type].model` >\n // `options.model` > inherit the parent run's model (`ctx.model`).\n const requestedModel = modelCatalog && typeof input.model === 'string' && input.model.trim() !== ''\n ? input.model.trim()\n : undefined\n if (requestedModel && modelCatalog && !modelCatalog.some(e => e.model.id === requestedModel)) {\n const near = matchModelEntries(modelCatalog, requestedModel).slice(0, 8)\n const shown = near.length > 0 ? near : modelCatalog.slice(0, 8)\n return {\n outcome: {\n status: 'rejected',\n text: '',\n message: `Cannot spawn: unknown model \"${requestedModel}\". ${near.length > 0 ? 'Closest matches' : 'Available'}: ${shown.map(e => e.model.id).join(', ')}${\n modelCatalog.length > shown.length ? ` … (${modelCatalog.length} total; use model_search to browse)` : ''}`,\n },\n }\n }\n const chosenModelId = requestedModel ?? subagentDef?.model ?? options.model\n // Provider routing: a catalog-listed model runs on the provider\n // that serves it (matched by `Provider.name` against the run's\n // provider list). A model-requested id whose provider isn't in\n // this run is rejected — host-configured ids (subagent presets /\n // options.model) degrade to the parent's provider instead, since\n // the model can't fix host config by retrying.\n let childProvider = ctx.provider\n const chosenEntry = chosenModelId && modelCatalog\n ? modelCatalog.find(e => e.model.id === chosenModelId)\n : undefined\n if (chosenEntry) {\n const routed = resolveProviderByName(chosenEntry.provider, ctx)\n if (routed) {\n childProvider = routed\n }\n else if (requestedModel !== undefined) {\n return {\n outcome: {\n status: 'rejected',\n text: '',\n message: `Cannot spawn: model \"${chosenModelId}\" is served by provider \"${chosenEntry.provider}\", which is not available in this run. Pick a model from an available provider${modelCatalog && modelCatalog.length > EMBEDDED_CATALOG_MAX ? ' (use model_search)' : ''}.`,\n },\n }\n }\n }\n // The child's effective model. `ctx.model` (inherit) only applies when\n // the child stays on the parent's provider — a routed child would\n // reject a foreign model id, so it uses its own provider default\n // instead. Resolved HERE (not at `agent.run` time) so `spawn:before`\n // can announce the actual model to hosts (TUI spawn-start marker).\n const inheritedModel = childProvider === ctx.provider ? ctx.model : undefined\n const childModel = chosenModelId ?? inheritedModel\n const announcedModel = childModel ?? childProvider.meta.defaultModel\n\n // Resume resolution (`input.resume`): map the child label / run id to\n // a prior terminal child run whose turns are persisted in the shared\n // session. Validated up front so every failure mode is a cheap\n // rejection the model can self-correct from — no slot reserved, no\n // agent built. Labels resolve against the label persisted at\n // `startRun` (`SessionRun.label`) first — immune to out-of-order\n // `startRun`s under concurrent spawns, counter drift, and reload\n // reordering — with positional fallback for legacy sessions, then\n // raw run ids.\n let resumeRun: SessionRun | undefined\n let resumeLabel: string | undefined\n if (input.resume !== undefined && input.resume !== null) {\n // Malformed values (numbers, empty strings) must reject, not fall\n // through to a FRESH spawn — the task is a continuation instruction\n // that makes no sense as a standalone prompt.\n if (typeof input.resume !== 'string' || input.resume.trim() === '') {\n return { outcome: { status: 'rejected', text: '', message: `Cannot resume: invalid resume value ${JSON.stringify(input.resume)}; pass a child label like \"child-2\".` } }\n }\n const wanted = input.resume.trim()\n if (!options.persist || !ctx.session) {\n return { outcome: { status: 'rejected', text: '', message: 'Cannot resume: resuming a sub-agent requires the spawn tool to be configured with persist: true and the parent to have a session; no prior child turns are stored here.' } }\n }\n const childRuns = childRunsOf(ctx.session)\n let index = childRuns.findIndex(r => r.label === wanted)\n if (index < 0) {\n const labelMatch = /^child-(\\d+)$/.exec(wanted)\n // Positional fallback is for FULLY-LEGACY sessions only (no run\n // carries a persisted label). In a mixed session a positional\n // guess can silently land on a DIFFERENT labeled run (reload\n // reordering), resuming the wrong child — reject into the run\n // listing below instead so the model re-issues a real label.\n const anyLabeled = childRuns.some(r => r.label !== undefined)\n index = labelMatch && !anyLabeled\n ? Number(labelMatch[1]) - 1\n : childRuns.findIndex(r => r.id === wanted)\n }\n const run = index >= 0 ? childRuns[index] : undefined\n if (!run) {\n return { outcome: { status: 'rejected', text: '', message: `Cannot resume: no child run matches \"${wanted}\". Child runs in this session:\\n${describeChildRuns(ctx.session)}` } }\n }\n const runLabel = run.label ?? `child-${index + 1}`\n if (run.status === 'running') {\n return { outcome: { status: 'rejected', text: '', message: `Cannot resume: ${runLabel} is still running. Only terminal children (aborted / error / completed) can be resumed.` } }\n }\n // Chain-aware: a resumed run may have zero own turns while its\n // resume lineage still holds the recoverable conversation.\n const chain = resumeChainRunIds(ctx.session.runs, run.id)\n if (!ctx.session.turns.some(t => t.runId !== undefined && chain.has(t.runId))) {\n return { outcome: { status: 'rejected', text: '', message: `Cannot resume: ${runLabel} has no persisted turns (it likely failed before producing anything). Spawn a fresh child with a full task instead.` } }\n }\n resumeRun = run\n resumeLabel = runLabel\n }\n\n const parentDepth = ctx.depth ?? 0\n const childDepth = parentDepth + 1\n\n // Reject before any await so the parent-level LLM sees the failure\n // immediately. The concurrency cap is `runSpawnTask`'s: a top-level call\n // waits for a slot there instead of being refused.\n if (childDepth > maxDepth) {\n return { outcome: { status: 'rejected', text: '', message: `Cannot spawn: maxDepth=${maxDepth} reached (parent depth=${parentDepth}). Deepen the cap with createSpawnTool({ maxDepth }).` } }\n }\n\n // Signal short-circuit: a pre-aborted parent means the child would\n // immediately no-op on its first `signal.aborted` check. Skip the\n // agent/handle/session setup cost entirely.\n if (ctx.signal.aborted) {\n return { outcome: { status: 'aborted', text: '', message: `[sub-agent pre-aborted] Parent signal was already aborted: skipped \"${task.slice(0, 80)}\"` } }\n }\n\n const reattach = reattachableChildRun(ctx)\n return { task, systemOverride, subagentDef, childProvider, childModel, announcedModel, resumeRun, resumeLabel, childDepth, ...(reattach ? { reattach } : {}) }\n}\n\n/**\n * The child run of this very spawn call (same parent run, same call id: the\n * parent's step key of the call), left by a process that died before the\n * parent saved the call's result: still running then (resumable), or\n * already ended. Only a checkpoint run has one.\n */\nfunction reattachableChildRun(ctx: ToolContext): SessionRun | undefined {\n if (!ctx.durable?.checkpoint || !ctx.session || ctx.runId === undefined || ctx.callId === undefined)\n return undefined\n return ctx.session.runs.find(r => r.parentRunId === ctx.runId && r.parentCallId === ctx.callId)\n}\n\n/**\n * {@link SpawnTool.runTask}: validate, take a slot (waiting for one at the\n * cap), run the child, release the slot.\n */\nexport async function runSpawnTask(env: SpawnToolEnv, input: SpawnTaskInput, ctx: ToolContext): Promise<SpawnTaskOutcome> {\n const { state, maxConcurrent } = env\n const localChildren = state.children\n const resolved = resolveSpawnRequest(env, input, ctx)\n if ('outcome' in resolved)\n return resolved.outcome\n const { task, childDepth } = resolved\n // Ended before the process died: nothing runs, no slot is taken.\n if (resolved.reattach && resolved.reattach.resumable !== true && ctx.session)\n return finishedChildOutcome(env, ctx, ctx.session, resolved, resolved.reattach)\n\n if (state.activeCount < maxConcurrent) {\n state.activeCount++\n }\n else if (childDepth > 1) {\n // A subagent's spawn is refused at the cap rather than waiting: the\n // slots are shared with its parent's children, and if every one of\n // them waited on a grandchild, none could ever finish.\n return { status: 'rejected', text: '', message: `Cannot spawn: ${state.activeCount}/${maxConcurrent} sub-agents already running, and a sub-agent's spawns don't wait for a slot. Start them one after another (each after the previous one finished), or do the work yourself.` }\n }\n else {\n // The top-level agent holds no slot, so it can wait for one.\n const aborted = await waitForSlot(env, ctx, task, childDepth)\n if (aborted)\n return aborted\n // Stopped after the slot was handed over: give it on, start nothing.\n if (ctx.signal.aborted) {\n releaseSlot(state)\n return { status: 'aborted', text: '', message: skippedWhileWaiting(task) }\n }\n }\n\n // Reserve the id SYNCHRONOUSLY once the slot is ours — no `await` in\n // between, so the session-scoped child counter (see `reserveChildLabel`)\n // sees a consistent `session.runs` snapshot between concurrent spawns\n // sharing this session. (The slot itself is taken above without an\n // `await` either, so two parallel spawns can't both pass the cap.)\n const id = resolved.reattach?.label\n ?? (ctx.session ? reserveChildLabel(ctx.session) : `child-${++state.counter}`)\n const child: ChildAgent = { id, task, startedAt: Date.now(), depth: childDepth }\n localChildren.set(id, child)\n\n const run: SpawnRunState = {\n destroyError: undefined,\n childRunStatus: 'completed',\n finalStats: undefined,\n result: '',\n responseText: '',\n // Bubble child hook events to parent if requested. Wired BEFORE\n // `agent.run()` so even the very first `turn:before` is observable.\n unbubble: undefined,\n reportedStats: undefined,\n deadlineExceeded: false,\n }\n\n try {\n return await runReservedChild(env, ctx, resolved, child, run)\n }\n finally {\n run.unbubble?.()\n releaseSlot(state)\n localChildren.delete(id)\n }\n}\n\n/** A finished child's slot goes to the first waiting call, else back to the pool. */\nfunction releaseSlot(state: SpawnInstanceState): void {\n const next = state.waiters.shift()\n if (next)\n next()\n else\n state.activeCount--\n}\n\n/**\n * Wait for a slot handed over by `releaseSlot`, announcing the wait\n * (`spawn:queued`). Resolves `null` once the slot is this call's, or the\n * aborted outcome when the run is stopped first (no child starts).\n */\nasync function waitForSlot(env: SpawnToolEnv, ctx: ToolContext, task: string, depth: number): Promise<SpawnTaskOutcome | null> {\n const { state, maxConcurrent } = env\n let granted = false\n let resolveTurn: (outcome: SpawnTaskOutcome | null) => void = () => {}\n const turn = new Promise<SpawnTaskOutcome | null>((resolve) => {\n resolveTurn = resolve\n })\n /** Leave the queue; `false` when the slot was already handed to this call. */\n const leave = (): boolean => {\n const at = state.waiters.indexOf(waiter)\n if (at >= 0)\n state.waiters.splice(at, 1)\n ctx.signal.removeEventListener('abort', onAbort)\n return at >= 0\n }\n function waiter(): void {\n granted = true\n ctx.signal.removeEventListener('abort', onAbort)\n resolveTurn(null)\n }\n function onAbort(): void {\n if (leave())\n resolveTurn({ status: 'aborted', text: '', message: skippedWhileWaiting(task) })\n }\n state.waiters.push(waiter)\n ctx.signal.addEventListener('abort', onAbort, { once: true })\n try {\n await ctx.hooks.callHook('spawn:queued', {\n task,\n ...(ctx.callId ? { callId: ctx.callId } : {}),\n depth,\n waitingFor: { active: state.activeCount, max: maxConcurrent },\n })\n }\n catch (err) {\n // A failing listener fails the call, as `spawn:before` would; the call's\n // place in the queue (or the slot it was already handed) is given back.\n if (!leave() && granted)\n releaseSlot(state)\n throw err\n }\n return turn\n}\n\nfunction skippedWhileWaiting(task: string): string {\n return `[sub-agent aborted] The run stopped while this spawn waited for a slot: skipped \"${task.slice(0, 80)}\"`\n}\n","/**\n * Spawn tool — create sub-agents from a parent agent.\n *\n * A configurable factory that reads the parent's preset-y fields from ToolContext.\n *\n * Usage:\n * ```ts\n * import { createSpawnTool } from 'zidane'\n * import { definePreset, basicTools } from 'zidane/presets'\n *\n * const preset = definePreset({\n * name: 'orchestrator',\n * tools: { ...basicTools, spawn: createSpawnTool({ maxConcurrent: 5 }) },\n * })\n * ```\n *\n * Each `createSpawnTool()` call returns a fresh instance with its own\n * concurrency counter, depth cap, and child-stats accumulator — never\n * share an instance across unrelated parent agents.\n *\n * Key guarantees:\n * - **Depth-capped** to `maxDepth` (default 3) to prevent infinite recursion.\n * - **Concurrency slot is reserved synchronously** before any `await`, so a\n * parent running tools in parallel cannot exceed `maxConcurrent`. The\n * top-level agent's calls past the cap wait for a slot, first come first\n * served (`spawn:queued` announces each); a subagent's are refused, since\n * waiting on slots its own ancestors hold could never end.\n * - **A refused call fails** (the tool throws): no child ran.\n * - **Pre-aborted signals short-circuit** without paying agent-spawn cost.\n * - **Abort / timeout / error are surfaced distinctly** in the returned text\n * and via `ChildRunStats.status` on `spawn:complete`.\n * - **`agent.destroy()` errors never mask the original run error** (captured\n * and emitted via `spawn:error` but the primary error wins).\n * - **Child hooks bubble** to the parent as `child:*` events when\n * `forwardHooks` is set (default `true`).\n * - **Persistence** via `persist: true` — child runs get appended to the\n * parent's session with `parentRunId` wired, so the run tree is\n * reconstructible from a stored `SessionData`.\n */\n\nimport type { Preset } from '../presets'\nimport type { AgentStats, ChildRunStats } from '../types'\nimport type { SpawnModelEntry } from './model-search'\nimport type { SpawnInstanceState, SpawnToolEnv } from './spawn-run'\nimport type { DurableToolDef, ToolContext, ToolDef } from './types'\nimport { isSpawnTool } from './is-spawn-tool'\nimport { toolPrompts } from './prompts'\nimport { loadAgentModule } from './spawn-child'\nimport { buildModelFieldDescription, buildSubagentTypeDescription } from './spawn-helpers'\nimport { SPAWN_OUTPUT_SCHEMA, spawnStructuredResult } from './spawn-result'\n\nimport { runSpawnTask } from './spawn-run'\n\nexport { isSpawnTool } from './is-spawn-tool'\n\nexport { reserveChildLabel } from './spawn-helpers'\nexport { SPAWN_OUTPUT_SCHEMA, spawnStructuredResult } from './spawn-result'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A running child agent started by the spawn tool. */\nexport interface ChildAgent {\n /** Child label, such as `child-1`. */\n id: string\n /** Task the child was given. */\n task: string\n /** Start time as epoch milliseconds. */\n startedAt: number\n /** Subagent depth — 1 for a direct child of a top-level agent. */\n depth: number\n}\n\n/** Read-only view of the children a spawn tool instance has run. */\nexport interface SpawnToolState {\n /** Currently running children. */\n readonly children: ReadonlyMap<string, ChildAgent>\n /**\n * Cumulative stats across every completed direct child of this spawn-tool\n * instance (returns a copy). Each child's contribution is the cumulative\n * `AgentStats` returned by its `agent.run()` — so\n * `totalIn`/`totalOut`/`totalCacheRead`/`totalCacheCreation` cover the\n * entire subtree (children + grandchildren + …), while `turns` and\n * `elapsed` stay parent-loop-only per child and are summed across direct\n * children. `elapsed` over-counts when children ran in parallel.\n *\n * Lives across multiple parent runs that share this instance.\n */\n readonly totalChildStats: Readonly<AgentStats>\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/** Options for {@link createSpawnTool}. */\nexport interface SpawnToolOptions {\n /**\n * Maximum concurrent sub-agents (default: 3); `Infinity` removes the cap.\n * Past it, the top-level agent's spawn calls wait for a slot; a subagent's\n * are refused. One turn still runs at most `behavior.maxConcurrentTools`\n * tool calls at once (default 10), spawns included.\n */\n maxConcurrent?: number\n /**\n * Maximum subagent depth. 0 disables spawning entirely; 1 allows top-level\n * spawns but forbids grandchildren; 3 (default) allows three levels of\n * recursion — enough for most orchestration patterns, a sharp ceiling\n * against runaway loops.\n */\n maxDepth?: number\n /**\n * Child model override. When unset, the child inherits the parent run's\n * resolved model (`ToolContext.model`), falling back to\n * `provider.meta.defaultModel` only when the parent didn't expose one.\n */\n model?: string\n /**\n * Catalog of models children may run on. When set, the spawn input\n * schema gains an optional `model` field so the CALLING MODEL can\n * cost-tier its delegation (mechanical / high-volume work on cheaper\n * models, synthesis on the primary). Reuses the chat layer's\n * `ModelInfo` objects verbatim — real `cost` pricing and context\n * windows, no separate catalog to maintain — paired with the runtime\n * `Provider.name` that serves each model (see {@link SpawnModelEntry}).\n *\n * - ≤ {@link EMBEDDED_CATALOG_MAX} entries → the list is embedded in\n * the field description (id · price · context) so no extra round-trip\n * and no system-prompt bloat.\n * - Larger → the description points at the `model_search` tool\n * (register {@link createModelSearchTool} with the same entries).\n * - Model-supplied ids are validated: unknown ids are rejected with\n * the closest matches so the model can self-correct; ids served by\n * a provider not present in the run are rejected with the reason.\n *\n * Default: unset — no `model` field, children always inherit.\n */\n models?: readonly SpawnModelEntry[]\n /** Child system prompt override. Per-spawn `input.system` takes precedence. */\n system?: string\n /** Child thinking level. */\n thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'\n /** Preset override for children. Shallow-merged over the parent's preset (parent fields still win for anything left unset). */\n preset?: Preset\n /**\n * Per-child timeout, in milliseconds. When the child exceeds it the spawn\n * tool returns a timeout marker, fires `spawn:error`, and destroys the\n * child agent. Default: none.\n */\n timeoutMs?: number\n /**\n * When `true` and the parent has a session, the child reuses the parent's\n * session — child turns are appended with the child's own `runId`, and the\n * resulting `SessionRun` carries `parentRunId` so the tree is\n * reconstructible. Default: `false` (child is in-memory only).\n *\n * **Read-state isolation.** Sharing the session also shares the\n * `read_file` / `requireReadBeforeEdit` tracking map (it's keyed\n * by `Session`). With `persist: false` the child gets no session,\n * so reads inside the subagent populate nothing the parent can see —\n * a follow-up `edit` / `multi_edit` in the parent will trip the\n * gate with `\"has not been read\"` even though the model just\n * read the file in the child. Use {@link shareReadState} when\n * you want the parent's gate to honor the child's reads WITHOUT\n * also persisting child turns to the parent's session.\n */\n persist?: boolean\n /**\n * Forward the parent's read-state map to the child agent so the\n * `requireReadBeforeEdit` gate and `dedupReads` cache see reads\n * across the parent/child boundary. Orthogonal to {@link persist} —\n * use this when you want shared read tracking without sharing the\n * session's turn history. Default: `false`.\n *\n * Has no effect when the parent has no read-state to share (no\n * session and no explicit `readState` on the parent agent's\n * options). Implementation: passes the parent's resolved\n * `ReadStateMap` to the child via `AgentOptions.readState`, which\n * tools resolve via `ctx.readState ?? getReadState(ctx.session)`.\n */\n shareReadState?: boolean\n /**\n * Run children on the parent's execution handle instead of letting each\n * child mint (and destroy) its own. Default: `false` — an isolated handle\n * per child.\n *\n * Why you'd turn it on: for a remote context (sandbox / container), a child\n * calling `execution.spawn()` is a real allocation. Under a durable runtime\n * that allocation is NOT a recorded side effect, so a replayed attempt\n * mints a FRESH sandbox and orphans the first — one leak per child per\n * attempt. It also removes a per-child spawn/destroy round-trip on the hot\n * path.\n *\n * The trade: children see the parent's filesystem and background-task\n * namespace directly, so an isolated scratch space per child is gone. The\n * child never destroys a shared handle (that's `AgentOptions.handle`\n * semantics — host owns the lifecycle), and teardown skips background-task\n * reassignment entirely since there is no child handle to promote from.\n *\n * No effect when the parent has no handle (`ctx.handle` absent).\n */\n shareHandle?: boolean\n /**\n * Forward a curated subset of child hook events (`stream:*`, `tool:*`,\n * `turn:after`) onto the parent's hook bus as `child:*` events. Default:\n * `true`. Grandchildren bubble through their child transparently.\n */\n forwardHooks?: boolean\n /** Called when a child agent starts. */\n onSpawn?: (child: ChildAgent) => void\n /** Called when a child agent completes (success, abort, timeout, or error). */\n onComplete?: (child: ChildAgent, stats: AgentStats, status: NonNullable<ChildRunStats['status']>) => void\n /**\n * Named subagent presets the model can select via the `subagent_type`\n * input field. Mirrors the Claude Code SDK's surface — models trained\n * on it routinely emit `subagent_type: 'Explore' | 'Plan' |\n * 'Verification' | 'general-purpose'`, and without a registry the\n * field is silently dropped, so hosts wanting type-specialized\n * subagents have to invent their own dispatch layer.\n *\n * Each entry overlays the base spawn config for that particular\n * dispatch. Per-call `input.system` still wins over `subagents[type].system`\n * so the model can always specialize further.\n *\n * When the registry is non-empty:\n * - `subagent_type` appears in the spawn input schema as a `string`\n * enum of the registered keys (plus the always-available\n * `'general-purpose'` fallback).\n * - Models that pass an unregistered type are routed to\n * `'general-purpose'` (no error — degrade gracefully so trained\n * models keep working even on hosts that haven't wired every\n * type Claude Code uses).\n *\n * When the registry is empty / unset, the field is omitted entirely.\n *\n * Default: `undefined` (no subagent types; `subagent_type` schema\n * field hidden).\n */\n subagents?: SubagentRegistry\n}\n\n/**\n * Per-type subagent override applied when the model calls\n * `spawn({ subagent_type: '…' })`. All fields are optional; absent\n * fields fall back to the parent's resolved configuration (see\n * {@link SpawnToolOptions} comments for the merge order).\n */\nexport interface SubagentDef {\n /**\n * System prompt override for this subagent type. Per-call\n * `input.system` still wins — model-supplied specialization beats\n * preset defaults.\n */\n system?: string\n /**\n * Default model for this subagent type (e.g. an Explore preset pinned\n * to a fast, cheap model). Precedence: per-call `input.model` >\n * this > `SpawnToolOptions.model` > inherit the parent run's model.\n * When a catalog is configured and lists this id, the child also\n * routes to the provider that serves it.\n */\n model?: string\n /**\n * Default thinking level for this subagent type. Precedence: this >\n * `SpawnToolOptions.thinking` > provider default.\n */\n thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'\n /**\n * Restrict the child agent's tool registry to this list of canonical\n * tool names. Operates as a filter over the parent's tools (the\n * parent's selection is the upper bound — a subagent can never gain\n * tools the parent doesn't have). When unset, the child inherits the\n * parent's full tool list.\n *\n * Tool names are canonical (registry-key) not wire/alias names — the\n * filter runs before aliases are applied. Names that don't match a\n * parent tool are silently dropped (matches the lenient behaviour of\n * `enabledTools` on MCP configs).\n *\n * MCP tools (namespaced `mcp_<server>_<tool>` names) can be listed too:\n * they inherit through the parent's shared live connection, filtered to\n * exactly the listed names — see `inheritedMcpForSubagent`. An explicit\n * list (or `readonly`) with no MCP names gives the child no MCP tools.\n */\n tools?: readonly string[]\n /**\n * Mark this subagent as read-only — equivalent to listing only\n * obviously-non-mutating tools (`read_file`, `grep`, `glob`,\n * `list_files`) in {@link SubagentDef.tools}. Convenience for the\n * common \"Plan\" / \"Explore\" subagent shape Claude Code ships.\n * Read-only children inherit no MCP tools (unknown mutation risk).\n *\n * When both `readonly: true` and `tools` are set, `tools` wins\n * (explicit beats implicit).\n */\n readonly?: boolean\n /**\n * Short description rendered into the spawn tool's schema (the\n * `subagent_type` field's description) so the model can pick a type\n * that matches the task without round-tripping through docs.\n */\n description?: string\n}\n\n/**\n * Map of subagent-type key → preset. Keys are case-sensitive and\n * appear verbatim in the spawn input schema's enum so the model emits\n * them with the same casing. Common conventions: `'Explore'`,\n * `'Plan'`, `'Verification'`, `'general-purpose'` (Claude Code SDK's\n * built-in set).\n */\nexport type SubagentRegistry = Record<string, SubagentDef>\n\n/**\n * A subagent def carried by an extension's `registerSubagent` — same as\n * {@link SubagentDef} but carrying its own dispatch `name` (the registry\n * key). Self-describing so the def survives the trip from extension\n * `setup` through the merged {@link ExtensionRegistry} to the host's\n * {@link SpawnTool.withSubagents} merge.\n */\nexport interface ExtensionSubagentDef extends SubagentDef {\n /** Registry key the model emits as `subagent_type`. */\n name: string\n}\n\n/**\n * Editing function for an existing subagent. Receives the current def\n * (host- or extension-provided; `undefined` when the name is unknown)\n * and returns the replacement — or `undefined` to delete the entry.\n */\nexport type SubagentOverride = (def: SubagentDef | undefined) => SubagentDef | undefined\n\n/**\n * The object {@link createSpawnTool} returns: a {@link ToolDef} that also\n * exposes live {@link SpawnToolState} plus {@link SpawnTool.withSubagents}\n * for rebuilding the tool against a merged subagent registry (the seam the\n * extension system uses to add / edit spawnable subagents).\n */\nexport interface SpawnTool extends ToolDef, SpawnToolState {\n /**\n * Return a FRESH spawn tool whose `subagent_type` enum is recomputed\n * from the base registry merged with `extra` (adds), then `overrides`\n * (edits, applied last — an override returning `undefined` deletes the\n * entry). Precedence: host base < adds < overrides. The rebuilt\n * instance shares this one's concurrency / stats / child-label state.\n */\n withSubagents: (extra: SubagentRegistry, overrides?: Record<string, SubagentOverride>) => SpawnTool\n /**\n * Return a FRESH spawn tool with the given model catalog (the `model`\n * schema field + validation — see {@link SpawnToolOptions.models}),\n * sharing this instance's counters, stats, and concurrency slots.\n * Hosts call it at agent-build time when the available models are only\n * known then (e.g. the TUI's provider chain).\n */\n withModels: (models: readonly SpawnModelEntry[]) => SpawnTool\n /**\n * Return a FRESH spawn tool with the same options but its OWN state:\n * concurrency slots, cumulative stats, child-label counter. Hosts that\n * build many agents from one shared preset (the daemon / GUI chat host,\n * one agent per session) call it per agent build — otherwise every\n * session shares one slot pool and one session's fan-out queues behind\n * (or, for a subagent's spawns, is refused by) another session's children.\n * `options.maxConcurrent` replaces the copy's cap, for a host that takes\n * it from a setting.\n */\n isolated: (options?: Pick<SpawnToolOptions, 'maxConcurrent'>) => SpawnTool\n /**\n * Host-facing structured variant of `execute` — same child lifecycle\n * (model routing, hook bubbling, session persistence, concurrency\n * slots), but returns a {@link SpawnTaskOutcome} instead of the\n * model-facing string, so hosts (e.g. command `ctx.spawnAgents`) can\n * branch on `status` and read the bare `text` without string parsing.\n * `execute` is a thin formatter over this.\n */\n runTask: (input: SpawnTaskInput, ctx: ToolContext) => Promise<SpawnTaskOutcome>\n /**\n * The tool's simultaneous-children cap (`createSpawnTool({ maxConcurrent })`,\n * default 3; `Infinity` when uncapped). Hosts driving {@link runTask}\n * directly size their worker pools to this, so an admitted task starts at\n * once instead of queuing.\n */\n readonly maxConcurrent: number\n}\n\n/**\n * Input accepted by {@link SpawnTool.runTask} — the typed mirror of the\n * `execute` schema. Fields beyond `task` only take effect when the tool\n * was built with the matching capability (a subagent registry for\n * `subagent_type`, a model catalog for `model`).\n */\nexport interface SpawnTaskInput {\n /** Task prompt for the child agent. */\n task: string\n /** System prompt override for the child. Wins over a subagent preset's system. */\n system?: string\n /** Registered subagent type. Unknown types degrade to `general-purpose`. */\n subagent_type?: string\n /** Catalog model id to pin the child to. Unknown ids reject the task. */\n model?: string\n /**\n * Child label (`child-2`) or raw run id of a prior stopped/failed child\n * to resume. The new child is seeded with that run's persisted turns and\n * `task` becomes the continuation instruction. Requires the tool to be\n * built with `persist: true` and the parent to have a session.\n */\n resume?: string\n}\n\n/**\n * Structured outcome of one spawned child run — the host-facing shape\n * behind {@link SpawnTool.runTask}. `message` is the exact model-facing\n * string `execute` returns (header + stats + response), while `text` is\n * the child's bare final response so hosts don't have to parse the\n * formatted message.\n */\nexport interface SpawnTaskOutcome {\n /** Child label (`child-1`, …). Absent when no child slot was reserved (rejections, pre-aborted parent). */\n id?: string\n /**\n * Terminal status. `'rejected'` = refused before any child ran\n * (unknown model, depth/concurrency cap, unavailable provider).\n */\n status: 'completed' | 'aborted' | 'timeout' | 'error' | 'rejected'\n /** The child's final assistant text. Empty unless `status === 'completed'`. */\n text: string\n /** Model-facing formatted result — exactly what `execute` returns. */\n message: string\n /** Cumulative child stats (subtree-wide). Absent on rejection. */\n stats?: AgentStats\n}\n\n/**\n * Give a preset its own spawn tool state (see {@link SpawnTool.isolated}).\n * Agent profiles are module constants holding ONE spawn instance, so a host\n * that builds agents from them repeatedly (one per session in the chat host;\n * one per activation / session switch in the TUI) must isolate at each\n * build, or every agent shares one slot pool and child-label counter.\n * Apply AFTER extension composition: its `withSubagents` rebuild keeps the\n * shared state.\n * @param preset - Preset that may hold a spawn tool under `tools.spawn`. Returned unchanged when it has none.\n * @param options - The isolated copy's cap (`maxConcurrent`, `Infinity` for none). Omitted, it keeps the preset's.\n */\nexport function withIsolatedSpawnTool<P extends { tools?: Record<string, ToolDef> }>(preset: P, options?: Pick<SpawnToolOptions, 'maxConcurrent'>): P {\n const spawn = preset.tools?.spawn\n return spawn && isSpawnTool(spawn) ? { ...preset, tools: { ...preset.tools, spawn: spawn.isolated(options) } } : preset\n}\n\nfunction createSpawnState(): SpawnInstanceState {\n return {\n children: new Map<string, ChildAgent>(),\n stats: { totalIn: 0, totalOut: 0, totalCacheRead: 0, totalCacheCreation: 0, turns: 0, elapsed: 0 },\n counter: 0,\n activeCount: 0,\n waiters: [],\n }\n}\n\n/**\n * Create a configured spawn tool.\n *\n * State (`children`, `totalChildStats`, counters, active count) is scoped to\n * the returned instance. Multiple parent agents using the same instance will\n * share counters + stats + concurrency slots — call `createSpawnTool()` per\n * agent (or use the stateless default `spawn`) to keep them isolated.\n * @param options - Limits, model catalog, subagent registry and child defaults. See {@link SpawnToolOptions}.\n * @example\n * ```ts\n * import { createAgent } from 'zidane'\n * import { anthropic } from 'zidane/providers'\n * import { createSpawnTool } from 'zidane/tools'\n *\n * const spawn = createSpawnTool({ maxConcurrent: 2, maxDepth: 1 })\n * const agent = createAgent({\n * provider: anthropic({ apiKey: 'sk-ant-...' }),\n * tools: { spawn },\n * })\n * ```\n */\nexport function createSpawnTool(options: SpawnToolOptions = {}): SpawnTool {\n // A child's first run shouldn't wait on loading the agent module.\n void loadAgentModule().catch(() => {})\n return buildSpawnTool(options, createSpawnState())\n}\n\n/**\n * Build a spawn-tool instance bound to `state`. Factored out of\n * {@link createSpawnTool} so {@link SpawnTool.withSubagents} can rebuild the\n * tool — recomputing the `subagent_type` enum from a merged registry —\n * while threading the SAME `state` so child counters / stats survive.\n */\nfunction buildSpawnTool(options: SpawnToolOptions, state: SpawnInstanceState): SpawnTool {\n const localChildren = state.children\n const localStats = state.stats\n const maxConcurrent = options.maxConcurrent ?? 3\n const maxDepth = options.maxDepth ?? 3\n const forwardHooks = options.forwardHooks ?? true\n\n // Pre-compute the subagent_type schema piece once. Including the\n // enum keys (plus the canonical `general-purpose` fallback) saves\n // the host from re-typing them in their preset description. Empty\n // registry — or one passed as `{}` with no entries — drops the field\n // entirely. We don't surface\n // `subagent_type` with only `general-purpose` in the enum (a\n // single-value enum is noise to the model with no decision to make).\n const subagentRegistry = options.subagents\n const hasSubagentEntries = !!subagentRegistry && Object.keys(subagentRegistry).length > 0\n const subagentTypeKeys = hasSubagentEntries\n ? [...new Set([...Object.keys(subagentRegistry!), 'general-purpose'])]\n : []\n const subagentTypeProperty = subagentTypeKeys.length > 0\n ? {\n subagent_type: {\n type: 'string' as const,\n enum: subagentTypeKeys,\n description: buildSubagentTypeDescription(subagentRegistry!),\n },\n }\n : {}\n\n // Model catalog → optional `model` schema field. Empty/absent catalog\n // drops the field entirely (children always inherit the parent's model).\n // Small catalogs embed the list in\n // the field description; large ones defer to `model_search` so the\n // schema doesn't balloon.\n const modelCatalog = options.models && options.models.length > 0 ? options.models : undefined\n const modelProperty = modelCatalog\n ? {\n model: {\n type: 'string' as const,\n description: buildModelFieldDescription(modelCatalog),\n },\n }\n : {}\n\n // Resume field — only surfaced when the tool persists child turns into\n // the parent's session (`persist: true`); without that there is nothing\n // to seed a continuation from.\n const resumeProperty = options.persist\n ? {\n resume: {\n type: 'string' as const,\n description: 'Child label of a prior stopped/failed sub-agent to resume (e.g. \"child-2\", as reported in its result header). The new run is seeded with that child\\'s full prior conversation; `task` becomes the continuation instruction instead of a fresh task. Only terminal children (aborted / timed out / errored / completed) can be resumed.',\n },\n }\n : {}\n\n const env: SpawnToolEnv = { options, state, maxConcurrent, maxDepth, forwardHooks, subagentRegistry, modelCatalog }\n const tool: SpawnTool & DurableToolDef = {\n maxConcurrent,\n get children() { return localChildren },\n get totalChildStats() { return { ...localStats } },\n\n // Rebuild against a merged subagent registry. Precedence:\n // host base (`options.subagents`) < `extra` (adds) < `overrides`.\n // Overrides run last so an extension can edit a host/extension def\n // by name (or delete it by returning `undefined`). The rebuilt\n // instance reuses the closed-over `options` and the SAME `state`,\n // so concurrency slots, cumulative stats, and child-label counters\n // carry across the rebuild.\n withSubagents(extra, overrides) {\n // Null prototype: a def named `toString` or `constructor` must never\n // see an inherited Object.prototype member as its current value.\n const merged: SubagentRegistry = Object.assign(Object.create(null), options.subagents, extra)\n if (overrides) {\n for (const [name, fn] of Object.entries(overrides)) {\n const next = fn(Object.hasOwn(merged, name) ? merged[name] : undefined)\n if (next === undefined)\n delete merged[name]\n else\n merged[name] = next\n }\n }\n return buildSpawnTool({ ...options, subagents: merged }, state)\n },\n\n // Rebuild with a model catalog (the `model` schema field + validation).\n // Same shared-state contract as `withSubagents`: concurrency slots,\n // cumulative stats, and child-label counters carry across the rebuild.\n // Hosts call this at agent-build time when the available models are\n // only known then (e.g. the TUI's provider chain).\n withModels(models) {\n return buildSpawnTool({ ...options, models }, state)\n },\n\n isolated(overrides) {\n const maxConcurrent = overrides?.maxConcurrent\n return buildSpawnTool(maxConcurrent === undefined ? options : { ...options, maxConcurrent }, createSpawnState())\n },\n\n // Sub-agents fan out by design — multiple spawn calls in a single\n // batch run in parallel (each child has its own context window,\n // its own retry budget, and its own session linkage). The internal\n // `maxConcurrent` here is the spawn-tool-level cap on simultaneous\n // children; `behavior.maxConcurrentTools` is the loop-level cap on\n // all concurrent tools regardless of kind.\n isConcurrencySafe: true,\n\n // Declares \"my execute runs a whole agent loop\". A replay-mode run reads\n // this to keep the tool OUT of a step: the child's own model/tool calls\n // are steps themselves, and nesting those inside one step is illegal. See\n // `DurableToolDef.runsNestedAgent`.\n runsNestedAgent: true,\n\n spec: {\n name: 'spawn',\n description: toolPrompts.spawn.core\n + (modelCatalog ? toolPrompts.spawn.modelTiering : '')\n + (options.persist ? toolPrompts.spawn.resume : ''),\n inputSchema: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'The task prompt for the sub-agent. Be specific about what you want it to accomplish.',\n },\n system: {\n type: 'string',\n description: 'Optional system prompt override for this specific sub-agent. REPLACES the entire inherited system prompt: identity, doctrine, and environment info (cwd, platform, date) are all lost. Prefer omitting this and putting specialization in `task`; if you do override, restate the working directory and any constraints the child must keep.',\n },\n ...subagentTypeProperty,\n ...modelProperty,\n ...resumeProperty,\n },\n required: ['task'],\n },\n outputSchema: SPAWN_OUTPUT_SCHEMA,\n },\n\n async execute(input: Record<string, unknown>, ctx: ToolContext): Promise<string> {\n // Schema-validated model input → typed task input: the one cast at the\n // LLM boundary. Via the named const (not `this`) so a destructured\n // `execute` keeps working.\n const outcome = await tool.runTask(input as unknown as SpawnTaskInput, ctx)\n // A refused call is a failed tool call: no child ran.\n if (outcome.status === 'rejected')\n throw new Error(outcome.message)\n // For scripts (codemode): the report and its numbers, not the formatted text.\n ctx.reportStructured?.(spawnStructuredResult(outcome))\n return outcome.message\n },\n\n async runTask(input: SpawnTaskInput, ctx: ToolContext): Promise<SpawnTaskOutcome> {\n return runSpawnTask(env, input, ctx)\n },\n }\n return tool\n}\n","/**\n * `record_artifact` — explicitly record something this session produced\n * (a pull request, branch, commit, file, deployment, issue…) so it shows\n * up in the artifacts rail and on the session.\n *\n * The built-in detectors (`extensions/builtin-artifact-kinds.ts`) cover\n * `gh pr create`, `git commit` and branch creation, but can't see output\n * that never reaches a tool result (a background-shell PR, an opaque MCP\n * shape, a deployment URL) — and files are deliberately never detected:\n * a source edit is not a deliverable. This tool is how the model marks\n * the outputs that ARE deliverables. The description below is the\n * model's only guidance on that judgment, so it carries the examples.\n *\n * The tool itself has no store access and returns plain text; the\n * `recordArtifactKind` detector in the artifacts preset reads the INPUT\n * and emits it through the same reserved metadata namespace every other\n * producer uses, so validation, bounds, and the `artifact:recorded` hook\n * are identical.\n */\n\nimport type { ToolDef } from './types'\nimport { ARTIFACT_KIND_PATTERN, ARTIFACT_LABEL_MAX_CHARS, ARTIFACT_URI_MAX_CHARS } from '../session/artifacts'\nimport { ToolFailure } from './failure'\nimport { toolPrompts } from './prompts'\n\n/** Name of the {@link recordArtifact} tool. */\nexport const RECORD_ARTIFACT_TOOL = 'record_artifact'\n\n/**\n * The `record_artifact` tool. Records a pull request, branch, commit, file or custom artifact on the session.\n */\nexport const recordArtifact: ToolDef = {\n isConcurrencySafe: true,\n spec: {\n name: RECORD_ARTIFACT_TOOL,\n description: toolPrompts.record_artifact,\n inputSchema: {\n type: 'object',\n properties: {\n kind: {\n type: 'string',\n description: 'Artifact kind: `pull_request`, `branch`, `commit`, `file` (a deliverable file, not a source edit), or a custom kind such as `deployment`, `issue`, `release` (`[\\\\w.:-]+`).',\n },\n uri: {\n type: 'string',\n description: 'Canonical locator: a URL (`https://github.com/o/r/pull/12`), `file:<path>` (relative paths resolve against the working directory), `git:commit:<sha>`, `git:branch:<name>`.',\n },\n label: { type: 'string', description: 'Short human label. Defaults to the uri.' },\n meta: { type: 'object', description: 'Optional small JSON payload (≤ 16 KB) — e.g. `{ \"number\": 12, \"state\": \"open\" }`.' },\n },\n required: ['kind', 'uri'],\n additionalProperties: false,\n },\n },\n async execute(input): Promise<string> {\n const kind = typeof input.kind === 'string' ? input.kind.trim() : ''\n const uri = typeof input.uri === 'string' ? input.uri.trim() : ''\n if (!kind || !ARTIFACT_KIND_PATTERN.test(kind))\n throw new ToolFailure(`record_artifact error: kind must match [\\\\w.:-]+ (got ${JSON.stringify(input.kind)}).`)\n if (!uri)\n throw new ToolFailure('record_artifact error: uri is required.')\n if (uri.length > ARTIFACT_URI_MAX_CHARS)\n throw new ToolFailure(`record_artifact error: uri exceeds ${ARTIFACT_URI_MAX_CHARS} characters.`)\n const label = typeof input.label === 'string' && input.label.trim() ? input.label.trim() : uri\n const clipped = label.length > ARTIFACT_LABEL_MAX_CHARS ? `${label.slice(0, ARTIFACT_LABEL_MAX_CHARS - 1)}…` : label\n // Persistence happens in the detector that watches this tool; the text\n // is the model's receipt.\n return `Recorded ${kind} artifact: ${clipped}${clipped !== uri ? ` (${uri})` : ''}`\n },\n}\n","/**\n * Path-suggestion helper for file-not-found errors.\n *\n * When `read_file` / `edit` / `multi_edit` get a missing-file error, walk the\n * parent directory in the agent's execution context for files sharing the\n * same basename (sans extension) — common cause: model picked the wrong\n * extension (`.js` vs `.ts`, `.md` vs `.mdx`). Returns the closest sibling\n * filename so the tool can append `Did you mean X?` to the error.\n *\n * Mirrors `claude-code/utils/file.ts` `findSimilarFile`. Goes through the\n * `ExecutionContext.listFiles` seam so it works in process / docker / sandbox.\n */\n\nimport type { ExecutionContext, ExecutionHandle, ListFilesEntry } from '../contexts'\n\nfunction entryPath(entry: ListFilesEntry): string {\n return typeof entry === 'string' ? entry : entry.path\n}\n\n/**\n * Find a sibling file in the same directory sharing `path`'s basename\n * (sans extension), excluding the missing path itself. Returns just the\n * filename (not the full path) when found, otherwise `null`.\n *\n * Silent on errors — a missing parent directory or a `listFiles` failure\n * means we have no suggestion, not that anything is wrong.\n */\nexport async function findSimilarFile(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n): Promise<string | null> {\n const slash = path.lastIndexOf('/')\n const dir = slash === -1 ? '.' : (path.slice(0, slash) || '/')\n const target = slash === -1 ? path : path.slice(slash + 1)\n const dot = target.lastIndexOf('.')\n const targetBase = dot === -1 ? target : target.slice(0, dot)\n\n if (targetBase.length === 0)\n return null\n\n let entries: ListFilesEntry[]\n try {\n entries = await execution.listFiles(handle, dir)\n }\n catch {\n return null\n }\n\n for (const item of entries) {\n const entry = entryPath(item)\n if (entry === target)\n continue\n const entryDot = entry.lastIndexOf('.')\n const entryBase = entryDot === -1 ? entry : entry.slice(0, entryDot)\n if (entryBase === targetBase)\n return entry\n }\n return null\n}\n\n/**\n * Format a `Did you mean X?` suffix for missing-file errors. Returns an empty\n * string when no suggestion is available so callers can string-concat\n * unconditionally.\n */\nexport async function suggestionFor(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n): Promise<string> {\n const sibling = await findSimilarFile(execution, handle, path)\n return sibling ? ` Did you mean ${sibling}?` : ''\n}\n","/**\n * OOM guard POLICY for tools that must materialize a WHOLE file in\n * memory (`read_file`'s text path, `edit` / `multi_edit`'s\n * read-replace-write, grep's no-ripgrep fallback): the\n * `ExecutionContext.readFile` primitive has no partial read, so a\n * multi-GB target would be pulled into the host process wholesale —\n * well past JS string limits and into OOM territory — before any\n * output cap gets a chance to apply.\n *\n * The size CAPABILITY lives on the execution context\n * (`ExecutionContext.fileSize`, containment-aware), keeping the\n * tools-never-touch-host-fs boundary intact: this module only decides\n * what to do with the number. Contexts without the probe (remote\n * sandboxes where it would cost a round-trip per read) return\n * `undefined`/`null` and the read proceeds unguarded — their own\n * resource limits are the backstop, as documented on the interface.\n */\n\nimport type { ExecutionContext, ExecutionHandle } from '../contexts'\n\n/**\n * Refuse whole-file reads above this. Chosen well under engine string\n * limits (≈512MB–1GB) with headroom for the copies string processing\n * makes (line split, slice, join ≈ 2–3× peak).\n */\nexport const WHOLE_READ_CEILING_BYTES = 256 * 1024 * 1024\n\n/**\n * `null` when the read may proceed; a ready-to-return refusal message\n * otherwise. Same bracketed-message convention as the attachment caps.\n */\nexport async function wholeReadRefusal(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n what: 'read' | 'edit',\n): Promise<string | null> {\n const size = await execution.fileSize?.(handle, path) ?? null\n if (size === null || size <= WHOLE_READ_CEILING_BYTES)\n return null\n const mb = Math.round(size / 1024 / 1024)\n const capMb = WHOLE_READ_CEILING_BYTES / 1024 / 1024\n return what === 'read'\n ? `[file too large to ${what}: ${path} is ${mb}MB (whole-file ceiling ${capMb}MB). Use shell (head/tail/sed -n/grep) to inspect slices of it.]`\n : `[file too large to ${what}: ${path} is ${mb}MB (whole-file ceiling ${capMb}MB). Use shell (sed -i/awk) for targeted in-place changes.]`\n}\n","import type { ReadStateEntry, ReadStateMap } from './read-state'\nimport type { ToolContext, ToolDef } from './types'\nimport { isOutputExceededMessage } from '../contexts/output-cap'\nimport { errorMessage } from '../errors'\nimport { describeVia, resolveOldString, stripLineNumberPrefixes, styleReplacementForVia } from './edit-utils'\nimport { ToolFailure } from './failure'\nimport { suggestionFor } from './path-suggest'\nimport { toolPrompts } from './prompts'\nimport { hashContent, noteStaleRejection, readStateKey, resolveReadStateMap, staleRefusalHint } from './read-state'\nimport { pathArgError } from './validation'\nimport { wholeReadRefusal } from './whole-read-guard'\n\n/**\n * Surgical edit — replace `old_string` with `new_string` in a single file.\n *\n * Mirrors Claude Code's `Edit` semantics so models post-trained on Anthropic's\n * tool surface need no relearning. Fails clearly when `old_string` isn't unique\n * (unless `replace_all: true`) and when not found, with a nearest-match preview\n * so the model can recover without a separate `read_file` round-trip.\n */\n\nexport const edit: ToolDef = {\n spec: {\n name: 'edit',\n description: toolPrompts.edit,\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'File path (relative to the execution-context cwd, or absolute).' },\n old_string: { type: 'string', description: 'Exact substring to find.' },\n new_string: { type: 'string', description: 'Replacement substring.' },\n replace_all: { type: 'boolean', description: 'Replace every occurrence. Default: false.' },\n },\n required: ['path', 'old_string', 'new_string'],\n },\n },\n async execute({ path, old_string, new_string, replace_all }, ctx: ToolContext) {\n const target = path as string\n const find = old_string as string\n const replacement = new_string as string\n const replaceAll = replace_all === true\n\n const pathErr = pathArgError(target)\n if (pathErr) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`Edit error: ${pathErr}`)\n }\n\n if (find === replacement) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`Edit error: old_string and new_string are identical: nothing to change in ${target}. If the file already holds the new text, this edit is done; otherwise new_string must differ.`)\n }\n\n if (find.length === 0) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`Edit error: old_string is empty. Use write_file to create or fully overwrite a file.`)\n }\n\n const refusal = await wholeReadRefusal(ctx.execution, ctx.handle, target, 'edit')\n if (refusal) {\n ctx.reportOutcome?.('failed')\n return refusal\n }\n\n let original: string\n try {\n original = await ctx.execution.readFile(ctx.handle, target)\n }\n catch (err) {\n // Transport output-cap errors (docker probe-failure safety net)\n // must not masquerade as missing files — see read-file.ts.\n const message = errorMessage(err)\n if (isOutputExceededMessage(message)) {\n ctx.reportOutcome?.('failed')\n return `[file too large to edit: ${target}: ${message}. Use shell (sed -i/awk) for targeted in-place changes.]`\n }\n const hint = await suggestionFor(ctx.execution, ctx.handle, target)\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`Edit error: file not found: ${target}.${hint}`)\n }\n\n // Read-before-edit guard. When `behavior.requireReadBeforeEdit` is on\n // and a read-state map is available (session-keyed or forwarded via\n // `ctx.readState` from a spawn `shareReadState` parent), refuse edits\n // against files the model hasn't read this session — an edit applied\n // against bytes the model only \"remembers\" is how files get silently\n // corrupted.\n //\n // Content DRIFT (read it, but the bytes changed since — a formatter,\n // codegen, an editor auto-save) is handled tolerantly rather than with\n // a flat refusal: the hazard drift creates is a MIS-ANCHORED\n // `old_string`, so the guard defers to the anchor itself. If\n // `old_string` still resolves cleanly against the CURRENT bytes the\n // edit does exactly what it says and proceeds (with a notice); only\n // when resolution fails is the drift surfaced as the error — at that\n // point \"re-read the file\" is the right advice, whereas the plain\n // not-found/ambiguous message would mislead. A flat refusal here is\n // what taught models to abandon `edit` for shell one-liners that\n // bypass every guard: churny workflows (lint --fix between edits)\n // made the refusal near-permanent.\n //\n // Without any read-state map (no session, no explicit forward) the\n // guard is skipped: tracking has nowhere to live, so the gate has\n // nothing to check against.\n let drift: { readState: ReadStateMap, absKey: string, prior: ReadStateEntry } | null = null\n if (ctx.behavior?.requireReadBeforeEdit) {\n const readState = resolveReadStateMap(ctx)\n if (readState) {\n const absKey = readStateKey(ctx.handle.cwd, target)\n const prior = readState.get(absKey)\n if (!prior) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`Edit error: ${target} has not been read in this session. Call read_file first so the edit applies against the current contents${ctx.behavior?.trackShellReads !== false ? ' (plain shell reads such as cat or sed -n also count).' : ' — reads through shell (cat, grep, sed) don\\'t register.'}`)\n }\n if (prior.contentHash !== hashContent(original))\n drift = { readState, absKey, prior }\n }\n }\n\n // Resolve `old_string` against the file content with the recovery\n // cascade in `resolveOldString` (exact → quotes → desanitize → combined\n // → line-number-strip → strip+quotes). On a non-exact hit, `match.actual`\n // is the file-side substring (preserves the file's typography) and the\n // replacement is re-styled below to match.\n const match = resolveOldString(original, find)\n\n if (!match) {\n ctx.reportOutcome?.('failed')\n // On drifted content the not-found preview would mislead — the drift\n // is the probable cause, and a fresh read is the correct recovery.\n if (drift)\n return staleEditRefusal(target, drift)\n const preview = nearestMatchPreview(original, find)\n throw new ToolFailure(preview\n ? `Edit error: old_string not found in ${target}. Closest match in the file: ${preview}`\n : `Edit error: old_string not found in ${target}.`)\n }\n\n const { actual, occurrences, via } = match\n\n if (occurrences > 1 && !replaceAll) {\n ctx.reportOutcome?.('failed')\n // Same reasoning as not-found: \"expand old_string\" advice computed\n // against bytes the model hasn't seen would have it guessing blind.\n if (drift)\n return staleEditRefusal(target, drift)\n throw new ToolFailure(`Edit error: old_string appears ${occurrences} times in ${target}. Pass replace_all=true or expand old_string for uniqueness.`)\n }\n\n // Drift tolerance is for anchors that hold VERBATIM against the current\n // bytes. A fuzzy recovery (quote normalization, desanitize, line-number\n // strip) on drifted content is the one combination where mis-anchoring\n // is genuinely plausible — the anchor was composed against bytes that no\n // longer exist AND doesn't match the bytes that do. Refuse and ask for a\n // fresh read instead of compounding two approximations.\n if (drift && via !== 'exact') {\n ctx.reportOutcome?.('failed')\n return staleEditRefusal(target, drift)\n }\n\n const styledReplacement = styleReplacementForVia(replacement, via, actual)\n\n const updated = replaceAll\n ? original.split(actual).join(styledReplacement)\n : original.replace(actual, styledReplacement)\n\n if (updated === original) {\n ctx.reportOutcome?.('noop')\n throw new ToolFailure(`Edit error: replacement produced no change in ${target}.`)\n }\n\n await ctx.execution.writeFile(ctx.handle, target, updated)\n\n // Keep read-state coherent — after a successful edit, the model\n // knows the post-edit content (it produced new_string), so we\n // record the new hash against the same slice. This lets a chain\n // of edits proceed without re-reading between each one even with\n // `requireReadBeforeEdit` on.\n //\n // `elided: true` rides the same update: the refreshed hash now matches the\n // post-edit file, so without the flag a re-read would hit `read_file`'s\n // dedup and claim the PRE-edit body still on the wire is \"still current\".\n // Marking here — at the mutation, where the staleness is created — keeps\n // dedup honest in every `elideStaleReads` mode, including off. The next\n // fresh read clears the flag (`rememberRead`), so dedup resumes for\n // genuinely unchanged files.\n // `staleRejections` resets alongside: a successful edit ends any\n // refusal streak the escalating drift hint was counting.\n const readState = resolveReadStateMap(ctx)\n if (readState) {\n const absKey = readStateKey(ctx.handle.cwd, target)\n const prior = readState.get(absKey)\n if (prior)\n readState.set(absKey, { ...prior, contentHash: hashContent(updated), mtimeMs: Date.now(), elided: true, staleRejections: 0 })\n }\n\n ctx.reportOutcome?.('edited')\n // Flag non-exact recoveries so a mistargeted fallback is visible in the\n // transcript instead of silently passing as a verbatim match.\n const viaNote = via === 'exact' ? '' : ` (old_string was not found verbatim; matched via ${describeVia(via)})`\n // Drift is disclosed even on success: the model should know its mental\n // copy is behind and re-read before composing the NEXT old_string.\n const driftNote = drift ? ` Note: the file had changed on disk since your last read — old_string still anchored cleanly, but re-read before further edits.` : ''\n return `Edited ${target}: replaced ${occurrences} occurrence${occurrences === 1 ? '' : 's'}.${viaNote}${driftNote}`\n },\n}\n\n/**\n * Drift refusal for `edit`: records the rejection against the read-state\n * entry so consecutive refusals escalate from \"re-read the file\" to naming\n * the external-writer hypothesis — see {@link staleRefusalHint}.\n */\nfunction staleEditRefusal(target: string, drift: { readState: ReadStateMap, absKey: string, prior: ReadStateEntry }): never {\n const count = noteStaleRejection(drift.readState, drift.absKey, drift.prior)\n throw new ToolFailure(`Edit error: ${target} has changed on disk since the last read. Re-read the file before editing.${staleRefusalHint(count)}`)\n}\n\n/**\n * Find the line that shares the longest common prefix with the needle's first\n * line. Cheap heuristic — better than nothing for the common \"model has a typo\"\n * case (off-by-one indent, trailing whitespace, escape mismatch).\n *\n * Returns a \"line N: <preview>\" snippet or null when no line shares a useful\n * prefix. Strips line-number prefixes from the needle first so a model that\n * pasted a numbered `read_file` chunk verbatim still gets a useful diagnostic.\n */\nfunction nearestMatchPreview(haystack: string, needle: string): string | null {\n // If the model included `<N>\\t` (or `<N>|` / `<N>→`) prefixes from a\n // numbered read, strip them before scoring — otherwise the prefix\n // dominates and we never match real file lines.\n const normalizedNeedle = stripLineNumberPrefixes(needle)\n const needleFirstLine = normalizedNeedle.split('\\n')[0]\n if (needleFirstLine.length < 3)\n return null\n\n const lines = haystack.split('\\n')\n let bestScore = 0\n let bestIdx = -1\n for (let i = 0; i < lines.length; i++) {\n const score = sharedPrefixLength(lines[i], needleFirstLine)\n if (score > bestScore) {\n bestScore = score\n bestIdx = i\n }\n }\n if (bestIdx < 0 || bestScore < Math.min(8, Math.floor(needleFirstLine.length / 2)))\n return null\n\n const snippet = lines[bestIdx].slice(0, 80)\n return `line ${bestIdx + 1}: ${JSON.stringify(snippet)}`\n}\n\nfunction sharedPrefixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length)\n let i = 0\n while (i < max && a.charCodeAt(i) === b.charCodeAt(i))\n i++\n return i\n}\n","import type { ListFilesEntry } from '../contexts'\nimport type { ToolContext, ToolDef } from './types'\nimport { errorMessage } from '../errors'\nimport { toolPrompts } from './prompts'\n\nfunction entryPath(entry: ListFilesEntry): string {\n return typeof entry === 'string' ? entry : entry.path\n}\n\n/**\n * Entry ceiling — matches glob's default limit so a pathological\n * 100k-entry directory can't flood the context window.\n */\nconst MAX_ENTRIES = 1000\n\n/** The `list_files` tool. Lists the entries of one directory, capped at 1000 entries. */\nexport const listFiles: ToolDef = {\n // Directory listing only — safe to parallelize alongside other reads.\n isConcurrencySafe: true,\n // A read: a resumed durable run runs an unfinished call again.\n replay: 'safe',\n spec: {\n name: 'list_files',\n description: toolPrompts.list_files,\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Directory path (relative to the execution-context cwd, or absolute). Defaults to `.`.' },\n },\n required: [],\n },\n },\n async execute({ path }, ctx: ToolContext) {\n const target = (path as string) || '.'\n try {\n const entries = await ctx.execution.listFiles(ctx.handle, target)\n if (entries.length > MAX_ENTRIES)\n return `${entries.slice(0, MAX_ENTRIES).map(entryPath).join('\\n')}\\n…(${entries.length - MAX_ENTRIES} more entries omitted; use glob with a narrower pattern)`\n return entries.map(entryPath).join('\\n') || '(empty directory)'\n }\n catch (err) {\n // Differentiate the common failure shapes — reporting a permission\n // error or a file-not-a-directory as \"not found\" sends the model\n // chasing path typos that don't exist.\n ctx.reportOutcome?.('failed')\n // Matches both Node error codes (process context) and `ls` stderr\n // phrasing (docker context).\n const message = errorMessage(err)\n if (message.includes('ENOTDIR') || message.includes('Not a directory'))\n return `Not a directory: ${target}, it is a file; use read_file instead.`\n if (message.includes('EACCES') || message.includes('EPERM') || message.includes('Permission denied'))\n return `Permission denied: ${target}.`\n if (message.includes('ENOENT') || message.includes('No such file'))\n return `Directory not found: ${target}`\n return `list_files failed for ${target}: ${message}`\n }\n },\n}\n","import type { ReadStateEntry, ReadStateMap } from './read-state'\nimport type { ToolContext, ToolDef } from './types'\nimport { describeVia, resolveOldString, styleReplacementForVia } from './edit-utils'\nimport { ToolFailure } from './failure'\nimport { suggestionFor } from './path-suggest'\nimport { toolPrompts } from './prompts'\nimport { hashContent, noteStaleRejection, readStateKey, resolveReadStateMap, staleRefusalHint } from './read-state'\nimport { pathArgError } from './validation'\nimport { wholeReadRefusal } from './whole-read-guard'\n\ninterface EditStep {\n old_string: string\n new_string: string\n replace_all?: boolean\n}\n\ninterface StepOutcome {\n kind: 'applied' | 'failed'\n reason?: string\n}\n\n/**\n * Inline annotation builder — kept local to avoid importing from\n * `chat/edit-approval.ts` (that's a renderer-side module; tools live\n * one layer below). Line shape matches `parseEditOutcomesFromResult`'s\n * regex so the round-trip is lossless.\n *\n * Newlines in `reason` are folded to spaces because the parser is line-\n * scoped (`body.split('\\n')`); a multi-line reason would split into a\n * \"trailing prose\" line and trip the malformed-block guard, losing every\n * outcome below it. Static reasons in this file are single-line; the\n * sanitize is a guard against a pathological `target` (file path\n * containing a newline) leaking into `old_string not found in <target>`.\n */\nfunction annotationFor(outcomes: readonly StepOutcome[]): string {\n const lines = ['<edit-outcomes>']\n for (let i = 0; i < outcomes.length; i++) {\n const o = outcomes[i]\n const reason = o.reason ? `: ${o.reason.replace(/\\r?\\n/g, ' ')}` : ''\n lines.push(`#${i + 1} ${o.kind}${reason}`)\n }\n lines.push('</edit-outcomes>')\n return lines.join('\\n')\n}\n\n/**\n * The `multi_edit` tool. Applies a list of string replacements to one file in order, each on the output of the previous one.\n * Best-effort, per-hunk semantics.\n *\n * Each step replaces `old_string` with `new_string` against the file\n * contents *as left by the previous applied edit*. A per-step failure\n * (`old_string` not found, ambiguous match without `replace_all`,\n * identical strings, malformed input) is recorded against THAT step\n * only — the remaining steps still run. The file is written iff at\n * least one step applied. The result text reports per-hunk outcomes\n * inline and (when any step failed) carries an\n * `<edit-outcomes>…</edit-outcomes>` annotation block so the chat layer\n * + replay can paint per-hunk badges via `parseEditOutcomesFromResult`.\n *\n * Per-hunk approval is a TUI/host concern. When the user partially\n * denies a `multi_edit` from the file-edit modal, the gate handler\n * rebinds `ctx.input.edits` to the approved subset before this tool\n * runs — so the body sees a smaller all-approved batch and reports\n * outcomes keyed against THAT subset. The host's `tool:transform`\n * hook merges this subset-keyed result with the approval-side denied\n * entries (1:1 with the model's ORIGINAL `edits` list) before the\n * canonical `<edit-outcomes>` block lands on the wire — see\n * `mergeApprovalAndBodyOutcomes` in `chat/edit-approval.ts`.\n *\n * Wire / replay format (see `parseEditOutcomesFromResult`):\n *\n * Edited <path>: applied N of M edits (R replacements).\n * edit #2 failed: old_string not found in <path>.\n *\n * <edit-outcomes>\n * #1 applied\n * #2 failed: old_string not found in <path>\n * #3 applied\n * </edit-outcomes>\n *\n * The annotation is omitted entirely on the all-applied path — the\n * renderer's `isEditErrorResult` check then suppresses the paired\n * `tool-result` so the diff stands alone.\n */\nexport const multiEdit: ToolDef = {\n spec: {\n name: 'multi_edit',\n description: toolPrompts.multi_edit,\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'File path (relative to the execution-context cwd, or absolute).' },\n edits: {\n type: 'array',\n description: 'List of edits applied in order; each operates on the previous applied edit\\'s output.',\n items: {\n type: 'object',\n properties: {\n old_string: { type: 'string' },\n new_string: { type: 'string' },\n replace_all: { type: 'boolean' },\n },\n required: ['old_string', 'new_string'],\n },\n },\n },\n required: ['path', 'edits'],\n },\n },\n async execute({ path, edits }, ctx: ToolContext) {\n const target = path as string\n const steps = edits as EditStep[]\n\n const pathErr = pathArgError(target)\n if (pathErr) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`multi_edit error: ${pathErr}`)\n }\n\n if (!Array.isArray(steps) || steps.length === 0) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`multi_edit error: edits must be a non-empty array.`)\n }\n\n const refusal = await wholeReadRefusal(ctx.execution, ctx.handle, target, 'edit')\n if (refusal)\n return refusal\n\n let current: string\n try {\n current = await ctx.execution.readFile(ctx.handle, target)\n }\n catch {\n const hint = await suggestionFor(ctx.execution, ctx.handle, target)\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`multi_edit error: file not found: ${target}.${hint}`)\n }\n\n // Read-before-edit guard — see the matching block in `src/tools/\n // edit.ts` for the rationale, the anchor-tolerant drift handling, and\n // the no-read-state-map fall-through. Here drift defers to the per-hunk\n // anchors: each step already requires a clean resolution against the\n // CURRENT bytes, so drifted content only blocks the batch when nothing\n // anchors at all (below) — at which point drift is the probable cause\n // and the per-hunk \"not found\" reasons would mislead.\n let drift: { readState: ReadStateMap, absKey: string, prior: ReadStateEntry } | null = null\n if (ctx.behavior?.requireReadBeforeEdit) {\n const readState = resolveReadStateMap(ctx)\n if (readState) {\n const absKey = readStateKey(ctx.handle.cwd, target)\n const prior = readState.get(absKey)\n if (!prior) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`multi_edit error: ${target} has not been read in this session. Call read_file first so the edits apply against the current contents${ctx.behavior?.trackShellReads !== false ? ' (plain shell reads such as cat or sed -n also count).' : ' — reads through shell (cat, grep, sed) don\\'t register.'}`)\n }\n if (prior.contentHash !== hashContent(current))\n drift = { readState, absKey, prior }\n }\n }\n\n const outcomes: StepOutcome[] = []\n // Non-exact recovery notes (one per step that matched via a fallback) —\n // kept OUT of the `<edit-outcomes>` annotation block, whose line format\n // is parsed strictly by `parseEditOutcomesFromResult`.\n const viaNotes: string[] = []\n let totalReplacements = 0\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const find = step.old_string\n const replacement = step.new_string\n const replaceAll = step.replace_all === true\n\n if (typeof find !== 'string' || typeof replacement !== 'string') {\n outcomes.push({ kind: 'failed', reason: 'missing old_string or new_string' })\n continue\n }\n\n if (find.length === 0) {\n outcomes.push({ kind: 'failed', reason: 'empty old_string (use write_file to fully replace a file)' })\n continue\n }\n\n if (find === replacement) {\n outcomes.push({ kind: 'failed', reason: 'old_string and new_string are identical' })\n continue\n }\n\n const match = resolveOldString(current, find)\n if (!match) {\n outcomes.push({ kind: 'failed', reason: `old_string not found in ${target}` })\n continue\n }\n\n const { actual, occurrences, via } = match\n if (occurrences > 1 && !replaceAll) {\n outcomes.push({\n kind: 'failed',\n reason: `old_string appears ${occurrences} times; pass replace_all=true on this edit or expand old_string for uniqueness`,\n })\n continue\n }\n\n // Same rule as `edit`: drift tolerance is for anchors that hold\n // VERBATIM against the current bytes. A fuzzy recovery on drifted\n // content compounds two approximations — fail the hunk and let the\n // batch-level drift messaging steer toward a fresh read.\n if (drift && via !== 'exact') {\n outcomes.push({ kind: 'failed', reason: `old_string only matched via ${describeVia(via)}, and the file has changed on disk since your last read — re-read before applying non-verbatim anchors` })\n continue\n }\n\n const styledReplacement = styleReplacementForVia(replacement, via, actual)\n current = replaceAll\n ? current.split(actual).join(styledReplacement)\n : current.replace(actual, styledReplacement)\n totalReplacements += occurrences\n if (via !== 'exact')\n viaNotes.push(`edit #${i + 1}: old_string was not found verbatim; matched via ${describeVia(via)}`)\n outcomes.push({ kind: 'applied' })\n }\n\n const appliedCount = outcomes.reduce((n, o) => o.kind === 'applied' ? n + 1 : n, 0)\n const failedCount = outcomes.length - appliedCount\n\n // Skip the write when nothing changed. Preserves mtime so a partner\n // process watching the file doesn't see a phantom touch on a fully-\n // failed batch.\n if (appliedCount > 0) {\n await ctx.execution.writeFile(ctx.handle, target, current)\n // Reported only AFTER the write lands — a throwing `writeFile` falls\n // through to the loop's error path, which must not see a stale `edited`.\n ctx.reportOutcome?.('edited')\n\n // Bring the tracked hash forward so a follow-up edit on the same\n // file doesn't trip the drift branch on freshly-rewritten bytes.\n // `elided: true` for the same reason as `edit`: the refreshed hash\n // would otherwise let dedup serve a \"still current\" stub pointing at\n // the pre-edit body on the next re-read. Cleared by the next fresh read.\n // `staleRejections` resets alongside — a success ends the refusal streak.\n const readState = resolveReadStateMap(ctx)\n if (readState) {\n const absKey = readStateKey(ctx.handle.cwd, target)\n const prior = readState.get(absKey)\n if (prior)\n readState.set(absKey, { ...prior, contentHash: hashContent(current), mtimeMs: Date.now(), elided: true, staleRejections: 0 })\n }\n }\n else {\n // No edit applied — nothing reached disk.\n ctx.reportOutcome?.('failed')\n // Drift + zero anchors: the per-hunk failure reasons were computed\n // against bytes the model has not seen — surface the drift instead,\n // with the escalating external-writer hint on repeat refusals.\n if (drift) {\n const count = noteStaleRejection(drift.readState, drift.absKey, drift.prior)\n throw new ToolFailure(`multi_edit error: ${target} has changed on disk since the last read. Re-read the file before editing.${staleRefusalHint(count)}`)\n }\n }\n\n const n = steps.length\n\n // Header shape — three branches, each chosen for renderer + model\n // legibility:\n //\n // - All applied → \"Edited X: applied N edits (R replacements).\"\n // so the renderer's `isEditErrorResult` keeps suppressing the\n // paired tool-result (the diff stands alone on a clean success).\n // - Mixed → \"Edited X: applied N of M edits (R replacements).\"\n // plus per-failure lines + `<edit-outcomes>` block.\n // - All failed → \"multi_edit error: no edits applied to X (M attempted).\"\n // keeps the \"multi_edit error:\" prefix so anything that\n // pattern-matched on it (renderer visibility branch, status\n // ribbons, log filters) keeps working.\n let header: string\n if (appliedCount === n) {\n header = `Edited ${target}: applied ${n} edit${n === 1 ? '' : 's'} (${totalReplacements} replacement${totalReplacements === 1 ? '' : 's'}).`\n }\n else if (appliedCount > 0) {\n header = `Edited ${target}: applied ${appliedCount} of ${n} edits (${totalReplacements} replacement${totalReplacements === 1 ? '' : 's'}).`\n }\n else {\n header = `multi_edit error: no edits applied to ${target} (${n} attempted).`\n }\n\n const failureLines: string[] = []\n for (let i = 0; i < outcomes.length; i++) {\n const o = outcomes[i]\n if (o.kind === 'failed')\n failureLines.push(`edit #${i + 1} failed: ${o.reason}`)\n }\n\n // Annotation is the body's side-channel for replay + chat-layer\n // merge. Omit on the all-applied happy path so the renderer can\n // continue to hide the paired tool-result; emit whenever any step\n // failed so the chat layer + replay can paint per-hunk badges.\n const parts = [header]\n // Drift is disclosed even when hunks landed: the model's mental copy is\n // behind, and the NEXT batch's anchors should come from a fresh read.\n if (drift && appliedCount > 0)\n parts.push(`Note: the file had changed on disk since your last read — the applied edits anchored cleanly against the current content, but re-read before further edits.`)\n if (viaNotes.length > 0)\n parts.push(viaNotes.join('\\n'))\n if (failureLines.length > 0)\n parts.push(failureLines.join('\\n'))\n if (failedCount > 0)\n parts.push(annotationFor(outcomes))\n if (appliedCount === 0)\n throw new ToolFailure(parts.join('\\n\\n'))\n return parts.join('\\n\\n')\n },\n}\n","/**\n * Binary-aware file read for the `read_file` tool.\n *\n * Dispatches to `ExecutionContext.readFileBinary` when implemented; otherwise\n * shells out via `base64 < path` so docker / sandbox contexts don't have to\n * implement a custom primitive. The shell fallback is portable (busybox /\n * coreutils / macOS all ship `base64`) and only fires when the native path\n * is unavailable.\n *\n * Returns a base64 string ready to drop into a `ToolResultContent` image\n * block. Raises on read failure — caller is responsible for catching and\n * formatting the error message.\n */\n\nimport type { ExecutionContext, ExecutionHandle } from '../contexts'\nimport { Buffer } from 'node:buffer'\nimport { alwaysQuote } from './shell-quote'\n\n/**\n * Best-effort guess at IANA media type from a file extension. Covers the\n * extensions Zidane's `read_file` actually dispatches to image blocks\n * (png/jpg/jpeg/gif/webp). Other extensions return `undefined` and the\n * caller short-circuits the binary route.\n */\nexport function imageMediaTypeFor(path: string): string | undefined {\n const dot = path.lastIndexOf('.')\n if (dot === -1)\n return undefined\n const ext = path.slice(dot + 1).toLowerCase()\n switch (ext) {\n case 'png':\n return 'image/png'\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg'\n case 'gif':\n return 'image/gif'\n case 'webp':\n return 'image/webp'\n default:\n return undefined\n }\n}\n\n/**\n * Read a file as base64. Prefers `ExecutionContext.readFileBinary` (zero\n * subprocess overhead in-process) and falls back to `base64 < path` via\n * the shell seam — works on docker / sandbox without an interface change.\n *\n * Returns `{ base64, byteLength }`. `byteLength` is the *decoded* byte count\n * so callers can size-budget against the original file, not the inflated\n * base64 representation (which is ~4/3× larger).\n */\nexport async function readFileAsBase64(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n): Promise<{ base64: string, byteLength: number }> {\n if (execution.readFileBinary) {\n const bytes = await execution.readFileBinary(handle, path)\n const b64 = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')\n return { base64: b64, byteLength: bytes.byteLength }\n }\n\n // Shell fallback. Reading from stdin (`base64 < path`) behaves the same on\n // GNU coreutils, busybox and macOS, so no per-platform flag is needed.\n const cmd = `base64 < ${alwaysQuote(path)}`\n const result = await execution.exec(handle, cmd)\n if (result.exitCode !== 0)\n throw new Error(`base64 read failed: ${result.stderr || `exit ${result.exitCode}`}`)\n // `base64` may emit line-wrapped output (76-col default); strip whitespace.\n const b64 = result.stdout.replace(/\\s+/g, '')\n return { base64: b64, byteLength: decodedBase64ByteLength(b64) }\n}\n\n/**\n * Decoded byte length of a (whitespace-stripped) base64 string. Accounts for\n * `=` padding so the value matches the original file size to the byte —\n * `Math.floor(len * 3 / 4)` over-reports by 1–2 bytes on padded payloads.\n */\nfunction decodedBase64ByteLength(b64: string): number {\n if (b64.length === 0)\n return 0\n let pad = 0\n if (b64.endsWith('=='))\n pad = 2\n else if (b64.endsWith('='))\n pad = 1\n return Math.max(0, (b64.length * 3) / 4 - pad)\n}\n","import type { ResolvedAttachment } from '../attachment-handle'\nimport type { ToolResultContent } from '../types'\nimport type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\nimport { parseAttachmentHandle, resolveAttachmentFromTurns } from '../attachment-handle'\nimport { normalizeReadFileInteger, resolveReadFileDefaults } from '../behaviors/read-file-defaults'\nimport { isOutputExceededMessage } from '../contexts/output-cap'\nimport { errorMessage } from '../errors'\nimport { readPersistedBlobOnHost } from '../persisted-blob-io'\nimport { looksBinary } from './binary-detect'\nimport { imageMediaTypeFor, readFileAsBase64 } from './binary-read'\nimport { isToolFailure, ToolFailure } from './failure'\nimport { reconcileImageMediaType } from './media-sniff'\nimport { suggestionFor } from './path-suggest'\nimport { toolPrompts } from './prompts'\nimport { READ_FILE_MAX_BATCH, readFileBatchHeader, readFileTargets } from './read-file-targets'\nimport { hashContent, readStateKey, resolveReadStateMap } from './read-state'\nimport { pathArgError } from './validation'\nimport { wholeReadRefusal } from './whole-read-guard'\n\n/** Default line limit of a text read. */\nconst DEFAULT_LINE_LIMIT = 2000\n/** Default byte cap of a text read: 256 KiB. */\nconst DEFAULT_BYTE_CAP = 262_144\n\n/**\n * Default upper bound on raw attachment bytes we'll inline as a base64 block.\n * Above this, we return a marker instead — the model won't get useful\n * information from a 10 MB+ screenshot rendered as one tool result, and\n * the wire bill gets ugly. Override via the `maxBytes` parameter on the\n * tool call.\n */\nconst DEFAULT_ATTACHMENT_BYTE_CAP = 5 * 1024 * 1024\n\nfunction attachmentByteLength(data: string, encoding?: 'base64' | 'text'): number {\n if (encoding === 'text')\n return Buffer.byteLength(data)\n if (data.length === 0)\n return 0\n const pad = data.endsWith('==') ? 2 : data.endsWith('=') ? 1 : 0\n return Math.max(0, Math.floor((data.length * 3) / 4) - pad)\n}\n\n/**\n * Decode a resolved document attachment to text when its bytes are actually\n * textual. Unknown-extension source files (e.g. `.asm`) ingest as base64\n * `application/octet-stream` blobs; re-inlining megabytes of base64 whole is\n * exactly what OOMs a session, so textual payloads get routed through the\n * line-paged renderer instead. Returns `null` for images, PDFs, and genuinely\n * binary payloads — those keep the whole-blob inline path.\n */\nfunction attachmentText(found: ResolvedAttachment): string | null {\n if (found.kind !== 'document')\n return null\n if (found.encoding === 'text')\n return found.data\n if (found.mediaType === 'application/pdf')\n return null\n const decoded = Buffer.from(found.data, 'base64').toString('utf-8')\n return looksBinary(decoded) ? null : decoded\n}\n\ninterface TextSliceOptions {\n /** 1-indexed start line (already normalized). */\n offset: number\n /** Max lines; 0 = unlimited (already normalized). */\n limit: number\n /** Byte cap; 0 = unlimited (already normalized). */\n maxBytes: number\n lineNumbers: boolean\n}\n\n/**\n * Line-sliced, byte-capped rendering with the standard truncation footers.\n * Shared by the filesystem text path and the text-attachment re-resolve path\n * so both page identically (`offset`/`limit`/`maxBytes` semantics, footer\n * guidance included).\n */\nfunction renderTextSlice(raw: string, opts: TextSliceOptions): string {\n const { offset: offsetN, limit: limitN, maxBytes: maxBytesN, lineNumbers: showLineNumbers } = opts\n const totalBytes = Buffer.byteLength(raw)\n\n const lines = raw.split('\\n')\n const totalLines = lines.length\n\n // 1-indexed offset → 0-indexed slice start.\n const startIdx = Math.max(0, offsetN - 1)\n const endIdx = limitN > 0 ? Math.min(totalLines, startIdx + limitN) : totalLines\n let slice = lines.slice(startIdx, endIdx)\n\n // Apply byte cap at the line boundary. Walk lines, accumulating bytes; cut\n // just below the cap. The \"truncatedSlice.length > 0\" guard ensures we\n // always emit at least one line — files with a single oversized line would\n // otherwise return empty. The single-line overflow gets handled by the\n // hard-cap pass below.\n let bytesCut = false\n if (maxBytesN > 0) {\n const truncatedSlice: string[] = []\n let bytesUsed = 0\n for (const line of slice) {\n const lineBytes = Buffer.byteLength(line) + 1 // +1 for the '\\n' rejoin\n if (bytesUsed + lineBytes > maxBytesN && truncatedSlice.length > 0) {\n bytesCut = true\n break\n }\n truncatedSlice.push(line)\n bytesUsed += lineBytes\n if (bytesUsed >= maxBytesN) {\n // Budget consumed — keep this line, stop here.\n break\n }\n }\n if (truncatedSlice.length < slice.length)\n bytesCut = true\n slice = truncatedSlice\n }\n\n // Hard-cap pass: when the line-boundary loop had to admit an oversized line\n // (single huge line, or first line ≥ maxBytes), the body still exceeds the\n // budget. Truncate the last line at a UTF-8-safe boundary and flag it as a\n // mid-line cut so the footer can warn the reader that offset+1 won't pick\n // up where this read left off.\n let midLineCut = false\n if (maxBytesN > 0 && slice.length > 0) {\n const bodyBytes = Buffer.byteLength(slice.join('\\n'))\n if (bodyBytes > maxBytesN) {\n const lastIdx = slice.length - 1\n const lastLine = slice[lastIdx]\n const otherBytes = lastIdx > 0\n ? Buffer.byteLength(slice.slice(0, lastIdx).join('\\n')) + 1 // +1 for the joining '\\n'\n : 0\n const budgetForLast = Math.max(0, maxBytesN - otherBytes)\n // Estimate cut at char count = byte budget (correct for ASCII), then\n // walk back if the resulting prefix still overflows because of multi-\n // byte codepoints. Worst case ~3 iterations (max UTF-8 width is 4).\n let cut = Math.min(lastLine.length, budgetForLast)\n while (cut > 0 && Buffer.byteLength(lastLine.slice(0, cut)) > budgetForLast)\n cut--\n slice[lastIdx] = lastLine.slice(0, cut)\n midLineCut = true\n bytesCut = true\n }\n }\n\n const linesReturned = slice.length\n const lastLineRead = startIdx + linesReturned\n\n // Line numbers default on. Format: `<line-no>\\t<content>` — bare digit,\n // tab separator, no padding. Matches Claude Code's compact `cat -n`\n // output for token efficiency (~5 chars saved per line vs. padded\n // forms). Models treat the prefix as metadata; `edit` strips it from\n // `old_string` when the model pastes a numbered chunk back, and also\n // accepts `<N>|<content>` / `<N>→<content>` for cross-stack tolerance.\n const body = showLineNumbers\n ? slice.map((line, i) => `${startIdx + i + 1}\\t${line}`).join('\\n')\n : slice.join('\\n')\n\n const linesTruncated = endIdx < totalLines || bytesCut\n if (!linesTruncated && offsetN === 1)\n return body\n\n if (!linesTruncated) {\n // Reading from a non-1 offset; tell the model where the read started.\n return `${body}\\n\\n…read lines ${offsetN}-${lastLineRead} of ${totalLines}.`\n }\n\n if (midLineCut) {\n // Line N was only partially read, so offset=N+1 would skip the unread\n // portion — we don't suggest it. Raising maxBytes is the only lossless\n // way forward. Avoid suggesting shell+sed/awk slicing here: that primes\n // a debugging anti-pattern where the model loops on narrow shell probes\n // instead of using paginated read_file calls.\n return `${body}\\n\\n…truncated mid-line at line ${lastLineRead} (byte cap ${maxBytesN} reached). File has ${totalLines} lines, ${totalBytes} bytes total. Raise maxBytes to read the full line.`\n }\n\n const reason = bytesCut ? `byte cap (${maxBytesN}) reached` : `line limit (${limitN}) reached`\n return `${body}\\n\\n…truncated at line ${lastLineRead} (${reason}). File has ${totalLines} lines, ${totalBytes} bytes total; re-read with offset=${lastLineRead + 1} to continue.`\n}\n\n/**\n * Resolve the requested start line against the file body. A negative offset\n * counts from the end (`-50` = the last 50 lines, like `tail -n 50`); a\n * trailing newline doesn't count as an extra line. Anything else normalizes\n * like the other integer knobs (non-numbers fall back to line 1).\n */\nfunction resolveOffset(offset: unknown, raw: string): number {\n if (typeof offset === 'number' && Number.isFinite(offset) && offset < 0) {\n const lines = raw.split('\\n').length - (raw.endsWith('\\n') ? 1 : 0)\n return Math.max(1, lines + Math.floor(offset) + 1)\n }\n return normalizeReadFileInteger(offset, 1)\n}\n\ninterface ReadOneArgs {\n path?: unknown\n offset?: unknown\n limit?: unknown\n maxBytes?: unknown\n lineNumbers?: unknown\n}\n\ninterface ReadOneOptions {\n /** Upper bound on the TEXT byte cap (batch budget); attachments keep their own caps. */\n textByteBudget?: number\n}\n\n/**\n * The `read_file` tool. Reads one file, or several files and ranges in one call, from the execution context,\n * with line-based offset/limit and a hard byte cap.\n *\n * Defaults are tuned for source code: 2000 lines / 256 KiB. A typical source\n * file, lockfile, or large config fits in one read; logs and very large\n * fixtures get truncated with a footer that documents how to fetch the\n * remainder.\n *\n * Binary files are detected on the leading characters of the decoded text — if\n * the sample contains a NUL or a high proportion of U+FFFD replacement\n * characters, we return a marker so the model doesn't drown in mojibake.\n */\n\nexport const readFile: ToolDef = {\n // Pure read — fans out in parallel with other concurrency-safe siblings\n // up to `behavior.maxConcurrentTools`.\n isConcurrencySafe: true,\n // A read: a resumed durable run runs an unfinished call again.\n replay: 'safe',\n spec: {\n name: 'read_file',\n description: toolPrompts.read_file,\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'File path (relative to the execution-context cwd, or absolute). Use `paths` instead to read several files or ranges in one call.' },\n paths: {\n type: 'array',\n description: `Read several files, or several ranges of one file, in one call (max ${READ_FILE_MAX_BATCH}). Each entry is \\`{ path, offset?, limit? }\\`; repeat a path to read several ranges. Output is one \\`==> path <==\\` section per entry, sharing one byte budget (\\`maxBytes\\`). Use instead of \\`path\\`.`,\n items: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'File path.' },\n offset: { type: 'integer', description: 'Start line; negative counts from the end.' },\n limit: { type: 'integer', description: 'Max lines.' },\n },\n required: ['path'],\n },\n },\n offset: { type: 'integer', description: '1-indexed line number to start from. Negative counts from the end (`-50` = last 50 lines). Default: 1.' },\n limit: { type: 'integer', description: 'Max lines to return. Default: 2000. Set 0 for unlimited.' },\n maxBytes: { type: 'integer', description: 'Hard byte cap on file content read, regardless of line count. Default: 262144 for text, 5242880 for image/PDF attachments. Set 0 for unlimited. The rendered output may be slightly larger than this cap when `lineNumbers` is on (each line carries a `<N>\\\\t` prefix).' },\n lineNumbers: { type: 'boolean', description: 'Prefix each line with its 1-indexed line number. Default: true (the agent-wide `behavior.readLineNumbers`), false inside codemode scripts.' },\n },\n required: [],\n },\n },\n async execute(input, ctx: ToolContext) {\n if (input.paths !== undefined)\n return readBatch(input, ctx)\n return readOne(input, ctx)\n },\n}\n\nfunction readDefaults(ctx: ToolContext) {\n return resolveReadFileDefaults(ctx.behavior, {\n lineLimit: DEFAULT_LINE_LIMIT,\n textMaxBytes: DEFAULT_BYTE_CAP,\n attachmentMaxBytes: DEFAULT_ATTACHMENT_BYTE_CAP,\n })\n}\n\n/**\n * Whether a `read_file` call prefixes each line with its number: the call's\n * `lineNumbers`, else off inside a codemode script (a nested call: the script\n * splits, parses or matches the text), else `behavior.readLineNumbers`\n * (default on).\n *\n * @param lineNumbers - The call's `lineNumbers` argument.\n * @param ctx - The call's context; `parentToolCallId` marks a nested call.\n */\nexport function readFileLineNumbers(lineNumbers: unknown, ctx: Pick<ToolContext, 'behavior' | 'parentToolCallId'>): boolean {\n if (typeof lineNumbers === 'boolean')\n return lineNumbers\n return ctx.parentToolCallId === undefined && (ctx.behavior?.readLineNumbers ?? true)\n}\n\n/** Text byte cap for one read: the requested/default cap, bounded by a batch budget. */\nfunction textCap(requested: number, budget: number | undefined): number {\n if (budget === undefined)\n return requested\n return requested === 0 ? budget : Math.min(requested, budget)\n}\n\n/**\n * `paths` batch: each entry goes through {@link readOne} (so read-state,\n * dedup, binary/attachment handling behave exactly like single reads) and\n * renders as a `==> path <==` section. Text sections share one byte budget\n * (`maxBytes`, default 256 KiB, 0 = unlimited); entries past it get a\n * one-line skip note instead of silent truncation.\n */\nasync function readBatch(input: Record<string, unknown>, ctx: ToolContext): Promise<string | ToolResultContent[]> {\n if (input.path !== undefined)\n throw new ToolFailure('Read error: pass either `path` or `paths`, not both.')\n if (!Array.isArray(input.paths) || input.paths.length === 0)\n throw new ToolFailure('Read error: `paths` must be a non-empty array of `{ path, offset?, limit? }` entries.')\n if (input.paths.length > READ_FILE_MAX_BATCH)\n throw new ToolFailure(`Read error: \\`paths\\` holds ${input.paths.length} entries; the limit is ${READ_FILE_MAX_BATCH} per call. Split the batch.`)\n const targets = readFileTargets(input)\n if (targets.length !== input.paths.length)\n throw new ToolFailure('Read error: every `paths` entry needs a non-empty string `path`.')\n\n const cap = normalizeReadFileInteger(input.maxBytes, readDefaults(ctx).textMaxBytes)\n let remaining = cap\n const sections: Array<string | ToolResultContent[]> = []\n for (const target of targets) {\n const header = readFileBatchHeader(target.path)\n if (cap > 0 && remaining <= 0) {\n sections.push(`${header}\\n[skipped: the batch byte budget (${cap}) is used up; read this entry in a separate call]`)\n continue\n }\n // One entry failing (a bad path) keeps the rest of the batch: its section carries the failure.\n const out = await readOne(\n { path: target.path, offset: target.offset, limit: target.limit, lineNumbers: input.lineNumbers },\n ctx,\n cap > 0 ? { textByteBudget: remaining } : {},\n ).catch((error: unknown) => {\n if (isToolFailure(error))\n return (error as Error).message\n throw error\n })\n if (typeof out === 'string') {\n remaining -= Buffer.byteLength(out)\n sections.push(`${header}\\n${out}`)\n }\n else {\n for (const part of out)\n remaining -= part.type === 'text' ? Buffer.byteLength(part.text) : 'data' in part && typeof part.data === 'string' ? part.data.length : 0\n sections.push([{ type: 'text', text: header }, ...out])\n }\n }\n\n if (sections.every(section => typeof section === 'string'))\n return (sections as string[]).join('\\n\\n')\n const content: ToolResultContent[] = []\n for (const section of sections) {\n if (typeof section === 'string')\n content.push({ type: 'text', text: section })\n else\n content.push(...section)\n }\n return content\n}\n\nasync function readOne({ path, offset, limit, maxBytes, lineNumbers }: ReadOneArgs, ctx: ToolContext, opts: ReadOneOptions = {}): Promise<string | ToolResultContent[]> {\n if (typeof path !== 'string' || path.length === 0)\n throw new ToolFailure('Read error: missing `path` (or pass `paths` to read several files).')\n const defaults = readDefaults(ctx)\n // Attachment re-resolve: `read_file path=\"attachment://<hash>\"` pulls an\n // aged-out image/document back from session history (see media age-out in\n // the loop). Branch before the filesystem-path checks — the handle is not a\n // real path. Re-inlines the bytes for THIS turn only; they age out again on\n // the natural schedule.\n const handleHash = typeof path === 'string' ? parseAttachmentHandle(path) : null\n if (handleHash) {\n const turns = ctx.session?.turns\n if (!turns)\n throw new ToolFailure(`Attachment ${path} cannot be resolved: no session is bound to this run.`)\n const found = resolveAttachmentFromTurns(turns, handleHash)\n if (!found)\n throw new ToolFailure(`Attachment ${path} not found in this session's history (it may predate this session, or only ever lived as a host-offloaded reference).`)\n // Textual documents page through the standard line renderer — honoring\n // offset/limit/maxBytes with the TEXT defaults — instead of re-inlining\n // the whole payload (which OOMs the session for multi-MB attachments).\n const asText = attachmentText(found)\n if (asText !== null) {\n const header = `Document${found.name ? ` \"${found.name}\"` : ''} re-resolved from session history (${found.mediaType}, rendered as text).`\n const body = renderTextSlice(asText, {\n offset: resolveOffset(offset, asText),\n limit: normalizeReadFileInteger(limit, defaults.lineLimit),\n maxBytes: textCap(normalizeReadFileInteger(maxBytes, defaults.textMaxBytes), opts.textByteBudget),\n lineNumbers: readFileLineNumbers(lineNumbers, ctx),\n })\n return `${header}\\n\\n${body}`\n }\n const sizeCap = normalizeReadFileInteger(maxBytes, defaults.attachmentMaxBytes)\n const byteLength = attachmentByteLength(found.data, found.encoding)\n if (sizeCap > 0 && byteLength > sizeCap)\n return `[attachment too large to re-inline: ${path}, ${byteLength} bytes (cap ${sizeCap}). Raise maxBytes if you need the original bytes.]`\n const label = found.kind === 'image' ? 'Image' : 'Document'\n const content: ToolResultContent[] = [\n { type: 'text', text: `${label} re-resolved from session history (${found.mediaType}${found.name ? `, \"${found.name}\"` : ''}).` },\n found.kind === 'image'\n ? { type: 'image', mediaType: found.mediaType, data: found.data, ...(found.name ? { name: found.name } : {}) }\n : { type: 'document', mediaType: found.mediaType, data: found.data, encoding: found.encoding ?? 'base64', ...(found.name ? { name: found.name } : {}) },\n ]\n return content\n }\n\n // Reasoning-leak backstop — see `pathArgError`.\n const pathErr = pathArgError(path as string)\n if (pathErr)\n throw new ToolFailure(`Read error: ${pathErr}`)\n\n // Image dispatch — vision-aware models can answer questions directly\n // against the image bytes; non-vision models get the marker substitution\n // applied later in the loop (`stripImagesForNonVision`). Skips the line-\n // based read entirely. Gated on extension first (cheap), then reconciled\n // against magic bytes — Anthropic rejects the whole request when the\n // declared `media_type` disagrees with the actual bytes (e.g. a JPEG\n // saved with a `.webp` extension).\n const extMedia = imageMediaTypeFor(path as string)\n if (extMedia) {\n const sizeCap = normalizeReadFileInteger(maxBytes, defaults.attachmentMaxBytes)\n try {\n // Size-probe BEFORE reading — readFileAsBase64 materializes the\n // whole file (at 1.33× for base64) and an oversized image would\n // OOM the host before the post-read cap check could fire. The\n // post-read check stays as the backstop: the probe can race with\n // writes, and contexts without `fileSize` return null.\n const probed = await ctx.execution.fileSize?.(ctx.handle, path as string) ?? null\n if (probed !== null && sizeCap > 0 && probed > sizeCap) {\n return `[image too large to inline: ${path}, ${probed} bytes (cap ${sizeCap}). Raise maxBytes, or use shell to inspect.]`\n }\n const { base64, byteLength } = await readFileAsBase64(ctx.execution, ctx.handle, path as string)\n if (sizeCap > 0 && byteLength > sizeCap) {\n return `[image too large to inline: ${path}, ${byteLength} bytes (cap ${sizeCap}). Raise maxBytes, or use shell to inspect.]`\n }\n const imgMedia = reconcileImageMediaType(extMedia, base64)\n const content: ToolResultContent[] = [\n { type: 'text', text: `Image: ${path} (${byteLength} bytes, ${imgMedia})` },\n { type: 'image', mediaType: imgMedia, data: base64 },\n ]\n return content\n }\n catch (err) {\n const hint = await suggestionFor(ctx.execution, ctx.handle, path as string)\n throw new ToolFailure(`Image read failed: ${path}: ${errorMessage(err)}.${hint}`)\n }\n }\n\n const docMedia = documentMediaTypeFor(path as string)\n if (docMedia) {\n const sizeCap = normalizeReadFileInteger(maxBytes, defaults.attachmentMaxBytes)\n try {\n // Same probe-before-read OOM guard as the image branch above.\n const probed = await ctx.execution.fileSize?.(ctx.handle, path as string) ?? null\n if (probed !== null && sizeCap > 0 && probed > sizeCap) {\n return `[document too large to attach: ${path}, ${probed} bytes (cap ${sizeCap}). Raise maxBytes, or use shell/read text extraction to inspect.]`\n }\n const { base64, byteLength } = await readFileAsBase64(ctx.execution, ctx.handle, path as string)\n if (sizeCap > 0 && byteLength > sizeCap) {\n return `[document too large to attach: ${path}, ${byteLength} bytes (cap ${sizeCap}). Raise maxBytes, or use shell/read text extraction to inspect.]`\n }\n if (docMedia === 'application/pdf' && !isPdfBase64(base64)) {\n return `[binary file: ${path}, ${byteLength} bytes; extension suggests PDF but file header does not start with %PDF-]`\n }\n const content: ToolResultContent[] = [\n { type: 'text', text: `Document: ${path} (${byteLength} bytes, ${docMedia})` },\n { type: 'document', mediaType: docMedia, data: base64, encoding: 'base64', name: fileNameForPath(path as string) },\n ]\n return content\n }\n catch (err) {\n const hint = await suggestionFor(ctx.execution, ctx.handle, path as string)\n throw new ToolFailure(`Document read failed: ${path}: ${errorMessage(err)}.${hint}`)\n }\n }\n\n // Whole-read OOM guard — see whole-read-guard.ts. Applies to the\n // text path only; attachments already have their own byte caps above.\n const refusal = await wholeReadRefusal(ctx.execution, ctx.handle, path as string, 'read')\n if (refusal)\n return refusal\n\n let raw: string\n try {\n raw = await ctx.execution.readFile(ctx.handle, path as string)\n }\n catch (err) {\n // A spilled tool result the stub pointed at, refused by a confined process context.\n const blob = await readPersistedBlobOnHost(ctx.behavior?.persistDir, ctx.handle, path as string)\n if (blob === undefined) {\n // Transport-level output cap (docker probe-failure safety net) —\n // reporting it as \"File not found\" would send the model chasing\n // path typos. Surface the real reason with the same guidance as\n // the whole-read refusal.\n const message = errorMessage(err)\n if (isOutputExceededMessage(message))\n return `[file too large to read: ${path}: ${message}. Use shell (head/tail/sed -n/grep) to inspect slices of it.]`\n const hint = await suggestionFor(ctx.execution, ctx.handle, path as string)\n throw new ToolFailure(`File not found: ${path}.${hint}`)\n }\n raw = blob\n }\n\n const totalBytes = Buffer.byteLength(raw)\n\n // Read-state tracking + per-session dedup. Tracking populates the\n // map so `requireReadBeforeEdit` can confirm the model has seen\n // the file; dedup decides whether identical re-reads should\n // short-circuit to a \"still current\" stub. The two are\n // INDEPENDENT — turning off dedup must NOT also break the gate.\n //\n // Tracking runs whenever either feature is enabled (or by default,\n // since dedup defaults on); dedup short-circuit only fires when\n // `dedupReads` is explicitly on. Costs nothing when no session is\n // bound (direct/standalone tool invocations).\n //\n // The hash is taken on the *raw* file before any truncation so a\n // future read with a wider slice still invalidates the prior\n // stub-eligible entry — re-emitting the freshly-included bytes.\n //\n // A nested read (`ToolContext.callTool`, e.g. from codemode) is read by the\n // calling tool, not the model: it gets the full body (no stub). It still\n // records the file as read, so an edit in the same script (or a later one)\n // passes `requireReadBeforeEdit`, but flagged `elided`: a later direct\n // read must not dedup to a stub pointing at content the model never saw.\n const nested = ctx.parentToolCallId !== undefined\n const dedupEnabled = !nested && ctx.behavior?.dedupReads !== false\n const gateEnabled = ctx.behavior?.requireReadBeforeEdit === true\n const trackingEnabled = ctx.behavior?.dedupReads !== false || gateEnabled\n const readState = trackingEnabled ? resolveReadStateMap(ctx) : undefined\n const absKey = readStateKey(ctx.handle.cwd, path as string)\n const offsetForKey = resolveOffset(offset, raw)\n const limitForKey = normalizeReadFileInteger(limit, defaults.lineLimit)\n const requestedMaxBytes = normalizeReadFileInteger(maxBytes, defaults.textMaxBytes)\n const effectiveMaxBytes = textCap(requestedMaxBytes, opts.textByteBudget)\n // Key dedup on the requested cap whenever a batch budget didn't bind (the\n // whole file fits under it), so a repeated batch dedups every entry even\n // though earlier stubs left a different remaining budget.\n const maxBytesForKey = effectiveMaxBytes === 0 || totalBytes <= effectiveMaxBytes ? requestedMaxBytes : effectiveMaxBytes\n const showLineNumbers = readFileLineNumbers(lineNumbers, ctx)\n const currentHash = readState ? hashContent(raw) : ''\n const rememberRead = () => {\n if (!readState)\n return\n if (nested) {\n // The model's own read of these bytes stays valid (and dedup-able).\n if (readState.get(absKey)?.contentHash !== currentHash)\n readState.set(absKey, { contentHash: currentHash, offset: offsetForKey, limit: limitForKey, maxBytes: maxBytesForKey, lineNumbers: showLineNumbers, mtimeMs: Date.now(), elided: true })\n return\n }\n readState.set(absKey, {\n contentHash: currentHash,\n offset: offsetForKey,\n limit: limitForKey,\n maxBytes: maxBytesForKey,\n lineNumbers: showLineNumbers,\n mtimeMs: Date.now(),\n })\n }\n if (dedupEnabled && readState) {\n const prior = readState.get(absKey)\n if (\n prior\n && prior.contentHash === currentHash\n && prior.offset === offsetForKey\n && prior.limit === limitForKey\n && prior.maxBytes === maxBytesForKey\n // Toggling `lineNumbers` between reads must miss dedup: the stub\n // claims \"the prior result is still current\", but the prior\n // output was a different shape — the model would draw bogus\n // conclusions if we replayed it.\n && prior.lineNumbers === showLineNumbers\n // Stale-read elision removed the prior output from the on-wire\n // history — the stub would point at content the model can no\n // longer see. Serve the full body; `rememberRead` clears the flag.\n && prior.elided !== true\n ) {\n // A dedup hit still represents an intentional re-read. Refresh the\n // tracking entry so `requireReadBeforeEdit` sees the re-read even\n // though we keep the token-saving stub output.\n //\n // This stub only fires when the prior output is still on the wire:\n // every elision path (stale-read elision, tail compaction) flips the\n // entry's `elided` flag, which the guard above checks so a re-read of\n // compacted-away content MISSES dedup and re-serves the full body.\n // So we deliberately do NOT tell the model to \"re-read with a\n // different offset/limit\" — that advice, when the content was already\n // gone, drove an infinite offset-cycling re-read loop.\n rememberRead()\n return `File ${path} unchanged since the previous read in this session; the prior result above is still current, so this duplicate read was skipped to save tokens.`\n }\n }\n\n // Cheap binary detection on a leading sample. ExecutionContext.readFile\n // returns UTF-8-decoded text already — but if the underlying file was\n // binary, the decode replaces invalid sequences with U+FFFD. Use a NUL\n // byte and replacement-char ratio in the sample as a heuristic.\n if (looksBinary(raw)) {\n return `[binary file: ${path}, ${totalBytes} bytes; use shell with hexdump | xxd | od to inspect]`\n }\n\n rememberRead()\n\n return renderTextSlice(raw, {\n offset: offsetForKey,\n limit: limitForKey,\n maxBytes: effectiveMaxBytes,\n lineNumbers: showLineNumbers,\n })\n}\n\nfunction documentMediaTypeFor(path: string): string | undefined {\n const dot = path.lastIndexOf('.')\n if (dot === -1)\n return undefined\n const ext = path.slice(dot + 1).toLowerCase()\n return ext === 'pdf' ? 'application/pdf' : undefined\n}\n\nfunction fileNameForPath(path: string): string {\n const normalized = path.replace(/\\\\/g, '/')\n const slash = normalized.lastIndexOf('/')\n return slash === -1 ? normalized : normalized.slice(slash + 1)\n}\n\nfunction isPdfBase64(base64: string): boolean {\n return Buffer.from(base64.slice(0, 16), 'base64').toString('ascii').startsWith('%PDF-')\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\nimport { ToolFailure } from './failure'\nimport { toolPrompts } from './prompts'\nimport { hashContent, readStateKey, resolveReadStateMap } from './read-state'\nimport { pathArgError } from './validation'\n\n/**\n * Write a file, with an idempotency signal when the content is unchanged.\n *\n * Three return shapes — chosen so the model can recognize a no-op without a\n * separate read:\n * - `Created path (N bytes)` — file did not exist\n * - `Updated path (N bytes)` — content differed from on-disk\n * - `No change needed: path already at target state (N bytes)` — equal\n *\n * Race window: in non-process execution contexts (docker, sandbox) shared by\n * multiple agents, another writer can mutate the file between our read and\n * our write. Local process context is single-writer per agent so the race is\n * a non-issue there. Documented rather than locked because the cost of\n * cross-context locking outweighs the cost of a stale \"No change\" message.\n */\n\nexport const writeFile: ToolDef = {\n spec: {\n name: 'write_file',\n description: toolPrompts.write_file,\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'File path (relative to the execution-context cwd, or absolute).' },\n content: { type: 'string', description: 'Complete file content. Overwrites any existing file at `path`.' },\n },\n required: ['path', 'content'],\n },\n },\n async execute({ path, content }, ctx: ToolContext) {\n const targetPath = path as string\n const targetContent = content as string\n\n // Reasoning-leak backstop — reject pathologically-shaped paths with a\n // steering message instead of letting the fs surface ENAMETOOLONG.\n const pathErr = pathArgError(targetPath)\n if (pathErr) {\n ctx.reportOutcome?.('failed')\n throw new ToolFailure(`Write error: ${pathErr}`)\n }\n\n let existing: string | undefined\n try {\n existing = await ctx.execution.readFile(ctx.handle, targetPath)\n }\n catch {\n // File does not exist (or read failed for unrelated reasons — we'll let\n // writeFile surface that error). Either way: treat as a fresh write.\n }\n\n const bytes = Buffer.byteLength(targetContent)\n\n if (existing === targetContent) {\n ctx.reportOutcome?.('noop')\n return `No change needed: ${targetPath} already at target state (${bytes} bytes).`\n }\n\n await ctx.execution.writeFile(ctx.handle, targetPath, targetContent)\n\n // Seed read-state with the just-written bytes so a follow-up `edit` /\n // `multi_edit` on this path passes the `requireReadBeforeEdit` gate and\n // compares against current content — the model demonstrably knows the\n // file's bytes (it just authored them), so forcing a redundant `read_file`\n // would be pure overhead. Slice params mirror a full read (offset 0, no\n // limit) so a later partial re-read still invalidates cleanly. No-op\n // without a read-state map (sessionless, no shared map).\n const readState = resolveReadStateMap(ctx)\n if (readState) {\n readState.set(readStateKey(ctx.handle.cwd, targetPath), {\n contentHash: hashContent(targetContent),\n offset: 0,\n limit: Number.POSITIVE_INFINITY,\n maxBytes: Number.POSITIVE_INFINITY,\n mtimeMs: Date.now(),\n // The write superseded whatever a read previously put on the wire (and\n // on a fresh create there is no prior read output at all), so the next\n // re-read must serve the full body rather than dedup's \"the prior\n // result above is still current\" stub. The no-op branch above returns\n // before this seed, so an unchanged write never forfeits a dedup hit.\n elided: true,\n })\n }\n\n ctx.reportOutcome?.(existing === undefined ? 'created' : 'updated')\n return existing === undefined\n ? `Created ${targetPath} (${bytes} bytes).`\n : `Updated ${targetPath} (${bytes} bytes).`\n },\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAWA,SAAgB,yBAAyB,OAAgB,UAA0B;CACjF,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GACrD,OAAO;CAGT,IAAI,QAAQ,GACV,OAAO;CACT,OAAO,KAAK,MAAM,KAAK;AACzB;AAEA,SAAgB,wBACd,UACA,WAC0B;CAC1B,OAAO;EACL,WAAW,yBAAyB,UAAU,kBAAkB,OAAO,UAAU,SAAS;EAC1F,cAAc,yBAAyB,UAAU,kBAAkB,UAAU,UAAU,YAAY;EAGnG,oBAAoB,UAAU;CAChC;AACF;;;ACdA,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAMA,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;AACF;AAQA,MAAM,mBAA2D;CAC/D,eAAe;CACf,mBAAmB;CACnB,cAAc;CACd,gBAAgB;CAChB,0BAA0B;CAC1B,6BAA6B;CAC7B,gBAAgB;CAChB,mBAAmB;CACnB,eAAe;CACf,cAAc;CACd,cAAc;CACd,qBAAqB;CACrB,yBAAyB;CACzB,kBAAkB;CAClB,oBAAoB;CACpB,mBAAmB;CACnB,uBAAuB;CACvB,cAAc;CACd,qBAAqB;AACvB;AAEA,MAAM,2BAA0E;CAC9E,uBAAuB;CACvB,aAAa;CACb,iBAAiB;CACjB,kBAAkB;AACpB;AAMA,MAAM,yBAAyB;CAC7B,gBAAgB;CAChB,kBAAkB;CAClB,eAAe;AACjB;;;;;;;;;;;;AAaA,SAAS,mBAAmB,WAAmB,KAAoB;CACjE,IAAI,CAAC,QAAQ,IAAI,cACf;CACF,MAAM,UAAU,eAAe,QAAS,IAAI,SAAS,IAAI,UAAW,OAAO,GAAG;CAC9E,QAAQ,OAAO,MAAM,uCAAuC,UAAU,cAAc,QAAQ,GAAG;AACjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,YACd,YACA,aACA,SACA,OACY;CACZ,MAAM,cAAiC,CAAC;CAIxC,MAAM,OAAO,YAAY;CAazB,KAAK,MAAM,OAAO,gBAAgB;EAChC,MAAM,YAAY,iBAAiB;EACnC,MAAM,aAAa,WAAW,KAAK,MAAM,QAAgB;GACvD,QAAQ,QAAQ,KAAK,WAAW;IAAE,GAAI;IAAiC;IAAS;GAAM,CAAC,CAAC,CAAC,CACtF,OAAM,QAAO,mBAAmB,WAAW,GAAG,CAAC;EACpD,CAAC;EACD,YAAY,KAAK,UAAU;CAC7B;CAOA,MAAM,YAAY,QAAiC;EACjD,IAAI,YAAY;EAChB,IAAI,UAAU;CAChB;CACA,KAAK,MAAM,OAAO,wBAAwB;EACxC,MAAM,YAAY,yBAAyB;EAC3C,MAAM,aAAa,WAAW,KAAK,KAAK,OAAO,QAAgB;GAC7D,SAAS,GAA8B;GACvC,MAAM,KAAK,WAAW,GAA8B;EACtD,CAAC;EACD,YAAY,KAAK,UAAU;CAC7B;CAMA,KAAK,MAAM,CAAC,KAAK,cAAc,OAAO,QAAQ,sBAAsB,GAClE,YAAY,KAAK,WAAW,KAAK,MAAM,QAAgB;EACrD,MAAM,EAAE,gBAAgB,UAAU,GAAG,WAAW;EAChD,QAAQ,QAAQ,KAAK,WAAW;GAAE,GAAG;GAAQ,eAAe;EAAQ,CAAC,CAAC,CAAC,CACpE,OAAM,QAAO,mBAAmB,WAAW,GAAG,CAAC;CACpD,CAAC,CAAC;CAMJ,MAAM,YAAY,WAAW;CAI7B,MAAM,UAAmC,CACvC,GAAG,eAAe,KAAI,QAAO,iBAAiB,IAAI,GAElD,GAAG,OAAO,OAAO,sBAAsB,CACzC;CACA,KAAK,MAAM,aAAa,SACtB,YAAY,KAAK,UAAU,YAAY,QAAQ;EAC7C,QAAQ,QAAQ,KAAK,WAAW,GAA8B,CAAC,CAAC,CAC7D,OAAM,QAAO,mBAAmB,WAAW,GAAG,CAAC;CACpD,CAAC,CAAC;CAEJ,KAAK,MAAM,OAAO,wBAAwB;EACxC,MAAM,YAAY,yBAAyB;EAO3C,IAAI,cAAc,KAChB;EACF,YAAY,KAAK,UAAU,WAAW,OAAO,QAAQ;GAInD,MAAM,KAAK,WAAW,GAA8B;EACtD,CAAC,CAAC;CACJ;CAEA,aAAa;EACX,KAAK,MAAM,KAAK,aAAa,EAAE;CACjC;AACF;;;ACtOA,IAAI;;;;;;;AAQJ,SAAgB,kBAAsD;CACpE,gBAAgB,OAAO,sBAAW,CAAA,MAAA,MAAA,EAAA,CAAA;CAClC,OAAO;AACT;;;;;;AAyCA,eAAe,kBACb,KACA,KACA,KACA,IACA,KACyC;CACzC,MAAM,EAAE,gBAAgB,MAAM,gBAAgB;CAC9C,MAAM,EAAE,SAAS,iBAAiB;CAClC,MAAM,EAAE,aAAa,eAAe,eAAe;CAKnD,MAAM,gBAAgB,cAClB,uBAAuB,IAAI,OAAO,WAAW,IAC7C,IAAI;CAMR,MAAM,eAAe,wBAAwB,KAAK,WAAW;CAC7D,MAAM,eAAuB;EAC3B,GAAI,IAAI,SAAS,KAAA,IAAY,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;EACnD,GAAI,IAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EACzD,OAAO;EACP,GAAI,IAAI,gBAAgB,KAAA,IAAY,EAAE,aAAa,IAAI,YAAY,IAAI,CAAC;EACxE,GAAI,IAAI,qBAAqB,KAAA,IAAY,EAAE,kBAAkB,IAAI,iBAAiB,IAAI,CAAC;EACvF,GAAI,aAAa,eAAe,KAAA,IAAY,EAAE,YAAY,aAAa,WAAW,IAAI,CAAC;EACvF,GAAI,IAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EACzD,GAAI,IAAI,aAAa,KAAA,IAAY,EAAE,UAAU,IAAI,SAAS,IAAI,CAAC;CACjE;CAUA,MAAM,kBAAkB,QAAQ,iBAC5B,oBAAoB,GAAG,IACvB,KAAA;CAyBJ,MAAM,mBAAmB,uBAAuB,IAAI,KAAK;CACzD,MAAM,kBAAkB,mBACpB,sBAAsB,kBAAkB;EACtC,SAAS;EACT,GAAI,IAAI,UAAU,KAAA,IAAY,EAAE,aAAa,IAAI,MAAM,IAAI,CAAC;EAC5D,UAAU,kBAAkB,IAAI;CAClC,CAAC,IACD,KAAA;CACJ,MAAM,YAAY,IAAI,SAAS,SAAS;CACxC,MAAM,sBAAsB,aACvB,QAAQ,cAAc,KAAA,KACtB,QAAQ,YAAY,IACrB,QAAQ,YACR,KAAA;CACJ,MAAM,QAAQ,YAAY;EACxB,GAAG;EACH,GAAG,QAAQ;EAQX,GAAI,aAAa,iBAAiB,KAAA,KAAa,QAAQ,QAAQ,eAAe,KAAA,IAC1E,EAAE,cAAc,aAAa,aAAa,IAC1C,CAAC;EACL,UAAU;EACV,WAAW,IAAI;EAGf,GAAI,aAAa,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,QAAQ,IAAI,CAAC;EAInE,GAAI,IAAI,SAAS,cAAc,QAAQ,WAAW,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,QAAQ,IAAI,CAAC;EAMpG,GAAI,IAAI,QAAQ,EAAE,OAAO,IAAI,MAAM,IAAI,CAAC;EAIxC,GAAI,QAAQ,eAAe,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAIlE,GAAI,QAAQ,WAAW,IAAI,UAAU,EAAE,SAAS,IAAI,QAAQ,IAAI,CAAC;EACjE,GAAI,kBAAkB,EAAE,WAAW,gBAAgB,IAAI,CAAC;EACxD,GAAG;CACL,CAAC;CAUD,MAAM,MAAM,KAAK,eAAe,UAAU;EACxC,IAAI,gBAAgB;CACtB,CAAC;CA2BD,MAAM,cAAwC,IAAI,QAAQ,IAAI,MAAM,IAAI,IAAI,KAAK,IAAI;CACrF,MAAM,iBAAiB,MAAM,MAAM;CACnC,IAAI,wBAAwB,KAAA,GAC1B,MAAM,MAAM,KAAK,eAAe,YAAY;EAC1C,IAAI,IAAI,kBACN;EACF,IAAI,QAAQ,QAAQ,YAAY,iBAAiB,qBAC/C;EACF,IAAI,mBAAmB;EACvB,MAAM,MAAM;CACd,CAAC;CAEH,IAAI,cAAc;EAmBhB,MAAM,qBAAqB,MAAM,MAAM,KAAK,eAAe,OAAO,YAAY;GAC5E,IAAI,QAAQ,SAAS,gBAAgB,QAAQ,SAAS,UAAU,QAAQ,SAAS,cAC/E;GACF,IAAI,CAAC,MAAM,QACT;GACF,MAAM,YAAY,QAAQ,OAAO;GACjC,IAAI,OAAO,cAAc,UACvB;GACF,IAAI;IACF,QAAQ,eAAe,MAAM,MAAM,UAAU,SAAS,MAAM,QAAQ,SAAS;GAC/E,QACM,CAMN;EACF,CAAC;EACD,MAAM,gBAAgB,YAAY,MAAM,OAAO,IAAI,OAAO,IAAI,UAAU;EACxE,IAAI,iBAAiB;GACnB,mBAAmB;GACnB,cAAc;EAChB;CACF;CAEA,OAAO;EAAE;EAAO;EAAO;EAAgB;CAAoB;AAC7D;;AAGA,eAAsB,iBACpB,KACA,KACA,KACA,OACA,KAC2B;CAC3B,MAAM,EAAE,YAAY;CACpB,MAAM,aAAa,IAAI,MAAM;CAC7B,MAAM,EAAE,MAAM,gBAAgB,aAAa,eAAe,YAAY,gBAAgB,WAAW,aAAa,eAAe;CAC7H,MAAM,EAAE,OAAO;CACf,MAAM,EAAE,OAAO,OAAO,gBAAgB,wBAAwB,MAAM,kBAAkB,KAAK,KAAK,KAAK,IAAI,GAAG;CAE5G,QAAQ,UAAU,KAAK;CAOvB,MAAM,eAA+K;EACnL;EACA;EAKA,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAG3C,GAAI,gBAAgB,KAAA,IAAY,EAAE,gBAAgB,YAAY,IAAI,CAAC;EACnE,OAAO;EAGP,OAAO;EACP,UAAU,cAAc;EACxB,gBAAgB,CAAC;CACnB;CACA,MAAM,IAAI,MAAM,SAAS,gBAAgB,YAAY;CAOrD,MAAM,oBAAoB,OAAO,KAAK,aAAa,cAAc,CAAC,CAAC,SAAS,IACxE,OAAO,OAAO,EAAE,GAAG,aAAa,eAAe,CAAC,IAChD,KAAA;CAQJ,MAAM,kBACF,kBACG,aAAa,UACb,QAAQ;CAQf,MAAM,aAAa;EACjB,GAAI,eAAe,KAAA,IAAY,EAAE,OAAO,WAAW,IAAI,CAAC;EACxD,QAAQ;EACR,UAAU,aAAa,YAAY,QAAQ;EAC3C,OAAO;EACP,GAAI,QAAQ,WAAW,IAAI,QAAQ,EAAE,aAAa,IAAI,MAAM,IAAI,CAAC;EAMjE,GAAI,IAAI,SAAS,EAAE,cAAc,IAAI,OAAO,IAAI,CAAC;EAIjD,GAAI,QAAQ,WAAW,IAAI,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;EACzD,GAAI,oBAAoB,EAAE,gBAAgB,kBAAkB,IAAI,CAAC;CACnE;CAGA,MAAM,aAAa,IAAI,WACnB,MAAM,OAAO;EAAE,OAAO,IAAI,SAAS;EAAI,QAAQ,IAAI;EAAQ,KAAK;CAAW,CAAC,CAAC,CAAC,MAAK,UAAS,SAAS,QAAQ,uBAAO,IAAI,MAAM,cAAc,IAAI,SAAU,GAAG,8BAA8B,CAAC,CAAC,IAC7L,MAAM,IAAI;EAAE,QAAQ;EAAM,QAAQ,IAAI;EAAQ,GAAG;EAAY,GAAI,YAAY,EAAE,aAAa,UAAU,GAAG,IAAI,CAAC;CAAG,CAAC;CAGtH,MAAM,qBAA2B;EAC/B,MAAM,QAAQ,CAAC,CAAC,YAAY,KAAA,CAAS;CACvC;CACA,MAAM,EAAE,kBAAkB;CAC1B,IAAI,eAAe,SACjB,aAAa;MAEb,eAAe,iBAAiB,SAAS,cAAc,EAAE,MAAM,KAAK,CAAC;CACvE,IAAI;EACF,IAAI,aAAa,MAAM,gBACrB,YACA,wBAAwB,KAAA,IAAY,QAAQ,YAAY,KAAA,CAC1D;EAEA,IAAI,IAAI,WAAW,WACjB,MAAM,aAAa,aAAa,KAAK,IAAI,kBAAkB;EAO7D,MAAM,YAAY,aAAa,IAAI,UAAU,CAAC,CAAC;EAI/C,MAAM,QAAQ,iBAAiB,IAAI,UAAU;EAE7C,MAAM,YAAa,MAAM,MAAM,IAAK;EACpC,IAAI,IAAI,kBAAkB;GAIxB,IAAI,iBAAiB;GACrB,IAAI,SAAS,cAAc,GAAG,oBAAoB,oBAAoB;EACxE,OACK,IAAI,IAAI,OAAO,SAAS;GAC3B,IAAI,iBAAiB;GACrB,IAAI,SAAS,CACX,cAAc,GAAG,kBAAkB,UAAU,UAAU,UAAU,MACjE,WAAW,OACb,CAAC,CAAC,KAAK,IAAI;EACb,OACK;GACH,MAAM,WAAW,YAAY,MAAM,MAAM,GAAG,EAAE,CAAC;GAC/C,IAAI,eAAe,YAAY;GAC/B,IAAI,SAAS;IACX,cAAc,GAAG,iBAAiB,UAAU,UAAU,UAAU;IAChE,WAAW;IACX;IACA,YAAY;GACd,CAAC,CAAC,KAAK,IAAI;EACb;CACF,SACO,KAAK;EACV,IAAI,eAAe,mBACjB,MAAM;EAMR,MAAM,kBAAkB,eAAe,oBACnC,IAAI,YACJ,IAAI,mBACF,sBACA,KAAA;EACN,IAAI,oBAAoB,KAAA,GAAW;GACjC,IAAI,iBAAiB;GACrB,MAAM,MAAM;GAIZ,IAAI;IACF,IAAI,aAAa,MAAM;GACzB,QACM;IAKJ,IAAI,aAAa,IAAI,iBAAiB;KACpC,SAAS;KACT,UAAU;KACV,gBAAgB;KAChB,oBAAoB;KACpB,OAAO;KACP,SAAS;IACX;GACF;GACA,IAAI,SAAS,cAAc,GAAG,oBAAoB,gBAAgB;EACpE,OACK;GACH,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;GAChE,IAAI,iBAAiB;GAGrB,IAAI,aAAa,IAAI,iBAAiB;IACpC,SAAS;IACT,UAAU;IACV,gBAAgB;IAChB,oBAAoB;IACpB,OAAO;IACP,SAAS;GACX;GACA,IAAI,SAAS,cAAc,GAAG,WAAW,MAAM;GAC/C,MAAM,IAAI,MAAM,SAAS,eAAe;IAAE;IAAI;IAAM,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;IAAI,OAAO;IAAY,OAAO;IAAgB,UAAU,cAAc;IAAM;GAAM,CAAC;EACpL;CACF,UACQ;EACN,eAAe,oBAAoB,SAAS,YAAY;EACxD,MAAM,mBAAmB,KAAK,OAAO,IAAI,GAAG;CAC9C;CAIA,IAAI,IAAI,YAAY;EAClB,WAAW,WAAW,IAAI,WAAW;EACrC,WAAW,YAAY,IAAI,WAAW;EACtC,WAAW,kBAAkB,IAAI,WAAW;EAC5C,WAAW,sBAAsB,IAAI,WAAW;EAChD,WAAW,SAAS,IAAI,WAAW;EAInC,WAAW,WAAW,IAAI,WAAW;CACvC;CAKA,MAAM,gBAA+B;EACnC;EACA;EACA,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAC3C,OAAO,IAAI;EACX,OAAO;EACP,QAAQ,IAAI;EACZ,GAAI,IAAI,WAAY,SAAS,EAAE,QAAQ,IAAI,WAAY,OAAO,IAAI,CAAC;CACrE;CACA,QAAQ,aAAa,OAAO,IAAI,YAAa,IAAI,cAAc;CAC/D,MAAM,IAAI,MAAM,SAAS,kBAAkB,aAAa;CAExD,IAAI,IAAI,cAGN,MAAM,IAAI,MAAM,SAAS,eAAe;EACtC;EACA;EACA,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAC3C,OAAO;EACP,OAAO;EACP,UAAU,cAAc;EACxB,OAAO,IAAI;CACb,CAAC;CAGH,OAAO;EAAE;EAAI,QAAQ,IAAI;EAAgB,MAAM,IAAI;EAAc,SAAS,IAAI;EAAQ,GAAI,IAAI,aAAa,EAAE,OAAO,IAAI,WAAW,IAAI,CAAC;CAAG;AAC7I;;;;;;;;AASA,eAAsB,qBAAqB,KAAmB,KAAkB,SAAkB,KAAmB,UAAiD;CACpK,MAAM,EAAE,YAAY;CACpB,MAAM,KAAK,SAAS,SAAS,SAAS;CACtC,MAAM,QAAQ,eAAe,SAAS,QAAQ;CAC9C,MAAM,SAAS,gBAAgB,QAAQ;CACvC,MAAM,QAAQ,iBAAiB,KAAK;CACpC,MAAM,YAAY,aAAa,KAAK,CAAC,CAAC;CACtC,IAAI,OAAO;CACX,IAAI;CACJ,IAAI,WAAW,aAAa;EAC1B,OAAO,YAAY,QAAQ,MAAM,UAAS,MAAK,EAAE,UAAU,SAAS,MAAM,EAAE,SAAS,eAAe,CAAC,EAAE,OAAO,CAAC;EAC/G,UAAU;GAAC,cAAc,GAAG,iBAAiB,UAAU,UAAU,MAAM,QAAQ;GAAM,WAAW;GAAS;GAAI,QAAQ;EAAoB,CAAC,CAAC,KAAK,IAAI;CACtJ,OACK,IAAI,WAAW,WAClB,UAAU,CAAC,cAAc,GAAG,kBAAkB,UAAU,UAAU,MAAM,QAAQ,MAAM,WAAW,OAAO,CAAC,CAAC,KAAK,IAAI;MAGnH,UAAU,cAAc,GAAG,WAAW,SAAS,SAAS;CAE1D,MAAM,aAAa,IAAI,MAAM;CAC7B,WAAW,WAAW,MAAM;CAC5B,WAAW,YAAY,MAAM;CAC7B,WAAW,kBAAkB,MAAM;CACnC,WAAW,sBAAsB,MAAM;CACvC,WAAW,SAAS,MAAM;CAC1B,WAAW,WAAW,MAAM;CAC5B,QAAQ,aAAa;EAAE;EAAI,MAAM,IAAI;EAAM,WAAW,SAAS;EAAW,OAAO,IAAI;CAAW,GAAG,OAAO,MAAM;CAChH,MAAM,IAAI,MAAM,SAAS,kBAAkB;EACzC;EACA,MAAM,IAAI;EACV,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;EAC3C;EACA,OAAO,IAAI;EACX;CACF,CAAC;CACD,OAAO;EAAE;EAAI;EAAQ;EAAM;EAAS;CAAM;AAC5C;AAEA,SAAS,gBAAgB,KAAuD;CAC9E,OAAO,IAAI,WAAW,cAAc,cAAc,IAAI,WAAW,UAAU,UAAU;AACvF;;AAGA,SAAS,eAAe,SAAkB,KAA6B;CACrE,MAAM,YAAyB,IAAI,aAAa,CAAC;CACjD,MAAM,OAAO,SAAuD,UAAU,QAAQ,GAAG,MAAM,KAAK,KAAK,CAAC,KAAK,IAAI,CAAC;CACpH,MAAM,WAA4B,QAAQ,KACvC,QAAO,MAAK,EAAE,gBAAgB,IAAI,EAAE,CAAC,CACrC,KAAI,OAAM;EACT,IAAI,EAAE,SAAS,EAAE;EACjB,MAAM,EAAE;EACR,GAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,IAAI,CAAC;EACnD,OAAO,eAAe,SAAS,CAAC;EAChC,GAAI,EAAE,UAAU,KAAA,IAAY,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;EAClD,QAAQ,gBAAgB,CAAC;CAC3B,EAAE;CACJ,MAAM,QAAQ,KAAa,SAA4C,SAAS,QAAQ,GAAG,MAAM,IAAI,KAAK,EAAE,KAAK,GAAG,GAAG;CACvH,MAAM,OAAO,KAAK,IAAI,QAAQ,IAAG,MAAK,EAAE,QAAQ,CAAC;CACjD,OAAO;EACL,SAAS,KAAK,IAAI,YAAY,KAAI,MAAK,EAAE,KAAK,IAAG,MAAK,EAAE,OAAO;EAC/D,UAAU,KAAK,IAAI,aAAa,KAAI,MAAK,EAAE,MAAM,IAAG,MAAK,EAAE,QAAQ;EACnE,gBAAgB,KAAK,KAAI,MAAK,EAAE,SAAS,IAAG,MAAK,EAAE,cAAc;EACjE,oBAAoB,KAAK,KAAI,MAAK,EAAE,aAAa,IAAG,MAAK,EAAE,kBAAkB;EAC7E,OAAO,IAAI,SAAS,UAAU;EAC9B,SAAS,KAAK,IAAI,IAAI,IAAI,WAAW,IAAI,aAAa,IAAI,SAAS;EACnE,GAAI,UAAU,SAAS,IAAI,EAAE,UAAU,IAAI,CAAC;EAC5C,GAAI,OAAO,IAAI,EAAE,KAAK,IAAI,CAAC;EAC3B,GAAI,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;CAC5C;AACF;;;;;AAMA,eAAe,mBAAmB,KAAkB,OAAc,IAAY,KAAmC;CA+B/G,MAAM,cAAc,MAAM;CAC1B,IAAI,eAAe,YAAY,OAAO,IAAI,OAAO,MAAM,IAAI,UAAU,yBACnE,IAAI;EACF,MAAM,aAAa,MAAM,IAAI,UAAU,wBACrC,aACA,IAAI,SACH,SAAS;GACR,QAAa,QAAQ,IAAI,MAAM,SAAS,mBAAmB,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;EAClF,CACF;EACA,KAAK,MAAM,SAAS,YAClB,MAAM,IAAI,MAAM,SAAS,uBAAuB;GAC9C,QAAQ,MAAM;GACd,cAAc,YAAY;GAC1B,YAAY,IAAI,OAAO;GACvB,SAAS;GACT,KAAK,MAAM;GACX,SAAS,MAAM;GACf,YAAY,MAAM;GAClB,WAAW,MAAM;EACnB,CAAC;CAEL,SACO,KAAK;EAKV,IAAI,QAAQ,IAAI,cACd,QAAQ,OAAO,MAAM,kDAAkD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,GAAG;CAC/H;CAKF,IAAI;EACF,MAAM,MAAM,QAAQ;CACtB,SACO,KAAK;EACV,IAAI,eAAe,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;CACvE;AACF;;;;;;;;;AC5lBA,SAAgB,oBAAoB,KAAmB,OAAuB,KAAgE;CAC5I,MAAM,EAAE,SAAS,UAAU,kBAAkB,iBAAiB;CAC9D,MAAM,OAAO,MAAM;CACnB,MAAM,iBAAiB,MAAM;CAC7B,MAAM,wBAAwB,OAAO,MAAM,kBAAkB,WACzD,MAAM,gBACN,KAAA;CAMJ,MAAM,cAAc,yBAAyB,oBAAoB,OAAO,OAAO,kBAAkB,qBAAqB,IAClH,iBAAiB,yBACjB,KAAA;CAQJ,MAAM,iBAAiB,gBAAgB,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,MAAM,KAC7F,MAAM,MAAM,KAAK,IACjB,KAAA;CACJ,IAAI,kBAAkB,gBAAgB,CAAC,aAAa,MAAK,MAAK,EAAE,MAAM,OAAO,cAAc,GAAG;EAC5F,MAAM,OAAO,kBAAkB,cAAc,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC;EACvE,MAAM,QAAQ,KAAK,SAAS,IAAI,OAAO,aAAa,MAAM,GAAG,CAAC;EAC9D,OAAO,EACL,SAAS;GACP,QAAQ;GACR,MAAM;GACN,SAAS,gCAAgC,eAAe,KAAK,KAAK,SAAS,IAAI,oBAAoB,YAAY,IAAI,MAAM,KAAI,MAAK,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,IACrJ,aAAa,SAAS,MAAM,SAAS,OAAO,aAAa,OAAO,uCAAuC;EAC3G,EACF;CACF;CACA,MAAM,gBAAgB,kBAAkB,aAAa,SAAS,QAAQ;CAOtE,IAAI,gBAAgB,IAAI;CACxB,MAAM,cAAc,iBAAiB,eACjC,aAAa,MAAK,MAAK,EAAE,MAAM,OAAO,aAAa,IACnD,KAAA;CACJ,IAAI,aAAa;EACf,MAAM,SAAS,sBAAsB,YAAY,UAAU,GAAG;EAC9D,IAAI,QACF,gBAAgB;OAEb,IAAI,mBAAmB,KAAA,GAC1B,OAAO,EACL,SAAS;GACP,QAAQ;GACR,MAAM;GACN,SAAS,wBAAwB,cAAc,2BAA2B,YAAY,SAAS,gFAAgF,gBAAgB,aAAa,SAAA,IAAgC,wBAAwB,GAAG;EACzQ,EACF;CAEJ;CAMA,MAAM,iBAAiB,kBAAkB,IAAI,WAAW,IAAI,QAAQ,KAAA;CACpE,MAAM,aAAa,iBAAiB;CACpC,MAAM,iBAAiB,cAAc,cAAc,KAAK;CAWxD,IAAI;CACJ,IAAI;CACJ,IAAI,MAAM,WAAW,KAAA,KAAa,MAAM,WAAW,MAAM;EAIvD,IAAI,OAAO,MAAM,WAAW,YAAY,MAAM,OAAO,KAAK,MAAM,IAC9D,OAAO,EAAE,SAAS;GAAE,QAAQ;GAAY,MAAM;GAAI,SAAS,uCAAuC,KAAK,UAAU,MAAM,MAAM,EAAE;EAAsC,EAAE;EAEzK,MAAM,SAAS,MAAM,OAAO,KAAK;EACjC,IAAI,CAAC,QAAQ,WAAW,CAAC,IAAI,SAC3B,OAAO,EAAE,SAAS;GAAE,QAAQ;GAAY,MAAM;GAAI,SAAS;EAA0K,EAAE;EAEzO,MAAM,YAAY,YAAY,IAAI,OAAO;EACzC,IAAI,QAAQ,UAAU,WAAU,MAAK,EAAE,UAAU,MAAM;EACvD,IAAI,QAAQ,GAAG;GACb,MAAM,aAAa,gBAAgB,KAAK,MAAM;GAM9C,MAAM,aAAa,UAAU,MAAK,MAAK,EAAE,UAAU,KAAA,CAAS;GAC5D,QAAQ,cAAc,CAAC,aACnB,OAAO,WAAW,EAAE,IAAI,IACxB,UAAU,WAAU,MAAK,EAAE,OAAO,MAAM;EAC9C;EACA,MAAM,MAAM,SAAS,IAAI,UAAU,SAAS,KAAA;EAC5C,IAAI,CAAC,KACH,OAAO,EAAE,SAAS;GAAE,QAAQ;GAAY,MAAM;GAAI,SAAS,wCAAwC,OAAO,kCAAkC,kBAAkB,IAAI,OAAO;EAAI,EAAE;EAEjL,MAAM,WAAW,IAAI,SAAS,SAAS,QAAQ;EAC/C,IAAI,IAAI,WAAW,WACjB,OAAO,EAAE,SAAS;GAAE,QAAQ;GAAY,MAAM;GAAI,SAAS,kBAAkB,SAAS;EAAyF,EAAE;EAInL,MAAM,QAAQ,kBAAkB,IAAI,QAAQ,MAAM,IAAI,EAAE;EACxD,IAAI,CAAC,IAAI,QAAQ,MAAM,MAAK,MAAK,EAAE,UAAU,KAAA,KAAa,MAAM,IAAI,EAAE,KAAK,CAAC,GAC1E,OAAO,EAAE,SAAS;GAAE,QAAQ;GAAY,MAAM;GAAI,SAAS,kBAAkB,SAAS;EAAqH,EAAE;EAE/M,YAAY;EACZ,cAAc;CAChB;CAEA,MAAM,cAAc,IAAI,SAAS;CACjC,MAAM,aAAa,cAAc;CAKjC,IAAI,aAAa,UACf,OAAO,EAAE,SAAS;EAAE,QAAQ;EAAY,MAAM;EAAI,SAAS,0BAA0B,SAAS,yBAAyB,YAAY;CAAuD,EAAE;CAM9L,IAAI,IAAI,OAAO,SACb,OAAO,EAAE,SAAS;EAAE,QAAQ;EAAW,MAAM;EAAI,SAAS,uEAAuE,KAAK,MAAM,GAAG,EAAE,EAAE;CAAG,EAAE;CAG1J,MAAM,WAAW,qBAAqB,GAAG;CACzC,OAAO;EAAE;EAAM;EAAgB;EAAa;EAAe;EAAY;EAAgB;EAAW;EAAa;EAAY,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;CAAG;AAC/J;;;;;;;AAQA,SAAS,qBAAqB,KAA0C;CACtE,IAAI,CAAC,IAAI,SAAS,cAAc,CAAC,IAAI,WAAW,IAAI,UAAU,KAAA,KAAa,IAAI,WAAW,KAAA,GACxF,OAAO,KAAA;CACT,OAAO,IAAI,QAAQ,KAAK,MAAK,MAAK,EAAE,gBAAgB,IAAI,SAAS,EAAE,iBAAiB,IAAI,MAAM;AAChG;;;;;AAMA,eAAsB,aAAa,KAAmB,OAAuB,KAA6C;CACxH,MAAM,EAAE,OAAO,kBAAkB;CACjC,MAAM,gBAAgB,MAAM;CAC5B,MAAM,WAAW,oBAAoB,KAAK,OAAO,GAAG;CACpD,IAAI,aAAa,UACf,OAAO,SAAS;CAClB,MAAM,EAAE,MAAM,eAAe;CAE7B,IAAI,SAAS,YAAY,SAAS,SAAS,cAAc,QAAQ,IAAI,SACnE,OAAO,qBAAqB,KAAK,KAAK,IAAI,SAAS,UAAU,SAAS,QAAQ;CAEhF,IAAI,MAAM,cAAc,eACtB,MAAM;MAEH,IAAI,aAAa,GAIpB,OAAO;EAAE,QAAQ;EAAY,MAAM;EAAI,SAAS,iBAAiB,MAAM,YAAY,GAAG,cAAc;CAA4K;MAE7Q;EAEH,MAAM,UAAU,MAAM,YAAY,KAAK,KAAK,MAAM,UAAU;EAC5D,IAAI,SACF,OAAO;EAET,IAAI,IAAI,OAAO,SAAS;GACtB,YAAY,KAAK;GACjB,OAAO;IAAE,QAAQ;IAAW,MAAM;IAAI,SAAS,oBAAoB,IAAI;GAAE;EAC3E;CACF;CAOA,MAAM,KAAK,SAAS,UAAU,UACxB,IAAI,UAAU,kBAAkB,IAAI,OAAO,IAAI,SAAS,EAAE,MAAM;CACtE,MAAM,QAAoB;EAAE;EAAI;EAAM,WAAW,KAAK,IAAI;EAAG,OAAO;CAAW;CAC/E,cAAc,IAAI,IAAI,KAAK;CAE3B,MAAM,MAAqB;EACzB,cAAc,KAAA;EACd,gBAAgB;EAChB,YAAY,KAAA;EACZ,QAAQ;EACR,cAAc;EAGd,UAAU,KAAA;EACV,eAAe,KAAA;EACf,kBAAkB;CACpB;CAEA,IAAI;EACF,OAAO,MAAM,iBAAiB,KAAK,KAAK,UAAU,OAAO,GAAG;CAC9D,UACQ;EACN,IAAI,WAAW;EACf,YAAY,KAAK;EACjB,cAAc,OAAO,EAAE;CACzB;AACF;;AAGA,SAAS,YAAY,OAAiC;CACpD,MAAM,OAAO,MAAM,QAAQ,MAAM;CACjC,IAAI,MACF,KAAK;MAEL,MAAM;AACV;;;;;;AAOA,eAAe,YAAY,KAAmB,KAAkB,MAAc,OAAiD;CAC7H,MAAM,EAAE,OAAO,kBAAkB;CACjC,IAAI,UAAU;CACd,IAAI,oBAAgE,CAAC;CACrE,MAAM,OAAO,IAAI,SAAkC,YAAY;EAC7D,cAAc;CAChB,CAAC;;CAED,MAAM,cAAuB;EAC3B,MAAM,KAAK,MAAM,QAAQ,QAAQ,MAAM;EACvC,IAAI,MAAM,GACR,MAAM,QAAQ,OAAO,IAAI,CAAC;EAC5B,IAAI,OAAO,oBAAoB,SAAS,OAAO;EAC/C,OAAO,MAAM;CACf;CACA,SAAS,SAAe;EACtB,UAAU;EACV,IAAI,OAAO,oBAAoB,SAAS,OAAO;EAC/C,YAAY,IAAI;CAClB;CACA,SAAS,UAAgB;EACvB,IAAI,MAAM,GACR,YAAY;GAAE,QAAQ;GAAW,MAAM;GAAI,SAAS,oBAAoB,IAAI;EAAE,CAAC;CACnF;CACA,MAAM,QAAQ,KAAK,MAAM;CACzB,IAAI,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC5D,IAAI;EACF,MAAM,IAAI,MAAM,SAAS,gBAAgB;GACvC;GACA,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;GAC3C;GACA,YAAY;IAAE,QAAQ,MAAM;IAAa,KAAK;GAAc;EAC9D,CAAC;CACH,SACO,KAAK;EAGV,IAAI,CAAC,MAAM,KAAK,SACd,YAAY,KAAK;EACnB,MAAM;CACR;CACA,OAAO;AACT;AAEA,SAAS,oBAAoB,MAAsB;CACjD,OAAO,oFAAoF,KAAK,MAAM,GAAG,EAAE,EAAE;AAC/G;;;;;;;;;;;;;;ACmEA,SAAgB,sBAAqE,QAAW,SAAsD;CACpJ,MAAM,QAAQ,OAAO,OAAO;CAC5B,OAAO,SAAS,YAAY,KAAK,IAAI;EAAE,GAAG;EAAQ,OAAO;GAAE,GAAG,OAAO;GAAO,OAAO,MAAM,SAAS,OAAO;EAAE;CAAE,IAAI;AACnH;AAEA,SAAS,mBAAuC;CAC9C,OAAO;EACL,0BAAU,IAAI,IAAwB;EACtC,OAAO;GAAE,SAAS;GAAG,UAAU;GAAG,gBAAgB;GAAG,oBAAoB;GAAG,OAAO;GAAG,SAAS;EAAE;EACjG,SAAS;EACT,aAAa;EACb,SAAS,CAAC;CACZ;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,gBAAgB,UAA4B,CAAC,GAAc;CAEzE,gBAAqB,CAAC,CAAC,YAAY,CAAC,CAAC;CACrC,OAAO,eAAe,SAAS,iBAAiB,CAAC;AACnD;;;;;;;AAQA,SAAS,eAAe,SAA2B,OAAsC;CACvF,MAAM,gBAAgB,MAAM;CAC5B,MAAM,aAAa,MAAM;CACzB,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,eAAe,QAAQ,gBAAgB;CAS7C,MAAM,mBAAmB,QAAQ;CAEjC,MAAM,mBADqB,CAAC,CAAC,oBAAoB,OAAO,KAAK,gBAAgB,CAAC,CAAC,SAAS,IAEpF,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,gBAAiB,GAAG,iBAAiB,CAAC,CAAC,IACnE,CAAC;CACL,MAAM,uBAAuB,iBAAiB,SAAS,IACnD,EACE,eAAe;EACb,MAAM;EACN,MAAM;EACN,aAAa,6BAA6B,gBAAiB;CAC7D,EACF,IACA,CAAC;CAOL,MAAM,eAAe,QAAQ,UAAU,QAAQ,OAAO,SAAS,IAAI,QAAQ,SAAS,KAAA;CACpF,MAAM,gBAAgB,eAClB,EACE,OAAO;EACL,MAAM;EACN,aAAa,2BAA2B,YAAY;CACtD,EACF,IACA,CAAC;CAKL,MAAM,iBAAiB,QAAQ,UAC3B,EACE,QAAQ;EACN,MAAM;EACN,aAAa;CACf,EACF,IACA,CAAC;CAEL,MAAM,MAAoB;EAAE;EAAS;EAAO;EAAe;EAAU;EAAc;EAAkB;CAAa;CAClH,MAAM,OAAmC;EACvC;EACA,IAAI,WAAW;GAAE,OAAO;EAAc;EACtC,IAAI,kBAAkB;GAAE,OAAO,EAAE,GAAG,WAAW;EAAE;EASjD,cAAc,OAAO,WAAW;GAG9B,MAAM,SAA2B,OAAO,OAAO,OAAO,OAAO,IAAI,GAAG,QAAQ,WAAW,KAAK;GAC5F,IAAI,WACF,KAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,SAAS,GAAG;IAClD,MAAM,OAAO,GAAG,OAAO,OAAO,QAAQ,IAAI,IAAI,OAAO,QAAQ,KAAA,CAAS;IACtE,IAAI,SAAS,KAAA,GACX,OAAO,OAAO;SAEd,OAAO,QAAQ;GACnB;GAEF,OAAO,eAAe;IAAE,GAAG;IAAS,WAAW;GAAO,GAAG,KAAK;EAChE;EAOA,WAAW,QAAQ;GACjB,OAAO,eAAe;IAAE,GAAG;IAAS;GAAO,GAAG,KAAK;EACrD;EAEA,SAAS,WAAW;GAClB,MAAM,gBAAgB,WAAW;GACjC,OAAO,eAAe,kBAAkB,KAAA,IAAY,UAAU;IAAE,GAAG;IAAS;GAAc,GAAG,iBAAiB,CAAC;EACjH;EAQA,mBAAmB;EAMnB,iBAAiB;EAEjB,MAAM;GACJ,MAAM;GACN,aAAa,YAAY,MAAM,QAC1B,eAAe,YAAY,MAAM,eAAe,OAChD,QAAQ,UAAU,YAAY,MAAM,SAAS;GAClD,aAAa;IACX,MAAM;IACN,YAAY;KACV,MAAM;MACJ,MAAM;MACN,aAAa;KACf;KACA,QAAQ;MACN,MAAM;MACN,aAAa;KACf;KACA,GAAG;KACH,GAAG;KACH,GAAG;IACL;IACA,UAAU,CAAC,MAAM;GACnB;GACA,cAAc;EAChB;EAEA,MAAM,QAAQ,OAAgC,KAAmC;GAI/E,MAAM,UAAU,MAAM,KAAK,QAAQ,OAAoC,GAAG;GAE1E,IAAI,QAAQ,WAAW,YACrB,MAAM,IAAI,MAAM,QAAQ,OAAO;GAEjC,IAAI,mBAAmB,sBAAsB,OAAO,CAAC;GACrD,OAAO,QAAQ;EACjB;EAEA,MAAM,QAAQ,OAAuB,KAA6C;GAChF,OAAO,aAAa,KAAK,OAAO,GAAG;EACrC;CACF;CACA,OAAO;AACT;;;;AC7mBA,MAAa,uBAAuB;;;;AAKpC,MAAa,iBAA0B;CACrC,mBAAmB;CACnB,MAAM;EACJ,MAAM;EACN,aAAa,YAAY;EACzB,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KACJ,MAAM;KACN,aAAa;IACf;IACA,KAAK;KACH,MAAM;KACN,aAAa;IACf;IACA,OAAO;KAAE,MAAM;KAAU,aAAa;IAA0C;IAChF,MAAM;KAAE,MAAM;KAAU,aAAa;IAAoF;GAC3H;GACA,UAAU,CAAC,QAAQ,KAAK;GACxB,sBAAsB;EACxB;CACF;CACA,MAAM,QAAQ,OAAwB;EACpC,MAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,KAAK,IAAI;EAClE,MAAM,MAAM,OAAO,MAAM,QAAQ,WAAW,MAAM,IAAI,KAAK,IAAI;EAC/D,IAAI,CAAC,QAAQ,CAAC,sBAAsB,KAAK,IAAI,GAC3C,MAAM,IAAI,YAAY,yDAAyD,KAAK,UAAU,MAAM,IAAI,EAAE,GAAG;EAC/G,IAAI,CAAC,KACH,MAAM,IAAI,YAAY,yCAAyC;EACjE,IAAI,IAAI,SAAA,MACN,MAAM,IAAI,YAAY,sCAAsC,uBAAuB,aAAa;EAClG,MAAM,QAAQ,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,IAAI,MAAM,MAAM,KAAK,IAAI;EAC3F,MAAM,UAAU,MAAM,SAAA,MAAoC,GAAG,MAAM,MAAM,GAAA,GAA+B,EAAE,KAAK;EAG/G,OAAO,YAAY,KAAK,aAAa,UAAU,YAAY,MAAM,KAAK,IAAI,KAAK;CACjF;AACF;;;ACtDA,SAASA,YAAU,OAA+B;CAChD,OAAO,OAAO,UAAU,WAAW,QAAQ,MAAM;AACnD;;;;;;;;;AAUA,eAAsB,gBACpB,WACA,QACA,MACwB;CACxB,MAAM,QAAQ,KAAK,YAAY,GAAG;CAClC,MAAM,MAAM,UAAU,KAAK,MAAO,KAAK,MAAM,GAAG,KAAK,KAAK;CAC1D,MAAM,SAAS,UAAU,KAAK,OAAO,KAAK,MAAM,QAAQ,CAAC;CACzD,MAAM,MAAM,OAAO,YAAY,GAAG;CAClC,MAAM,aAAa,QAAQ,KAAK,SAAS,OAAO,MAAM,GAAG,GAAG;CAE5D,IAAI,WAAW,WAAW,GACxB,OAAO;CAET,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,UAAU,UAAU,QAAQ,GAAG;CACjD,QACM;EACJ,OAAO;CACT;CAEA,KAAK,MAAM,QAAQ,SAAS;EAC1B,MAAM,QAAQA,YAAU,IAAI;EAC5B,IAAI,UAAU,QACZ;EACF,MAAM,WAAW,MAAM,YAAY,GAAG;EAEtC,KADkB,aAAa,KAAK,QAAQ,MAAM,MAAM,GAAG,QAAQ,OACjD,YAChB,OAAO;CACX;CACA,OAAO;AACT;;;;;;AAOA,eAAsB,cACpB,WACA,QACA,MACiB;CACjB,MAAM,UAAU,MAAM,gBAAgB,WAAW,QAAQ,IAAI;CAC7D,OAAO,UAAU,iBAAiB,QAAQ,KAAK;AACjD;;;;;;;;AChDA,MAAa,2BAA2B;;;;;AAMxC,eAAsB,iBACpB,WACA,QACA,MACA,MACwB;CACxB,MAAM,OAAO,MAAM,UAAU,WAAW,QAAQ,IAAI,KAAK;CACzD,IAAI,SAAS,QAAQ,QAAA,WACnB,OAAO;CACT,MAAM,KAAK,KAAK,MAAM,OAAO,OAAO,IAAI;CACxC,MAAM,QAAQ,2BAA2B,OAAO;CAChD,OAAO,SAAS,SACZ,sBAAsB,KAAK,IAAI,KAAK,MAAM,GAAG,yBAAyB,MAAM,oEAC5E,sBAAsB,KAAK,IAAI,KAAK,MAAM,GAAG,yBAAyB,MAAM;AAClF;;;;;;;;;;;ACxBA,MAAa,OAAgB;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa,YAAY;EACzB,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;IAAkE;IACvG,YAAY;KAAE,MAAM;KAAU,aAAa;IAA2B;IACtE,YAAY;KAAE,MAAM;KAAU,aAAa;IAAyB;IACpE,aAAa;KAAE,MAAM;KAAW,aAAa;IAA4C;GAC3F;GACA,UAAU;IAAC;IAAQ;IAAc;GAAY;EAC/C;CACF;CACA,MAAM,QAAQ,EAAE,MAAM,YAAY,YAAY,eAAe,KAAkB;EAC7E,MAAM,SAAS;EACf,MAAM,OAAO;EACb,MAAM,cAAc;EACpB,MAAM,aAAa,gBAAgB;EAEnC,MAAM,UAAU,aAAa,MAAM;EACnC,IAAI,SAAS;GACX,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,eAAe,SAAS;EAChD;EAEA,IAAI,SAAS,aAAa;GACxB,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,6EAA6E,OAAO,+FAA+F;EAC3M;EAEA,IAAI,KAAK,WAAW,GAAG;GACrB,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,sFAAsF;EAC9G;EAEA,MAAM,UAAU,MAAM,iBAAiB,IAAI,WAAW,IAAI,QAAQ,QAAQ,MAAM;EAChF,IAAI,SAAS;GACX,IAAI,gBAAgB,QAAQ;GAC5B,OAAO;EACT;EAEA,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,MAAM;EAC5D,SACO,KAAK;GAGV,MAAM,UAAU,aAAa,GAAG;GAChC,IAAI,wBAAwB,OAAO,GAAG;IACpC,IAAI,gBAAgB,QAAQ;IAC5B,OAAO,4BAA4B,OAAO,IAAI,QAAQ;GACxD;GACA,MAAM,OAAO,MAAM,cAAc,IAAI,WAAW,IAAI,QAAQ,MAAM;GAClE,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,+BAA+B,OAAO,GAAG,MAAM;EACvE;EAyBA,IAAI,QAAmF;EACvF,IAAI,IAAI,UAAU,uBAAuB;GACvC,MAAM,YAAY,oBAAoB,GAAG;GACzC,IAAI,WAAW;IACb,MAAM,SAAS,aAAa,IAAI,OAAO,KAAK,MAAM;IAClD,MAAM,QAAQ,UAAU,IAAI,MAAM;IAClC,IAAI,CAAC,OAAO;KACV,IAAI,gBAAgB,QAAQ;KAC5B,MAAM,IAAI,YAAY,eAAe,OAAO,2GAA2G,IAAI,UAAU,oBAAoB,QAAQ,2DAA2D,2DAA4D;IAC1T;IACA,IAAI,MAAM,gBAAgB,YAAY,QAAQ,GAC5C,QAAQ;KAAE;KAAW;KAAQ;IAAM;GACvC;EACF;EAOA,MAAM,QAAQ,iBAAiB,UAAU,IAAI;EAE7C,IAAI,CAAC,OAAO;GACV,IAAI,gBAAgB,QAAQ;GAG5B,IAAI,OACF,OAAO,iBAAiB,QAAQ,KAAK;GACvC,MAAM,UAAU,oBAAoB,UAAU,IAAI;GAClD,MAAM,IAAI,YAAY,UAClB,uCAAuC,OAAO,+BAA+B,YAC7E,uCAAuC,OAAO,EAAE;EACtD;EAEA,MAAM,EAAE,QAAQ,aAAa,QAAQ;EAErC,IAAI,cAAc,KAAK,CAAC,YAAY;GAClC,IAAI,gBAAgB,QAAQ;GAG5B,IAAI,OACF,OAAO,iBAAiB,QAAQ,KAAK;GACvC,MAAM,IAAI,YAAY,kCAAkC,YAAY,YAAY,OAAO,6DAA6D;EACtJ;EAQA,IAAI,SAAS,QAAQ,SAAS;GAC5B,IAAI,gBAAgB,QAAQ;GAC5B,OAAO,iBAAiB,QAAQ,KAAK;EACvC;EAEA,MAAM,oBAAoB,uBAAuB,aAAa,KAAK,MAAM;EAEzE,MAAM,UAAU,aACZ,SAAS,MAAM,MAAM,CAAC,CAAC,KAAK,iBAAiB,IAC7C,SAAS,QAAQ,QAAQ,iBAAiB;EAE9C,IAAI,YAAY,UAAU;GACxB,IAAI,gBAAgB,MAAM;GAC1B,MAAM,IAAI,YAAY,iDAAiD,OAAO,EAAE;EAClF;EAEA,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,QAAQ,OAAO;EAiBzD,MAAM,YAAY,oBAAoB,GAAG;EACzC,IAAI,WAAW;GACb,MAAM,SAAS,aAAa,IAAI,OAAO,KAAK,MAAM;GAClD,MAAM,QAAQ,UAAU,IAAI,MAAM;GAClC,IAAI,OACF,UAAU,IAAI,QAAQ;IAAE,GAAG;IAAO,aAAa,YAAY,OAAO;IAAG,SAAS,KAAK,IAAI;IAAG,QAAQ;IAAM,iBAAiB;GAAE,CAAC;EAChI;EAEA,IAAI,gBAAgB,QAAQ;EAG5B,MAAM,UAAU,QAAQ,UAAU,KAAK,oDAAoD,YAAY,GAAG,EAAE;EAI5G,OAAO,UAAU,OAAO,aAAa,YAAY,aAAa,gBAAgB,IAAI,KAAK,IAAI,GAAG,UAD5E,QAAQ,oIAAoI;CAEhK;AACF;;;;;;AAOA,SAAS,iBAAiB,QAAgB,OAAkF;CAC1H,MAAM,QAAQ,mBAAmB,MAAM,WAAW,MAAM,QAAQ,MAAM,KAAK;CAC3E,MAAM,IAAI,YAAY,eAAe,OAAO,4EAA4E,iBAAiB,KAAK,GAAG;AACnJ;;;;;;;;;;AAWA,SAAS,oBAAoB,UAAkB,QAA+B;CAK5E,MAAM,kBADmB,wBAAwB,MACV,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;CACrD,IAAI,gBAAgB,SAAS,GAC3B,OAAO;CAET,MAAM,QAAQ,SAAS,MAAM,IAAI;CACjC,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,QAAQ,mBAAmB,MAAM,IAAI,eAAe;EAC1D,IAAI,QAAQ,WAAW;GACrB,YAAY;GACZ,UAAU;EACZ;CACF;CACA,IAAI,UAAU,KAAK,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,gBAAgB,SAAS,CAAC,CAAC,GAC/E,OAAO;CAET,MAAM,UAAU,MAAM,QAAQ,CAAC,MAAM,GAAG,EAAE;CAC1C,OAAO,QAAQ,UAAU,EAAE,IAAI,KAAK,UAAU,OAAO;AACvD;AAEA,SAAS,mBAAmB,GAAW,GAAmB;CACxD,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;CACvC,IAAI,IAAI;CACR,OAAO,IAAI,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,GAClD;CACF,OAAO;AACT;;;AC7PA,SAAS,UAAU,OAA+B;CAChD,OAAO,OAAO,UAAU,WAAW,QAAQ,MAAM;AACnD;;;;;AAMA,MAAM,cAAc;;AAGpB,MAAa,YAAqB;CAEhC,mBAAmB;CAEnB,QAAQ;CACR,MAAM;EACJ,MAAM;EACN,aAAa,YAAY;EACzB,aAAa;GACX,MAAM;GACN,YAAY,EACV,MAAM;IAAE,MAAM;IAAU,aAAa;GAAwF,EAC/H;GACA,UAAU,CAAC;EACb;CACF;CACA,MAAM,QAAQ,EAAE,QAAQ,KAAkB;EACxC,MAAM,SAAU,QAAmB;EACnC,IAAI;GACF,MAAM,UAAU,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,MAAM;GAChE,IAAI,QAAQ,SAAS,aACnB,OAAO,GAAG,QAAQ,MAAM,GAAG,WAAW,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE,MAAM,QAAQ,SAAS,YAAY;GACvG,OAAO,QAAQ,IAAI,SAAS,CAAC,CAAC,KAAK,IAAI,KAAK;EAC9C,SACO,KAAK;GAIV,IAAI,gBAAgB,QAAQ;GAG5B,MAAM,UAAU,aAAa,GAAG;GAChC,IAAI,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,iBAAiB,GACnE,OAAO,oBAAoB,OAAO;GACpC,IAAI,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,OAAO,KAAK,QAAQ,SAAS,mBAAmB,GACjG,OAAO,sBAAsB,OAAO;GACtC,IAAI,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,cAAc,GAC/D,OAAO,wBAAwB;GACjC,OAAO,yBAAyB,OAAO,IAAI;EAC7C;CACF;AACF;;;;;;;;;;;;;;;;ACvBA,SAAS,cAAc,UAA0C;CAC/D,MAAM,QAAQ,CAAC,iBAAiB;CAChC,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;EACxC,MAAM,IAAI,SAAS;EACnB,MAAM,SAAS,EAAE,SAAS,KAAK,EAAE,OAAO,QAAQ,UAAU,GAAG,MAAM;EACnE,MAAM,KAAK,IAAI,IAAI,EAAE,GAAG,EAAE,OAAO,QAAQ;CAC3C;CACA,MAAM,KAAK,kBAAkB;CAC7B,OAAO,MAAM,KAAK,IAAI;AACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA,MAAa,YAAqB;CAChC,MAAM;EACJ,MAAM;EACN,aAAa,YAAY;EACzB,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;IAAkE;IACvG,OAAO;KACL,MAAM;KACN,aAAa;KACb,OAAO;MACL,MAAM;MACN,YAAY;OACV,YAAY,EAAE,MAAM,SAAS;OAC7B,YAAY,EAAE,MAAM,SAAS;OAC7B,aAAa,EAAE,MAAM,UAAU;MACjC;MACA,UAAU,CAAC,cAAc,YAAY;KACvC;IACF;GACF;GACA,UAAU,CAAC,QAAQ,OAAO;EAC5B;CACF;CACA,MAAM,QAAQ,EAAE,MAAM,SAAS,KAAkB;EAC/C,MAAM,SAAS;EACf,MAAM,QAAQ;EAEd,MAAM,UAAU,aAAa,MAAM;EACnC,IAAI,SAAS;GACX,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,qBAAqB,SAAS;EACtD;EAEA,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAAG;GAC/C,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,oDAAoD;EAC5E;EAEA,MAAM,UAAU,MAAM,iBAAiB,IAAI,WAAW,IAAI,QAAQ,QAAQ,MAAM;EAChF,IAAI,SACF,OAAO;EAET,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,MAAM;EAC3D,QACM;GACJ,MAAM,OAAO,MAAM,cAAc,IAAI,WAAW,IAAI,QAAQ,MAAM;GAClE,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,qCAAqC,OAAO,GAAG,MAAM;EAC7E;EASA,IAAI,QAAmF;EACvF,IAAI,IAAI,UAAU,uBAAuB;GACvC,MAAM,YAAY,oBAAoB,GAAG;GACzC,IAAI,WAAW;IACb,MAAM,SAAS,aAAa,IAAI,OAAO,KAAK,MAAM;IAClD,MAAM,QAAQ,UAAU,IAAI,MAAM;IAClC,IAAI,CAAC,OAAO;KACV,IAAI,gBAAgB,QAAQ;KAC5B,MAAM,IAAI,YAAY,qBAAqB,OAAO,0GAA0G,IAAI,UAAU,oBAAoB,QAAQ,2DAA2D,2DAA4D;IAC/T;IACA,IAAI,MAAM,gBAAgB,YAAY,OAAO,GAC3C,QAAQ;KAAE;KAAW;KAAQ;IAAM;GACvC;EACF;EAEA,MAAM,WAA0B,CAAC;EAIjC,MAAM,WAAqB,CAAC;EAC5B,IAAI,oBAAoB;EAExB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,OAAO,KAAK;GAClB,MAAM,cAAc,KAAK;GACzB,MAAM,aAAa,KAAK,gBAAgB;GAExC,IAAI,OAAO,SAAS,YAAY,OAAO,gBAAgB,UAAU;IAC/D,SAAS,KAAK;KAAE,MAAM;KAAU,QAAQ;IAAmC,CAAC;IAC5E;GACF;GAEA,IAAI,KAAK,WAAW,GAAG;IACrB,SAAS,KAAK;KAAE,MAAM;KAAU,QAAQ;IAA4D,CAAC;IACrG;GACF;GAEA,IAAI,SAAS,aAAa;IACxB,SAAS,KAAK;KAAE,MAAM;KAAU,QAAQ;IAA0C,CAAC;IACnF;GACF;GAEA,MAAM,QAAQ,iBAAiB,SAAS,IAAI;GAC5C,IAAI,CAAC,OAAO;IACV,SAAS,KAAK;KAAE,MAAM;KAAU,QAAQ,2BAA2B;IAAS,CAAC;IAC7E;GACF;GAEA,MAAM,EAAE,QAAQ,aAAa,QAAQ;GACrC,IAAI,cAAc,KAAK,CAAC,YAAY;IAClC,SAAS,KAAK;KACZ,MAAM;KACN,QAAQ,sBAAsB,YAAY;IAC5C,CAAC;IACD;GACF;GAMA,IAAI,SAAS,QAAQ,SAAS;IAC5B,SAAS,KAAK;KAAE,MAAM;KAAU,QAAQ,+BAA+B,YAAY,GAAG,EAAE;IAAwG,CAAC;IACjM;GACF;GAEA,MAAM,oBAAoB,uBAAuB,aAAa,KAAK,MAAM;GACzE,UAAU,aACN,QAAQ,MAAM,MAAM,CAAC,CAAC,KAAK,iBAAiB,IAC5C,QAAQ,QAAQ,QAAQ,iBAAiB;GAC7C,qBAAqB;GACrB,IAAI,QAAQ,SACV,SAAS,KAAK,SAAS,IAAI,EAAE,mDAAmD,YAAY,GAAG,GAAG;GACpG,SAAS,KAAK,EAAE,MAAM,UAAU,CAAC;EACnC;EAEA,MAAM,eAAe,SAAS,QAAQ,GAAG,MAAM,EAAE,SAAS,YAAY,IAAI,IAAI,GAAG,CAAC;EAClF,MAAM,cAAc,SAAS,SAAS;EAKtC,IAAI,eAAe,GAAG;GACpB,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,QAAQ,OAAO;GAGzD,IAAI,gBAAgB,QAAQ;GAQ5B,MAAM,YAAY,oBAAoB,GAAG;GACzC,IAAI,WAAW;IACb,MAAM,SAAS,aAAa,IAAI,OAAO,KAAK,MAAM;IAClD,MAAM,QAAQ,UAAU,IAAI,MAAM;IAClC,IAAI,OACF,UAAU,IAAI,QAAQ;KAAE,GAAG;KAAO,aAAa,YAAY,OAAO;KAAG,SAAS,KAAK,IAAI;KAAG,QAAQ;KAAM,iBAAiB;IAAE,CAAC;GAChI;EACF,OACK;GAEH,IAAI,gBAAgB,QAAQ;GAI5B,IAAI,OAAO;IACT,MAAM,QAAQ,mBAAmB,MAAM,WAAW,MAAM,QAAQ,MAAM,KAAK;IAC3E,MAAM,IAAI,YAAY,qBAAqB,OAAO,4EAA4E,iBAAiB,KAAK,GAAG;GACzJ;EACF;EAEA,MAAM,IAAI,MAAM;EAchB,IAAI;EACJ,IAAI,iBAAiB,GACnB,SAAS,UAAU,OAAO,YAAY,EAAE,OAAO,MAAM,IAAI,KAAK,IAAI,IAAI,kBAAkB,cAAc,sBAAsB,IAAI,KAAK,IAAI;OAEtI,IAAI,eAAe,GACtB,SAAS,UAAU,OAAO,YAAY,aAAa,MAAM,EAAE,UAAU,kBAAkB,cAAc,sBAAsB,IAAI,KAAK,IAAI;OAGxI,SAAS,yCAAyC,OAAO,IAAI,EAAE;EAGjE,MAAM,eAAyB,CAAC;EAChC,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;GACxC,MAAM,IAAI,SAAS;GACnB,IAAI,EAAE,SAAS,UACb,aAAa,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,QAAQ;EAC1D;EAMA,MAAM,QAAQ,CAAC,MAAM;EAGrB,IAAI,SAAS,eAAe,GAC1B,MAAM,KAAK,6JAA6J;EAC1K,IAAI,SAAS,SAAS,GACpB,MAAM,KAAK,SAAS,KAAK,IAAI,CAAC;EAChC,IAAI,aAAa,SAAS,GACxB,MAAM,KAAK,aAAa,KAAK,IAAI,CAAC;EACpC,IAAI,cAAc,GAChB,MAAM,KAAK,cAAc,QAAQ,CAAC;EACpC,IAAI,iBAAiB,GACnB,MAAM,IAAI,YAAY,MAAM,KAAK,MAAM,CAAC;EAC1C,OAAO,MAAM,KAAK,MAAM;CAC1B;AACF;;;;;;;;;AC/RA,SAAgB,kBAAkB,MAAkC;CAClE,MAAM,MAAM,KAAK,YAAY,GAAG;CAChC,IAAI,QAAQ,IACV,OAAO,KAAA;CAET,QADY,KAAK,MAAM,MAAM,CAAC,CAAC,CAAC,YACtB,GAAV;EACE,KAAK,OACH,OAAO;EACT,KAAK;EACL,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE;CACJ;AACF;;;;;;;;;;AAWA,eAAsB,iBACpB,WACA,QACA,MACiD;CACjD,IAAI,UAAU,gBAAgB;EAC5B,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI;EAEzD,OAAO;GAAE,QADG,OAAO,KAAK,MAAM,QAAQ,MAAM,YAAY,MAAM,UAAU,CAAC,CAAC,SAAS,QAChE;GAAG,YAAY,MAAM;EAAW;CACrD;CAIA,MAAM,MAAM,YAAY,YAAY,IAAI;CACxC,MAAM,SAAS,MAAM,UAAU,KAAK,QAAQ,GAAG;CAC/C,IAAI,OAAO,aAAa,GACtB,MAAM,IAAI,MAAM,uBAAuB,OAAO,UAAU,QAAQ,OAAO,YAAY;CAErF,MAAM,MAAM,OAAO,OAAO,QAAQ,QAAQ,EAAE;CAC5C,OAAO;EAAE,QAAQ;EAAK,YAAY,wBAAwB,GAAG;CAAE;AACjE;;;;;;AAOA,SAAS,wBAAwB,KAAqB;CACpD,IAAI,IAAI,WAAW,GACjB,OAAO;CACT,IAAI,MAAM;CACV,IAAI,IAAI,SAAS,IAAI,GACnB,MAAM;MACH,IAAI,IAAI,SAAS,GAAG,GACvB,MAAM;CACR,OAAO,KAAK,IAAI,GAAI,IAAI,SAAS,IAAK,IAAI,GAAG;AAC/C;;;;ACpEA,MAAM,qBAAqB;;AAE3B,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,8BAA8B;AAEpC,SAAS,qBAAqB,MAAc,UAAsC;CAChF,IAAI,aAAa,QACf,OAAO,OAAO,WAAW,IAAI;CAC/B,IAAI,KAAK,WAAW,GAClB,OAAO;CACT,MAAM,MAAM,KAAK,SAAS,IAAI,IAAI,IAAI,KAAK,SAAS,GAAG,IAAI,IAAI;CAC/D,OAAO,KAAK,IAAI,GAAG,KAAK,MAAO,KAAK,SAAS,IAAK,CAAC,IAAI,GAAG;AAC5D;;;;;;;;;AAUA,SAAS,eAAe,OAA0C;CAChE,IAAI,MAAM,SAAS,YACjB,OAAO;CACT,IAAI,MAAM,aAAa,QACrB,OAAO,MAAM;CACf,IAAI,MAAM,cAAc,mBACtB,OAAO;CACT,MAAM,UAAU,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,OAAO;CAClE,OAAO,YAAY,OAAO,IAAI,OAAO;AACvC;;;;;;;AAkBA,SAAS,gBAAgB,KAAa,MAAgC;CACpE,MAAM,EAAE,QAAQ,SAAS,OAAO,QAAQ,UAAU,WAAW,aAAa,oBAAoB;CAC9F,MAAM,aAAa,OAAO,WAAW,GAAG;CAExC,MAAM,QAAQ,IAAI,MAAM,IAAI;CAC5B,MAAM,aAAa,MAAM;CAGzB,MAAM,WAAW,KAAK,IAAI,GAAG,UAAU,CAAC;CACxC,MAAM,SAAS,SAAS,IAAI,KAAK,IAAI,YAAY,WAAW,MAAM,IAAI;CACtE,IAAI,QAAQ,MAAM,MAAM,UAAU,MAAM;CAOxC,IAAI,WAAW;CACf,IAAI,YAAY,GAAG;EACjB,MAAM,iBAA2B,CAAC;EAClC,IAAI,YAAY;EAChB,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAY,OAAO,WAAW,IAAI,IAAI;GAC5C,IAAI,YAAY,YAAY,aAAa,eAAe,SAAS,GAAG;IAClE,WAAW;IACX;GACF;GACA,eAAe,KAAK,IAAI;GACxB,aAAa;GACb,IAAI,aAAa,WAEf;EAEJ;EACA,IAAI,eAAe,SAAS,MAAM,QAChC,WAAW;EACb,QAAQ;CACV;CAOA,IAAI,aAAa;CACjB,IAAI,YAAY,KAAK,MAAM,SAAS,GAChB;MAAA,OAAO,WAAW,MAAM,KAAK,IAAI,CACvC,IAAI,WAAW;GACzB,MAAM,UAAU,MAAM,SAAS;GAC/B,MAAM,WAAW,MAAM;GACvB,MAAM,aAAa,UAAU,IACzB,OAAO,WAAW,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,IACxD;GACJ,MAAM,gBAAgB,KAAK,IAAI,GAAG,YAAY,UAAU;GAIxD,IAAI,MAAM,KAAK,IAAI,SAAS,QAAQ,aAAa;GACjD,OAAO,MAAM,KAAK,OAAO,WAAW,SAAS,MAAM,GAAG,GAAG,CAAC,IAAI,eAC5D;GACF,MAAM,WAAW,SAAS,MAAM,GAAG,GAAG;GACtC,aAAa;GACb,WAAW;EACb;;CAIF,MAAM,eAAe,WADC,MAAM;CAS5B,MAAM,OAAO,kBACT,MAAM,KAAK,MAAM,MAAM,GAAG,WAAW,IAAI,EAAE,IAAI,MAAM,CAAC,CAAC,KAAK,IAAI,IAChE,MAAM,KAAK,IAAI;CAEnB,MAAM,iBAAiB,SAAS,cAAc;CAC9C,IAAI,CAAC,kBAAkB,YAAY,GACjC,OAAO;CAET,IAAI,CAAC,gBAEH,OAAO,GAAG,KAAK,kBAAkB,QAAQ,GAAG,aAAa,MAAM,WAAW;CAG5E,IAAI,YAMF,OAAO,GAAG,KAAK,kCAAkC,aAAa,aAAa,UAAU,sBAAsB,WAAW,UAAU,WAAW;CAI7I,OAAO,GAAG,KAAK,yBAAyB,aAAa,IADtC,WAAW,aAAa,UAAU,aAAa,eAAe,OAAO,WACpB,cAAc,WAAW,UAAU,WAAW,oCAAoC,eAAe,EAAE;AACrK;;;;;;;AAQA,SAAS,cAAc,QAAiB,KAAqB;CAC3D,IAAI,OAAO,WAAW,YAAY,OAAO,SAAS,MAAM,KAAK,SAAS,GAAG;EACvE,MAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,CAAC,UAAU,IAAI,SAAS,IAAI,IAAI,IAAI;EACjE,OAAO,KAAK,IAAI,GAAG,QAAQ,KAAK,MAAM,MAAM,IAAI,CAAC;CACnD;CACA,OAAO,yBAAyB,QAAQ,CAAC;AAC3C;;;;;;;;;;;;;;AA6BA,MAAa,WAAoB;CAG/B,mBAAmB;CAEnB,QAAQ;CACR,MAAM;EACJ,MAAM;EACN,aAAa,YAAY;EACzB,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;IAAmI;IACxK,OAAO;KACL,MAAM;KACN,aAAa;KACb,OAAO;MACL,MAAM;MACN,YAAY;OACV,MAAM;QAAE,MAAM;QAAU,aAAa;OAAa;OAClD,QAAQ;QAAE,MAAM;QAAW,aAAa;OAA4C;OACpF,OAAO;QAAE,MAAM;QAAW,aAAa;OAAa;MACtD;MACA,UAAU,CAAC,MAAM;KACnB;IACF;IACA,QAAQ;KAAE,MAAM;KAAW,aAAa;IAAyG;IACjJ,OAAO;KAAE,MAAM;KAAW,aAAa;IAA2D;IAClG,UAAU;KAAE,MAAM;KAAW,aAAa;IAA2Q;IACrT,aAAa;KAAE,MAAM;KAAW,aAAa;IAA6I;GAC5L;GACA,UAAU,CAAC;EACb;CACF;CACA,MAAM,QAAQ,OAAO,KAAkB;EACrC,IAAI,MAAM,UAAU,KAAA,GAClB,OAAO,UAAU,OAAO,GAAG;EAC7B,OAAO,QAAQ,OAAO,GAAG;CAC3B;AACF;AAEA,SAAS,aAAa,KAAkB;CACtC,OAAO,wBAAwB,IAAI,UAAU;EAC3C,WAAW;EACX,cAAc;EACd,oBAAoB;CACtB,CAAC;AACH;;;;;;;;;;AAWA,SAAgB,oBAAoB,aAAsB,KAAkE;CAC1H,IAAI,OAAO,gBAAgB,WACzB,OAAO;CACT,OAAO,IAAI,qBAAqB,KAAA,MAAc,IAAI,UAAU,mBAAmB;AACjF;;AAGA,SAAS,QAAQ,WAAmB,QAAoC;CACtE,IAAI,WAAW,KAAA,GACb,OAAO;CACT,OAAO,cAAc,IAAI,SAAS,KAAK,IAAI,WAAW,MAAM;AAC9D;;;;;;;;AASA,eAAe,UAAU,OAAgC,KAAyD;CAChH,IAAI,MAAM,SAAS,KAAA,GACjB,MAAM,IAAI,YAAY,sDAAsD;CAC9E,IAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,KAAK,MAAM,MAAM,WAAW,GACxD,MAAM,IAAI,YAAY,uFAAuF;CAC/G,IAAI,MAAM,MAAM,SAAA,IACd,MAAM,IAAI,YAAY,+BAA+B,MAAM,MAAM,OAAO,qDAAyE;CACnJ,MAAM,UAAU,gBAAgB,KAAK;CACrC,IAAI,QAAQ,WAAW,MAAM,MAAM,QACjC,MAAM,IAAI,YAAY,kEAAkE;CAE1F,MAAM,MAAM,yBAAyB,MAAM,UAAU,aAAa,GAAG,CAAC,CAAC,YAAY;CACnF,IAAI,YAAY;CAChB,MAAM,WAAgD,CAAC;CACvD,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,SAAS,oBAAoB,OAAO,IAAI;EAC9C,IAAI,MAAM,KAAK,aAAa,GAAG;GAC7B,SAAS,KAAK,GAAG,OAAO,qCAAqC,IAAI,kDAAkD;GACnH;EACF;EAEA,MAAM,MAAM,MAAM,QAChB;GAAE,MAAM,OAAO;GAAM,QAAQ,OAAO;GAAQ,OAAO,OAAO;GAAO,aAAa,MAAM;EAAY,GAChG,KACA,MAAM,IAAI,EAAE,gBAAgB,UAAU,IAAI,CAAC,CAC7C,CAAC,CAAC,OAAO,UAAmB;GAC1B,IAAI,cAAc,KAAK,GACrB,OAAQ,MAAgB;GAC1B,MAAM;EACR,CAAC;EACD,IAAI,OAAO,QAAQ,UAAU;GAC3B,aAAa,OAAO,WAAW,GAAG;GAClC,SAAS,KAAK,GAAG,OAAO,IAAI,KAAK;EACnC,OACK;GACH,KAAK,MAAM,QAAQ,KACjB,aAAa,KAAK,SAAS,SAAS,OAAO,WAAW,KAAK,IAAI,IAAI,UAAU,QAAQ,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS;GAC1I,SAAS,KAAK,CAAC;IAAE,MAAM;IAAQ,MAAM;GAAO,GAAG,GAAG,GAAG,CAAC;EACxD;CACF;CAEA,IAAI,SAAS,OAAM,YAAW,OAAO,YAAY,QAAQ,GACvD,OAAQ,SAAsB,KAAK,MAAM;CAC3C,MAAM,UAA+B,CAAC;CACtC,KAAK,MAAM,WAAW,UACpB,IAAI,OAAO,YAAY,UACrB,QAAQ,KAAK;EAAE,MAAM;EAAQ,MAAM;CAAQ,CAAC;MAE5C,QAAQ,KAAK,GAAG,OAAO;CAE3B,OAAO;AACT;AAEA,eAAe,QAAQ,EAAE,MAAM,QAAQ,OAAO,UAAU,eAA4B,KAAkB,OAAuB,CAAC,GAA0C;CACtK,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C,MAAM,IAAI,YAAY,qEAAqE;CAC7F,MAAM,WAAW,aAAa,GAAG;CAMjC,MAAM,aAAa,OAAO,SAAS,WAAW,sBAAsB,IAAI,IAAI;CAC5E,IAAI,YAAY;EACd,MAAM,QAAQ,IAAI,SAAS;EAC3B,IAAI,CAAC,OACH,MAAM,IAAI,YAAY,cAAc,KAAK,sDAAsD;EACjG,MAAM,QAAQ,2BAA2B,OAAO,UAAU;EAC1D,IAAI,CAAC,OACH,MAAM,IAAI,YAAY,cAAc,KAAK,sHAAsH;EAIjK,MAAM,SAAS,eAAe,KAAK;EACnC,IAAI,WAAW,MAQb,OAAO,GAAG,WAPgB,MAAM,OAAO,KAAK,MAAM,KAAK,KAAK,GAAG,qCAAqC,MAAM,UAAU,sBAOnG,MANJ,gBAAgB,QAAQ;GACnC,QAAQ,cAAc,QAAQ,MAAM;GACpC,OAAO,yBAAyB,OAAO,SAAS,SAAS;GACzD,UAAU,QAAQ,yBAAyB,UAAU,SAAS,YAAY,GAAG,KAAK,cAAc;GAChG,aAAa,oBAAoB,aAAa,GAAG;EACnD,CAC0B;EAE5B,MAAM,UAAU,yBAAyB,UAAU,SAAS,kBAAkB;EAC9E,MAAM,aAAa,qBAAqB,MAAM,MAAM,MAAM,QAAQ;EAClE,IAAI,UAAU,KAAK,aAAa,SAC9B,OAAO,uCAAuC,KAAK,IAAI,WAAW,cAAc,QAAQ;EAQ1F,OAAO,CALL;GAAE,MAAM;GAAQ,MAAM,GAFV,MAAM,SAAS,UAAU,UAAU,WAEhB,qCAAqC,MAAM,YAAY,MAAM,OAAO,MAAM,MAAM,KAAK,KAAK,GAAG;EAAI,GAChI,MAAM,SAAS,UACX;GAAE,MAAM;GAAS,WAAW,MAAM;GAAW,MAAM,MAAM;GAAM,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;EAAG,IAC3G;GAAE,MAAM;GAAY,WAAW,MAAM;GAAW,MAAM,MAAM;GAAM,UAAU,MAAM,YAAY;GAAU,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;EAAG,CAE7I;CACf;CAGA,MAAM,UAAU,aAAa,IAAc;CAC3C,IAAI,SACF,MAAM,IAAI,YAAY,eAAe,SAAS;CAShD,MAAM,WAAW,kBAAkB,IAAc;CACjD,IAAI,UAAU;EACZ,MAAM,UAAU,yBAAyB,UAAU,SAAS,kBAAkB;EAC9E,IAAI;GAMF,MAAM,SAAS,MAAM,IAAI,UAAU,WAAW,IAAI,QAAQ,IAAc,KAAK;GAC7E,IAAI,WAAW,QAAQ,UAAU,KAAK,SAAS,SAC7C,OAAO,+BAA+B,KAAK,IAAI,OAAO,cAAc,QAAQ;GAE9E,MAAM,EAAE,QAAQ,eAAe,MAAM,iBAAiB,IAAI,WAAW,IAAI,QAAQ,IAAc;GAC/F,IAAI,UAAU,KAAK,aAAa,SAC9B,OAAO,+BAA+B,KAAK,IAAI,WAAW,cAAc,QAAQ;GAElF,MAAM,WAAW,wBAAwB,UAAU,MAAM;GAKzD,OAAO,CAHL;IAAE,MAAM;IAAQ,MAAM,UAAU,KAAK,IAAI,WAAW,UAAU,SAAS;GAAG,GAC1E;IAAE,MAAM;IAAS,WAAW;IAAU,MAAM;GAAO,CAExC;EACf,SACO,KAAK;GACV,MAAM,OAAO,MAAM,cAAc,IAAI,WAAW,IAAI,QAAQ,IAAc;GAC1E,MAAM,IAAI,YAAY,sBAAsB,KAAK,IAAI,aAAa,GAAG,EAAE,GAAG,MAAM;EAClF;CACF;CAEA,MAAM,WAAW,qBAAqB,IAAc;CACpD,IAAI,UAAU;EACZ,MAAM,UAAU,yBAAyB,UAAU,SAAS,kBAAkB;EAC9E,IAAI;GAEF,MAAM,SAAS,MAAM,IAAI,UAAU,WAAW,IAAI,QAAQ,IAAc,KAAK;GAC7E,IAAI,WAAW,QAAQ,UAAU,KAAK,SAAS,SAC7C,OAAO,kCAAkC,KAAK,IAAI,OAAO,cAAc,QAAQ;GAEjF,MAAM,EAAE,QAAQ,eAAe,MAAM,iBAAiB,IAAI,WAAW,IAAI,QAAQ,IAAc;GAC/F,IAAI,UAAU,KAAK,aAAa,SAC9B,OAAO,kCAAkC,KAAK,IAAI,WAAW,cAAc,QAAQ;GAErF,IAAI,aAAa,qBAAqB,CAAC,YAAY,MAAM,GACvD,OAAO,iBAAiB,KAAK,IAAI,WAAW;GAM9C,OAAO,CAHL;IAAE,MAAM;IAAQ,MAAM,aAAa,KAAK,IAAI,WAAW,UAAU,SAAS;GAAG,GAC7E;IAAE,MAAM;IAAY,WAAW;IAAU,MAAM;IAAQ,UAAU;IAAU,MAAM,gBAAgB,IAAc;GAAE,CAEtG;EACf,SACO,KAAK;GACV,MAAM,OAAO,MAAM,cAAc,IAAI,WAAW,IAAI,QAAQ,IAAc;GAC1E,MAAM,IAAI,YAAY,yBAAyB,KAAK,IAAI,aAAa,GAAG,EAAE,GAAG,MAAM;EACrF;CACF;CAIA,MAAM,UAAU,MAAM,iBAAiB,IAAI,WAAW,IAAI,QAAQ,MAAgB,MAAM;CACxF,IAAI,SACF,OAAO;CAET,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,IAAc;CAC/D,SACO,KAAK;EAEV,MAAM,OAAO,MAAM,wBAAwB,IAAI,UAAU,YAAY,IAAI,QAAQ,IAAc;EAC/F,IAAI,SAAS,KAAA,GAAW;GAKtB,MAAM,UAAU,aAAa,GAAG;GAChC,IAAI,wBAAwB,OAAO,GACjC,OAAO,4BAA4B,KAAK,IAAI,QAAQ;GACtD,MAAM,OAAO,MAAM,cAAc,IAAI,WAAW,IAAI,QAAQ,IAAc;GAC1E,MAAM,IAAI,YAAY,mBAAmB,KAAK,GAAG,MAAM;EACzD;EACA,MAAM;CACR;CAEA,MAAM,aAAa,OAAO,WAAW,GAAG;CAsBxC,MAAM,SAAS,IAAI,qBAAqB,KAAA;CACxC,MAAM,eAAe,CAAC,UAAU,IAAI,UAAU,eAAe;CAC7D,MAAM,cAAc,IAAI,UAAU,0BAA0B;CAE5D,MAAM,YADkB,IAAI,UAAU,eAAe,SAAS,cAC1B,oBAAoB,GAAG,IAAI,KAAA;CAC/D,MAAM,SAAS,aAAa,IAAI,OAAO,KAAK,IAAc;CAC1D,MAAM,eAAe,cAAc,QAAQ,GAAG;CAC9C,MAAM,cAAc,yBAAyB,OAAO,SAAS,SAAS;CACtE,MAAM,oBAAoB,yBAAyB,UAAU,SAAS,YAAY;CAClF,MAAM,oBAAoB,QAAQ,mBAAmB,KAAK,cAAc;CAIxE,MAAM,iBAAiB,sBAAsB,KAAK,cAAc,oBAAoB,oBAAoB;CACxG,MAAM,kBAAkB,oBAAoB,aAAa,GAAG;CAC5D,MAAM,cAAc,YAAY,YAAY,GAAG,IAAI;CACnD,MAAM,qBAAqB;EACzB,IAAI,CAAC,WACH;EACF,IAAI,QAAQ;GAEV,IAAI,UAAU,IAAI,MAAM,CAAC,EAAE,gBAAgB,aACzC,UAAU,IAAI,QAAQ;IAAE,aAAa;IAAa,QAAQ;IAAc,OAAO;IAAa,UAAU;IAAgB,aAAa;IAAiB,SAAS,KAAK,IAAI;IAAG,QAAQ;GAAK,CAAC;GACzL;EACF;EACA,UAAU,IAAI,QAAQ;GACpB,aAAa;GACb,QAAQ;GACR,OAAO;GACP,UAAU;GACV,aAAa;GACb,SAAS,KAAK,IAAI;EACpB,CAAC;CACH;CACA,IAAI,gBAAgB,WAAW;EAC7B,MAAM,QAAQ,UAAU,IAAI,MAAM;EAClC,IACE,SACG,MAAM,gBAAgB,eACtB,MAAM,WAAW,gBACjB,MAAM,UAAU,eAChB,MAAM,aAAa,kBAKnB,MAAM,gBAAgB,mBAItB,MAAM,WAAW,MACpB;GAYA,aAAa;GACb,OAAO,QAAQ,KAAK;EACtB;CACF;CAMA,IAAI,YAAY,GAAG,GACjB,OAAO,iBAAiB,KAAK,IAAI,WAAW;CAG9C,aAAa;CAEb,OAAO,gBAAgB,KAAK;EAC1B,QAAQ;EACR,OAAO;EACP,UAAU;EACV,aAAa;CACf,CAAC;AACH;AAEA,SAAS,qBAAqB,MAAkC;CAC9D,MAAM,MAAM,KAAK,YAAY,GAAG;CAChC,IAAI,QAAQ,IACV,OAAO,KAAA;CAET,OADY,KAAK,MAAM,MAAM,CAAC,CAAC,CAAC,YACvB,MAAM,QAAQ,oBAAoB,KAAA;AAC7C;AAEA,SAAS,gBAAgB,MAAsB;CAC7C,MAAM,aAAa,KAAK,QAAQ,OAAO,GAAG;CAC1C,MAAM,QAAQ,WAAW,YAAY,GAAG;CACxC,OAAO,UAAU,KAAK,aAAa,WAAW,MAAM,QAAQ,CAAC;AAC/D;AAEA,SAAS,YAAY,QAAyB;CAC5C,OAAO,OAAO,KAAK,OAAO,MAAM,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC,WAAW,OAAO;AACxF;;;;;;;;;;;;;;;;;;ACllBA,MAAa,YAAqB;CAChC,MAAM;EACJ,MAAM;EACN,aAAa,YAAY;EACzB,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;IAAkE;IACvG,SAAS;KAAE,MAAM;KAAU,aAAa;IAAiE;GAC3G;GACA,UAAU,CAAC,QAAQ,SAAS;EAC9B;CACF;CACA,MAAM,QAAQ,EAAE,MAAM,WAAW,KAAkB;EACjD,MAAM,aAAa;EACnB,MAAM,gBAAgB;EAItB,MAAM,UAAU,aAAa,UAAU;EACvC,IAAI,SAAS;GACX,IAAI,gBAAgB,QAAQ;GAC5B,MAAM,IAAI,YAAY,gBAAgB,SAAS;EACjD;EAEA,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,UAAU;EAChE,QACM,CAGN;EAEA,MAAM,QAAQ,OAAO,WAAW,aAAa;EAE7C,IAAI,aAAa,eAAe;GAC9B,IAAI,gBAAgB,MAAM;GAC1B,OAAO,qBAAqB,WAAW,4BAA4B,MAAM;EAC3E;EAEA,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,YAAY,aAAa;EASnE,MAAM,YAAY,oBAAoB,GAAG;EACzC,IAAI,WACF,UAAU,IAAI,aAAa,IAAI,OAAO,KAAK,UAAU,GAAG;GACtD,aAAa,YAAY,aAAa;GACtC,QAAQ;GACR,OAAO,OAAO;GACd,UAAU,OAAO;GACjB,SAAS,KAAK,IAAI;GAMlB,QAAQ;EACV,CAAC;EAGH,IAAI,gBAAgB,aAAa,KAAA,IAAY,YAAY,SAAS;EAClE,OAAO,aAAa,KAAA,IAChB,WAAW,WAAW,IAAI,MAAM,YAChC,WAAW,WAAW,IAAI,MAAM;CACtC;AACF"}
|