@ashx-j/lunr 0.2.17 → 0.2.18
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/CHANGELOG.md +19 -1
- package/README.md +2 -1
- package/dist/builtin-extensions/ashxj-thinking.d.ts +1 -0
- package/dist/builtin-extensions/ashxj-thinking.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js +44 -19
- package/dist/builtin-extensions/ashxj-thinking.js.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts +2 -2
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +8 -11
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +2 -1
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts +4 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js +172 -171
- package/dist/builtin-extensions/pi-lsp-extension/src/index.js.map +1 -1
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts +50 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js +131 -0
- package/dist/builtin-extensions/pi-lsp-extension/src/runtime.js.map +1 -0
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts +7 -0
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js +211 -0
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tool-executor.js.map +1 -0
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts +0 -5
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js +0 -202
- package/dist/builtin-extensions/pi-mcp-adapter/direct-tools.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/index.js +276 -109
- package/dist/builtin-extensions/pi-mcp-adapter/index.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts +4 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/init.js +10 -3
- package/dist/builtin-extensions/pi-mcp-adapter/init.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js +6 -1
- package/dist/builtin-extensions/pi-mcp-adapter/metadata-cache.js.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts +6 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js +33 -8
- package/dist/builtin-extensions/pi-mcp-adapter/server-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js +2 -1
- package/dist/builtin-extensions/pi-prompt-template-model/prompt-loader.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/tool-manager.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +68 -15
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +5 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/fork-context.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +72 -31
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js +2 -1
- package/dist/builtin-extensions/pi-subagents/src/watchdog/review.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/extract.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/extract.js +105 -54
- package/dist/builtin-extensions/pi-web-access/extract.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts +1 -1
- package/dist/builtin-extensions/pi-web-access/gemini-search.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/gemini-search.js +82 -65
- package/dist/builtin-extensions/pi-web-access/gemini-search.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/github-extract.js +2 -0
- package/dist/builtin-extensions/pi-web-access/github-extract.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +259 -168
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/lazy.d.ts +18 -0
- package/dist/builtin-extensions/pi-web-access/lazy.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/lazy.js +19 -0
- package/dist/builtin-extensions/pi-web-access/lazy.js.map +1 -0
- package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts +6 -0
- package/dist/builtin-extensions/pi-web-access/session-cleanup.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/session-cleanup.js +17 -0
- package/dist/builtin-extensions/pi-web-access/session-cleanup.js.map +1 -0
- package/dist/cli-runtime.d.ts +3 -0
- package/dist/cli-runtime.d.ts.map +1 -0
- package/dist/cli-runtime.js +72 -0
- package/dist/cli-runtime.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -60
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +6 -3
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/host-static.d.ts.map +1 -1
- package/dist/core/extensions/host-static.js +34 -12
- package/dist/core/extensions/host-static.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +10 -64
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/keybindings.d.ts +2 -2
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +2 -2
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/timings.d.ts +2 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +17 -2
- package/dist/core/timings.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +6 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +23 -6
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/cron.d.ts +1 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +3 -1
- package/dist/gateway/cron.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +20 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/injected-context.d.ts +2 -0
- package/dist/modes/interactive/injected-context.d.ts.map +1 -0
- package/dist/modes/interactive/injected-context.js +7 -0
- package/dist/modes/interactive/injected-context.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +32 -8
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/thinking-level-slash.d.ts +4 -0
- package/dist/modes/interactive/thinking-level-slash.d.ts.map +1 -0
- package/dist/modes/interactive/thinking-level-slash.js +23 -0
- package/dist/modes/interactive/thinking-level-slash.js.map +1 -0
- package/dist/node-runtime/agent-session-services-35WNVGMR.js +36 -0
- package/dist/node-runtime/benchmark-request-UC7PD3V3.js +57 -0
- package/dist/node-runtime/brave-UWDA3I22.js +143 -0
- package/dist/node-runtime/builtin-extensions-QATGXENO.js +28 -0
- package/dist/node-runtime/chunk-2SJB2AWP.js +47 -0
- package/dist/node-runtime/chunk-3NMWLTPV.js +64 -0
- package/dist/node-runtime/chunk-3WFAEVKS.js +115 -0
- package/dist/node-runtime/chunk-3X3KZKMI.js +49 -0
- package/dist/node-runtime/chunk-4CSFRBCN.js +7558 -0
- package/dist/node-runtime/chunk-4DJ6HEGH.js +296 -0
- package/dist/node-runtime/chunk-4HXHDDCF.js +16 -0
- package/dist/node-runtime/chunk-4I23VTC4.js +429 -0
- package/dist/node-runtime/chunk-4TLO4PO2.js +3427 -0
- package/dist/node-runtime/chunk-4ZWGEEAS.js +69 -0
- package/dist/node-runtime/chunk-53YJI7JU.js +137 -0
- package/dist/node-runtime/chunk-5EFIU3OM.js +295 -0
- package/dist/node-runtime/chunk-6BEIBLQ3.js +53 -0
- package/dist/node-runtime/chunk-6KDIOJL3.js +72 -0
- package/dist/node-runtime/chunk-7N3YHTYF.js +26 -0
- package/dist/node-runtime/chunk-7NBZ5P7I.js +24 -0
- package/dist/node-runtime/chunk-AD6VXAO7.js +342 -0
- package/dist/node-runtime/chunk-ARC4KOTI.js +11178 -0
- package/dist/node-runtime/chunk-AROOY4BB.js +173 -0
- package/dist/node-runtime/chunk-ATGA2WLC.js +5646 -0
- package/dist/node-runtime/chunk-AUXVGBO4.js +19 -0
- package/dist/node-runtime/chunk-AY6CAJSL.js +30 -0
- package/dist/node-runtime/chunk-BHO7O6E5.js +296 -0
- package/dist/node-runtime/chunk-BI3DHYCN.js +8845 -0
- package/dist/node-runtime/chunk-BOHIDQT4.js +21 -0
- package/dist/node-runtime/chunk-BRJX2PRC.js +53 -0
- package/dist/node-runtime/chunk-CBGB57XT.js +20211 -0
- package/dist/node-runtime/chunk-CCZJ3PYY.js +17 -0
- package/dist/node-runtime/chunk-CGBXPL3E.js +1171 -0
- package/dist/node-runtime/chunk-CJECDQKP.js +19 -0
- package/dist/node-runtime/chunk-CSFI6YXL.js +130 -0
- package/dist/node-runtime/chunk-DAPBPCBP.js +53 -0
- package/dist/node-runtime/chunk-DDWHZ633.js +37 -0
- package/dist/node-runtime/chunk-DMMTJQMQ.js +43 -0
- package/dist/node-runtime/chunk-DVGWF6A2.js +1180 -0
- package/dist/node-runtime/chunk-EBF6COVM.js +1734 -0
- package/dist/node-runtime/chunk-FQMM2EZ2.js +248 -0
- package/dist/node-runtime/chunk-FVDOXRUD.js +96 -0
- package/dist/node-runtime/chunk-G4P75AIS.js +9471 -0
- package/dist/node-runtime/chunk-G6LRAP36.js +105 -0
- package/dist/node-runtime/chunk-GKLEQ3I4.js +860 -0
- package/dist/node-runtime/chunk-H2EOZYMP.js +57 -0
- package/dist/node-runtime/chunk-HQCKFM2O.js +56 -0
- package/dist/node-runtime/chunk-HYHJIRDW.js +19 -0
- package/dist/node-runtime/chunk-I6R76AG7.js +22 -0
- package/dist/node-runtime/chunk-IRPJXI6U.js +1269 -0
- package/dist/node-runtime/chunk-J26TSGDL.js +633 -0
- package/dist/node-runtime/chunk-JZQ7F36T.js +610 -0
- package/dist/node-runtime/chunk-KBKMCJDU.js +126 -0
- package/dist/node-runtime/chunk-KWA4OC2J.js +100 -0
- package/dist/node-runtime/chunk-M3LZLQW2.js +98 -0
- package/dist/node-runtime/chunk-MCUNIRD5.js +8388 -0
- package/dist/node-runtime/chunk-NI6OTSBH.js +966 -0
- package/dist/node-runtime/chunk-NUIFPZWX.js +209 -0
- package/dist/node-runtime/chunk-OBMWP3I5.js +68 -0
- package/dist/node-runtime/chunk-OCVIXVTZ.js +88 -0
- package/dist/node-runtime/chunk-OPEK5RRY.js +466 -0
- package/dist/node-runtime/chunk-OR4L3IB2.js +42 -0
- package/dist/node-runtime/chunk-PL6JKXWI.js +3622 -0
- package/dist/node-runtime/chunk-PNJSG3IZ.js +807 -0
- package/dist/node-runtime/chunk-PVCDKGR6.js +55 -0
- package/dist/node-runtime/chunk-Q4Q6D4IY.js +364 -0
- package/dist/node-runtime/chunk-Q5ZU2VRT.js +83 -0
- package/dist/node-runtime/chunk-QFWG2RVL.js +5477 -0
- package/dist/node-runtime/chunk-QZMODZQ2.js +305 -0
- package/dist/node-runtime/chunk-R5EDISSV.js +375 -0
- package/dist/node-runtime/chunk-RNBHABBA.js +986 -0
- package/dist/node-runtime/chunk-RQ2Q5IYR.js +72 -0
- package/dist/node-runtime/chunk-RRIZE6QQ.js +17 -0
- package/dist/node-runtime/chunk-SN6G4OU6.js +4753 -0
- package/dist/node-runtime/chunk-STERBGUB.js +949 -0
- package/dist/node-runtime/chunk-UWQYRSYQ.js +8973 -0
- package/dist/node-runtime/chunk-VRB2IYGG.js +53 -0
- package/dist/node-runtime/chunk-VSELYKWU.js +772 -0
- package/dist/node-runtime/chunk-W3CVH5RX.js +62 -0
- package/dist/node-runtime/chunk-WJVFOIB5.js +24921 -0
- package/dist/node-runtime/chunk-WKDK4C5P.js +2834 -0
- package/dist/node-runtime/chunk-XATUM2HK.js +46 -0
- package/dist/node-runtime/chunk-XBWPBZBN.js +125 -0
- package/dist/node-runtime/chunk-XTHQ7XR7.js +509 -0
- package/dist/node-runtime/chunk-ZBV7FAHG.js +1345 -0
- package/dist/node-runtime/cli-runtime.js +80 -0
- package/dist/node-runtime/clipboard-OZ63BBC6.js +12 -0
- package/dist/node-runtime/clipboard-image-7QR6GXVA.js +13 -0
- package/dist/node-runtime/command-AAV3YRR5.js +13 -0
- package/dist/node-runtime/commands-MV5KOZ64.js +291 -0
- package/dist/node-runtime/config-QDD5PUE2.js +73 -0
- package/dist/node-runtime/curator-server-XCM43VEF.js +3816 -0
- package/dist/node-runtime/customize-XEXL2DGQ.js +12 -0
- package/dist/node-runtime/direct-tool-executor-BK7CLEBX.js +188 -0
- package/dist/node-runtime/exa-LL64QZR2.js +329 -0
- package/dist/node-runtime/export-html-TEXVV5RP.js +150 -0
- package/dist/node-runtime/extension-input-O4HSAEM4.js +14 -0
- package/dist/node-runtime/extension-selector-X5FCX43D.js +14 -0
- package/dist/node-runtime/extract-XLQSJN4V.js +17 -0
- package/dist/node-runtime/file-sync-HCOP2QVF.js +117 -0
- package/dist/node-runtime/gateway-OAC4OBBL.js +2137 -0
- package/dist/node-runtime/gemini-api-QE7ANVDZ.js +29 -0
- package/dist/node-runtime/gemini-search-U7SUMPQA.js +330 -0
- package/dist/node-runtime/gemini-url-context-PXWCBQHK.js +103 -0
- package/dist/node-runtime/gemini-web-MM446SEH.js +14 -0
- package/dist/node-runtime/github-extract-F64RZOEA.js +619 -0
- package/dist/node-runtime/goal-NJEE5CTU.js +1831 -0
- package/dist/node-runtime/index.js +859 -0
- package/dist/node-runtime/init-3C7Z24OI.js +28 -0
- package/dist/node-runtime/install-cli-EXMJQESX.js +308 -0
- package/dist/node-runtime/interactive-mode-2SZUO53H.js +56 -0
- package/dist/node-runtime/interactive-view-S6J3QHEF.js +247 -0
- package/dist/node-runtime/lsp-manager-3ASUSO4T.js +1104 -0
- package/dist/node-runtime/lunr-cron-AUUYP4N4.js +272 -0
- package/dist/node-runtime/main.js +54 -0
- package/dist/node-runtime/mcp-auth-flow-QIXHW6QN.js +32 -0
- package/dist/node-runtime/mcp-panel-IIGMXQGP.js +501 -0
- package/dist/node-runtime/mcp-setup-panel-FEK7663I.js +355 -0
- package/dist/node-runtime/memory-cap-3S4XRLNP.js +20 -0
- package/dist/node-runtime/model-tiers-NJLHUEGK.js +20 -0
- package/dist/node-runtime/openai-search-B3MSNCQA.js +288 -0
- package/dist/node-runtime/package-manager-cli-7RKSZGEN.js +749 -0
- package/dist/node-runtime/parallel-AI2MNSCU.js +265 -0
- package/dist/node-runtime/parser-manager-TQHWYDH7.js +152 -0
- package/dist/node-runtime/pdf-extract-IPE6H4HP.js +57 -0
- package/dist/node-runtime/perplexity-QVJW3I35.js +12 -0
- package/dist/node-runtime/pi-intercom-EEMBGQID.js +2215 -0
- package/dist/node-runtime/pi-mcp-adapter-GUFZWW54.js +428 -0
- package/dist/node-runtime/pi-ollama-cloud-2F3Y2QNM.js +1440 -0
- package/dist/node-runtime/pi-prompt-template-model-QWTCGLJU.js +3946 -0
- package/dist/node-runtime/pi-subagents-7YJ3I4VE.js +6048 -0
- package/dist/node-runtime/pi-web-access-2CQGFLT2.js +1867 -0
- package/dist/node-runtime/print-mode-XSFM26EL.js +12 -0
- package/dist/node-runtime/proxy-modes-V6YVFH3C.js +685 -0
- package/dist/node-runtime/rpc-entry.js +62 -0
- package/dist/node-runtime/rpc-mode-W5ZTLTMZ.js +13 -0
- package/dist/node-runtime/runtime-bridges-3RKBDLNA.js +14 -0
- package/dist/node-runtime/session-manager-E7AREDTV.js +33 -0
- package/dist/node-runtime/session-selector-FJ7M2AIX.js +14 -0
- package/dist/node-runtime/settings-manager-GHPTUN7R.js +21 -0
- package/dist/node-runtime/src-BPQFJR76.js +2427 -0
- package/dist/node-runtime/subagent-executor-5Q5A4HJ2.js +8499 -0
- package/dist/node-runtime/summary-review-YSMXKITO.js +228 -0
- package/dist/node-runtime/tavily-WEZFVFP7.js +154 -0
- package/dist/node-runtime/timings-UAD5BEAS.js +16 -0
- package/dist/node-runtime/tool-renderer-MV5O452K.js +204 -0
- package/dist/node-runtime/update-cli-L3JIBH2U.js +70 -0
- package/dist/node-runtime/v4-5MNC3H7G.js +424 -0
- package/dist/node-runtime/video-extract-OYT5WKS5.js +304 -0
- package/dist/node-runtime/workspace-index-6DBXSTJ6.js +163 -0
- package/dist/node-runtime/youtube-extract-TQYKGFGS.js +264 -0
- package/dist/rpc.d.ts +3 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +18 -0
- package/dist/rpc.js.map +1 -0
- package/dist/startup/benchmark-request.d.ts +3 -0
- package/dist/startup/benchmark-request.d.ts.map +1 -0
- package/dist/startup/benchmark-request.js +65 -0
- package/dist/startup/benchmark-request.js.map +1 -0
- package/dist/startup/interactive-view.d.ts.map +1 -1
- package/dist/startup/interactive-view.js +1 -2
- package/dist/startup/interactive-view.js.map +1 -1
- package/dist/startup/startup-milestones.d.ts +1 -1
- package/dist/startup/startup-milestones.d.ts.map +1 -1
- package/dist/startup/startup-milestones.js.map +1 -1
- package/dist/utils/await-with-abort.d.ts +2 -0
- package/dist/utils/await-with-abort.d.ts.map +1 -0
- package/dist/utils/await-with-abort.js +19 -0
- package/dist/utils/await-with-abort.js.map +1 -0
- package/docs/development.md +5 -1
- package/docs/features.md +2 -2
- package/docs/interactive-startup.md +95 -48
- package/docs/keybindings.md +2 -2
- package/docs/terminal-setup.md +1 -1
- package/docs/usage.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/hidden-thinking-label.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "@ashx-j/lunr";
|
|
2
2
|
export interface ToolManagerDeps {
|
|
3
3
|
isActive(): boolean;
|
|
4
4
|
getStoredCtx(): ExtensionCommandContext | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-manager.d.ts","sourceRoot":"","sources":["../../../src/builtin-extensions/pi-prompt-template-model/tool-manager.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"tool-manager.d.ts","sourceRoot":"","sources":["../../../src/builtin-extensions/pi-prompt-template-model/tool-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAK/G,MAAM,WAAW,eAAe;IAC/B,QAAQ,IAAI,OAAO,CAAC;IACpB,YAAY,IAAI,uBAAuB,GAAG,IAAI,CAAC;IAC/C,YAAY,CAAC,GAAG,EAAE,uBAAuB,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7E;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe;;;;;;;;EA+MxE","sourcesContent":["// @ts-nocheck\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from \"@ashx-j/lunr\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { Type } from \"typebox\";\nimport { notify } from \"./notifications.ts\";\n\nexport interface ToolManagerDeps {\n\tisActive(): boolean;\n\tgetStoredCtx(): ExtensionCommandContext | null;\n\tsetStoredCtx(ctx: ExtensionCommandContext | null): void;\n\texecuteCommand(command: string, ctx: ExtensionCommandContext): Promise<void>;\n}\n\nexport function createToolManager(pi: ExtensionAPI, deps: ToolManagerDeps) {\n\tlet toolEnabled = false;\n\tlet toolGuidance: string | null = null;\n\tlet toolRegistered = false;\n\tlet toolQueuedCommand: string | null = null;\n\tconst configPath = join(getAgentDir(), \"prompt-template-model.json\");\n\n\ttry {\n\t\tconst rawConfig = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\t\tif (rawConfig && typeof rawConfig === \"object\") {\n\t\t\tconst config = rawConfig as { toolEnabled?: unknown; toolGuidance?: unknown };\n\t\t\tif (typeof config.toolEnabled === \"boolean\") {\n\t\t\t\ttoolEnabled = config.toolEnabled;\n\t\t\t}\n\t\t\tif (typeof config.toolGuidance === \"string\") {\n\t\t\t\ttoolGuidance = config.toolGuidance;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconst err = error as NodeJS.ErrnoException;\n\t\tif (err.code !== \"ENOENT\") {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`[pi-prompt-template-model] Failed to read ${configPath}: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction saveToolConfig() {\n\t\ttry {\n\t\t\tmkdirSync(getAgentDir(), { recursive: true });\n\t\t\twriteFileSync(configPath, JSON.stringify({ toolEnabled, toolGuidance }, null, 2));\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`[pi-prompt-template-model] Failed to write ${configPath}: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction ensureRegistered() {\n\t\tif (toolRegistered) return;\n\t\ttoolRegistered = true;\n\t\tpi.registerTool({\n\t\t\tname: \"run-prompt\",\n\t\t\tlabel: \"Run Prompt\",\n\t\t\tdescription:\n\t\t\t\t\"Run a prompt template command. Pass the template name and any arguments. \" +\n\t\t\t\t\"Supports --loop for loops (e.g. 'deslop --loop 5', 'deslop --loop=5', 'deslop --loop' for unlimited until convergence with a 999-iteration cap), \" +\n\t\t\t\t\"--fresh for context collapse between iterations, and --no-converge to disable early stopping for bounded loops. \" +\n\t\t\t\t\"Supports runtime delegation override via --subagent, --subagent=<name>, or --subagent:<name>. \" +\n\t\t\t\t\"Use 'chain-prompts template1 -> template2' for chaining and add --chain-context to pass previous step summaries into delegated steps.\",\n\t\t\tpromptSnippet:\n\t\t\t\t\"Use this to run slash/prompt templates by name with args (including --loop/--fresh and chain-prompts flows) when the user asks to execute a prompt template.\",\n\t\t\tparameters: Type.Object({\n\t\t\t\tcommand: Type.String({\n\t\t\t\t\tdescription: \"Template name and arguments (e.g. 'deslop --loop 5 --fresh', 'deslop --subagent:worker', 'deslop --subagent', 'chain-prompts analyze -> fix --chain-context', 'chain-prompts analyze -> fix --loop=3')\",\n\t\t\t\t}),\n\t\t\t}),\n\t\t\texecute: async (_id, params) => {\n\t\t\t\tif (!toolEnabled) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"run-prompt tool is disabled. User must run `/prompt-tool on` to enable.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (deps.isActive()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"A prompt command is already running. Wait for it to complete.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!deps.getStoredCtx()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No command context. Run any prompt command first to initialize.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst commandParam = (params as { command?: unknown }).command;\n\t\t\t\tconst command = typeof commandParam === \"string\" ? commandParam.trim() : \"\";\n\t\t\t\tif (!command) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No command specified.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (toolQueuedCommand) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"A prompt command is already queued. Wait for it to execute.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\ttoolQueuedCommand = command;\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Prompt command queued: \"${command}\". Will execute when this turn ends.` }],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tfunction registerCommand() {\n\t\tpi.registerCommand(\"prompt-tool\", {\n\t\t\tdescription: \"Manage the run-prompt tool (agent-accessible prompt execution)\",\n\t\t\thandler: async (args, ctx) => {\n\t\t\t\tdeps.setStoredCtx(ctx);\n\t\t\t\tconst trimmed = args.trim();\n\n\t\t\t\tif (trimmed === \"on\" || trimmed.startsWith(\"on \")) {\n\t\t\t\t\ttoolEnabled = true;\n\t\t\t\t\tensureRegistered();\n\t\t\t\t\tconst guidanceRaw = trimmed.slice(\"on\".length).trim();\n\t\t\t\t\tif (guidanceRaw) {\n\t\t\t\t\t\ttoolGuidance = guidanceRaw.replace(/^[\"']|[\"']$/g, \"\");\n\t\t\t\t\t\tnotify(ctx, `run-prompt tool enabled with guidance: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(ctx, \"run-prompt tool enabled.\", \"info\");\n\t\t\t\t\t}\n\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (trimmed === \"off\") {\n\t\t\t\t\ttoolEnabled = false;\n\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\tnotify(ctx, \"run-prompt tool disabled.\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (trimmed === \"guidance\" || trimmed.startsWith(\"guidance \")) {\n\t\t\t\t\tif (trimmed === \"guidance\" || trimmed === \"guidance show\") {\n\t\t\t\t\t\tif (toolGuidance) {\n\t\t\t\t\t\t\tnotify(ctx, `Current guidance: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnotify(ctx, \"No guidance set. Use `/prompt-tool guidance <text>` to set.\", \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (trimmed === \"guidance clear\") {\n\t\t\t\t\t\ttoolGuidance = null;\n\t\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\t\tnotify(ctx, \"Guidance cleared.\", \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst guidanceRaw = trimmed.slice(\"guidance\".length).trim();\n\t\t\t\t\t\ttoolGuidance = guidanceRaw.replace(/^[\"']|[\"']$/g, \"\");\n\t\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\t\tnotify(ctx, `Guidance set: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!trimmed) {\n\t\t\t\t\tif (toolEnabled) {\n\t\t\t\t\t\tconst guidanceInfo = toolGuidance ? ` | Guidance: \"${toolGuidance}\"` : \"\";\n\t\t\t\t\t\tnotify(ctx, `run-prompt tool is enabled${guidanceInfo}`, \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(ctx, \"run-prompt tool is disabled\", \"info\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tnotify(ctx, \"Usage: /prompt-tool [on [guidance] | off | guidance [text|clear]]\", \"error\");\n\t\t\t},\n\t\t});\n\t}\n\n\tasync function processQueue(ctx: ExtensionContext, restoreFn: () => Promise<void>) {\n\t\tif (!toolQueuedCommand) return false;\n\t\tconst storedCtx = deps.getStoredCtx();\n\t\tif (!storedCtx) {\n\t\t\ttoolQueuedCommand = null;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst command = toolQueuedCommand;\n\t\ttoolQueuedCommand = null;\n\t\tawait restoreFn();\n\t\ttry {\n\t\t\tawait deps.executeCommand(command, storedCtx);\n\t\t} catch (error) {\n\t\t\tnotify(\n\t\t\t\tctx,\n\t\t\t\t`Failed to execute queued prompt command \"${command}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\"error\",\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\treturn {\n\t\tisEnabled() {\n\t\t\treturn toolEnabled;\n\t\t},\n\t\tgetGuidance() {\n\t\t\treturn toolGuidance;\n\t\t},\n\t\thasQueuedCommand() {\n\t\t\treturn toolQueuedCommand !== null;\n\t\t},\n\t\tclearQueue() {\n\t\t\ttoolQueuedCommand = null;\n\t\t},\n\t\tensureRegistered,\n\t\tregisterCommand,\n\t\tprocessQueue,\n\t};\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { getAgentDir } from "
|
|
4
|
+
import { getAgentDir } from "../../config.js";
|
|
5
5
|
import { Type } from "typebox";
|
|
6
6
|
import { notify } from "./notifications.js";
|
|
7
7
|
export function createToolManager(pi, deps) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-manager.js","sourceRoot":"","sources":["../../../src/builtin-extensions/pi-prompt-template-model/tool-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { getAgentDir, type ExtensionAPI, type ExtensionCommandContext, type ExtensionContext } from \"@ashx-j/lunr\";\nimport { Type } from \"typebox\";\nimport { notify } from \"./notifications.ts\";\n\nexport interface ToolManagerDeps {\n\tisActive(): boolean;\n\tgetStoredCtx(): ExtensionCommandContext | null;\n\tsetStoredCtx(ctx: ExtensionCommandContext | null): void;\n\texecuteCommand(command: string, ctx: ExtensionCommandContext): Promise<void>;\n}\n\nexport function createToolManager(pi: ExtensionAPI, deps: ToolManagerDeps) {\n\tlet toolEnabled = false;\n\tlet toolGuidance: string | null = null;\n\tlet toolRegistered = false;\n\tlet toolQueuedCommand: string | null = null;\n\tconst configPath = join(getAgentDir(), \"prompt-template-model.json\");\n\n\ttry {\n\t\tconst rawConfig = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\t\tif (rawConfig && typeof rawConfig === \"object\") {\n\t\t\tconst config = rawConfig as { toolEnabled?: unknown; toolGuidance?: unknown };\n\t\t\tif (typeof config.toolEnabled === \"boolean\") {\n\t\t\t\ttoolEnabled = config.toolEnabled;\n\t\t\t}\n\t\t\tif (typeof config.toolGuidance === \"string\") {\n\t\t\t\ttoolGuidance = config.toolGuidance;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconst err = error as NodeJS.ErrnoException;\n\t\tif (err.code !== \"ENOENT\") {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`[pi-prompt-template-model] Failed to read ${configPath}: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction saveToolConfig() {\n\t\ttry {\n\t\t\tmkdirSync(getAgentDir(), { recursive: true });\n\t\t\twriteFileSync(configPath, JSON.stringify({ toolEnabled, toolGuidance }, null, 2));\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`[pi-prompt-template-model] Failed to write ${configPath}: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction ensureRegistered() {\n\t\tif (toolRegistered) return;\n\t\ttoolRegistered = true;\n\t\tpi.registerTool({\n\t\t\tname: \"run-prompt\",\n\t\t\tlabel: \"Run Prompt\",\n\t\t\tdescription:\n\t\t\t\t\"Run a prompt template command. Pass the template name and any arguments. \" +\n\t\t\t\t\"Supports --loop for loops (e.g. 'deslop --loop 5', 'deslop --loop=5', 'deslop --loop' for unlimited until convergence with a 999-iteration cap), \" +\n\t\t\t\t\"--fresh for context collapse between iterations, and --no-converge to disable early stopping for bounded loops. \" +\n\t\t\t\t\"Supports runtime delegation override via --subagent, --subagent=<name>, or --subagent:<name>. \" +\n\t\t\t\t\"Use 'chain-prompts template1 -> template2' for chaining and add --chain-context to pass previous step summaries into delegated steps.\",\n\t\t\tpromptSnippet:\n\t\t\t\t\"Use this to run slash/prompt templates by name with args (including --loop/--fresh and chain-prompts flows) when the user asks to execute a prompt template.\",\n\t\t\tparameters: Type.Object({\n\t\t\t\tcommand: Type.String({\n\t\t\t\t\tdescription: \"Template name and arguments (e.g. 'deslop --loop 5 --fresh', 'deslop --subagent:worker', 'deslop --subagent', 'chain-prompts analyze -> fix --chain-context', 'chain-prompts analyze -> fix --loop=3')\",\n\t\t\t\t}),\n\t\t\t}),\n\t\t\texecute: async (_id, params) => {\n\t\t\t\tif (!toolEnabled) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"run-prompt tool is disabled. User must run `/prompt-tool on` to enable.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (deps.isActive()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"A prompt command is already running. Wait for it to complete.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!deps.getStoredCtx()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No command context. Run any prompt command first to initialize.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst commandParam = (params as { command?: unknown }).command;\n\t\t\t\tconst command = typeof commandParam === \"string\" ? commandParam.trim() : \"\";\n\t\t\t\tif (!command) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No command specified.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (toolQueuedCommand) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"A prompt command is already queued. Wait for it to execute.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\ttoolQueuedCommand = command;\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Prompt command queued: \"${command}\". Will execute when this turn ends.` }],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tfunction registerCommand() {\n\t\tpi.registerCommand(\"prompt-tool\", {\n\t\t\tdescription: \"Manage the run-prompt tool (agent-accessible prompt execution)\",\n\t\t\thandler: async (args, ctx) => {\n\t\t\t\tdeps.setStoredCtx(ctx);\n\t\t\t\tconst trimmed = args.trim();\n\n\t\t\t\tif (trimmed === \"on\" || trimmed.startsWith(\"on \")) {\n\t\t\t\t\ttoolEnabled = true;\n\t\t\t\t\tensureRegistered();\n\t\t\t\t\tconst guidanceRaw = trimmed.slice(\"on\".length).trim();\n\t\t\t\t\tif (guidanceRaw) {\n\t\t\t\t\t\ttoolGuidance = guidanceRaw.replace(/^[\"']|[\"']$/g, \"\");\n\t\t\t\t\t\tnotify(ctx, `run-prompt tool enabled with guidance: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(ctx, \"run-prompt tool enabled.\", \"info\");\n\t\t\t\t\t}\n\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (trimmed === \"off\") {\n\t\t\t\t\ttoolEnabled = false;\n\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\tnotify(ctx, \"run-prompt tool disabled.\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (trimmed === \"guidance\" || trimmed.startsWith(\"guidance \")) {\n\t\t\t\t\tif (trimmed === \"guidance\" || trimmed === \"guidance show\") {\n\t\t\t\t\t\tif (toolGuidance) {\n\t\t\t\t\t\t\tnotify(ctx, `Current guidance: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnotify(ctx, \"No guidance set. Use `/prompt-tool guidance <text>` to set.\", \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (trimmed === \"guidance clear\") {\n\t\t\t\t\t\ttoolGuidance = null;\n\t\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\t\tnotify(ctx, \"Guidance cleared.\", \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst guidanceRaw = trimmed.slice(\"guidance\".length).trim();\n\t\t\t\t\t\ttoolGuidance = guidanceRaw.replace(/^[\"']|[\"']$/g, \"\");\n\t\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\t\tnotify(ctx, `Guidance set: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!trimmed) {\n\t\t\t\t\tif (toolEnabled) {\n\t\t\t\t\t\tconst guidanceInfo = toolGuidance ? ` | Guidance: \"${toolGuidance}\"` : \"\";\n\t\t\t\t\t\tnotify(ctx, `run-prompt tool is enabled${guidanceInfo}`, \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(ctx, \"run-prompt tool is disabled\", \"info\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tnotify(ctx, \"Usage: /prompt-tool [on [guidance] | off | guidance [text|clear]]\", \"error\");\n\t\t\t},\n\t\t});\n\t}\n\n\tasync function processQueue(ctx: ExtensionContext, restoreFn: () => Promise<void>) {\n\t\tif (!toolQueuedCommand) return false;\n\t\tconst storedCtx = deps.getStoredCtx();\n\t\tif (!storedCtx) {\n\t\t\ttoolQueuedCommand = null;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst command = toolQueuedCommand;\n\t\ttoolQueuedCommand = null;\n\t\tawait restoreFn();\n\t\ttry {\n\t\t\tawait deps.executeCommand(command, storedCtx);\n\t\t} catch (error) {\n\t\t\tnotify(\n\t\t\t\tctx,\n\t\t\t\t`Failed to execute queued prompt command \"${command}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\"error\",\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\treturn {\n\t\tisEnabled() {\n\t\t\treturn toolEnabled;\n\t\t},\n\t\tgetGuidance() {\n\t\t\treturn toolGuidance;\n\t\t},\n\t\thasQueuedCommand() {\n\t\t\treturn toolQueuedCommand !== null;\n\t\t},\n\t\tclearQueue() {\n\t\t\ttoolQueuedCommand = null;\n\t\t},\n\t\tensureRegistered,\n\t\tregisterCommand,\n\t\tprocessQueue,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tool-manager.js","sourceRoot":"","sources":["../../../src/builtin-extensions/pi-prompt-template-model/tool-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// @ts-nocheck\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from \"@ashx-j/lunr\";\nimport { getAgentDir } from \"../../config.ts\";\nimport { Type } from \"typebox\";\nimport { notify } from \"./notifications.ts\";\n\nexport interface ToolManagerDeps {\n\tisActive(): boolean;\n\tgetStoredCtx(): ExtensionCommandContext | null;\n\tsetStoredCtx(ctx: ExtensionCommandContext | null): void;\n\texecuteCommand(command: string, ctx: ExtensionCommandContext): Promise<void>;\n}\n\nexport function createToolManager(pi: ExtensionAPI, deps: ToolManagerDeps) {\n\tlet toolEnabled = false;\n\tlet toolGuidance: string | null = null;\n\tlet toolRegistered = false;\n\tlet toolQueuedCommand: string | null = null;\n\tconst configPath = join(getAgentDir(), \"prompt-template-model.json\");\n\n\ttry {\n\t\tconst rawConfig = JSON.parse(readFileSync(configPath, \"utf-8\"));\n\t\tif (rawConfig && typeof rawConfig === \"object\") {\n\t\t\tconst config = rawConfig as { toolEnabled?: unknown; toolGuidance?: unknown };\n\t\t\tif (typeof config.toolEnabled === \"boolean\") {\n\t\t\t\ttoolEnabled = config.toolEnabled;\n\t\t\t}\n\t\t\tif (typeof config.toolGuidance === \"string\") {\n\t\t\t\ttoolGuidance = config.toolGuidance;\n\t\t\t}\n\t\t}\n\t} catch (error) {\n\t\tconst err = error as NodeJS.ErrnoException;\n\t\tif (err.code !== \"ENOENT\") {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`[pi-prompt-template-model] Failed to read ${configPath}: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction saveToolConfig() {\n\t\ttry {\n\t\t\tmkdirSync(getAgentDir(), { recursive: true });\n\t\t\twriteFileSync(configPath, JSON.stringify({ toolEnabled, toolGuidance }, null, 2));\n\t\t} catch (error) {\n\t\t\tprocess.stderr.write(\n\t\t\t\t`[pi-prompt-template-model] Failed to write ${configPath}: ${error instanceof Error ? error.message : String(error)}\\n`,\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction ensureRegistered() {\n\t\tif (toolRegistered) return;\n\t\ttoolRegistered = true;\n\t\tpi.registerTool({\n\t\t\tname: \"run-prompt\",\n\t\t\tlabel: \"Run Prompt\",\n\t\t\tdescription:\n\t\t\t\t\"Run a prompt template command. Pass the template name and any arguments. \" +\n\t\t\t\t\"Supports --loop for loops (e.g. 'deslop --loop 5', 'deslop --loop=5', 'deslop --loop' for unlimited until convergence with a 999-iteration cap), \" +\n\t\t\t\t\"--fresh for context collapse between iterations, and --no-converge to disable early stopping for bounded loops. \" +\n\t\t\t\t\"Supports runtime delegation override via --subagent, --subagent=<name>, or --subagent:<name>. \" +\n\t\t\t\t\"Use 'chain-prompts template1 -> template2' for chaining and add --chain-context to pass previous step summaries into delegated steps.\",\n\t\t\tpromptSnippet:\n\t\t\t\t\"Use this to run slash/prompt templates by name with args (including --loop/--fresh and chain-prompts flows) when the user asks to execute a prompt template.\",\n\t\t\tparameters: Type.Object({\n\t\t\t\tcommand: Type.String({\n\t\t\t\t\tdescription: \"Template name and arguments (e.g. 'deslop --loop 5 --fresh', 'deslop --subagent:worker', 'deslop --subagent', 'chain-prompts analyze -> fix --chain-context', 'chain-prompts analyze -> fix --loop=3')\",\n\t\t\t\t}),\n\t\t\t}),\n\t\t\texecute: async (_id, params) => {\n\t\t\t\tif (!toolEnabled) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"run-prompt tool is disabled. User must run `/prompt-tool on` to enable.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (deps.isActive()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"A prompt command is already running. Wait for it to complete.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!deps.getStoredCtx()) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No command context. Run any prompt command first to initialize.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst commandParam = (params as { command?: unknown }).command;\n\t\t\t\tconst command = typeof commandParam === \"string\" ? commandParam.trim() : \"\";\n\t\t\t\tif (!command) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"No command specified.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (toolQueuedCommand) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: \"A prompt command is already queued. Wait for it to execute.\" }],\n\t\t\t\t\t\tdetails: {},\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\ttoolQueuedCommand = command;\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Prompt command queued: \"${command}\". Will execute when this turn ends.` }],\n\t\t\t\t\tdetails: {},\n\t\t\t\t};\n\t\t\t},\n\t\t});\n\t}\n\n\tfunction registerCommand() {\n\t\tpi.registerCommand(\"prompt-tool\", {\n\t\t\tdescription: \"Manage the run-prompt tool (agent-accessible prompt execution)\",\n\t\t\thandler: async (args, ctx) => {\n\t\t\t\tdeps.setStoredCtx(ctx);\n\t\t\t\tconst trimmed = args.trim();\n\n\t\t\t\tif (trimmed === \"on\" || trimmed.startsWith(\"on \")) {\n\t\t\t\t\ttoolEnabled = true;\n\t\t\t\t\tensureRegistered();\n\t\t\t\t\tconst guidanceRaw = trimmed.slice(\"on\".length).trim();\n\t\t\t\t\tif (guidanceRaw) {\n\t\t\t\t\t\ttoolGuidance = guidanceRaw.replace(/^[\"']|[\"']$/g, \"\");\n\t\t\t\t\t\tnotify(ctx, `run-prompt tool enabled with guidance: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(ctx, \"run-prompt tool enabled.\", \"info\");\n\t\t\t\t\t}\n\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (trimmed === \"off\") {\n\t\t\t\t\ttoolEnabled = false;\n\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\tnotify(ctx, \"run-prompt tool disabled.\", \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (trimmed === \"guidance\" || trimmed.startsWith(\"guidance \")) {\n\t\t\t\t\tif (trimmed === \"guidance\" || trimmed === \"guidance show\") {\n\t\t\t\t\t\tif (toolGuidance) {\n\t\t\t\t\t\t\tnotify(ctx, `Current guidance: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnotify(ctx, \"No guidance set. Use `/prompt-tool guidance <text>` to set.\", \"info\");\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (trimmed === \"guidance clear\") {\n\t\t\t\t\t\ttoolGuidance = null;\n\t\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\t\tnotify(ctx, \"Guidance cleared.\", \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst guidanceRaw = trimmed.slice(\"guidance\".length).trim();\n\t\t\t\t\t\ttoolGuidance = guidanceRaw.replace(/^[\"']|[\"']$/g, \"\");\n\t\t\t\t\t\tsaveToolConfig();\n\t\t\t\t\t\tnotify(ctx, `Guidance set: \"${toolGuidance}\"`, \"info\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!trimmed) {\n\t\t\t\t\tif (toolEnabled) {\n\t\t\t\t\t\tconst guidanceInfo = toolGuidance ? ` | Guidance: \"${toolGuidance}\"` : \"\";\n\t\t\t\t\t\tnotify(ctx, `run-prompt tool is enabled${guidanceInfo}`, \"info\");\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnotify(ctx, \"run-prompt tool is disabled\", \"info\");\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tnotify(ctx, \"Usage: /prompt-tool [on [guidance] | off | guidance [text|clear]]\", \"error\");\n\t\t\t},\n\t\t});\n\t}\n\n\tasync function processQueue(ctx: ExtensionContext, restoreFn: () => Promise<void>) {\n\t\tif (!toolQueuedCommand) return false;\n\t\tconst storedCtx = deps.getStoredCtx();\n\t\tif (!storedCtx) {\n\t\t\ttoolQueuedCommand = null;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst command = toolQueuedCommand;\n\t\ttoolQueuedCommand = null;\n\t\tawait restoreFn();\n\t\ttry {\n\t\t\tawait deps.executeCommand(command, storedCtx);\n\t\t} catch (error) {\n\t\t\tnotify(\n\t\t\t\tctx,\n\t\t\t\t`Failed to execute queued prompt command \"${command}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\"error\",\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\treturn {\n\t\tisEnabled() {\n\t\t\treturn toolEnabled;\n\t\t},\n\t\tgetGuidance() {\n\t\t\treturn toolGuidance;\n\t\t},\n\t\thasQueuedCommand() {\n\t\t\treturn toolQueuedCommand !== null;\n\t\t},\n\t\tclearQueue() {\n\t\t\ttoolQueuedCommand = null;\n\t\t},\n\t\tensureRegistered,\n\t\tregisterCommand,\n\t\tprocessQueue,\n\t};\n}\n"]}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Config file: ~/.lunr/agent/extensions/subagent/config.json
|
|
12
12
|
* { "asyncByDefault": true, "forceTopLevelAsync": true, "maxSubagentDepth": 1, "intercomBridge": { "mode": "always", "instructionFile": "./intercom-bridge.md" }, "worktreeSetupHook": "./scripts/setup-worktree.mjs" }
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import type { ExtensionAPI } from "@ashx-j/lunr";
|
|
15
15
|
import { Text } from "@ashx-j/lunr-tui";
|
|
16
16
|
export { loadConfig } from "./config.ts";
|
|
17
17
|
export declare function renderSubagentCall(args: any, theme: any, context: any): Text;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/index.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AAOH,OAAO,EAAW,KAAK,YAAY,EAA8C,MAAM,iCAAiC,CAAC;AACzH,OAAO,EAA0B,IAAI,EAAmE,MAAM,wBAAwB,CAAC;AAmDvI,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAwEzC,wBAAgB,kBAAkB,CAAC,IAAI,KAAA,EAAE,KAAK,KAAA,EAAE,OAAO,KAAA,GAAG,IAAI,CAiC7D;AA8FD,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA0XxE","sourcesContent":["// @ts-nocheck\n/**\n * Subagent Tool\n *\n * Full-featured subagent with sync and async modes.\n * - Sync (default): Streams output, renders markdown, tracks usage\n * - Async: Background execution, emits events when done\n *\n * Modes: single (agent + task), parallel (tasks[]), chain (chain[] with {previous})\n * Toggle: async parameter (default: false, configurable via config.json)\n *\n * Config file: ~/.lunr/agent/extensions/subagent/config.json\n * { \"asyncByDefault\": true, \"forceTopLevelAsync\": true, \"maxSubagentDepth\": 1, \"intercomBridge\": { \"mode\": \"always\", \"instructionFile\": \"./intercom-bridge.md\" }, \"worktreeSetupHook\": \"./scripts/setup-worktree.mjs\" }\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { AgentToolResult } from \"@ashx-j/lunr-agent\";\nimport { keyText, type ExtensionAPI, type ExtensionContext, type ToolDefinition } from \"@ashx-j/lunr\";\nimport { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from \"@ashx-j/lunr-tui\";\n\nimport { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from \"../shared/artifacts.ts\";\nimport { resolveCurrentSessionId } from \"../shared/session-identity.ts\";\nimport { cleanupOldChainDirs } from \"../shared/settings.ts\";\nimport { clearLegacyResultAnimationTimer, renderSubagentResult, subagentAnimSink } from \"../tui/render.ts\";\nimport { SubagentParams } from \"./schemas.ts\";\nimport { validateChainInput } from \"./chain-validation.ts\";\nimport { createSubagentExecutor, type SubagentParamsLike } from \"../runs/foreground/subagent-executor.ts\";\nimport { createAsyncJobTracker } from \"../runs/background/async-job-tracker.ts\";\nimport { createResultWatcher } from \"../runs/background/result-watcher.ts\";\nimport { createScheduledRunManager } from \"../runs/background/scheduled-runs.ts\";\nimport { registerSlashCommands } from \"../slash/slash-commands.ts\";\nimport { registerPromptTemplateDelegationBridge } from \"../slash/prompt-template-bridge.ts\";\nimport { registerMainWatchdog } from \"../watchdog/register-main.ts\";\nimport { registerSlashSubagentBridge } from \"../slash/slash-bridge.ts\";\nimport { createNativeSupervisorChannel } from \"../intercom/native-supervisor-channel.ts\";\nimport { registerSubagentRpcBridge } from \"./rpc.ts\";\nimport { clearSlashSnapshots, getSlashRenderableSnapshot, resolveSlashMessageDetails, restoreSlashFinalSnapshots, type SlashMessageDetails } from \"../slash/slash-live-state.ts\";\nimport { inspectSubagentStatus } from \"../runs/background/run-status.ts\";\nimport { resolveWaitToolConfig } from \"../runs/background/subagent-wait.ts\";\nimport { registerWaitTool } from \"../runs/background/wait-tool.ts\";\nimport { drainOutstandingWork } from \"../runs/background/auto-drain.ts\";\nimport registerSubagentNotify, { parseSubagentNotifyContent, type SubagentNotifyDetails } from \"../runs/background/notify.ts\";\nimport { formatSteeringNotice, handleSubagentSteeringNotice, SUBAGENT_STEERING_MESSAGE_TYPE, type SubagentSteeringMessageDetails } from \"./steering-notices.ts\";\nimport { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from \"../runs/shared/pi-args.ts\";\nimport { formatDuration, shortenPath } from \"../shared/formatters.ts\";\nimport { loadConfig } from \"./config.ts\";\nimport { buildSubagentToolDescription } from \"./tool-description.ts\";\nimport {\n\ttype Details,\n\ttype SubagentState,\n\tASYNC_DIR,\n\tDEFAULT_ARTIFACT_CONFIG,\n\tRESULTS_DIR,\n\tSLASH_RESULT_TYPE,\n\tSLASH_TEXT_RESULT_TYPE,\n\tSUBAGENT_ASYNC_COMPLETE_EVENT,\n\tSUBAGENT_ASYNC_STARTED_EVENT,\n\tSUBAGENT_CONTROL_EVENT,\n\tSUBAGENT_STEERING_NOTICE_EVENT,\n\tWIDGET_KEY,\n} from \"../shared/types.ts\";\nimport {\n\tclearPendingForegroundControlNotices,\n\tformatSubagentControlNotice,\n\thandleSubagentControlNotice,\n\tSUBAGENT_CONTROL_MESSAGE_TYPE,\n\ttype SubagentControlMessageDetails,\n} from \"./control-notices.ts\";\n\nexport { loadConfig } from \"./config.ts\";\n\n/**\n * Derive subagent session base directory from parent session file.\n * If parent session is ~/.lunr/agent/sessions/abc123.jsonl,\n * returns ~/.lunr/agent/sessions/abc123/ as the base.\n * Callers add runId to create the actual session root: abc123/{runId}/\n * Falls back to a unique temp directory if no parent session.\n */\nfunction getSubagentSessionRoot(parentSessionFile: string | null): string {\n\tif (parentSessionFile) {\n\t\tconst baseName = path.basename(parentSessionFile, \".jsonl\");\n\t\tconst sessionsDir = path.dirname(parentSessionFile);\n\t\treturn path.join(sessionsDir, baseName);\n\t}\n\treturn fs.mkdtempSync(path.join(os.tmpdir(), \"pi-subagent-session-\"));\n}\n\nfunction expandTilde(p: string): string {\n\treturn p.startsWith(\"~/\") ? path.join(os.homedir(), p.slice(2)) : p;\n}\n\n/**\n * Create a directory and verify it is actually accessible.\n * On Windows with Azure AD/Entra ID, directories created shortly after\n * wake-from-sleep can end up with broken NTFS ACLs (null DACL) when the\n * cloud SID cannot be resolved without network connectivity. This leaves\n * the directory completely inaccessible to the creating user.\n */\nfunction ensureAccessibleDir(dirPath: string): void {\n\tfs.mkdirSync(dirPath, { recursive: true });\n\ttry {\n\t\tfs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n\t} catch {\n\t\ttry {\n\t\t\tfs.rmSync(dirPath, { recursive: true, force: true });\n\t\t} catch {\n\t\t\t// Best effort: retry mkdir/access even if cleanup fails.\n\t\t}\n\t\tfs.mkdirSync(dirPath, { recursive: true });\n\t\tfs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n\t}\n}\n\nfunction isSlashResultRunning(result: { details?: Details }): boolean {\n\treturn result.details?.progress?.some((entry) => entry.status === \"running\")\n\t\t|| result.details?.results.some((entry) => entry.progress?.status === \"running\")\n\t\t|| false;\n}\n\n// Drives the inline running-indicator braille animation for foreground subagent\n// results. Foreground runs receive progress only on child events, so the glyph\n// (derived from progress fields) would freeze between events. While a result is\n// running we tick a frame counter every 80ms; renderResult registers the\n// running-glyph lines in state.animEntries (via subagentAnimSink) and the timer\n// rewrites just those Text nodes + requests a repaint, instead of invalidate()-ing\n// the whole tool component (a full renderSubagentResult rebuild 12.5x/s made the\n// spinner laggy).\nfunction subagentResultIsRunning(result: { details?: Details }): boolean {\n\treturn result.details?.progress?.some((entry) => entry.status === \"running\")\n\t\t|| result.details?.results.some((entry) => entry.progress?.status === \"running\")\n\t\t|| false;\n}\n\nfunction effectiveParallelTaskCount(tasks: Array<{ count?: unknown }> | undefined): number {\n\tif (!tasks || tasks.length === 0) return 0;\n\treturn tasks.reduce((total, task) => {\n\t\tconst count = typeof task.count === \"number\" && Number.isInteger(task.count) && task.count >= 1 ? task.count : 1;\n\t\treturn total + count;\n\t}, 0);\n}\n\nexport function renderSubagentCall(args, theme, context): Text {\n\tif (args.action) {\n\t\tconst target = args.id || args.runId || \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"subagent \"))}${args.action}${target ? ` ${theme.fg(\"accent\", target)}` : \"\"}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst isParallel = (args.tasks?.length ?? 0) > 0;\n\tconst parallelCount = effectiveParallelTaskCount(args.tasks as Array<{ count?: unknown }> | undefined);\n\tconst asyncLabel = args.async === true && args.clarify !== true ? theme.fg(\"warning\", \" [async]\") : \"\";\n\tif (args.chain?.length) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"subagent \"))}chain (${args.chain.length})${asyncLabel}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tif (isParallel) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"subagent \"))}parallel (${parallelCount})${asyncLabel}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst showDescription = !context?.isPartial && !context?.expanded && !context?.isError;\n\tconst description = showDescription ? theme.fg(\"accent\", args.description || args.task || \"?\") : \"\";\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(description ? \"subagent \" : \"subagent\"))}${description}${asyncLabel}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\nfunction ensureSubagentResultAnimation(context: { state: Record<string, unknown>; invalidate?: () => void; requestRender?: () => void }): void {\n\tconst state = context.state as {\n\t\tsubagentResultAnimationTimer?: ReturnType<typeof setInterval>;\n\t\tframe?: number;\n\t\tanimEntries?: Array<{ text: Text; line: (frame: number, now: number) => string }>;\n\t};\n\tif (state.subagentResultAnimationTimer) return;\n\tif (typeof context.invalidate !== \"function\") return;\n\tif (state.frame === undefined) state.frame = 0;\n\tstate.subagentResultAnimationTimer = setInterval(() => {\n\t\tstate.frame = ((state.frame ?? 0) + 1) % 10;\n\t\ttry {\n\t\t\tconst entries = state.animEntries;\n\t\t\tif (entries?.length && typeof context.requestRender === \"function\") {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tfor (const entry of entries) entry.text.setText(entry.line(state.frame ?? 0, now));\n\t\t\t\tcontext.requestRender();\n\t\t\t} else {\n\t\t\t\tcontext.invalidate();\n\t\t\t}\n\t\t} catch {}\n\t}, 80);\n}\n\nfunction isSlashResultError(result: { details?: Details }): boolean {\n\treturn result.details?.results.some((entry) => entry.exitCode !== 0 && entry.progress?.status !== \"running\") || false;\n}\n\nfunction isStaleExtensionContextError(error: unknown): boolean {\n\treturn error instanceof Error && error.message.includes(\"Extension context no longer active\");\n}\n\nfunction rebuildSlashResultContainer(\n\tcontainer: Container,\n\tresult: AgentToolResult<Details>,\n\toptions: { expanded: boolean },\n\ttheme: ExtensionContext[\"ui\"][\"theme\"],\n): void {\n\tcontainer.clear();\n\tcontainer.addChild(new Spacer(1));\n\tconst boxTheme = isSlashResultRunning(result) ? \"toolPendingBg\" : isSlashResultError(result) ? \"toolErrorBg\" : \"toolSuccessBg\";\n\tconst box = new Box(1, 1, (text: string) => theme.bg(boxTheme, text));\n\tbox.addChild(renderSubagentResult(result, options, theme));\n\tcontainer.addChild(box);\n}\n\nfunction createSlashResultComponent(\n\tdetails: SlashMessageDetails,\n\toptions: { expanded: boolean },\n\ttheme: ExtensionContext[\"ui\"][\"theme\"],\n): Container {\n\tconst container = new Container();\n\tlet lastVersion = -1;\n\tcontainer.render = (width: number): string[] => {\n\t\tconst snapshot = getSlashRenderableSnapshot(details);\n\t\tif (snapshot.version !== lastVersion || isSlashResultRunning(snapshot.result)) {\n\t\t\tlastVersion = snapshot.version;\n\t\t\trebuildSlashResultContainer(container, snapshot.result, options, theme);\n\t\t}\n\t\treturn Container.prototype.render.call(container, width);\n\t};\n\treturn container;\n}\n\nclass SubagentControlNoticeComponent implements Component {\n\tconstructor(\n\t\tprivate readonly details: SubagentControlMessageDetails,\n\t\tprivate readonly theme: ExtensionContext[\"ui\"][\"theme\"],\n\t) {}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst eventLabel = this.details.event.type.replaceAll(\"_\", \" \");\n\t\tif (width < 3) return [truncateToWidth(`Subagent ${eventLabel}`, width)];\n\t\tconst bodyWidth = Math.max(1, width - 2);\n\t\tconst borderChar = \"─\";\n\t\tconst header = ` ⚠ Subagent ${eventLabel}: ${this.details.event.agent} `;\n\t\tconst headerText = truncateToWidth(header, bodyWidth, \"\");\n\t\tconst headerPadding = Math.max(0, bodyWidth - visibleWidth(headerText));\n\t\tconst lines = [this.theme.fg(\"accent\", `╭${headerText}${borderChar.repeat(headerPadding)}╮`)];\n\n\t\tfor (const line of wrapTextWithAnsi(formatSubagentControlNotice(this.details), bodyWidth)) {\n\t\t\tconst text = truncateToWidth(line, bodyWidth, \"\");\n\t\t\tconst padding = Math.max(0, bodyWidth - visibleWidth(text));\n\t\t\tlines.push(this.theme.fg(\"accent\", `│${text}${\" \".repeat(padding)}│`));\n\t\t}\n\t\tlines.push(this.theme.fg(\"accent\", `╰${borderChar.repeat(bodyWidth)}╯`));\n\t\treturn lines;\n\t}\n}\n\nexport default function registerSubagentExtension(pi: ExtensionAPI): void {\n\tif (process.env[SUBAGENT_CHILD_ENV] === \"1\") {\n\t\treturn;\n\t}\n\tconst globalStore = globalThis as Record<string, unknown>;\n\tconst runtimeCleanupStoreKey = \"__piSubagentRuntimeCleanup\";\n\tconst previousRuntimeCleanup = globalStore[runtimeCleanupStoreKey];\n\tif (typeof previousRuntimeCleanup === \"function\") {\n\t\ttry {\n\t\t\tpreviousRuntimeCleanup();\n\t\t} catch {\n\t\t\t// Best effort cleanup for stale timers from an older reload.\n\t\t}\n\t}\n\n\tensureAccessibleDir(RESULTS_DIR);\n\tensureAccessibleDir(ASYNC_DIR);\n\tcleanupOldChainDirs();\n\n\tconst config = loadConfig();\n\tconst waitToolConfig = resolveWaitToolConfig(config.waitTool);\n\tconst asyncByDefault = config.asyncByDefault === true;\n\tconst tempArtifactsDir = getArtifactsDir(null);\n\tcleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);\n\n\tconst state: SubagentState = {\n\t\tbaseCwd: \"\",\n\t\tcurrentSessionId: null,\n\t\tforegroundSubagentInFlight: 0,\n\t\tsubagentSpawns: { sessionId: null, count: 0 },\n\t\tasyncJobs: new Map(),\n\t\tfleetJobs: new Map(),\n\t\tforegroundRuns: new Map(),\n\t\tforegroundControls: new Map(),\n\t\tlastForegroundControlId: null,\n\t\tpendingForegroundControlNotices: new Map(),\n\t\tcleanupTimers: new Map(),\n\t\tlastUiContext: null,\n\t\tpoller: null,\n\t\tcompletionSeen: new Map(),\n\t\twatcher: null,\n\t\twatcherRestartTimer: null,\n\t\tresultFileCoalescer: {\n\t\t\tschedule: () => false,\n\t\t\tclear: () => {},\n\t\t},\n\t};\n\n\tconst supervisorChannel = createNativeSupervisorChannel(pi, state);\n\tconst mainWatchdog = registerMainWatchdog(pi);\n\tconst { startResultWatcher, primeExistingResults, stopResultWatcher } = createResultWatcher(\n\t\tpi,\n\t\tstate,\n\t\tRESULTS_DIR,\n\t\t10 * 60 * 1000,\n\t);\n\tstartResultWatcher();\n\tprimeExistingResults();\n\n\tconst runtimeCleanup = () => {\n\t\tmainWatchdog.dispose();\n\t\tstopResultWatcher();\n\t\tscheduledRunManager.stop();\n\t\tsupervisorChannel.dispose();\n\t\tclearPendingForegroundControlNotices(state);\n\t\tif (state.poller) {\n\t\t\tclearInterval(state.poller);\n\t\t\tstate.poller = null;\n\t\t}\n\t};\n\tglobalStore[runtimeCleanupStoreKey] = runtimeCleanup;\n\n\tconst { ensurePoller, refreshWidget, handleStarted, handleComplete, resetJobs, restoreActiveJobs } = createAsyncJobTracker(pi, state, ASYNC_DIR, {\n\t\twidgetEnabled: config.asyncWidget !== false,\n\t});\n\tlet executorExecute: ((id: string, params: SubagentParamsLike, signal: AbortSignal, onUpdate: ((r: AgentToolResult<Details>) => void) | undefined, ctx: ExtensionContext) => Promise<AgentToolResult<Details>>) | undefined;\n\tconst scheduledRunManager = createScheduledRunManager({\n\t\tconfig,\n\t\tlaunch: (params, ctx, signal) => {\n\t\t\tif (!executorExecute) {\n\t\t\t\treturn Promise.resolve({\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"Scheduled subagent launch is unavailable (executor not ready).\" }],\n\t\t\t\t\tisError: true,\n\t\t\t\t\tdetails: { mode: \"management\" as const, results: [] },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn executorExecute(randomUUID(), params, signal, undefined, ctx);\n\t\t},\n\t});\n\tconst executor = createSubagentExecutor({\n\t\tpi,\n\t\tstate,\n\t\tconfig,\n\t\tasyncByDefault,\n\t\twaitToolEnabled: waitToolConfig.enabled,\n\t\thandleScheduledRunAction: (params, ctx) => scheduledRunManager.handleToolCall(params, ctx),\n\t\twatchdog: mainWatchdog,\n\t\ttempArtifactsDir,\n\t\tgetSubagentSessionRoot,\n\t\texpandTilde,\n\t});\n\texecutorExecute = executor.execute;\n\n\tpi.registerMessageRenderer<SlashMessageDetails>(SLASH_RESULT_TYPE, (message, options, theme) => {\n\t\tconst details = resolveSlashMessageDetails(message.details);\n\t\tif (!details) return undefined;\n\t\treturn createSlashResultComponent(details, options, theme);\n\t});\n\n\tpi.registerMessageRenderer<undefined>(SLASH_TEXT_RESULT_TYPE, (message, _options, _theme) => {\n\t\tconst content = typeof message.content === \"string\"\n\t\t\t? message.content\n\t\t\t: message.content\n\t\t\t\t.filter((entry) => entry.type === \"text\")\n\t\t\t\t.map((entry) => entry.text)\n\t\t\t\t.join(\"\\n\");\n\t\treturn new Text(content, 0, 0);\n\t});\n\n\tpi.registerMessageRenderer<SubagentNotifyDetails>(\"subagent-notify\", (message, options, theme) => {\n\t\tconst content = typeof message.content === \"string\" ? message.content : \"\";\n\t\tconst details = (message.details as SubagentNotifyDetails | undefined) ?? parseSubagentNotifyContent(content);\n\t\tif (!details) return new Text(content, 0, 0);\n\t\tconst icon = details.status === \"completed\"\n\t\t\t? theme.fg(\"success\", \"✓\")\n\t\t\t: details.status === \"paused\"\n\t\t\t\t? theme.fg(\"warning\", \"■\")\n\t\t\t\t: theme.fg(\"error\", \"✗\");\n\t\tconst parts: string[] = [];\n\t\tif (details.taskInfo) parts.push(details.taskInfo);\n\t\tif (details.durationMs !== undefined) parts.push(formatDuration(details.durationMs));\n\t\tconst notifyLabel = details.taskInfo || details.agent || \"child\";\n\t\tlet text = `${icon} ${theme.bold(notifyLabel)} ${theme.fg(\"dim\", details.status)}`;\n\t\tif (parts.length > 0) text += ` ${theme.fg(\"dim\", \"·\")} ${parts.map((part) => theme.fg(\"dim\", part)).join(` ${theme.fg(\"dim\", \"·\")} `)}`;\n\t\tconst trimmedPreview = details.resultPreview.trim();\n\t\tconst previewLines = options.expanded\n\t\t\t? trimmedPreview.split(\"\\n\").filter((line) => line.trim())\n\t\t\t: [trimmedPreview.split(\"\\n\", 1)[0] ?? \"\"].filter((line) => line.trim());\n\t\tfor (const line of previewLines.length > 0 ? previewLines : [\"(no output)\"]) {\n\t\t\ttext += `\\n ${theme.fg(\"dim\", `⎿ ${line}`)}`;\n\t\t}\n\t\tif (!options.expanded && trimmedPreview.includes(\"\\n\")) {\n\t\t\tconst expandKey = keyText(\"app.tools.expand\");\n\t\t\ttext += `\\n ${theme.fg(\"dim\", `${expandKey} full notification`)}`;\n\t\t}\n\t\tif (details.sessionLabel && details.sessionValue) {\n\t\t\ttext += `\\n ${theme.fg(\"muted\", `${details.sessionLabel}: ${shortenPath(details.sessionValue)}`)}`;\n\t\t}\n\t\treturn new Text(text, 0, 0);\n\t});\n\n\tpi.registerMessageRenderer<SubagentSteeringMessageDetails>(SUBAGENT_STEERING_MESSAGE_TYPE, (message, _options, theme) => {\n\t\tconst details = message.details as SubagentSteeringMessageDetails | undefined;\n\t\tif (!details) return undefined;\n\t\treturn new Text(theme.fg(details.state === \"recovered\" ? \"warning\" : \"error\", formatSteeringNotice(details)), 0, 0);\n\t});\n\n\tpi.registerMessageRenderer<SubagentControlMessageDetails>(SUBAGENT_CONTROL_MESSAGE_TYPE, () => undefined);\n\n\tconst executeSubagentCollapsed = (id: string, params: SubagentParamsLike, signal: AbortSignal, onUpdate: ((result: AgentToolResult<Details>) => void) | undefined, ctx: ExtensionContext) => {\n\t\tif (ctx.hasUI) ctx.ui.setToolsExpanded(false);\n\t\treturn executor.execute(id, params, signal, onUpdate, ctx);\n\t};\n\n\tconst slashBridge = registerSlashSubagentBridge({\n\t\tevents: pi.events,\n\t\tgetContext: () => state.lastUiContext,\n\t\texecute: (id, params, signal, onUpdate, ctx) =>\n\t\t\texecuteSubagentCollapsed(id, params, signal, onUpdate, ctx),\n\t});\n\n\tconst promptTemplateBridge = registerPromptTemplateDelegationBridge({\n\t\tevents: pi.events,\n\t\tgetContext: () => state.lastUiContext,\n\t\texecute: (requestId, params, signal, ctx, onUpdate) =>\n\t\t\texecuteSubagentCollapsed(requestId, params, signal, onUpdate, ctx),\n\t});\n\n\tconst rpcBridge = registerSubagentRpcBridge({\n\t\tevents: pi.events,\n\t\tgetContext: () => state.lastUiContext,\n\t\texecute: (id, params, signal, onUpdate, ctx) => executor.execute(id, params, signal, onUpdate, ctx),\n\t});\n\n\tconst tool: ToolDefinition<typeof SubagentParams, Details> = {\n\t\tname: \"subagent\",\n\t\tlabel: \"Subagent\",\n\t\tdescription: buildSubagentToolDescription(config),\n\t\tparameters: SubagentParams,\n\t\t// lunr: same-turn SINGLE calls overlap; sequential work uses chain.\n\t\texecutionMode: \"parallel\",\n\n\t\tprepareArguments(args) {\n\t\t\t// Run friendly chain validation before pi-ai's raw TypeBox schema check\n\t\t\t// so the model sees which property is disallowed, what is allowed, and a\n\t\t\t// valid example instead of `chain.N: must not have additional properties`.\n\t\t\tvalidateChainInput(args);\n\t\t\treturn args as never;\n\t\t},\n\n\t\texecute(id, params, signal, onUpdate, ctx) {\n\t\t\treturn executeSubagentCollapsed(id, params, signal, onUpdate, ctx);\n\t\t},\n\n\t\trenderCall: renderSubagentCall,\n\n\t\trenderResult(result, options, theme, context) {\n\t\t\tif (subagentResultIsRunning(result)) {\n\t\t\t\tensureSubagentResultAnimation(context);\n\t\t\t} else {\n\t\t\t\tclearLegacyResultAnimationTimer(context);\n\t\t\t}\n\t\t\tconst state = context.state as { frame?: number; animEntries?: Array<{ text: Text; line: (frame: number) => string }> };\n\t\t\t// lunr: collect running-glyph line templates while rendering so the\n\t\t\t// animation timer can rewrite them in place (see ensureSubagentResultAnimation).\n\t\t\tconst entries: Array<{ text: Text; line: (frame: number) => string }> = [];\n\t\t\tstate.animEntries = entries;\n\t\t\tsubagentAnimSink.current = entries;\n\t\t\ttry {\n\t\t\t\treturn renderSubagentResult(result, options, theme, state.frame ?? 0);\n\t\t\t} finally {\n\t\t\t\tsubagentAnimSink.current = null;\n\t\t\t}\n\t\t},\n\n\t};\n\n\tpi.registerTool(tool);\n\n\t// lunr: register a callback so toggling model tiers mid-session rebuilds the subagent\n\t// tool description (adds/removes MODEL TIERS guidance) and refreshes the tool registry.\n\tconst modelTierBridge = (globalThis as Record<symbol, unknown>)[Symbol.for(\"@lunr/model-tiers\")] as\n\t\t| { registerToolDescriptionRefresher?: (refresher: () => void) => void }\n\t\t| undefined;\n\tmodelTierBridge?.registerToolDescriptionRefresher?.(() => {\n\t\ttool.description = buildSubagentToolDescription(config);\n\t\t// pi.runtime is not on ExtensionAPI; registerTool refreshes the live registry.\n\t\tpi.registerTool(tool);\n\t});\n\n\tregisterWaitTool(pi, state, waitToolConfig.enabled);\n\n\tpi.on(\"agent_end\", async (_event, ctx) => {\n\t\tif (ctx.hasUI) return;\n\t\tawait drainOutstandingWork({ state, events: pi.events });\n\t});\n\n\tregisterSlashCommands(pi, state);\n\n\tconst eventUnsubscribeStoreKey = \"__piSubagentEventUnsubscribes\";\n\tconst controlNoticeSeenStoreKey = \"__piSubagentVisibleControlNotices\";\n\tconst previousEventUnsubscribes = globalStore[eventUnsubscribeStoreKey];\n\tif (Array.isArray(previousEventUnsubscribes)) {\n\t\tfor (const unsubscribe of previousEventUnsubscribes) {\n\t\t\tif (typeof unsubscribe !== \"function\") continue;\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Best effort cleanup for stale handlers from an older reload.\n\t\t\t}\n\t\t}\n\t}\n\tregisterSubagentNotify(pi, state, { batchConfig: config.completionBatch });\n\n\tconst existingVisibleControlNotices = globalStore[controlNoticeSeenStoreKey];\n\tconst visibleControlNotices = existingVisibleControlNotices instanceof Set ? existingVisibleControlNotices as Set<string> : new Set<string>();\n\tglobalStore[controlNoticeSeenStoreKey] = visibleControlNotices;\n\tconst controlEventHandler = (payload: unknown) => {\n\t\thandleSubagentControlNotice({\n\t\t\tpi,\n\t\t\tstate,\n\t\t\tvisibleControlNotices,\n\t\t\tdetails: payload as SubagentControlMessageDetails,\n\t\t});\n\t};\n\tconst steeringNoticeHandler = (payload: unknown) => {\n\t\thandleSubagentSteeringNotice({ pi, state, details: payload as SubagentSteeringMessageDetails });\n\t};\n\tconst eventUnsubscribes = [\n\t\tpi.events.on(SUBAGENT_ASYNC_STARTED_EVENT, handleStarted),\n\t\tpi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, handleComplete),\n\t\tpi.events.on(SUBAGENT_CONTROL_EVENT, controlEventHandler),\n\t\tpi.events.on(SUBAGENT_STEERING_NOTICE_EVENT, steeringNoticeHandler),\n\t\trpcBridge.dispose,\n\t];\n\tglobalStore[eventUnsubscribeStoreKey] = eventUnsubscribes;\n\n\tpi.on(\"tool_result\", (event, ctx) => {\n\t\tif (event.toolName !== \"subagent\") return;\n\t\tif (!ctx.hasUI) return;\n\t\tstate.lastUiContext = ctx;\n\t\tif (state.asyncJobs.size > 0) {\n\t\t\trefreshWidget(ctx);\n\t\t\tensurePoller();\n\t\t}\n\t});\n\n\tconst cleanupSessionArtifacts = (ctx: ExtensionContext) => {\n\t\ttry {\n\t\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\t\tif (sessionFile) {\n\t\t\t\tcleanupOldArtifacts(getArtifactsDir(sessionFile), DEFAULT_ARTIFACT_CONFIG.cleanupDays);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Cleanup failures should not block session lifecycle events.\n\t\t}\n\t};\n\n\tconst resetSessionState = (ctx: ExtensionContext) => {\n\t\tstate.baseCwd = ctx.cwd;\n\t\tstate.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);\n\t\tstate.subagentSpawns = { sessionId: state.currentSessionId, count: 0 };\n\t\t// Set PI_SUBAGENT_PARENT_SESSION for permission-system forwarding.\n\t\t// Only set in the root session (the interactive UI session), not in\n\t\t// child subagent processes — children inherit the parent's value\n\t\t// through the process environment at spawn time and must not overwrite\n\t\t// it with their own session identity.\n\t\tif (!process.env[SUBAGENT_CHILD_ENV]) {\n\t\t\tconst sessionId = ctx.sessionManager.getSessionId();\n\t\t\tif (sessionId) {\n\t\t\t\tprocess.env[SUBAGENT_PARENT_SESSION_ENV] = sessionId;\n\t\t\t}\n\t\t}\n\t\tstate.lastUiContext = ctx;\n\t\tcleanupSessionArtifacts(ctx);\n\t\tclearPendingForegroundControlNotices(state);\n\t\tresetJobs(ctx);\n\t\trestoreActiveJobs(ctx);\n\t\tscheduledRunManager.bindSession(ctx);\n\t\trestoreSlashFinalSnapshots(ctx.sessionManager.getEntries());\n\t\tprimeExistingResults();\n\t};\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tresetSessionState(ctx);\n\t\trpcBridge.emitReady(ctx);\n\t\tsupervisorChannel.start();\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tdelete process.env[SUBAGENT_PARENT_SESSION_ENV];\n\t\tfor (const unsubscribe of eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Best effort cleanup during shutdown.\n\t\t\t}\n\t\t}\n\t\tif (globalStore[eventUnsubscribeStoreKey] === eventUnsubscribes) {\n\t\t\tdelete globalStore[eventUnsubscribeStoreKey];\n\t\t}\n\t\tstopResultWatcher();\n\t\tscheduledRunManager.stop();\n\t\tif (state.poller) clearInterval(state.poller);\n\t\tstate.poller = null;\n\t\tclearPendingForegroundControlNotices(state);\n\t\tfor (const timer of state.cleanupTimers.values()) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tstate.cleanupTimers.clear();\n\t\tstate.asyncJobs.clear();\n\t\tclearSlashSnapshots();\n\t\tslashBridge.cancelAll();\n\t\tslashBridge.dispose();\n\t\tpromptTemplateBridge.cancelAll();\n\t\tpromptTemplateBridge.dispose();\n\t\tsupervisorChannel.dispose();\n\t\tif (globalStore[runtimeCleanupStoreKey] === runtimeCleanup) {\n\t\t\tdelete globalStore[runtimeCleanupStoreKey];\n\t\t}\n\t\ttry {\n\t\t\tif (state.lastUiContext?.hasUI) {\n\t\t\t\tstate.lastUiContext.ui.setWidget(WIDGET_KEY, undefined);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (!isStaleExtensionContextError(error)) throw error;\n\t\t}\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/builtin-extensions/pi-subagents/src/extension/index.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAoC,MAAM,iCAAiC,CAAC;AAGtG,OAAO,EAA0B,IAAI,EAAmE,MAAM,wBAAwB,CAAC;AAmDvI,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAwEzC,wBAAgB,kBAAkB,CAAC,IAAI,KAAA,EAAE,KAAK,KAAA,EAAE,OAAO,KAAA,GAAG,IAAI,CAiC7D;AA8FD,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAyaxE","sourcesContent":["// @ts-nocheck\n/**\n * Subagent Tool\n *\n * Full-featured subagent with sync and async modes.\n * - Sync (default): Streams output, renders markdown, tracks usage\n * - Async: Background execution, emits events when done\n *\n * Modes: single (agent + task), parallel (tasks[]), chain (chain[] with {previous})\n * Toggle: async parameter (default: false, configurable via config.json)\n *\n * Config file: ~/.lunr/agent/extensions/subagent/config.json\n * { \"asyncByDefault\": true, \"forceTopLevelAsync\": true, \"maxSubagentDepth\": 1, \"intercomBridge\": { \"mode\": \"always\", \"instructionFile\": \"./intercom-bridge.md\" }, \"worktreeSetupHook\": \"./scripts/setup-worktree.mjs\" }\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { AgentToolResult } from \"@ashx-j/lunr-agent\";\nimport type { ExtensionAPI, ExtensionContext, ToolDefinition } from \"@ashx-j/lunr\";\nimport { keyText } from \"../../../../modes/interactive/components/keybinding-hints.ts\";\nimport { awaitWithAbort } from \"../../../../utils/await-with-abort.ts\";\nimport { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from \"@ashx-j/lunr-tui\";\n\nimport { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from \"../shared/artifacts.ts\";\nimport { resolveCurrentSessionId } from \"../shared/session-identity.ts\";\nimport { cleanupOldChainDirs } from \"../shared/settings.ts\";\nimport { clearLegacyResultAnimationTimer, renderSubagentResult, subagentAnimSink } from \"../tui/render.ts\";\nimport { SubagentParams } from \"./schemas.ts\";\nimport { validateChainInput } from \"./chain-validation.ts\";\nimport type { createSubagentExecutor, SubagentParamsLike } from \"../runs/foreground/subagent-executor.ts\";\nimport { createAsyncJobTracker } from \"../runs/background/async-job-tracker.ts\";\nimport { createResultWatcher } from \"../runs/background/result-watcher.ts\";\nimport { createScheduledRunManager } from \"../runs/background/scheduled-runs.ts\";\nimport { registerSlashCommands } from \"../slash/slash-commands.ts\";\nimport { registerPromptTemplateDelegationBridge } from \"../slash/prompt-template-bridge.ts\";\nimport { registerMainWatchdog } from \"../watchdog/register-main.ts\";\nimport { registerSlashSubagentBridge } from \"../slash/slash-bridge.ts\";\nimport { createNativeSupervisorChannel } from \"../intercom/native-supervisor-channel.ts\";\nimport { registerSubagentRpcBridge } from \"./rpc.ts\";\nimport { clearSlashSnapshots, getSlashRenderableSnapshot, resolveSlashMessageDetails, restoreSlashFinalSnapshots, type SlashMessageDetails } from \"../slash/slash-live-state.ts\";\nimport { inspectSubagentStatus } from \"../runs/background/run-status.ts\";\nimport { resolveWaitToolConfig } from \"../runs/background/subagent-wait.ts\";\nimport { registerWaitTool } from \"../runs/background/wait-tool.ts\";\nimport { drainOutstandingWork } from \"../runs/background/auto-drain.ts\";\nimport registerSubagentNotify, { parseSubagentNotifyContent, type SubagentNotifyDetails } from \"../runs/background/notify.ts\";\nimport { formatSteeringNotice, handleSubagentSteeringNotice, SUBAGENT_STEERING_MESSAGE_TYPE, type SubagentSteeringMessageDetails } from \"./steering-notices.ts\";\nimport { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from \"../runs/shared/pi-args.ts\";\nimport { formatDuration, shortenPath } from \"../shared/formatters.ts\";\nimport { loadConfig } from \"./config.ts\";\nimport { buildSubagentToolDescription } from \"./tool-description.ts\";\nimport {\n\ttype Details,\n\ttype SubagentState,\n\tASYNC_DIR,\n\tDEFAULT_ARTIFACT_CONFIG,\n\tRESULTS_DIR,\n\tSLASH_RESULT_TYPE,\n\tSLASH_TEXT_RESULT_TYPE,\n\tSUBAGENT_ASYNC_COMPLETE_EVENT,\n\tSUBAGENT_ASYNC_STARTED_EVENT,\n\tSUBAGENT_CONTROL_EVENT,\n\tSUBAGENT_STEERING_NOTICE_EVENT,\n\tWIDGET_KEY,\n} from \"../shared/types.ts\";\nimport {\n\tclearPendingForegroundControlNotices,\n\tformatSubagentControlNotice,\n\thandleSubagentControlNotice,\n\tSUBAGENT_CONTROL_MESSAGE_TYPE,\n\ttype SubagentControlMessageDetails,\n} from \"./control-notices.ts\";\n\nexport { loadConfig } from \"./config.ts\";\n\n/**\n * Derive subagent session base directory from parent session file.\n * If parent session is ~/.lunr/agent/sessions/abc123.jsonl,\n * returns ~/.lunr/agent/sessions/abc123/ as the base.\n * Callers add runId to create the actual session root: abc123/{runId}/\n * Falls back to a unique temp directory if no parent session.\n */\nfunction getSubagentSessionRoot(parentSessionFile: string | null): string {\n\tif (parentSessionFile) {\n\t\tconst baseName = path.basename(parentSessionFile, \".jsonl\");\n\t\tconst sessionsDir = path.dirname(parentSessionFile);\n\t\treturn path.join(sessionsDir, baseName);\n\t}\n\treturn fs.mkdtempSync(path.join(os.tmpdir(), \"pi-subagent-session-\"));\n}\n\nfunction expandTilde(p: string): string {\n\treturn p.startsWith(\"~/\") ? path.join(os.homedir(), p.slice(2)) : p;\n}\n\n/**\n * Create a directory and verify it is actually accessible.\n * On Windows with Azure AD/Entra ID, directories created shortly after\n * wake-from-sleep can end up with broken NTFS ACLs (null DACL) when the\n * cloud SID cannot be resolved without network connectivity. This leaves\n * the directory completely inaccessible to the creating user.\n */\nfunction ensureAccessibleDir(dirPath: string): void {\n\tfs.mkdirSync(dirPath, { recursive: true });\n\ttry {\n\t\tfs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n\t} catch {\n\t\ttry {\n\t\t\tfs.rmSync(dirPath, { recursive: true, force: true });\n\t\t} catch {\n\t\t\t// Best effort: retry mkdir/access even if cleanup fails.\n\t\t}\n\t\tfs.mkdirSync(dirPath, { recursive: true });\n\t\tfs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);\n\t}\n}\n\nfunction isSlashResultRunning(result: { details?: Details }): boolean {\n\treturn result.details?.progress?.some((entry) => entry.status === \"running\")\n\t\t|| result.details?.results.some((entry) => entry.progress?.status === \"running\")\n\t\t|| false;\n}\n\n// Drives the inline running-indicator braille animation for foreground subagent\n// results. Foreground runs receive progress only on child events, so the glyph\n// (derived from progress fields) would freeze between events. While a result is\n// running we tick a frame counter every 80ms; renderResult registers the\n// running-glyph lines in state.animEntries (via subagentAnimSink) and the timer\n// rewrites just those Text nodes + requests a repaint, instead of invalidate()-ing\n// the whole tool component (a full renderSubagentResult rebuild 12.5x/s made the\n// spinner laggy).\nfunction subagentResultIsRunning(result: { details?: Details }): boolean {\n\treturn result.details?.progress?.some((entry) => entry.status === \"running\")\n\t\t|| result.details?.results.some((entry) => entry.progress?.status === \"running\")\n\t\t|| false;\n}\n\nfunction effectiveParallelTaskCount(tasks: Array<{ count?: unknown }> | undefined): number {\n\tif (!tasks || tasks.length === 0) return 0;\n\treturn tasks.reduce((total, task) => {\n\t\tconst count = typeof task.count === \"number\" && Number.isInteger(task.count) && task.count >= 1 ? task.count : 1;\n\t\treturn total + count;\n\t}, 0);\n}\n\nexport function renderSubagentCall(args, theme, context): Text {\n\tif (args.action) {\n\t\tconst target = args.id || args.runId || \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"subagent \"))}${args.action}${target ? ` ${theme.fg(\"accent\", target)}` : \"\"}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst isParallel = (args.tasks?.length ?? 0) > 0;\n\tconst parallelCount = effectiveParallelTaskCount(args.tasks as Array<{ count?: unknown }> | undefined);\n\tconst asyncLabel = args.async === true && args.clarify !== true ? theme.fg(\"warning\", \" [async]\") : \"\";\n\tif (args.chain?.length) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"subagent \"))}chain (${args.chain.length})${asyncLabel}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tif (isParallel) {\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"subagent \"))}parallel (${parallelCount})${asyncLabel}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst showDescription = !context?.isPartial && !context?.expanded && !context?.isError;\n\tconst description = showDescription ? theme.fg(\"accent\", args.description || args.task || \"?\") : \"\";\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(description ? \"subagent \" : \"subagent\"))}${description}${asyncLabel}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\nfunction ensureSubagentResultAnimation(context: { state: Record<string, unknown>; invalidate?: () => void; requestRender?: () => void }): void {\n\tconst state = context.state as {\n\t\tsubagentResultAnimationTimer?: ReturnType<typeof setInterval>;\n\t\tframe?: number;\n\t\tanimEntries?: Array<{ text: Text; line: (frame: number, now: number) => string }>;\n\t};\n\tif (state.subagentResultAnimationTimer) return;\n\tif (typeof context.invalidate !== \"function\") return;\n\tif (state.frame === undefined) state.frame = 0;\n\tstate.subagentResultAnimationTimer = setInterval(() => {\n\t\tstate.frame = ((state.frame ?? 0) + 1) % 10;\n\t\ttry {\n\t\t\tconst entries = state.animEntries;\n\t\t\tif (entries?.length && typeof context.requestRender === \"function\") {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tfor (const entry of entries) entry.text.setText(entry.line(state.frame ?? 0, now));\n\t\t\t\tcontext.requestRender();\n\t\t\t} else {\n\t\t\t\tcontext.invalidate();\n\t\t\t}\n\t\t} catch {}\n\t}, 80);\n}\n\nfunction isSlashResultError(result: { details?: Details }): boolean {\n\treturn result.details?.results.some((entry) => entry.exitCode !== 0 && entry.progress?.status !== \"running\") || false;\n}\n\nfunction isStaleExtensionContextError(error: unknown): boolean {\n\treturn error instanceof Error && error.message.includes(\"Extension context no longer active\");\n}\n\nfunction rebuildSlashResultContainer(\n\tcontainer: Container,\n\tresult: AgentToolResult<Details>,\n\toptions: { expanded: boolean },\n\ttheme: ExtensionContext[\"ui\"][\"theme\"],\n): void {\n\tcontainer.clear();\n\tcontainer.addChild(new Spacer(1));\n\tconst boxTheme = isSlashResultRunning(result) ? \"toolPendingBg\" : isSlashResultError(result) ? \"toolErrorBg\" : \"toolSuccessBg\";\n\tconst box = new Box(1, 1, (text: string) => theme.bg(boxTheme, text));\n\tbox.addChild(renderSubagentResult(result, options, theme));\n\tcontainer.addChild(box);\n}\n\nfunction createSlashResultComponent(\n\tdetails: SlashMessageDetails,\n\toptions: { expanded: boolean },\n\ttheme: ExtensionContext[\"ui\"][\"theme\"],\n): Container {\n\tconst container = new Container();\n\tlet lastVersion = -1;\n\tcontainer.render = (width: number): string[] => {\n\t\tconst snapshot = getSlashRenderableSnapshot(details);\n\t\tif (snapshot.version !== lastVersion || isSlashResultRunning(snapshot.result)) {\n\t\t\tlastVersion = snapshot.version;\n\t\t\trebuildSlashResultContainer(container, snapshot.result, options, theme);\n\t\t}\n\t\treturn Container.prototype.render.call(container, width);\n\t};\n\treturn container;\n}\n\nclass SubagentControlNoticeComponent implements Component {\n\tconstructor(\n\t\tprivate readonly details: SubagentControlMessageDetails,\n\t\tprivate readonly theme: ExtensionContext[\"ui\"][\"theme\"],\n\t) {}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\tconst eventLabel = this.details.event.type.replaceAll(\"_\", \" \");\n\t\tif (width < 3) return [truncateToWidth(`Subagent ${eventLabel}`, width)];\n\t\tconst bodyWidth = Math.max(1, width - 2);\n\t\tconst borderChar = \"─\";\n\t\tconst header = ` ⚠ Subagent ${eventLabel}: ${this.details.event.agent} `;\n\t\tconst headerText = truncateToWidth(header, bodyWidth, \"\");\n\t\tconst headerPadding = Math.max(0, bodyWidth - visibleWidth(headerText));\n\t\tconst lines = [this.theme.fg(\"accent\", `╭${headerText}${borderChar.repeat(headerPadding)}╮`)];\n\n\t\tfor (const line of wrapTextWithAnsi(formatSubagentControlNotice(this.details), bodyWidth)) {\n\t\t\tconst text = truncateToWidth(line, bodyWidth, \"\");\n\t\t\tconst padding = Math.max(0, bodyWidth - visibleWidth(text));\n\t\t\tlines.push(this.theme.fg(\"accent\", `│${text}${\" \".repeat(padding)}│`));\n\t\t}\n\t\tlines.push(this.theme.fg(\"accent\", `╰${borderChar.repeat(bodyWidth)}╯`));\n\t\treturn lines;\n\t}\n}\n\nexport default function registerSubagentExtension(pi: ExtensionAPI): void {\n\tif (process.env[SUBAGENT_CHILD_ENV] === \"1\") {\n\t\treturn;\n\t}\n\tconst globalStore = globalThis as Record<string, unknown>;\n\tconst runtimeCleanupStoreKey = \"__piSubagentRuntimeCleanup\";\n\tconst previousRuntimeCleanup = globalStore[runtimeCleanupStoreKey];\n\tif (typeof previousRuntimeCleanup === \"function\") {\n\t\ttry {\n\t\t\tpreviousRuntimeCleanup();\n\t\t} catch {\n\t\t\t// Best effort cleanup for stale timers from an older reload.\n\t\t}\n\t}\n\n\tensureAccessibleDir(RESULTS_DIR);\n\tensureAccessibleDir(ASYNC_DIR);\n\tcleanupOldChainDirs();\n\n\tconst config = loadConfig();\n\tconst waitToolConfig = resolveWaitToolConfig(config.waitTool);\n\tconst asyncByDefault = config.asyncByDefault === true;\n\tconst tempArtifactsDir = getArtifactsDir(null);\n\tcleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);\n\n\tconst state: SubagentState = {\n\t\tbaseCwd: \"\",\n\t\tcurrentSessionId: null,\n\t\tforegroundSubagentInFlight: 0,\n\t\tsubagentSpawns: { sessionId: null, count: 0 },\n\t\tasyncJobs: new Map(),\n\t\tfleetJobs: new Map(),\n\t\tforegroundRuns: new Map(),\n\t\tforegroundControls: new Map(),\n\t\tlastForegroundControlId: null,\n\t\tpendingForegroundControlNotices: new Map(),\n\t\tcleanupTimers: new Map(),\n\t\tlastUiContext: null,\n\t\tpoller: null,\n\t\tcompletionSeen: new Map(),\n\t\twatcher: null,\n\t\twatcherRestartTimer: null,\n\t\tresultFileCoalescer: {\n\t\t\tschedule: () => false,\n\t\t\tclear: () => {},\n\t\t},\n\t};\n\n\tconst supervisorChannel = createNativeSupervisorChannel(pi, state);\n\tconst mainWatchdog = registerMainWatchdog(pi);\n\tconst { startResultWatcher, primeExistingResults, stopResultWatcher } = createResultWatcher(\n\t\tpi,\n\t\tstate,\n\t\tRESULTS_DIR,\n\t\t10 * 60 * 1000,\n\t);\n\tstartResultWatcher();\n\tprimeExistingResults();\n\n\tlet generation = 0;\n\tlet executorPromise: Promise<ReturnType<typeof createSubagentExecutor>> | undefined;\n\tconst pendingLaunches = new Set<Promise<void>>();\n\tconst runtimeCleanup = () => {\n\t\tgeneration++;\n\t\texecutorPromise = undefined;\n\t\tpendingLaunches.clear();\n\t\tmainWatchdog.dispose();\n\t\tstopResultWatcher();\n\t\tscheduledRunManager.stop();\n\t\tsupervisorChannel.dispose();\n\t\tclearPendingForegroundControlNotices(state);\n\t\tif (state.poller) {\n\t\t\tclearInterval(state.poller);\n\t\t\tstate.poller = null;\n\t\t}\n\t};\n\tglobalStore[runtimeCleanupStoreKey] = runtimeCleanup;\n\n\tconst { ensurePoller, refreshWidget, handleStarted, handleComplete, resetJobs, restoreActiveJobs } = createAsyncJobTracker(pi, state, ASYNC_DIR, {\n\t\twidgetEnabled: config.asyncWidget !== false,\n\t});\n\tlet executorExecute: ((id: string, params: SubagentParamsLike, signal: AbortSignal, onUpdate: ((r: AgentToolResult<Details>) => void) | undefined, ctx: ExtensionContext) => Promise<AgentToolResult<Details>>) | undefined;\n\tconst scheduledRunManager = createScheduledRunManager({\n\t\tconfig,\n\t\tlaunch: (params, ctx, signal) => {\n\t\t\tif (!executorExecute) {\n\t\t\t\treturn Promise.resolve({\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"Scheduled subagent launch is unavailable (executor not ready).\" }],\n\t\t\t\t\tisError: true,\n\t\t\t\t\tdetails: { mode: \"management\" as const, results: [] },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn executorExecute(randomUUID(), params, signal, undefined, ctx);\n\t\t},\n\t});\n\tconst executor: ReturnType<typeof createSubagentExecutor> = {\n\t\tasync execute(id, params, signal, onUpdate, ctx) {\n\t\t\tlet resolveLaunchReady!: () => void;\n\t\t\tlet launchReady = false;\n\t\t\tconst launchReadyPromise = new Promise<void>((resolve) => {\n\t\t\t\tresolveLaunchReady = resolve;\n\t\t\t});\n\t\t\tconst markLaunchReady = () => {\n\t\t\t\tif (launchReady) return;\n\t\t\t\tlaunchReady = true;\n\t\t\t\tpendingLaunches.delete(launchReadyPromise);\n\t\t\t\tresolveLaunchReady();\n\t\t\t};\n\t\t\tpendingLaunches.add(launchReadyPromise);\n\t\t\ttry {\n\t\t\t\tconst currentGeneration = generation;\n\t\t\t\tsignal?.throwIfAborted();\n\t\t\t\tif (!executorPromise) {\n\t\t\t\t\tconst pending = import(\"../runs/foreground/subagent-executor.ts\").then(({ createSubagentExecutor }) => {\n\t\t\t\t\t\tif (generation !== currentGeneration) throw new Error(\"Subagent session changed before initialization\");\n\t\t\t\t\t\treturn createSubagentExecutor({\n\t\t\t\t\t\t\tpi, state, config, asyncByDefault,\n\t\t\t\t\t\t\twaitToolEnabled: waitToolConfig.enabled,\n\t\t\t\t\t\t\thandleScheduledRunAction: (params, ctx) => scheduledRunManager.handleToolCall(params, ctx),\n\t\t\t\t\t\t\twatchdog: mainWatchdog, tempArtifactsDir, getSubagentSessionRoot, expandTilde,\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\texecutorPromise = pending;\n\t\t\t\t\tvoid pending.catch(() => {\n\t\t\t\t\t\tif (executorPromise === pending) executorPromise = undefined;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst ready = await awaitWithAbort(executorPromise, signal);\n\t\t\t\tsignal?.throwIfAborted();\n\t\t\t\tif (generation !== currentGeneration) throw new Error(\"Subagent session changed before execution\");\n\t\t\t\tconst execution = ready.execute(id, params, signal, onUpdate, ctx);\n\t\t\t\tmarkLaunchReady();\n\t\t\t\treturn await execution;\n\t\t\t} finally {\n\t\t\t\tmarkLaunchReady();\n\t\t\t}\n\t\t},\n\t};\n\texecutorExecute = executor.execute;\n\n\tpi.registerMessageRenderer<SlashMessageDetails>(SLASH_RESULT_TYPE, (message, options, theme) => {\n\t\tconst details = resolveSlashMessageDetails(message.details);\n\t\tif (!details) return undefined;\n\t\treturn createSlashResultComponent(details, options, theme);\n\t});\n\n\tpi.registerMessageRenderer<undefined>(SLASH_TEXT_RESULT_TYPE, (message, _options, _theme) => {\n\t\tconst content = typeof message.content === \"string\"\n\t\t\t? message.content\n\t\t\t: message.content\n\t\t\t\t.filter((entry) => entry.type === \"text\")\n\t\t\t\t.map((entry) => entry.text)\n\t\t\t\t.join(\"\\n\");\n\t\treturn new Text(content, 0, 0);\n\t});\n\n\tpi.registerMessageRenderer<SubagentNotifyDetails>(\"subagent-notify\", (message, options, theme) => {\n\t\tconst content = typeof message.content === \"string\" ? message.content : \"\";\n\t\tconst details = (message.details as SubagentNotifyDetails | undefined) ?? parseSubagentNotifyContent(content);\n\t\tif (!details) return new Text(content, 0, 0);\n\t\tconst icon = details.status === \"completed\"\n\t\t\t? theme.fg(\"success\", \"✓\")\n\t\t\t: details.status === \"paused\"\n\t\t\t\t? theme.fg(\"warning\", \"■\")\n\t\t\t\t: theme.fg(\"error\", \"✗\");\n\t\tconst parts: string[] = [];\n\t\tif (details.taskInfo) parts.push(details.taskInfo);\n\t\tif (details.durationMs !== undefined) parts.push(formatDuration(details.durationMs));\n\t\tconst notifyLabel = details.taskInfo || details.agent || \"child\";\n\t\tlet text = `${icon} ${theme.bold(notifyLabel)} ${theme.fg(\"dim\", details.status)}`;\n\t\tif (parts.length > 0) text += ` ${theme.fg(\"dim\", \"·\")} ${parts.map((part) => theme.fg(\"dim\", part)).join(` ${theme.fg(\"dim\", \"·\")} `)}`;\n\t\tconst trimmedPreview = details.resultPreview.trim();\n\t\tconst previewLines = options.expanded\n\t\t\t? trimmedPreview.split(\"\\n\").filter((line) => line.trim())\n\t\t\t: [trimmedPreview.split(\"\\n\", 1)[0] ?? \"\"].filter((line) => line.trim());\n\t\tfor (const line of previewLines.length > 0 ? previewLines : [\"(no output)\"]) {\n\t\t\ttext += `\\n ${theme.fg(\"dim\", `⎿ ${line}`)}`;\n\t\t}\n\t\tif (!options.expanded && trimmedPreview.includes(\"\\n\")) {\n\t\t\tconst expandKey = keyText(\"app.tools.expand\");\n\t\t\ttext += `\\n ${theme.fg(\"dim\", `${expandKey} full notification`)}`;\n\t\t}\n\t\tif (details.sessionLabel && details.sessionValue) {\n\t\t\ttext += `\\n ${theme.fg(\"muted\", `${details.sessionLabel}: ${shortenPath(details.sessionValue)}`)}`;\n\t\t}\n\t\treturn new Text(text, 0, 0);\n\t});\n\n\tpi.registerMessageRenderer<SubagentSteeringMessageDetails>(SUBAGENT_STEERING_MESSAGE_TYPE, (message, _options, theme) => {\n\t\tconst details = message.details as SubagentSteeringMessageDetails | undefined;\n\t\tif (!details) return undefined;\n\t\treturn new Text(theme.fg(details.state === \"recovered\" ? \"warning\" : \"error\", formatSteeringNotice(details)), 0, 0);\n\t});\n\n\tpi.registerMessageRenderer<SubagentControlMessageDetails>(SUBAGENT_CONTROL_MESSAGE_TYPE, () => undefined);\n\n\tconst executeSubagentCollapsed = (id: string, params: SubagentParamsLike, signal: AbortSignal, onUpdate: ((result: AgentToolResult<Details>) => void) | undefined, ctx: ExtensionContext) => {\n\t\tif (ctx.hasUI) ctx.ui.setToolsExpanded(false);\n\t\treturn executor.execute(id, params, signal, onUpdate, ctx);\n\t};\n\n\tconst slashBridge = registerSlashSubagentBridge({\n\t\tevents: pi.events,\n\t\tgetContext: () => state.lastUiContext,\n\t\texecute: (id, params, signal, onUpdate, ctx) =>\n\t\t\texecuteSubagentCollapsed(id, params, signal, onUpdate, ctx),\n\t});\n\n\tconst promptTemplateBridge = registerPromptTemplateDelegationBridge({\n\t\tevents: pi.events,\n\t\tgetContext: () => state.lastUiContext,\n\t\texecute: (requestId, params, signal, ctx, onUpdate) =>\n\t\t\texecuteSubagentCollapsed(requestId, params, signal, onUpdate, ctx),\n\t});\n\n\tconst rpcBridge = registerSubagentRpcBridge({\n\t\tevents: pi.events,\n\t\tgetContext: () => state.lastUiContext,\n\t\texecute: (id, params, signal, onUpdate, ctx) => executor.execute(id, params, signal, onUpdate, ctx),\n\t});\n\n\tconst tool: ToolDefinition<typeof SubagentParams, Details> = {\n\t\tname: \"subagent\",\n\t\tlabel: \"Subagent\",\n\t\tdescription: buildSubagentToolDescription(config),\n\t\tparameters: SubagentParams,\n\t\t// lunr: same-turn SINGLE calls overlap; sequential work uses chain.\n\t\texecutionMode: \"parallel\",\n\n\t\tprepareArguments(args) {\n\t\t\t// Run friendly chain validation before pi-ai's raw TypeBox schema check\n\t\t\t// so the model sees which property is disallowed, what is allowed, and a\n\t\t\t// valid example instead of `chain.N: must not have additional properties`.\n\t\t\tvalidateChainInput(args);\n\t\t\treturn args as never;\n\t\t},\n\n\t\texecute(id, params, signal, onUpdate, ctx) {\n\t\t\treturn executeSubagentCollapsed(id, params, signal, onUpdate, ctx);\n\t\t},\n\n\t\trenderCall: renderSubagentCall,\n\n\t\trenderResult(result, options, theme, context) {\n\t\t\tif (subagentResultIsRunning(result)) {\n\t\t\t\tensureSubagentResultAnimation(context);\n\t\t\t} else {\n\t\t\t\tclearLegacyResultAnimationTimer(context);\n\t\t\t}\n\t\t\tconst state = context.state as { frame?: number; animEntries?: Array<{ text: Text; line: (frame: number) => string }> };\n\t\t\t// lunr: collect running-glyph line templates while rendering so the\n\t\t\t// animation timer can rewrite them in place (see ensureSubagentResultAnimation).\n\t\t\tconst entries: Array<{ text: Text; line: (frame: number) => string }> = [];\n\t\t\tstate.animEntries = entries;\n\t\t\tsubagentAnimSink.current = entries;\n\t\t\ttry {\n\t\t\t\treturn renderSubagentResult(result, options, theme, state.frame ?? 0);\n\t\t\t} finally {\n\t\t\t\tsubagentAnimSink.current = null;\n\t\t\t}\n\t\t},\n\n\t};\n\n\tpi.registerTool(tool);\n\n\t// lunr: register a callback so toggling model tiers mid-session rebuilds the subagent\n\t// tool description (adds/removes MODEL TIERS guidance) and refreshes the tool registry.\n\tconst modelTierBridge = (globalThis as Record<symbol, unknown>)[Symbol.for(\"@lunr/model-tiers\")] as\n\t\t| { registerToolDescriptionRefresher?: (refresher: () => void) => void }\n\t\t| undefined;\n\tmodelTierBridge?.registerToolDescriptionRefresher?.(() => {\n\t\ttool.description = buildSubagentToolDescription(config);\n\t\t// pi.runtime is not on ExtensionAPI; registerTool refreshes the live registry.\n\t\tpi.registerTool(tool);\n\t});\n\n\tregisterWaitTool(pi, state, waitToolConfig.enabled, async (signal) => {\n\t\tconst launches = [...pendingLaunches];\n\t\tif (launches.length === 0) return;\n\t\tawait awaitWithAbort(Promise.all(launches).then(() => {}), signal);\n\t});\n\n\tpi.on(\"agent_end\", async (_event, ctx) => {\n\t\tif (ctx.hasUI) return;\n\t\tawait drainOutstandingWork({ state, events: pi.events });\n\t});\n\n\tregisterSlashCommands(pi, state);\n\n\tconst eventUnsubscribeStoreKey = \"__piSubagentEventUnsubscribes\";\n\tconst controlNoticeSeenStoreKey = \"__piSubagentVisibleControlNotices\";\n\tconst previousEventUnsubscribes = globalStore[eventUnsubscribeStoreKey];\n\tif (Array.isArray(previousEventUnsubscribes)) {\n\t\tfor (const unsubscribe of previousEventUnsubscribes) {\n\t\t\tif (typeof unsubscribe !== \"function\") continue;\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Best effort cleanup for stale handlers from an older reload.\n\t\t\t}\n\t\t}\n\t}\n\tregisterSubagentNotify(pi, state, { batchConfig: config.completionBatch });\n\n\tconst existingVisibleControlNotices = globalStore[controlNoticeSeenStoreKey];\n\tconst visibleControlNotices = existingVisibleControlNotices instanceof Set ? existingVisibleControlNotices as Set<string> : new Set<string>();\n\tglobalStore[controlNoticeSeenStoreKey] = visibleControlNotices;\n\tconst controlEventHandler = (payload: unknown) => {\n\t\thandleSubagentControlNotice({\n\t\t\tpi,\n\t\t\tstate,\n\t\t\tvisibleControlNotices,\n\t\t\tdetails: payload as SubagentControlMessageDetails,\n\t\t});\n\t};\n\tconst steeringNoticeHandler = (payload: unknown) => {\n\t\thandleSubagentSteeringNotice({ pi, state, details: payload as SubagentSteeringMessageDetails });\n\t};\n\tconst eventUnsubscribes = [\n\t\tpi.events.on(SUBAGENT_ASYNC_STARTED_EVENT, handleStarted),\n\t\tpi.events.on(SUBAGENT_ASYNC_COMPLETE_EVENT, handleComplete),\n\t\tpi.events.on(SUBAGENT_CONTROL_EVENT, controlEventHandler),\n\t\tpi.events.on(SUBAGENT_STEERING_NOTICE_EVENT, steeringNoticeHandler),\n\t\trpcBridge.dispose,\n\t];\n\tglobalStore[eventUnsubscribeStoreKey] = eventUnsubscribes;\n\n\tpi.on(\"tool_result\", (event, ctx) => {\n\t\tif (event.toolName !== \"subagent\") return;\n\t\tif (!ctx.hasUI) return;\n\t\tstate.lastUiContext = ctx;\n\t\tif (state.asyncJobs.size > 0) {\n\t\t\trefreshWidget(ctx);\n\t\t\tensurePoller();\n\t\t}\n\t});\n\n\tconst cleanupSessionArtifacts = (ctx: ExtensionContext) => {\n\t\ttry {\n\t\t\tconst sessionFile = ctx.sessionManager.getSessionFile();\n\t\t\tif (sessionFile) {\n\t\t\t\tcleanupOldArtifacts(getArtifactsDir(sessionFile), DEFAULT_ARTIFACT_CONFIG.cleanupDays);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Cleanup failures should not block session lifecycle events.\n\t\t}\n\t};\n\n\tconst resetSessionState = (ctx: ExtensionContext) => {\n\t\tgeneration++;\n\t\texecutorPromise = undefined;\n\t\tpendingLaunches.clear();\n\t\tstate.baseCwd = ctx.cwd;\n\t\tstate.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);\n\t\tstate.subagentSpawns = { sessionId: state.currentSessionId, count: 0 };\n\t\t// Set PI_SUBAGENT_PARENT_SESSION for permission-system forwarding.\n\t\t// Only set in the root session (the interactive UI session), not in\n\t\t// child subagent processes — children inherit the parent's value\n\t\t// through the process environment at spawn time and must not overwrite\n\t\t// it with their own session identity.\n\t\tif (!process.env[SUBAGENT_CHILD_ENV]) {\n\t\t\tconst sessionId = ctx.sessionManager.getSessionId();\n\t\t\tif (sessionId) {\n\t\t\t\tprocess.env[SUBAGENT_PARENT_SESSION_ENV] = sessionId;\n\t\t\t}\n\t\t}\n\t\tstate.lastUiContext = ctx;\n\t\tcleanupSessionArtifacts(ctx);\n\t\tclearPendingForegroundControlNotices(state);\n\t\tresetJobs(ctx);\n\t\trestoreActiveJobs(ctx);\n\t\tscheduledRunManager.bindSession(ctx);\n\t\trestoreSlashFinalSnapshots(ctx.sessionManager.getEntries());\n\t\tprimeExistingResults();\n\t};\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tresetSessionState(ctx);\n\t\trpcBridge.emitReady(ctx);\n\t\tsupervisorChannel.start();\n\t});\n\n\tpi.on(\"session_shutdown\", () => {\n\t\tgeneration++;\n\t\texecutorPromise = undefined;\n\t\tpendingLaunches.clear();\n\t\tdelete process.env[SUBAGENT_PARENT_SESSION_ENV];\n\t\tfor (const unsubscribe of eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Best effort cleanup during shutdown.\n\t\t\t}\n\t\t}\n\t\tif (globalStore[eventUnsubscribeStoreKey] === eventUnsubscribes) {\n\t\t\tdelete globalStore[eventUnsubscribeStoreKey];\n\t\t}\n\t\tstopResultWatcher();\n\t\tscheduledRunManager.stop();\n\t\tif (state.poller) clearInterval(state.poller);\n\t\tstate.poller = null;\n\t\tclearPendingForegroundControlNotices(state);\n\t\tfor (const timer of state.cleanupTimers.values()) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tstate.cleanupTimers.clear();\n\t\tstate.asyncJobs.clear();\n\t\tclearSlashSnapshots();\n\t\tslashBridge.cancelAll();\n\t\tslashBridge.dispose();\n\t\tpromptTemplateBridge.cancelAll();\n\t\tpromptTemplateBridge.dispose();\n\t\tsupervisorChannel.dispose();\n\t\tif (globalStore[runtimeCleanupStoreKey] === runtimeCleanup) {\n\t\t\tdelete globalStore[runtimeCleanupStoreKey];\n\t\t}\n\t\ttry {\n\t\t\tif (state.lastUiContext?.hasUI) {\n\t\t\t\tstate.lastUiContext.ui.setWidget(WIDGET_KEY, undefined);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (!isStaleExtensionContextError(error)) throw error;\n\t\t}\n\t});\n}\n"]}
|
|
@@ -16,7 +16,8 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
import * as fs from "node:fs";
|
|
17
17
|
import * as os from "node:os";
|
|
18
18
|
import * as path from "node:path";
|
|
19
|
-
import { keyText } from "
|
|
19
|
+
import { keyText } from "../../../../modes/interactive/components/keybinding-hints.js";
|
|
20
|
+
import { awaitWithAbort } from "../../../../utils/await-with-abort.js";
|
|
20
21
|
import { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@ashx-j/lunr-tui";
|
|
21
22
|
import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "../shared/artifacts.js";
|
|
22
23
|
import { resolveCurrentSessionId } from "../shared/session-identity.js";
|
|
@@ -24,7 +25,6 @@ import { cleanupOldChainDirs } from "../shared/settings.js";
|
|
|
24
25
|
import { clearLegacyResultAnimationTimer, renderSubagentResult, subagentAnimSink } from "../tui/render.js";
|
|
25
26
|
import { SubagentParams } from "./schemas.js";
|
|
26
27
|
import { validateChainInput } from "./chain-validation.js";
|
|
27
|
-
import { createSubagentExecutor } from "../runs/foreground/subagent-executor.js";
|
|
28
28
|
import { createAsyncJobTracker } from "../runs/background/async-job-tracker.js";
|
|
29
29
|
import { createResultWatcher } from "../runs/background/result-watcher.js";
|
|
30
30
|
import { createScheduledRunManager } from "../runs/background/scheduled-runs.js";
|
|
@@ -261,7 +261,13 @@ export default function registerSubagentExtension(pi) {
|
|
|
261
261
|
const { startResultWatcher, primeExistingResults, stopResultWatcher } = createResultWatcher(pi, state, RESULTS_DIR, 10 * 60 * 1000);
|
|
262
262
|
startResultWatcher();
|
|
263
263
|
primeExistingResults();
|
|
264
|
+
let generation = 0;
|
|
265
|
+
let executorPromise;
|
|
266
|
+
const pendingLaunches = new Set();
|
|
264
267
|
const runtimeCleanup = () => {
|
|
268
|
+
generation++;
|
|
269
|
+
executorPromise = undefined;
|
|
270
|
+
pendingLaunches.clear();
|
|
265
271
|
mainWatchdog.dispose();
|
|
266
272
|
stopResultWatcher();
|
|
267
273
|
scheduledRunManager.stop();
|
|
@@ -290,18 +296,54 @@ export default function registerSubagentExtension(pi) {
|
|
|
290
296
|
return executorExecute(randomUUID(), params, signal, undefined, ctx);
|
|
291
297
|
},
|
|
292
298
|
});
|
|
293
|
-
const executor =
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
299
|
+
const executor = {
|
|
300
|
+
async execute(id, params, signal, onUpdate, ctx) {
|
|
301
|
+
let resolveLaunchReady;
|
|
302
|
+
let launchReady = false;
|
|
303
|
+
const launchReadyPromise = new Promise((resolve) => {
|
|
304
|
+
resolveLaunchReady = resolve;
|
|
305
|
+
});
|
|
306
|
+
const markLaunchReady = () => {
|
|
307
|
+
if (launchReady)
|
|
308
|
+
return;
|
|
309
|
+
launchReady = true;
|
|
310
|
+
pendingLaunches.delete(launchReadyPromise);
|
|
311
|
+
resolveLaunchReady();
|
|
312
|
+
};
|
|
313
|
+
pendingLaunches.add(launchReadyPromise);
|
|
314
|
+
try {
|
|
315
|
+
const currentGeneration = generation;
|
|
316
|
+
signal?.throwIfAborted();
|
|
317
|
+
if (!executorPromise) {
|
|
318
|
+
const pending = import("../runs/foreground/subagent-executor.js").then(({ createSubagentExecutor }) => {
|
|
319
|
+
if (generation !== currentGeneration)
|
|
320
|
+
throw new Error("Subagent session changed before initialization");
|
|
321
|
+
return createSubagentExecutor({
|
|
322
|
+
pi, state, config, asyncByDefault,
|
|
323
|
+
waitToolEnabled: waitToolConfig.enabled,
|
|
324
|
+
handleScheduledRunAction: (params, ctx) => scheduledRunManager.handleToolCall(params, ctx),
|
|
325
|
+
watchdog: mainWatchdog, tempArtifactsDir, getSubagentSessionRoot, expandTilde,
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
executorPromise = pending;
|
|
329
|
+
void pending.catch(() => {
|
|
330
|
+
if (executorPromise === pending)
|
|
331
|
+
executorPromise = undefined;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
const ready = await awaitWithAbort(executorPromise, signal);
|
|
335
|
+
signal?.throwIfAborted();
|
|
336
|
+
if (generation !== currentGeneration)
|
|
337
|
+
throw new Error("Subagent session changed before execution");
|
|
338
|
+
const execution = ready.execute(id, params, signal, onUpdate, ctx);
|
|
339
|
+
markLaunchReady();
|
|
340
|
+
return await execution;
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
markLaunchReady();
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
};
|
|
305
347
|
executorExecute = executor.execute;
|
|
306
348
|
pi.registerMessageRenderer(SLASH_RESULT_TYPE, (message, options, theme) => {
|
|
307
349
|
const details = resolveSlashMessageDetails(message.details);
|
|
@@ -428,7 +470,12 @@ export default function registerSubagentExtension(pi) {
|
|
|
428
470
|
// pi.runtime is not on ExtensionAPI; registerTool refreshes the live registry.
|
|
429
471
|
pi.registerTool(tool);
|
|
430
472
|
});
|
|
431
|
-
registerWaitTool(pi, state, waitToolConfig.enabled)
|
|
473
|
+
registerWaitTool(pi, state, waitToolConfig.enabled, async (signal) => {
|
|
474
|
+
const launches = [...pendingLaunches];
|
|
475
|
+
if (launches.length === 0)
|
|
476
|
+
return;
|
|
477
|
+
await awaitWithAbort(Promise.all(launches).then(() => { }), signal);
|
|
478
|
+
});
|
|
432
479
|
pi.on("agent_end", async (_event, ctx) => {
|
|
433
480
|
if (ctx.hasUI)
|
|
434
481
|
return;
|
|
@@ -496,6 +543,9 @@ export default function registerSubagentExtension(pi) {
|
|
|
496
543
|
}
|
|
497
544
|
};
|
|
498
545
|
const resetSessionState = (ctx) => {
|
|
546
|
+
generation++;
|
|
547
|
+
executorPromise = undefined;
|
|
548
|
+
pendingLaunches.clear();
|
|
499
549
|
state.baseCwd = ctx.cwd;
|
|
500
550
|
state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
|
|
501
551
|
state.subagentSpawns = { sessionId: state.currentSessionId, count: 0 };
|
|
@@ -525,6 +575,9 @@ export default function registerSubagentExtension(pi) {
|
|
|
525
575
|
supervisorChannel.start();
|
|
526
576
|
});
|
|
527
577
|
pi.on("session_shutdown", () => {
|
|
578
|
+
generation++;
|
|
579
|
+
executorPromise = undefined;
|
|
580
|
+
pendingLaunches.clear();
|
|
528
581
|
delete process.env[SUBAGENT_PARENT_SESSION_ENV];
|
|
529
582
|
for (const unsubscribe of eventUnsubscribes) {
|
|
530
583
|
try {
|