@ashx-j/lunr 0.2.16 → 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 +25 -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/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +6 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.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/runs/foreground/request-params.d.ts +10 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.js +38 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/request-params.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +3 -16
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ashxj-tui.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/ashxj-tui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ashxj-tui — a custom slim chatbox for pi.\n *\n * Replaces pi-zentui's prompt box + statusline with:\n * - A rounded prompt box that auto-expands as the typed message wraps to\n * multiple rows (the sides extend; height grows with content).\n * - A right-aligned chip on the box's BOTTOM border:\n * model · provider · effort (e.g. `glm-5.2 · Ollama Cloud · xhigh`)\n * - A slim stats line (extension statuses · context% · ↑↓; each segment\n * toggle-gated via the lunr customize bridge) BELOW the box, not wrapped\n * around the input.\n * - No session-mode indicator anywhere (pi has no such concept).\n *\n * Loaded by pi via jiti — no build step, plain TypeScript.\n *\n * NOTE on type imports (see `ashxj-thinking`/`simple-memory` for the convention):\n * This file declares structural types inline rather than importing them from\n * `@ashx-j/lunr` / `@ashx-j/lunr-tui`.\n * pi-coding-agent's `index.d.ts` re-exports from internal `.d.ts` files that\n * contain subpath imports like `@ashx-j/lunr-ai/compat`, which do not\n * resolve under `tsc` with a file argument. We keep the typecheck\n * self-contained with inline types and verify via the included `tsconfig.json`\n * (`moduleResolution: \"Bundler\"` + `skipLibCheck: true`).\n *\n * The ONE exception is `CustomEditor`, imported as a RUNTIME VALUE directly\n * from its defining module (`modes/interactive/components/custom-editor.ts`).\n * We must `extends` it to inherit pi's app keybindings (escape, ctrl+d, model\n * switching, extension shortcuts) — wrapping would lose those. It is imported\n * from the concrete module, NOT the package barrel, because the barrel\n * re-exports main.ts which imports this file — a circular import that crashes\n * under vite-node (`Class extends value undefined`).\n */\n\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.js\";\n\nconst CUSTOMIZE_BRIDGE = Symbol.for(\"@lunr/customize\");\nconst PERMISSION_MODE_BRIDGE = Symbol.for(\"@lunr/permission-mode\");\ninterface CustomizeBridgeForPrompt {\n\tgetOpenAIFastMode?(): boolean;\n\t// lunr: footer element toggles (added to the same bridge).\n\tgetFooterMcp?(): boolean;\n\tgetFooterLsp?(): boolean;\n\tgetFooterContext?(): boolean;\n\tgetFooterTokens?(): boolean;\n\tgetFooterCacheHitRate?(): boolean;\n\tgetFooterTps?(): boolean;\n\tgetFooterStatuses?(): boolean;\n\tgetFooterGit?(): boolean;\n\tgetFooterPlan?(): boolean;\n\tgetFooterPlanBar?(): boolean;\n}\ninterface PermissionModeBridgeForFooter {\n\tgetMode(): string | undefined;\n}\nfunction lunrCustomizeBridge(): CustomizeBridgeForPrompt | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE] as CustomizeBridgeForPrompt | undefined;\n}\nfunction lunrPermissionModeBridge(): PermissionModeBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[PERMISSION_MODE_BRIDGE] as PermissionModeBridgeForFooter | undefined;\n}\n// lunr: footer toggles, read at render time. Bridgeless / missing-getter fallback\n// matches the settings-manager defaults: MCP on, LSP off, everything else on.\nfunction lunrFooterToggles(): {\n\tmcp: boolean;\n\tlsp: boolean;\n\tcontext: boolean;\n\ttokens: boolean;\n\tcacheHitRate: boolean;\n\ttps: boolean;\n\tstatuses: boolean;\n\tgit: boolean;\n\tplan: boolean;\n\tplanBar: boolean;\n} {\n\tconst bridge = lunrCustomizeBridge();\n\treturn {\n\t\tmcp: bridge?.getFooterMcp?.() ?? true,\n\t\tlsp: bridge?.getFooterLsp?.() ?? false,\n\t\tcontext: bridge?.getFooterContext?.() ?? true,\n\t\ttokens: bridge?.getFooterTokens?.() ?? true,\n\t\tcacheHitRate: bridge?.getFooterCacheHitRate?.() ?? true,\n\t\ttps: bridge?.getFooterTps?.() ?? true,\n\t\tstatuses: bridge?.getFooterStatuses?.() ?? true,\n\t\tgit: bridge?.getFooterGit?.() ?? true,\n\t\tplan: bridge?.getFooterPlan?.() ?? true,\n\t\tplanBar: bridge?.getFooterPlanBar?.() ?? true,\n\t};\n}\n\nconst USAGE_SERVICE_BRIDGE = Symbol.for(\"@lunr/usage-service\");\ninterface UsageServiceBridgeForFooter {\n\tpickForFooter?(providerId: string): { label: string; usedPercent: number } | undefined;\n\tprefetch?(providerId: string): void;\n}\nfunction lunrUsageBridge(): UsageServiceBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE] as UsageServiceBridgeForFooter | undefined;\n}\n\nfunction compactPlanBar(percent: number, theme: Theme): string {\n\tconst cells = 8;\n\tconst clamped = Math.max(0, Math.min(100, percent));\n\tconst filled = Math.round((clamped / 100) * cells);\n\tconst token = clamped > 90 ? \"error\" : clamped > 70 ? \"warning\" : \"success\";\n\tconst fill = filled > 0 ? color(theme, token, \"█\".repeat(filled)) : \"\";\n\tconst rest = filled < cells ? color(theme, \"dim\", \"░\".repeat(cells - filled)) : \"\";\n\treturn fill + rest;\n}\n// lunr: permission mode for the footer safety indicator (always shown).\nfunction lunrPermissionMode(): string | undefined {\n\treturn lunrPermissionModeBridge()?.getMode();\n}\nexport function lunrPromptGlyph(theme: Theme | undefined): string {\n\tconst arrow = theme?.glyph?.(\"promptArrow\") ?? \">\";\n\treturn arrow ? `${arrow} ` : \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Minimal structural types (inline — see file header)\n// ---------------------------------------------------------------------------\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\n/** Theme token for the chatbox thinking-level border / effort chip. */\nexport function thinkingThemeToken(level: ThinkingLevel): string {\n\tswitch (level) {\n\t\tcase \"off\":\n\t\t\treturn \"thinkingOff\";\n\t\tcase \"minimal\":\n\t\t\treturn \"thinkingMinimal\";\n\t\tcase \"low\":\n\t\t\treturn \"thinkingLow\";\n\t\tcase \"medium\":\n\t\t\treturn \"thinkingMedium\";\n\t\tcase \"high\":\n\t\t\treturn \"thinkingHigh\";\n\t\tcase \"xhigh\":\n\t\t\treturn \"thinkingXhigh\";\n\t\tcase \"max\":\n\t\t\treturn \"thinkingMax\";\n\t\tdefault:\n\t\t\treturn \"thinkingOff\";\n\t}\n}\n\n/** Chip effort label — identity, locked so xhigh/max are never mapped down to high. */\nexport function formatChipEffort(level: ThinkingLevel): string {\n\treturn level;\n}\n\n/** Trimmed view of pi's `Theme` — only the methods we use. */\ninterface Theme {\n\tfg(token: string, text: string): string;\n\t/** lunr: prompt glyph tokens (optional for forward/backward compat). */\n\tglyph?(name: \"promptArrow\"): string;\n}\n\n/** Trimmed view of `pi-tui`'s `TUI` — only the method we use. */\ninterface TUIHandle {\n\trequestRender(force?: boolean): void;\n}\n\n/** Trimmed view of `pi-tui`'s `EditorTheme`. */\ninterface EditorThemeLike {\n\tborderColor: (str: string) => string;\n\tselectList: unknown;\n}\n\n/** Opaque keybindings manager. */\ninterface KeybindingsLike {\n\treadonly _?: unknown;\n}\n\n/** Trimmed view of an autocomplete list (the editor's private `autocompleteList`). */\ninterface AutocompleteListLike {\n\trender(width: number): string[];\n}\n\n/** Trimmed view of pi's `ReadonlyFooterDataProvider`. */\ninterface ReadonlyFooterDataProvider {\n\tgetGitBranch(): string | null;\n\tgetGitDiffstat?(): { added: number; removed: number } | null;\n\tgetExtensionStatuses(): ReadonlyMap<string, string>;\n\tgetAvailableProviderCount(): number;\n\tonBranchChange(callback: () => void): () => void;\n}\n\n/** Trimmed view of the `getContextUsage` return value. */\ninterface ContextUsage {\n\ttokens: number | null;\n\tcontextWindow: number;\n\tpercent: number | null;\n}\n\n/** Trimmed view of an assistant message's usage — the bits we render. */\ninterface AssistantUsage {\n\tinput: number;\n\toutput: number;\n\tcacheRead?: number;\n\tcacheWrite?: number;\n\tcost: { total: number };\n}\n\n/** Trimmed view of an assistant message. */\ninterface AssistantMessageLike {\n\trole: \"assistant\";\n\tusage: AssistantUsage;\n}\n\n/** Trimmed view of a session entry — only what we iterate over. */\ntype SessionEntry =\n\t| { type: \"message\"; message: AssistantMessageLike }\n\t| { type: string; message?: unknown };\n\n/** Trimmed view of a `ReadonlySessionManager`. */\ninterface ReadonlySessionManagerLike {\n\tgetEntries(): readonly SessionEntry[];\n\tgetBranch?(): readonly SessionEntry[];\n}\n\n/** Trimmed view of a `Model`. */\ninterface ModelLike {\n\tid?: string;\n\tprovider?: string;\n\tcontextWindow?: number;\n\treasoning?: boolean;\n\tthinkingLevelMap?: Record<string, string | null>;\n}\n\ninterface ExtensionUIContextLike {\n\tsetEditorComponent(factory: EditorFactoryLike | undefined): void;\n\tsetFooter(factory: FooterFactoryLike | undefined): void;\n\treadonly theme?: Theme;\n}\n\n/** Trimmed view of `ExtensionContext`. */\ninterface ExtensionContextLike {\n\tmode: \"tui\" | \"rpc\" | \"json\" | \"print\";\n\thasUI: boolean;\n\tmodel: ModelLike | undefined;\n\tsessionManager: ReadonlySessionManagerLike;\n\tgetContextUsage(): ContextUsage | undefined;\n\tui: ExtensionUIContextLike;\n}\n\n/** Trimmed view of `ExtensionAPI`. */\ninterface ExtensionAPI {\n\tgetThinkingLevel(): ThinkingLevel;\n\ton(event: string, handler: (event: unknown, ctx: ExtensionContextLike) => void): void;\n}\n\n/** `setEditorComponent` factory shape. */\ntype EditorFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n) => EditorComponentLike;\n\ninterface EditorComponentLike {\n\trender(width: number): string[];\n\tgetText(): string;\n\tsetText(text: string): void;\n\tinvalidate(): void;\n\thandleInput?(data: string): void;\n}\n\n/** `setFooter` factory shape. */\ntype FooterFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n) => FooterComponentLike;\n\ninterface FooterComponentLike {\n\trender(width: number): string[];\n\tdispose?(): void;\n\tinvalidate?(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Display-width helpers (ANSI-aware; CJK-aware)\n//\n// The editor (`Editor.render`) word-wraps to the given width using grapheme\n// width, so each returned line is ≤ that many visual columns. To right-pad a\n// line for our box we need a width model that matches closely enough: skip ALL\n// escape sequences (SGR color, OSC/DCS/APC/PM/SOS string sequences such as\n// pi-tui's `CURSOR_MARKER` `ESC _pi:c BEL`, and two-char escapes), count common\n// East-Asian wide ranges as 2, combining marks and variation selectors as 0.\n// Handling the string sequences as 0-width is what keeps the right `│` rail\n// aligned on the focused (cursor) line — the base editor embeds the marker and\n// the TUI strips it at flush time, so we must not count it here.\n// ---------------------------------------------------------------------------\n\nfunction skipAnsi(str: string, pos: number): number {\n\tif (str.charCodeAt(pos) !== 0x1b) return 0;\n\tconst next = str.charCodeAt(pos + 1);\n\t// CSI: ESC [ ... <final 0x40-0x7e>\n\tif (next === 0x5b /* [ */) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c >= 0x40 && c <= 0x7e) return j + 1 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// String sequences — OSC (]), DCS (P), APC (_), PM (^), SOS (X) — terminated\n\t// by BEL (0x07) or ST (ESC \\). pi-tui's CURSOR_MARKER `ESC _pi:c BEL` is APC;\n\t// OSC color queries are OSC. All are zero visual width.\n\tif (\n\t\tnext === 0x5d /* ] */ ||\n\t\tnext === 0x50 /* P */ ||\n\t\tnext === 0x5f /* _ */ ||\n\t\tnext === 0x5e /* ^ */ ||\n\t\tnext === 0x58 /* X */\n\t) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c === 0x07 /* BEL */) return j + 1 - pos;\n\t\t\tif (c === 0x1b && str.charCodeAt(j + 1) === 0x5c /* \\ */) return j + 2 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// Any other ESC sequence: consume ESC + one final byte (e.g. ESC c, ESC \\,\n\t// ESC ( B). A lone trailing ESC with no following byte is 0 width too.\n\treturn Number.isNaN(next) ? 1 : 2;\n}\n\nfunction isWide(cp: number): boolean {\n\treturn (\n\t\t(cp >= 0x1100 && cp <= 0x115f) ||\n\t\t(cp >= 0x2e80 && cp <= 0x303e) ||\n\t\t(cp >= 0x3041 && cp <= 0x33ff) ||\n\t\t(cp >= 0x3400 && cp <= 0x4dbf) ||\n\t\t(cp >= 0x4e00 && cp <= 0x9fff) ||\n\t\t(cp >= 0xa000 && cp <= 0xa4cf) ||\n\t\t(cp >= 0xac00 && cp <= 0xd7a3) ||\n\t\t(cp >= 0xf900 && cp <= 0xfaff) ||\n\t\t(cp >= 0xfe30 && cp <= 0xfe4f) ||\n\t\t(cp >= 0xff00 && cp <= 0xff60) ||\n\t\t(cp >= 0xffe0 && cp <= 0xffe6) ||\n\t\t(cp >= 0x1f300 && cp <= 0x1faff) ||\n\t\t(cp >= 0x20000 && cp <= 0x3fffd)\n\t);\n}\n\nfunction charWidth(cp: number): number {\n\tif (cp >= 0x20 && cp < 0x7f) return 1;\n\tif ((cp >= 0x0300 && cp <= 0x036f) || (cp >= 0xfe00 && cp <= 0xfe0f) || cp === 0x200d) return 0;\n\treturn isWide(cp) ? 2 : 1;\n}\n\n/** Visible width of a string, ignoring SGR color codes. */\nfunction displayWidth(str: string): number {\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < str.length) {\n\t\tconst skip = skipAnsi(str, i);\n\t\tif (skip > 0) {\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst cp = str.codePointAt(i) ?? 0;\n\t\tw += charWidth(cp);\n\t\ti += cp > 0xffff ? 2 : 1;\n\t}\n\treturn w;\n}\n\n/** Right-pad a (possibly colored) line to `width` visible columns. */\nfunction padRight(line: string, width: number): string {\n\tconst w = displayWidth(line);\n\tif (w >= width) return line;\n\treturn line + \" \".repeat(width - w);\n}\n\n/** Truncate a plain (non-ANSI) string to `maxWidth` visible columns. */\nfunction truncatePlain(text: string, maxWidth: number): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length) {\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > maxWidth) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\treturn out;\n}\n\n/** Truncate a (possibly ANSI-colored) string to `maxWidth` visible columns,\n * re-emitting an SGR reset at the cut so styling doesn't bleed. */\nfunction truncateToWidth(text: string, maxWidth: number, ellipsis = \"\"): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tconst target = Math.max(0, maxWidth - displayWidth(ellipsis));\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length && w < target) {\n\t\tconst skip = skipAnsi(text, i);\n\t\tif (skip > 0) {\n\t\t\tout += text.slice(i, i + skip);\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > target) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\tout += \"\\x1b[0m\";\n\treturn out + ellipsis;\n}\n\n/** Clamp each rendered line to `width` visible columns (fallback path). */\nfunction clampLines(lines: string[], width: number): string[] {\n\treturn lines.map((l) => (displayWidth(l) > width ? truncateToWidth(l, width, \"\") : l));\n}\n\n/** Apply a theme `fg` token safely; falls back to plain text. */\nfunction color(theme: Theme | undefined, token: string, text: string): string {\n\ttry {\n\t\treturn theme?.fg?.(token, text) ?? text;\n\t} catch {\n\t\treturn text;\n\t}\n}\n\n// lunr: strip ANSI escape sequences so footer statuses can be re-colored uniformly.\nfunction stripAnsi(s: string): string {\n\treturn s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Stats formatting\n// ---------------------------------------------------------------------------\n\n/** Compact token-count formatter: `999`, `1.2k`, `15k`, `1.2M`, `15M`.\n * Matches pi's FooterComponent / the captured zentui examples\n * (`↑9.0M ↓112k`, `20%/1.0M`). */\nfunction formatCount(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\n/** Sum session token totals and derive the latest request's cache-hit rate. */\nfunction getUsageTotals(ctx: ExtensionContextLike): {\n\tinput: number;\n\toutput: number;\n\tcacheActivity: boolean;\n\tlatestCacheHitRate: number | undefined;\n} {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cacheRead = 0;\n\tlet cacheWrite = 0;\n\tlet latestCacheHitRate: number | undefined;\n\tconst entries = ctx.sessionManager.getEntries?.() ?? ctx.sessionManager.getBranch?.() ?? [];\n\tfor (const entry of entries as readonly SessionEntry[]) {\n\t\tif (entry.type !== \"message\") continue;\n\t\tconst m = entry.message as AssistantMessageLike | undefined;\n\t\tif (!m || m.role !== \"assistant\") continue;\n\t\tconst u = m.usage;\n\t\tif (!u) continue;\n\t\tconst usageInput = u.input ?? 0;\n\t\tconst usageCacheRead = u.cacheRead ?? 0;\n\t\tconst usageCacheWrite = u.cacheWrite ?? 0;\n\t\tinput += usageInput;\n\t\toutput += u.output ?? 0;\n\t\tcacheRead += usageCacheRead;\n\t\tcacheWrite += usageCacheWrite;\n\t\tconst promptTokens = usageInput + usageCacheRead + usageCacheWrite;\n\t\tlatestCacheHitRate = promptTokens > 0 ? (usageCacheRead / promptTokens) * 100 : undefined;\n\t}\n\treturn { input, output, cacheActivity: cacheRead > 0 || cacheWrite > 0, latestCacheHitRate };\n}\n\n// ---------------------------------------------------------------------------\n// Provider display label\n//\n// `ctx.model.provider` is a ProviderId string (e.g. `\"ollama-cloud\"`), NOT the\n// human label. `BUILT_IN_PROVIDER_DISPLAY_NAMES` exists in pi core but is not\n// re-exported to extensions, so we derive the label (mirrors zentui's\n// `formatProviderLabel`, with an explicit `ollama-cloud` entry).\n// ---------------------------------------------------------------------------\n\nfunction formatProviderLabel(provider: string | undefined): string {\n\tif (!provider) return \"Unknown\";\n\tconst known: Record<string, string> = {\n\t\tanthropic: \"Anthropic\",\n\t\tgemini: \"Google\",\n\t\tgoogle: \"Google\",\n\t\tollama: \"Ollama\",\n\t\t\"ollama-cloud\": \"Ollama Cloud\",\n\t\topenai: \"OpenAI\",\n\t\t\"openai-codex\": \"OpenAI\",\n\t\tmistral: \"Mistral\",\n\t};\n\treturn (\n\t\tknown[provider] ??\n\t\tprovider.replace(/[-_]/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase())\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// The chip: `model · provider · effort`\n// ---------------------------------------------------------------------------\n\nfunction colorEffort(theme: Theme | undefined, level: ThinkingLevel, text: string): string {\n\tconst token = thinkingThemeToken(level);\n\tconst painted = color(theme, token, text);\n\tif (token === \"thinkingMax\" && painted === text) {\n\t\treturn color(theme, \"thinkingXhigh\", text);\n\t}\n\treturn painted;\n}\n\nfunction buildChip(ctx: ExtensionContextLike, pi: ExtensionAPI): { left: string; effort: string; level: ThinkingLevel } {\n\tconst modelId = ctx.model?.id ?? \"no-model\";\n\tconst provider = ctx.model?.provider;\n\tconst providerLabel = formatProviderLabel(provider);\n\tconst fast = provider === \"openai-codex\" && lunrCustomizeBridge()?.getOpenAIFastMode?.() ? \" · fast\" : \"\";\n\tconst level = pi.getThinkingLevel();\n\tconst effort = formatChipEffort(level);\n\treturn { left: `${modelId}${fast} · ${providerLabel} · `, effort, level };\n}\n\n// ---------------------------------------------------------------------------\n// The prompt box — `ChatboxEditor extends CustomEditor`\n// ---------------------------------------------------------------------------\n\nexport class ChatboxEditor extends CustomEditor {\n\tprivate ctx: ExtensionContextLike;\n\tprivate pi: ExtensionAPI;\n\n\tbind(ctx: ExtensionContextLike, pi: ExtensionAPI): void {\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t}\n\n\t/** Keep the displayed values while /new or /resume replaces the old runtime. */\n\tunbind(): void {\n\t\tconst level = this.pi.getThinkingLevel();\n\t\tthis.bind(\n\t\t\t{\n\t\t\t\tmode: \"tui\",\n\t\t\t\thasUI: true,\n\t\t\t\tmodel: this.ctx.model,\n\t\t\t\tsessionManager: { getEntries: () => [] },\n\t\t\t\tgetContextUsage: () => undefined,\n\t\t\t\tui: { theme: this.ctx.ui?.theme, setEditorComponent() {}, setFooter() {} },\n\t\t\t},\n\t\t\t{ getThinkingLevel: () => level, on() {} },\n\t\t);\n\t}\n\n\tconstructor(\n\t\ttui: TUIHandle,\n\t\ttheme: EditorThemeLike,\n\t\tkeybindings: KeybindingsLike,\n\t\tctx: ExtensionContextLike,\n\t\tpi: ExtensionAPI,\n\t) {\n\t\t// CustomEditor ctor: (tui, theme, keybindings, options?: EditorOptions).\n\t\t// Casts keep the inline types from leaking into the real base signature.\n\t\tsuper(tui as unknown as never, theme as unknown as never, keybindings as unknown as never, {\n\t\t\tpaddingX: 0,\n\t\t});\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t\t// lunr: do not clobber borderColor — InteractiveMode.updateEditorBorderColor()\n\t\t// owns it (thinkingOff…thinkingMax, or bashMode).\n\t}\n\n\tprivate color(token: string, text: string): string {\n\t\treturn color(this.ctx.ui?.theme, token, text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// Too narrow to draw a box — defer to the base editor, clamped.\n\t\tif (width <= 4) {\n\t\t\treturn clampLines(super.render(width), width);\n\t\t}\n\n\t\t// Rails: `│ ` (left) + ` │` (right) => 4 columns of chrome.\n\t\tconst glyph = lunrPromptGlyph(this.ctx.ui?.theme);\n\t\tconst glyphW = displayWidth(glyph);\n\t\tconst innerWidth = Math.max(1, width - 4 - glyphW);\n\t\tconst base = super.render(innerWidth);\n\n\t\t// The base editor appends the autocomplete menu lines (if any) to the END\n\t\t// of its render output. Split them off so the body sits inside the box and\n\t\t// the autocomplete renders BELOW the bottom border (preserves slash\n\t\t// commands). Mirrors zentui's `renderPolishedFrame`.\n\t\tconst showing = this.isShowingAutocomplete();\n\t\tconst acList = (this as unknown as { autocompleteList?: AutocompleteListLike }).autocompleteList;\n\t\tlet acCount = 0;\n\t\tif (showing && acList && typeof acList.render === \"function\") {\n\t\t\ttry {\n\t\t\t\tacCount = acList.render(innerWidth).length;\n\t\t\t} catch {\n\t\t\t\tacCount = 0;\n\t\t\t}\n\t\t}\n\n\t\t// `super.render` returns [base top ─ border, ...wrapped text lines, base\n\t\t// bottom ─ border, ...autocomplete lines] — the base editor draws its OWN\n\t\t// straight borders and (when active) appends the autocomplete menu. Split the\n\t\t// autocomplete off the end, then STRIP the base's first/last lines (its own\n\t\t// borders) so we don't render them a second time inside our rounded frame.\n\t\t// Mirrors zentui's `editorFrame.slice(1, -1)` (renderPolishedFrame).\n\t\tlet frame = base;\n\t\tlet acLines: string[] = [];\n\t\tif (acCount > 0 && acCount < frame.length) {\n\t\t\tacLines = frame.slice(frame.length - acCount);\n\t\t\tframe = frame.slice(0, frame.length - acCount);\n\t\t}\n\t\tconst inner = frame.length >= 2 ? frame.slice(1, frame.length - 1) : frame;\n\t\tconst body = inner.length > 0 ? inner : [\"\"];\n\n\t\tconst border = (s: string): string => this.borderColor(s);\n\n\t\t// Top border: ╭─…─╮\n\t\tconst top = border(\"\\u256d\" + \"\\u2500\".repeat(width - 2) + \"\\u256e\");\n\n\t\t// Body: │ <padded line> │ (auto-grows with the number of wrapped lines)\n\t\t// lunr: prefix the first body line with the theme-controlled prompt arrow.\n\t\t// A same-width blank gutter keeps subsequent lines aligned.\n\t\tconst gutter = glyphW > 0 ? \" \".repeat(glyphW) : \"\";\n\t\tconst bodyLines = body.map((ln: string, i: number) => {\n\t\t\tconst prefix = i === 0 && glyphW > 0 ? this.color(\"dim\", glyph) : gutter;\n\t\t\treturn border(\"\\u2502 \") + prefix + padRight(ln, innerWidth) + border(\" \\u2502\");\n\t\t});\n\n\t\t// Bottom border with the right-aligned chip: ╰─…─ <chip> ─╯\n\t\tconst bottom = this.renderBottomBorder(width);\n\n\t\treturn [top, ...bodyLines, bottom, ...acLines];\n\t}\n\n\tprivate renderBottomBorder(width: number): string {\n\t\tconst border = (s: string): string => this.borderColor(s);\n\t\tconst parts = buildChip(this.ctx, this.pi);\n\t\tconst plain = parts.left + parts.effort;\n\t\tconst overhead = 4;\n\t\tconst maxChip = Math.max(0, width - overhead);\n\t\tconst truncated = displayWidth(plain) > maxChip;\n\t\tconst chipPlain = truncated ? truncatePlain(plain, maxChip) : plain;\n\t\tconst chipW = displayWidth(chipPlain);\n\t\tconst dashTotal = Math.max(0, width - overhead - chipW);\n\t\t// Right-align the chip: a single trailing dash before the corner, the\n\t\t// rest lead (right-aligns the chip near the corner).\n\t\tconst rightDashes = Math.min(dashTotal, 1);\n\t\tconst leftDashes = dashTotal - rightDashes;\n\n\t\tconst left = \"\\u2570\" + \"\\u2500\".repeat(leftDashes) + \" \";\n\t\tconst right = \" \" + \"\\u2500\".repeat(rightDashes) + \"\\u256f\";\n\t\tconst theme = this.ctx.ui?.theme;\n\t\t// Truncated chips may have lost the effort token — paint all white.\n\t\t// Otherwise model/provider stay white and the effort uses the thinking token.\n\t\tconst chip = truncated\n\t\t\t? this.color(\"white\", chipPlain)\n\t\t\t: this.color(\"white\", parts.left) + colorEffort(theme, parts.level, parts.effort);\n\t\treturn border(left) + chip + border(right);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// The stats line (footer) — slim, single line, BELOW the box\n// ---------------------------------------------------------------------------\n\nexport function renderStatsLine(\n\twidth: number,\n\tctx: ExtensionContextLike,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n): string[] {\n\tconst sep = color(theme, \"accent2\", \" | \"); // lunr: theme-polish — separator uses subtle accent2 blue (was bright-black plain fallback)\n\tconst parts: string[] = [];\n\n\t// lunr: mode zone — permission mode + agent-mode statuses (plan/goal)\n\t// render as ONE segment (dim middot-separated), not scattered across piped sections.\n\tconst modeZone: string[] = [];\n\n\t// lunr: permission mode safety indicator — always shown (not toggle-gated).\n\tconst mode = lunrPermissionMode();\n\tif (mode === \"yolo\" || mode === \"auto\") modeZone.push(color(theme, \"warning\", mode));\n\telse if (mode === \"manual\" || mode === \"plan\") modeZone.push(color(theme, \"white\", mode)); // lunr: theme-polish — manual/plan read white (was dim)\n\n\t// lunr: footer element toggles from the customize bridge (read at render time).\n\tconst footerToggles = lunrFooterToggles();\n\n\t// 1) Extension statuses published by other extensions (rendered as-is,\n\t// already styled): LSP (`pi-lsp-extension`), MCP (`pi-mcp-adapter`),\n\t// throughput/tokens (`pi-tps-was-taken`). These are NOT on `ctx` directly.\n\tconst statuses = footerData.getExtensionStatuses?.();\n\tif (statuses && statuses.size > 0) {\n\t\t// lunr: status segments are toggle-gated via the customize bridge:\n\t\t// footerStatuses gates plan/goal, footerTps gates tps,\n\t\t// footerMcp gates mcp/mcp-auth, footerLsp gates lsp. Publishers keep\n\t\t// calling ctx.ui.setStatus harmlessly when their segment is hidden.\n\t\t// lunr: plan/goal join the mode zone; tps/mcp/lsp stay piped.\n\t\tconst modeKeys: string[] = footerToggles.statuses ? [\"plan\", \"goal\"] : [];\n\t\tfor (const key of modeKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\tif (v) modeZone.push(color(theme, \"white\", stripAnsi(v)));\n\t\t}\n\t\tconst pipedKeys: string[] = [];\n\t\tif (footerToggles.tps) pipedKeys.push(\"tps\");\n\t\tif (footerToggles.mcp) pipedKeys.push(\"mcp\", \"mcp-auth\");\n\t\tif (footerToggles.lsp) pipedKeys.push(\"lsp\");\n\t\tfor (const key of pipedKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\t// lunr: unify footer status colors (white, was dim) so the whole stats line reads as one tone.\n\t\t\tif (v) parts.push(color(theme, \"white\", stripAnsi(v))); // lunr: theme-polish — status segments white (was dim)\n\t\t}\n\t}\n\tif (modeZone.length > 0) {\n\t\tparts.unshift(modeZone.join(color(theme, \"dim\", \" · \")));\n\t}\n\n\t// lunr: git branch + working-tree +/- vs HEAD (gated on footerGit).\n\tif (footerToggles.git) {\n\t\tconst branch = footerData.getGitBranch?.();\n\t\tif (branch) {\n\t\t\tconst diff = footerData.getGitDiffstat?.();\n\t\t\tlet gitSeg = color(theme, \"white\", branch);\n\t\t\tif (diff && (diff.added !== 0 || diff.removed !== 0)) {\n\t\t\t\tgitSeg +=\n\t\t\t\t\t` ${color(theme, \"success\", `+${diff.added}`)} ${color(theme, \"error\", `-${diff.removed}`)}`;\n\t\t\t}\n\t\t\tparts.push(gitSeg);\n\t\t}\n\t}\n\n\t// lunr: live subscription window bar (gated on footerPlan). Hidden with no plan.\n\tif (footerToggles.plan) {\n\t\tconst provider = ctx.model?.provider;\n\t\tif (provider) {\n\t\t\tconst usage = lunrUsageBridge();\n\t\t\tusage?.prefetch?.(provider);\n\t\t\tconst seg = usage?.pickForFooter?.(provider);\n\t\t\tif (seg) {\n\t\t\t\tconst pct = `${Math.round(seg.usedPercent)}%`;\n\t\t\t\tconst barColor = seg.usedPercent > 90 ? \"error\" : seg.usedPercent > 70 ? \"warning\" : \"success\";\n\t\t\t\tconst bar = footerToggles.planBar ? `${compactPlanBar(seg.usedPercent, theme)} ` : \"\";\n\t\t\t\tparts.push(color(theme, \"white\", seg.label) + \" \" + bar + color(theme, barColor, pct));\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2) Context usage: `pct/window` (lunr: gated on footerContext).\n\tif (footerToggles.context) {\n\t\tconst usage = ctx.getContextUsage();\n\t\tconst win = ctx.model?.contextWindow ?? usage?.contextWindow ?? 0;\n\t\tconst pct = usage?.percent == null ? \"?\" : `${Math.round(usage.percent)}%`;\n\t\tconst ctxSeg = `${pct}/${formatCount(win)}`;\n\t\tconst pv = usage?.percent ?? 0;\n\t\tif (pv > 90) parts.push(color(theme, \"error\", ctxSeg));\n\t\telse if (pv > 70) parts.push(color(theme, \"warning\", ctxSeg));\n\t\telse parts.push(color(theme, \"white\", ctxSeg)); // lunr: theme-polish — normal context % white (was dim)\n\t}\n\n\tconst totals = getUsageTotals(ctx);\n\n\t// 3) Token totals: ↑in ↓out (lunr: gated on footerTokens).\n\tif (footerToggles.tokens) {\n\t\tparts.push(color(theme, \"white\", `\\u2191${formatCount(totals.input)} \\u2193${formatCount(totals.output)}`)); // lunr: theme-polish — token totals white (was dim)\n\t}\n\n\t// 4) Latest prompt cache hit rate (gated on footerCacheHitRate).\n\tif (footerToggles.cacheHitRate && totals.cacheActivity && totals.latestCacheHitRate !== undefined) {\n\t\tparts.push(color(theme, \"white\", `CH${totals.latestCacheHitRate.toFixed(1)}%`));\n\t}\n\n\t// lunr: cost/usage counter segment removed entirely (both the $x.xxx dollar\n\t// counter for API-key providers and the plan-usage limit bar for OAuth/subscription\n\t// providers). Segments 1-3 (statuses, context, tokens) remain.\n\n\tlet line = parts.join(sep);\n\tif (displayWidth(line) > width) {\n\t\tline = truncateToWidth(line, width, \"\");\n\t}\n\treturn [line];\n}\n\n// ---------------------------------------------------------------------------\n// Install / teardown\n// ---------------------------------------------------------------------------\n\nconst chatboxEditors = new WeakMap<TUIHandle, ChatboxEditor>();\n\n/** The startup view and extension bind the same editor, preserving its complete draft state. */\nexport function getChatboxEditor(\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n): ChatboxEditor {\n\tlet editor = chatboxEditors.get(tui);\n\tif (editor) editor.bind(ctx, pi);\n\telse {\n\t\teditor = new ChatboxEditor(tui, theme, keybindings, ctx, pi);\n\t\tchatboxEditors.set(tui, editor);\n\t}\n\treturn editor;\n}\n\nfunction installEditor(\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n\tsetRequestor: (r: () => void) => void,\n): (() => void) | undefined {\n\tif (typeof ctx.ui.setEditorComponent !== \"function\") return;\n\tlet editor: ChatboxEditor | undefined;\n\tconst factory: EditorFactoryLike = (tui, _theme, _keybindings) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\teditor = getChatboxEditor(tui, _theme, _keybindings, ctx, pi);\n\t\treturn editor;\n\t};\n\tctx.ui.setEditorComponent(factory);\n\treturn () => editor?.unbind();\n}\n\nfunction installFooter(\n\tctx: ExtensionContextLike,\n\tsetRequestor: (r: () => void) => void,\n): void {\n\tif (typeof ctx.ui.setFooter !== \"function\") return;\n\tlet disposed = false;\n\tconst factory: FooterFactoryLike = (tui, _theme, _footerData) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tinvalidate(): void {\n\t\t\t\t// render is pure\n\t\t\t},\n\t\t\tdispose(): void {\n\t\t\t\tdisposed = true;\n\t\t\t},\n\t\t\trender(width: number): string[] {\n\t\t\t\tif (disposed) return [];\n\t\t\t\treturn renderStatsLine(width, ctx, _theme, _footerData);\n\t\t\t},\n\t\t};\n\t};\n\tctx.ui.setFooter(factory);\n}\n\n// ---------------------------------------------------------------------------\n// Extension entry point\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\tlet unbindEditor: (() => void) | undefined;\n\tlet renderRequestor: (() => void) | undefined = undefined;\n\tconst requestRender = (): void => {\n\t\ttry {\n\t\t\trenderRequestor?.();\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t};\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tif (!ctx.hasUI || ctx.mode !== \"tui\") return;\n\t\tunbindEditor = installEditor(ctx, pi, (r) => {\n\t\t\trenderRequestor = r;\n\t\t});\n\t\tinstallFooter(ctx, (r) => {\n\t\t\tif (!renderRequestor) renderRequestor = r;\n\t\t});\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tunbindEditor?.();\n\t\tunbindEditor = undefined;\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setEditorComponent === \"function\") ctx.ui.setEditorComponent(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setFooter === \"function\") ctx.ui.setFooter(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\trenderRequestor = undefined;\n\t});\n\n\t// Re-render triggers: model/provider + effort (chip), and token/cost/context\n\t// (stats line). Event names match those zentui wires.\n\tconst reRenderEvents = [\n\t\t\"model_select\",\n\t\t\"thinking_level_select\",\n\t\t\"agent_end\",\n\t\t\"message_end\",\n\t\t\"tool_execution_end\",\n\t\t\"session_compact\",\n\t];\n\tfor (const ev of reRenderEvents) {\n\t\tpi.on(ev, () => requestRender());\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ashxj-tui.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/ashxj-tui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ashxj-tui — a custom slim chatbox for pi.\n *\n * Replaces pi-zentui's prompt box + statusline with:\n * - A rounded prompt box that auto-expands as the typed message wraps.\n * Top and bottom rules only; no side rails.\n * - A right-aligned chip on the box's BOTTOM border:\n * model · provider · effort (e.g. `glm-5.2 · Ollama Cloud · xhigh`)\n * - A slim stats line (extension statuses · context% · ↑↓; each segment\n * toggle-gated via the lunr customize bridge) BELOW the box, not wrapped\n * around the input.\n * - No session-mode indicator anywhere (pi has no such concept).\n *\n * Loaded by pi via jiti — no build step, plain TypeScript.\n *\n * NOTE on type imports (see `ashxj-thinking`/`simple-memory` for the convention):\n * This file declares structural types inline rather than importing them from\n * `@ashx-j/lunr` / `@ashx-j/lunr-tui`.\n * pi-coding-agent's `index.d.ts` re-exports from internal `.d.ts` files that\n * contain subpath imports like `@ashx-j/lunr-ai/compat`, which do not\n * resolve under `tsc` with a file argument. We keep the typecheck\n * self-contained with inline types and verify via the included `tsconfig.json`\n * (`moduleResolution: \"Bundler\"` + `skipLibCheck: true`).\n *\n * The ONE exception is `CustomEditor`, imported as a RUNTIME VALUE directly\n * from its defining module (`modes/interactive/components/custom-editor.ts`).\n * We must `extends` it to inherit pi's app keybindings (escape, ctrl+d, model\n * switching, extension shortcuts) — wrapping would lose those. It is imported\n * from the concrete module, NOT the package barrel, because the barrel\n * re-exports main.ts which imports this file — a circular import that crashes\n * under vite-node (`Class extends value undefined`).\n */\n\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.js\";\n\nconst CUSTOMIZE_BRIDGE = Symbol.for(\"@lunr/customize\");\nconst PERMISSION_MODE_BRIDGE = Symbol.for(\"@lunr/permission-mode\");\ninterface CustomizeBridgeForPrompt {\n\tgetOpenAIFastMode?(): boolean;\n\t// lunr: footer element toggles (added to the same bridge).\n\tgetFooterMcp?(): boolean;\n\tgetFooterLsp?(): boolean;\n\tgetFooterContext?(): boolean;\n\tgetFooterTokens?(): boolean;\n\tgetFooterCacheHitRate?(): boolean;\n\tgetFooterTps?(): boolean;\n\tgetFooterStatuses?(): boolean;\n\tgetFooterGit?(): boolean;\n\tgetFooterPlan?(): boolean;\n\tgetFooterPlanBar?(): boolean;\n}\ninterface PermissionModeBridgeForFooter {\n\tgetMode(): string | undefined;\n}\nfunction lunrCustomizeBridge(): CustomizeBridgeForPrompt | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE] as CustomizeBridgeForPrompt | undefined;\n}\nfunction lunrPermissionModeBridge(): PermissionModeBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[PERMISSION_MODE_BRIDGE] as PermissionModeBridgeForFooter | undefined;\n}\n// lunr: footer toggles, read at render time. Bridgeless / missing-getter fallback\n// matches the settings-manager defaults: MCP on, LSP off, everything else on.\nfunction lunrFooterToggles(): {\n\tmcp: boolean;\n\tlsp: boolean;\n\tcontext: boolean;\n\ttokens: boolean;\n\tcacheHitRate: boolean;\n\ttps: boolean;\n\tstatuses: boolean;\n\tgit: boolean;\n\tplan: boolean;\n\tplanBar: boolean;\n} {\n\tconst bridge = lunrCustomizeBridge();\n\treturn {\n\t\tmcp: bridge?.getFooterMcp?.() ?? true,\n\t\tlsp: bridge?.getFooterLsp?.() ?? false,\n\t\tcontext: bridge?.getFooterContext?.() ?? true,\n\t\ttokens: bridge?.getFooterTokens?.() ?? true,\n\t\tcacheHitRate: bridge?.getFooterCacheHitRate?.() ?? true,\n\t\ttps: bridge?.getFooterTps?.() ?? true,\n\t\tstatuses: bridge?.getFooterStatuses?.() ?? true,\n\t\tgit: bridge?.getFooterGit?.() ?? true,\n\t\tplan: bridge?.getFooterPlan?.() ?? true,\n\t\tplanBar: bridge?.getFooterPlanBar?.() ?? true,\n\t};\n}\n\nconst USAGE_SERVICE_BRIDGE = Symbol.for(\"@lunr/usage-service\");\ninterface UsageServiceBridgeForFooter {\n\tpickForFooter?(providerId: string): { label: string; usedPercent: number } | undefined;\n\tprefetch?(providerId: string): void;\n}\nfunction lunrUsageBridge(): UsageServiceBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE] as UsageServiceBridgeForFooter | undefined;\n}\n\nfunction compactPlanBar(percent: number, theme: Theme): string {\n\tconst cells = 8;\n\tconst clamped = Math.max(0, Math.min(100, percent));\n\tconst filled = Math.round((clamped / 100) * cells);\n\tconst token = clamped > 90 ? \"error\" : clamped > 70 ? \"warning\" : \"success\";\n\tconst fill = filled > 0 ? color(theme, token, \"█\".repeat(filled)) : \"\";\n\tconst rest = filled < cells ? color(theme, \"dim\", \"░\".repeat(cells - filled)) : \"\";\n\treturn fill + rest;\n}\n// lunr: permission mode for the footer safety indicator (always shown).\nfunction lunrPermissionMode(): string | undefined {\n\treturn lunrPermissionModeBridge()?.getMode();\n}\nexport function lunrPromptGlyph(theme: Theme | undefined): string {\n\tconst arrow = theme?.glyph?.(\"promptArrow\") ?? \">\";\n\treturn arrow ? `${arrow} ` : \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Minimal structural types (inline — see file header)\n// ---------------------------------------------------------------------------\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\n/** Theme token for the chatbox thinking-level border / effort chip. */\nexport function thinkingThemeToken(level: ThinkingLevel): string {\n\tswitch (level) {\n\t\tcase \"off\":\n\t\t\treturn \"thinkingOff\";\n\t\tcase \"minimal\":\n\t\t\treturn \"thinkingMinimal\";\n\t\tcase \"low\":\n\t\t\treturn \"thinkingLow\";\n\t\tcase \"medium\":\n\t\t\treturn \"thinkingMedium\";\n\t\tcase \"high\":\n\t\t\treturn \"thinkingHigh\";\n\t\tcase \"xhigh\":\n\t\t\treturn \"thinkingXhigh\";\n\t\tcase \"max\":\n\t\t\treturn \"thinkingMax\";\n\t\tdefault:\n\t\t\treturn \"thinkingOff\";\n\t}\n}\n\n/** Chip effort label — identity, locked so xhigh/max are never mapped down to high. */\nexport function formatChipEffort(level: ThinkingLevel): string {\n\treturn level;\n}\n\n/** Trimmed view of pi's `Theme` — only the methods we use. */\ninterface Theme {\n\tfg(token: string, text: string): string;\n\t/** lunr: prompt glyph tokens (optional for forward/backward compat). */\n\tglyph?(name: \"promptArrow\"): string;\n}\n\n/** Trimmed view of `pi-tui`'s `TUI` — only the method we use. */\ninterface TUIHandle {\n\trequestRender(force?: boolean): void;\n}\n\n/** Trimmed view of `pi-tui`'s `EditorTheme`. */\ninterface EditorThemeLike {\n\tborderColor: (str: string) => string;\n\tselectList: unknown;\n}\n\n/** Opaque keybindings manager. */\ninterface KeybindingsLike {\n\treadonly _?: unknown;\n}\n\n/** Trimmed view of an autocomplete list (the editor's private `autocompleteList`). */\ninterface AutocompleteListLike {\n\trender(width: number): string[];\n}\n\n/** Trimmed view of pi's `ReadonlyFooterDataProvider`. */\ninterface ReadonlyFooterDataProvider {\n\tgetGitBranch(): string | null;\n\tgetGitDiffstat?(): { added: number; removed: number } | null;\n\tgetExtensionStatuses(): ReadonlyMap<string, string>;\n\tgetAvailableProviderCount(): number;\n\tonBranchChange(callback: () => void): () => void;\n}\n\n/** Trimmed view of the `getContextUsage` return value. */\ninterface ContextUsage {\n\ttokens: number | null;\n\tcontextWindow: number;\n\tpercent: number | null;\n}\n\n/** Trimmed view of an assistant message's usage — the bits we render. */\ninterface AssistantUsage {\n\tinput: number;\n\toutput: number;\n\tcacheRead?: number;\n\tcacheWrite?: number;\n\tcost: { total: number };\n}\n\n/** Trimmed view of an assistant message. */\ninterface AssistantMessageLike {\n\trole: \"assistant\";\n\tusage: AssistantUsage;\n}\n\n/** Trimmed view of a session entry — only what we iterate over. */\ntype SessionEntry =\n\t| { type: \"message\"; message: AssistantMessageLike }\n\t| { type: string; message?: unknown };\n\n/** Trimmed view of a `ReadonlySessionManager`. */\ninterface ReadonlySessionManagerLike {\n\tgetEntries(): readonly SessionEntry[];\n\tgetBranch?(): readonly SessionEntry[];\n}\n\n/** Trimmed view of a `Model`. */\ninterface ModelLike {\n\tid?: string;\n\tprovider?: string;\n\tcontextWindow?: number;\n\treasoning?: boolean;\n\tthinkingLevelMap?: Record<string, string | null>;\n}\n\ninterface ExtensionUIContextLike {\n\tsetEditorComponent(factory: EditorFactoryLike | undefined): void;\n\tsetFooter(factory: FooterFactoryLike | undefined): void;\n\treadonly theme?: Theme;\n}\n\n/** Trimmed view of `ExtensionContext`. */\ninterface ExtensionContextLike {\n\tmode: \"tui\" | \"rpc\" | \"json\" | \"print\";\n\thasUI: boolean;\n\tmodel: ModelLike | undefined;\n\tsessionManager: ReadonlySessionManagerLike;\n\tgetContextUsage(): ContextUsage | undefined;\n\tui: ExtensionUIContextLike;\n}\n\n/** Trimmed view of `ExtensionAPI`. */\ninterface ExtensionAPI {\n\tgetThinkingLevel(): ThinkingLevel;\n\ton(event: string, handler: (event: unknown, ctx: ExtensionContextLike) => void): void;\n}\n\n/** `setEditorComponent` factory shape. */\ntype EditorFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n) => EditorComponentLike;\n\ninterface EditorComponentLike {\n\trender(width: number): string[];\n\tgetText(): string;\n\tsetText(text: string): void;\n\tinvalidate(): void;\n\thandleInput?(data: string): void;\n}\n\n/** `setFooter` factory shape. */\ntype FooterFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n) => FooterComponentLike;\n\ninterface FooterComponentLike {\n\trender(width: number): string[];\n\tdispose?(): void;\n\tinvalidate?(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Display-width helpers (ANSI-aware; CJK-aware)\n//\n// The editor (`Editor.render`) word-wraps to the given width using grapheme\n// width, so each returned line is ≤ that many visual columns. To right-pad a\n// line for our box we need a width model that matches closely enough: skip ALL\n// escape sequences (SGR color, OSC/DCS/APC/PM/SOS string sequences such as\n// pi-tui's `CURSOR_MARKER` `ESC _pi:c BEL`, and two-char escapes), count common\n// East-Asian wide ranges as 2, combining marks and variation selectors as 0.\n// Handling the string sequences as 0-width keeps body padding aligned with the\n// top/bottom rules on the focused (cursor) line. The base editor embeds the\n// marker and the TUI strips it at flush time, so we must not count it here.\n// ---------------------------------------------------------------------------\n\nfunction skipAnsi(str: string, pos: number): number {\n\tif (str.charCodeAt(pos) !== 0x1b) return 0;\n\tconst next = str.charCodeAt(pos + 1);\n\t// CSI: ESC [ ... <final 0x40-0x7e>\n\tif (next === 0x5b /* [ */) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c >= 0x40 && c <= 0x7e) return j + 1 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// String sequences — OSC (]), DCS (P), APC (_), PM (^), SOS (X) — terminated\n\t// by BEL (0x07) or ST (ESC \\). pi-tui's CURSOR_MARKER `ESC _pi:c BEL` is APC;\n\t// OSC color queries are OSC. All are zero visual width.\n\tif (\n\t\tnext === 0x5d /* ] */ ||\n\t\tnext === 0x50 /* P */ ||\n\t\tnext === 0x5f /* _ */ ||\n\t\tnext === 0x5e /* ^ */ ||\n\t\tnext === 0x58 /* X */\n\t) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c === 0x07 /* BEL */) return j + 1 - pos;\n\t\t\tif (c === 0x1b && str.charCodeAt(j + 1) === 0x5c /* \\ */) return j + 2 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// Any other ESC sequence: consume ESC + one final byte (e.g. ESC c, ESC \\,\n\t// ESC ( B). A lone trailing ESC with no following byte is 0 width too.\n\treturn Number.isNaN(next) ? 1 : 2;\n}\n\nfunction isWide(cp: number): boolean {\n\treturn (\n\t\t(cp >= 0x1100 && cp <= 0x115f) ||\n\t\t(cp >= 0x2e80 && cp <= 0x303e) ||\n\t\t(cp >= 0x3041 && cp <= 0x33ff) ||\n\t\t(cp >= 0x3400 && cp <= 0x4dbf) ||\n\t\t(cp >= 0x4e00 && cp <= 0x9fff) ||\n\t\t(cp >= 0xa000 && cp <= 0xa4cf) ||\n\t\t(cp >= 0xac00 && cp <= 0xd7a3) ||\n\t\t(cp >= 0xf900 && cp <= 0xfaff) ||\n\t\t(cp >= 0xfe30 && cp <= 0xfe4f) ||\n\t\t(cp >= 0xff00 && cp <= 0xff60) ||\n\t\t(cp >= 0xffe0 && cp <= 0xffe6) ||\n\t\t(cp >= 0x1f300 && cp <= 0x1faff) ||\n\t\t(cp >= 0x20000 && cp <= 0x3fffd)\n\t);\n}\n\nfunction charWidth(cp: number): number {\n\tif (cp >= 0x20 && cp < 0x7f) return 1;\n\tif ((cp >= 0x0300 && cp <= 0x036f) || (cp >= 0xfe00 && cp <= 0xfe0f) || cp === 0x200d) return 0;\n\treturn isWide(cp) ? 2 : 1;\n}\n\n/** Visible width of a string, ignoring SGR color codes. */\nfunction displayWidth(str: string): number {\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < str.length) {\n\t\tconst skip = skipAnsi(str, i);\n\t\tif (skip > 0) {\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst cp = str.codePointAt(i) ?? 0;\n\t\tw += charWidth(cp);\n\t\ti += cp > 0xffff ? 2 : 1;\n\t}\n\treturn w;\n}\n\n/** Right-pad a (possibly colored) line to `width` visible columns. */\nfunction padRight(line: string, width: number): string {\n\tconst w = displayWidth(line);\n\tif (w >= width) return line;\n\treturn line + \" \".repeat(width - w);\n}\n\n/** Truncate a plain (non-ANSI) string to `maxWidth` visible columns. */\nfunction truncatePlain(text: string, maxWidth: number): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length) {\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > maxWidth) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\treturn out;\n}\n\n/** Truncate a (possibly ANSI-colored) string to `maxWidth` visible columns,\n * re-emitting an SGR reset at the cut so styling doesn't bleed. */\nfunction truncateToWidth(text: string, maxWidth: number, ellipsis = \"\"): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tconst target = Math.max(0, maxWidth - displayWidth(ellipsis));\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length && w < target) {\n\t\tconst skip = skipAnsi(text, i);\n\t\tif (skip > 0) {\n\t\t\tout += text.slice(i, i + skip);\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > target) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\tout += \"\\x1b[0m\";\n\treturn out + ellipsis;\n}\n\n/** Clamp each rendered line to `width` visible columns (fallback path). */\nfunction clampLines(lines: string[], width: number): string[] {\n\treturn lines.map((l) => (displayWidth(l) > width ? truncateToWidth(l, width, \"\") : l));\n}\n\n/** Apply a theme `fg` token safely; falls back to plain text. */\nfunction color(theme: Theme | undefined, token: string, text: string): string {\n\ttry {\n\t\treturn theme?.fg?.(token, text) ?? text;\n\t} catch {\n\t\treturn text;\n\t}\n}\n\n// lunr: strip ANSI escape sequences so footer statuses can be re-colored uniformly.\nfunction stripAnsi(s: string): string {\n\treturn s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Stats formatting\n// ---------------------------------------------------------------------------\n\n/** Compact token-count formatter: `999`, `1.2k`, `15k`, `1.2M`, `15M`.\n * Matches pi's FooterComponent / the captured zentui examples\n * (`↑9.0M ↓112k`, `20%/1.0M`). */\nfunction formatCount(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\n/** Sum session token totals and derive the latest request's cache-hit rate. */\nfunction getUsageTotals(ctx: ExtensionContextLike): {\n\tinput: number;\n\toutput: number;\n\tcacheActivity: boolean;\n\tlatestCacheHitRate: number | undefined;\n} {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cacheRead = 0;\n\tlet cacheWrite = 0;\n\tlet latestCacheHitRate: number | undefined;\n\tconst entries = ctx.sessionManager.getEntries?.() ?? ctx.sessionManager.getBranch?.() ?? [];\n\tfor (const entry of entries as readonly SessionEntry[]) {\n\t\tif (entry.type !== \"message\") continue;\n\t\tconst m = entry.message as AssistantMessageLike | undefined;\n\t\tif (!m || m.role !== \"assistant\") continue;\n\t\tconst u = m.usage;\n\t\tif (!u) continue;\n\t\tconst usageInput = u.input ?? 0;\n\t\tconst usageCacheRead = u.cacheRead ?? 0;\n\t\tconst usageCacheWrite = u.cacheWrite ?? 0;\n\t\tinput += usageInput;\n\t\toutput += u.output ?? 0;\n\t\tcacheRead += usageCacheRead;\n\t\tcacheWrite += usageCacheWrite;\n\t\tconst promptTokens = usageInput + usageCacheRead + usageCacheWrite;\n\t\tlatestCacheHitRate = promptTokens > 0 ? (usageCacheRead / promptTokens) * 100 : undefined;\n\t}\n\treturn { input, output, cacheActivity: cacheRead > 0 || cacheWrite > 0, latestCacheHitRate };\n}\n\n// ---------------------------------------------------------------------------\n// Provider display label\n//\n// `ctx.model.provider` is a ProviderId string (e.g. `\"ollama-cloud\"`), NOT the\n// human label. `BUILT_IN_PROVIDER_DISPLAY_NAMES` exists in pi core but is not\n// re-exported to extensions, so we derive the label (mirrors zentui's\n// `formatProviderLabel`, with an explicit `ollama-cloud` entry).\n// ---------------------------------------------------------------------------\n\nfunction formatProviderLabel(provider: string | undefined): string {\n\tif (!provider) return \"Unknown\";\n\tconst known: Record<string, string> = {\n\t\tanthropic: \"Anthropic\",\n\t\tgemini: \"Google\",\n\t\tgoogle: \"Google\",\n\t\tollama: \"Ollama\",\n\t\t\"ollama-cloud\": \"Ollama Cloud\",\n\t\topenai: \"OpenAI\",\n\t\t\"openai-codex\": \"OpenAI\",\n\t\tmistral: \"Mistral\",\n\t};\n\treturn (\n\t\tknown[provider] ??\n\t\tprovider.replace(/[-_]/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase())\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// The chip: `model · provider · effort`\n// ---------------------------------------------------------------------------\n\nfunction colorEffort(theme: Theme | undefined, level: ThinkingLevel, text: string): string {\n\tconst token = thinkingThemeToken(level);\n\tconst painted = color(theme, token, text);\n\tif (token === \"thinkingMax\" && painted === text) {\n\t\treturn color(theme, \"thinkingXhigh\", text);\n\t}\n\treturn painted;\n}\n\nfunction buildChip(ctx: ExtensionContextLike, pi: ExtensionAPI): { left: string; effort: string; level: ThinkingLevel } {\n\tconst modelId = ctx.model?.id ?? \"no-model\";\n\tconst provider = ctx.model?.provider;\n\tconst providerLabel = formatProviderLabel(provider);\n\tconst fast = provider === \"openai-codex\" && lunrCustomizeBridge()?.getOpenAIFastMode?.() ? \" · fast\" : \"\";\n\tconst level = pi.getThinkingLevel();\n\tconst effort = formatChipEffort(level);\n\treturn { left: `${modelId}${fast} · ${providerLabel} · `, effort, level };\n}\n\n// ---------------------------------------------------------------------------\n// The prompt box — `ChatboxEditor extends CustomEditor`\n// ---------------------------------------------------------------------------\n\nexport class ChatboxEditor extends CustomEditor {\n\tprivate ctx: ExtensionContextLike;\n\tprivate pi: ExtensionAPI;\n\n\tbind(ctx: ExtensionContextLike, pi: ExtensionAPI): void {\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t}\n\n\t/** Keep the displayed values while /new or /resume replaces the old runtime. */\n\tunbind(): void {\n\t\tconst level = this.pi.getThinkingLevel();\n\t\tthis.bind(\n\t\t\t{\n\t\t\t\tmode: \"tui\",\n\t\t\t\thasUI: true,\n\t\t\t\tmodel: this.ctx.model,\n\t\t\t\tsessionManager: { getEntries: () => [] },\n\t\t\t\tgetContextUsage: () => undefined,\n\t\t\t\tui: { theme: this.ctx.ui?.theme, setEditorComponent() {}, setFooter() {} },\n\t\t\t},\n\t\t\t{ getThinkingLevel: () => level, on() {} },\n\t\t);\n\t}\n\n\tconstructor(\n\t\ttui: TUIHandle,\n\t\ttheme: EditorThemeLike,\n\t\tkeybindings: KeybindingsLike,\n\t\tctx: ExtensionContextLike,\n\t\tpi: ExtensionAPI,\n\t) {\n\t\t// CustomEditor ctor: (tui, theme, keybindings, options?: EditorOptions).\n\t\t// Casts keep the inline types from leaking into the real base signature.\n\t\tsuper(tui as unknown as never, theme as unknown as never, keybindings as unknown as never, {\n\t\t\tpaddingX: 0,\n\t\t});\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t\t// lunr: do not clobber borderColor — InteractiveMode.updateEditorBorderColor()\n\t\t// owns it (thinkingOff…thinkingMax, or bashMode).\n\t}\n\n\tprivate color(token: string, text: string): string {\n\t\treturn color(this.ctx.ui?.theme, token, text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// Too narrow to draw a box — defer to the base editor, clamped.\n\t\tif (width <= 4) {\n\t\t\treturn clampLines(super.render(width), width);\n\t\t}\n\n\t\tconst glyph = lunrPromptGlyph(this.ctx.ui?.theme);\n\t\tconst glyphW = displayWidth(glyph);\n\t\tconst innerWidth = Math.max(1, width - glyphW);\n\t\tconst base = super.render(innerWidth);\n\n\t\t// The base editor appends the autocomplete menu lines (if any) to the END\n\t\t// of its render output. Split them off so the body sits inside the box and\n\t\t// the autocomplete renders BELOW the bottom border (preserves slash\n\t\t// commands). Mirrors zentui's `renderPolishedFrame`.\n\t\tconst showing = this.isShowingAutocomplete();\n\t\tconst acList = (this as unknown as { autocompleteList?: AutocompleteListLike }).autocompleteList;\n\t\tlet acCount = 0;\n\t\tif (showing && acList && typeof acList.render === \"function\") {\n\t\t\ttry {\n\t\t\t\tacCount = acList.render(innerWidth).length;\n\t\t\t} catch {\n\t\t\t\tacCount = 0;\n\t\t\t}\n\t\t}\n\n\t\t// `super.render` returns [base top ─ border, ...wrapped text lines, base\n\t\t// bottom ─ border, ...autocomplete lines] — the base editor draws its OWN\n\t\t// straight borders and (when active) appends the autocomplete menu. Split the\n\t\t// autocomplete off the end, then STRIP the base's first/last lines (its own\n\t\t// borders) so we don't render them a second time inside our rounded frame.\n\t\t// Mirrors zentui's `editorFrame.slice(1, -1)` (renderPolishedFrame).\n\t\tlet frame = base;\n\t\tlet acLines: string[] = [];\n\t\tif (acCount > 0 && acCount < frame.length) {\n\t\t\tacLines = frame.slice(frame.length - acCount);\n\t\t\tframe = frame.slice(0, frame.length - acCount);\n\t\t}\n\t\tconst inner = frame.length >= 2 ? frame.slice(1, frame.length - 1) : frame;\n\t\tconst body = inner.length > 0 ? inner : [\"\"];\n\n\t\tconst border = (s: string): string => this.borderColor(s);\n\n\t\t// Top border: ╭─…─╮\n\t\tconst top = border(\"\\u256d\" + \"\\u2500\".repeat(width - 2) + \"\\u256e\");\n\n\t\t// Body: prompt glyph + padded line. No side rails. Height grows with wrap.\n\t\tconst gutter = glyphW > 0 ? \" \".repeat(glyphW) : \"\";\n\t\tconst bodyLines = body.map((ln: string, i: number) => {\n\t\t\tconst prefix = i === 0 && glyphW > 0 ? this.color(\"dim\", glyph) : gutter;\n\t\t\treturn prefix + padRight(ln, innerWidth);\n\t\t});\n\n\t\t// Bottom border with the right-aligned chip: ╰─…─ <chip> ─╯\n\t\tconst bottom = this.renderBottomBorder(width);\n\n\t\treturn [top, ...bodyLines, bottom, ...acLines];\n\t}\n\n\tprivate renderBottomBorder(width: number): string {\n\t\tconst border = (s: string): string => this.borderColor(s);\n\t\tconst parts = buildChip(this.ctx, this.pi);\n\t\tconst plain = parts.left + parts.effort;\n\t\tconst overhead = 4;\n\t\tconst maxChip = Math.max(0, width - overhead);\n\t\tconst truncated = displayWidth(plain) > maxChip;\n\t\tconst chipPlain = truncated ? truncatePlain(plain, maxChip) : plain;\n\t\tconst chipW = displayWidth(chipPlain);\n\t\tconst dashTotal = Math.max(0, width - overhead - chipW);\n\t\t// Right-align the chip: a single trailing dash before the corner, the\n\t\t// rest lead (right-aligns the chip near the corner).\n\t\tconst rightDashes = Math.min(dashTotal, 1);\n\t\tconst leftDashes = dashTotal - rightDashes;\n\n\t\tconst left = \"\\u2570\" + \"\\u2500\".repeat(leftDashes) + \" \";\n\t\tconst right = \" \" + \"\\u2500\".repeat(rightDashes) + \"\\u256f\";\n\t\tconst theme = this.ctx.ui?.theme;\n\t\t// Truncated chips may have lost the effort token — paint all white.\n\t\t// Otherwise model/provider stay white and the effort uses the thinking token.\n\t\tconst chip = truncated\n\t\t\t? this.color(\"white\", chipPlain)\n\t\t\t: this.color(\"white\", parts.left) + colorEffort(theme, parts.level, parts.effort);\n\t\treturn border(left) + chip + border(right);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// The stats line (footer) — slim, single line, BELOW the box\n// ---------------------------------------------------------------------------\n\nexport function renderStatsLine(\n\twidth: number,\n\tctx: ExtensionContextLike,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n): string[] {\n\tconst sep = color(theme, \"accent2\", \" | \"); // lunr: theme-polish — separator uses subtle accent2 blue (was bright-black plain fallback)\n\tconst parts: string[] = [];\n\n\t// lunr: mode zone — permission mode + agent-mode statuses (plan/goal)\n\t// render as ONE segment (dim middot-separated), not scattered across piped sections.\n\tconst modeZone: string[] = [];\n\n\t// lunr: permission mode safety indicator — always shown (not toggle-gated).\n\tconst mode = lunrPermissionMode();\n\tif (mode === \"yolo\" || mode === \"auto\") modeZone.push(color(theme, \"warning\", mode));\n\telse if (mode === \"manual\" || mode === \"plan\") modeZone.push(color(theme, \"white\", mode)); // lunr: theme-polish — manual/plan read white (was dim)\n\n\t// lunr: footer element toggles from the customize bridge (read at render time).\n\tconst footerToggles = lunrFooterToggles();\n\n\t// 1) Extension statuses published by other extensions (rendered as-is,\n\t// already styled): LSP (`pi-lsp-extension`), MCP (`pi-mcp-adapter`),\n\t// throughput/tokens (`pi-tps-was-taken`). These are NOT on `ctx` directly.\n\tconst statuses = footerData.getExtensionStatuses?.();\n\tif (statuses && statuses.size > 0) {\n\t\t// lunr: status segments are toggle-gated via the customize bridge:\n\t\t// footerStatuses gates plan/goal, footerTps gates tps,\n\t\t// footerMcp gates mcp/mcp-auth, footerLsp gates lsp. Publishers keep\n\t\t// calling ctx.ui.setStatus harmlessly when their segment is hidden.\n\t\t// lunr: plan/goal join the mode zone; tps/mcp/lsp stay piped.\n\t\tconst modeKeys: string[] = footerToggles.statuses ? [\"plan\", \"goal\"] : [];\n\t\tfor (const key of modeKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\tif (v) modeZone.push(color(theme, \"white\", stripAnsi(v)));\n\t\t}\n\t\tconst pipedKeys: string[] = [];\n\t\tif (footerToggles.tps) pipedKeys.push(\"tps\");\n\t\tif (footerToggles.mcp) pipedKeys.push(\"mcp\", \"mcp-auth\");\n\t\tif (footerToggles.lsp) pipedKeys.push(\"lsp\");\n\t\tfor (const key of pipedKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\t// lunr: unify footer status colors (white, was dim) so the whole stats line reads as one tone.\n\t\t\tif (v) parts.push(color(theme, \"white\", stripAnsi(v))); // lunr: theme-polish — status segments white (was dim)\n\t\t}\n\t}\n\tif (modeZone.length > 0) {\n\t\tparts.unshift(modeZone.join(color(theme, \"dim\", \" · \")));\n\t}\n\n\t// lunr: git branch + working-tree +/- vs HEAD (gated on footerGit).\n\tif (footerToggles.git) {\n\t\tconst branch = footerData.getGitBranch?.();\n\t\tif (branch) {\n\t\t\tconst diff = footerData.getGitDiffstat?.();\n\t\t\tlet gitSeg = color(theme, \"white\", branch);\n\t\t\tif (diff && (diff.added !== 0 || diff.removed !== 0)) {\n\t\t\t\tgitSeg +=\n\t\t\t\t\t` ${color(theme, \"success\", `+${diff.added}`)} ${color(theme, \"error\", `-${diff.removed}`)}`;\n\t\t\t}\n\t\t\tparts.push(gitSeg);\n\t\t}\n\t}\n\n\t// lunr: live subscription window bar (gated on footerPlan). Hidden with no plan.\n\tif (footerToggles.plan) {\n\t\tconst provider = ctx.model?.provider;\n\t\tif (provider) {\n\t\t\tconst usage = lunrUsageBridge();\n\t\t\tusage?.prefetch?.(provider);\n\t\t\tconst seg = usage?.pickForFooter?.(provider);\n\t\t\tif (seg) {\n\t\t\t\tconst pct = `${Math.round(seg.usedPercent)}%`;\n\t\t\t\tconst barColor = seg.usedPercent > 90 ? \"error\" : seg.usedPercent > 70 ? \"warning\" : \"success\";\n\t\t\t\tconst bar = footerToggles.planBar ? `${compactPlanBar(seg.usedPercent, theme)} ` : \"\";\n\t\t\t\tparts.push(color(theme, \"white\", seg.label) + \" \" + bar + color(theme, barColor, pct));\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2) Context usage: `pct/window` (lunr: gated on footerContext).\n\tif (footerToggles.context) {\n\t\tconst usage = ctx.getContextUsage();\n\t\tconst win = ctx.model?.contextWindow ?? usage?.contextWindow ?? 0;\n\t\tconst pct = usage?.percent == null ? \"?\" : `${Math.round(usage.percent)}%`;\n\t\tconst ctxSeg = `${pct}/${formatCount(win)}`;\n\t\tconst pv = usage?.percent ?? 0;\n\t\tif (pv > 90) parts.push(color(theme, \"error\", ctxSeg));\n\t\telse if (pv > 70) parts.push(color(theme, \"warning\", ctxSeg));\n\t\telse parts.push(color(theme, \"white\", ctxSeg)); // lunr: theme-polish — normal context % white (was dim)\n\t}\n\n\tconst totals = getUsageTotals(ctx);\n\n\t// 3) Token totals: ↑in ↓out (lunr: gated on footerTokens).\n\tif (footerToggles.tokens) {\n\t\tparts.push(color(theme, \"white\", `\\u2191${formatCount(totals.input)} \\u2193${formatCount(totals.output)}`)); // lunr: theme-polish — token totals white (was dim)\n\t}\n\n\t// 4) Latest prompt cache hit rate (gated on footerCacheHitRate).\n\tif (footerToggles.cacheHitRate && totals.cacheActivity && totals.latestCacheHitRate !== undefined) {\n\t\tparts.push(color(theme, \"white\", `CH${totals.latestCacheHitRate.toFixed(1)}%`));\n\t}\n\n\t// lunr: cost/usage counter segment removed entirely (both the $x.xxx dollar\n\t// counter for API-key providers and the plan-usage limit bar for OAuth/subscription\n\t// providers). Segments 1-3 (statuses, context, tokens) remain.\n\n\tlet line = parts.join(sep);\n\tif (displayWidth(line) > width) {\n\t\tline = truncateToWidth(line, width, \"\");\n\t}\n\treturn [line];\n}\n\n// ---------------------------------------------------------------------------\n// Install / teardown\n// ---------------------------------------------------------------------------\n\nconst chatboxEditors = new WeakMap<TUIHandle, ChatboxEditor>();\n\n/** The startup view and extension bind the same editor, preserving its complete draft state. */\nexport function getChatboxEditor(\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n): ChatboxEditor {\n\tlet editor = chatboxEditors.get(tui);\n\tif (editor) editor.bind(ctx, pi);\n\telse {\n\t\teditor = new ChatboxEditor(tui, theme, keybindings, ctx, pi);\n\t\tchatboxEditors.set(tui, editor);\n\t}\n\treturn editor;\n}\n\nfunction installEditor(\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n\tsetRequestor: (r: () => void) => void,\n): (() => void) | undefined {\n\tif (typeof ctx.ui.setEditorComponent !== \"function\") return;\n\tlet editor: ChatboxEditor | undefined;\n\tconst factory: EditorFactoryLike = (tui, _theme, _keybindings) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\teditor = getChatboxEditor(tui, _theme, _keybindings, ctx, pi);\n\t\treturn editor;\n\t};\n\tctx.ui.setEditorComponent(factory);\n\treturn () => editor?.unbind();\n}\n\nfunction installFooter(\n\tctx: ExtensionContextLike,\n\tsetRequestor: (r: () => void) => void,\n): void {\n\tif (typeof ctx.ui.setFooter !== \"function\") return;\n\tlet disposed = false;\n\tconst factory: FooterFactoryLike = (tui, _theme, _footerData) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tinvalidate(): void {\n\t\t\t\t// render is pure\n\t\t\t},\n\t\t\tdispose(): void {\n\t\t\t\tdisposed = true;\n\t\t\t},\n\t\t\trender(width: number): string[] {\n\t\t\t\tif (disposed) return [];\n\t\t\t\treturn renderStatsLine(width, ctx, _theme, _footerData);\n\t\t\t},\n\t\t};\n\t};\n\tctx.ui.setFooter(factory);\n}\n\n// ---------------------------------------------------------------------------\n// Extension entry point\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\tlet unbindEditor: (() => void) | undefined;\n\tlet renderRequestor: (() => void) | undefined = undefined;\n\tconst requestRender = (): void => {\n\t\ttry {\n\t\t\trenderRequestor?.();\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t};\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tif (!ctx.hasUI || ctx.mode !== \"tui\") return;\n\t\tunbindEditor = installEditor(ctx, pi, (r) => {\n\t\t\trenderRequestor = r;\n\t\t});\n\t\tinstallFooter(ctx, (r) => {\n\t\t\tif (!renderRequestor) renderRequestor = r;\n\t\t});\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tunbindEditor?.();\n\t\tunbindEditor = undefined;\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setEditorComponent === \"function\") ctx.ui.setEditorComponent(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setFooter === \"function\") ctx.ui.setFooter(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\trenderRequestor = undefined;\n\t});\n\n\t// Re-render triggers: model/provider + effort (chip), and token/cost/context\n\t// (stats line). Event names match those zentui wires.\n\tconst reRenderEvents = [\n\t\t\"model_select\",\n\t\t\"thinking_level_select\",\n\t\t\"agent_end\",\n\t\t\"message_end\",\n\t\t\"tool_execution_end\",\n\t\t\"session_compact\",\n\t];\n\tfor (const ev of reRenderEvents) {\n\t\tpi.on(ev, () => requestRender());\n\t}\n}\n"]}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* ashxj-tui — a custom slim chatbox for pi.
|
|
3
3
|
*
|
|
4
4
|
* Replaces pi-zentui's prompt box + statusline with:
|
|
5
|
-
* - A rounded prompt box that auto-expands as the typed message wraps
|
|
6
|
-
*
|
|
5
|
+
* - A rounded prompt box that auto-expands as the typed message wraps.
|
|
6
|
+
* Top and bottom rules only; no side rails.
|
|
7
7
|
* - A right-aligned chip on the box's BOTTOM border:
|
|
8
8
|
* model · provider · effort (e.g. `glm-5.2 · Ollama Cloud · xhigh`)
|
|
9
9
|
* - A slim stats line (extension statuses · context% · ↑↓; each segment
|
|
@@ -111,9 +111,9 @@ export function formatChipEffort(level) {
|
|
|
111
111
|
// escape sequences (SGR color, OSC/DCS/APC/PM/SOS string sequences such as
|
|
112
112
|
// pi-tui's `CURSOR_MARKER` `ESC _pi:c BEL`, and two-char escapes), count common
|
|
113
113
|
// East-Asian wide ranges as 2, combining marks and variation selectors as 0.
|
|
114
|
-
// Handling the string sequences as 0-width
|
|
115
|
-
//
|
|
116
|
-
// the TUI strips it at flush time, so we must not count it here.
|
|
114
|
+
// Handling the string sequences as 0-width keeps body padding aligned with the
|
|
115
|
+
// top/bottom rules on the focused (cursor) line. The base editor embeds the
|
|
116
|
+
// marker and the TUI strips it at flush time, so we must not count it here.
|
|
117
117
|
// ---------------------------------------------------------------------------
|
|
118
118
|
function skipAnsi(str, pos) {
|
|
119
119
|
if (str.charCodeAt(pos) !== 0x1b)
|
|
@@ -395,10 +395,9 @@ export class ChatboxEditor extends CustomEditor {
|
|
|
395
395
|
if (width <= 4) {
|
|
396
396
|
return clampLines(super.render(width), width);
|
|
397
397
|
}
|
|
398
|
-
// Rails: `│ ` (left) + ` │` (right) => 4 columns of chrome.
|
|
399
398
|
const glyph = lunrPromptGlyph(this.ctx.ui?.theme);
|
|
400
399
|
const glyphW = displayWidth(glyph);
|
|
401
|
-
const innerWidth = Math.max(1, width -
|
|
400
|
+
const innerWidth = Math.max(1, width - glyphW);
|
|
402
401
|
const base = super.render(innerWidth);
|
|
403
402
|
// The base editor appends the autocomplete menu lines (if any) to the END
|
|
404
403
|
// of its render output. Split them off so the body sits inside the box and
|
|
@@ -432,13 +431,11 @@ export class ChatboxEditor extends CustomEditor {
|
|
|
432
431
|
const border = (s) => this.borderColor(s);
|
|
433
432
|
// Top border: ╭─…─╮
|
|
434
433
|
const top = border("\u256d" + "\u2500".repeat(width - 2) + "\u256e");
|
|
435
|
-
// Body:
|
|
436
|
-
// lunr: prefix the first body line with the theme-controlled prompt arrow.
|
|
437
|
-
// A same-width blank gutter keeps subsequent lines aligned.
|
|
434
|
+
// Body: prompt glyph + padded line. No side rails. Height grows with wrap.
|
|
438
435
|
const gutter = glyphW > 0 ? " ".repeat(glyphW) : "";
|
|
439
436
|
const bodyLines = body.map((ln, i) => {
|
|
440
437
|
const prefix = i === 0 && glyphW > 0 ? this.color("dim", glyph) : gutter;
|
|
441
|
-
return
|
|
438
|
+
return prefix + padRight(ln, innerWidth);
|
|
442
439
|
});
|
|
443
440
|
// Bottom border with the right-aligned chip: ╰─…─ <chip> ─╯
|
|
444
441
|
const bottom = this.renderBottomBorder(width);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ashxj-tui.js","sourceRoot":"","sources":["../../src/builtin-extensions/ashxj-tui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,kDAAkD,CAAC;AAEhF,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AACvD,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAkBnE,SAAS,mBAAmB,GAAyC;IACpE,OAAQ,UAAsC,CAAC,gBAAgB,CAAyC,CAAC;AAAA,CACzG;AACD,SAAS,wBAAwB,GAA8C;IAC9E,OAAQ,UAAsC,CAAC,sBAAsB,CAA8C,CAAC;AAAA,CACpH;AACD,kFAAkF;AAClF,8EAA8E;AAC9E,SAAS,iBAAiB,GAWxB;IACD,MAAM,MAAM,GAAG,mBAAmB,EAAE,CAAC;IACrC,OAAO;QACN,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,IAAI;QACrC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,KAAK;QACtC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,IAAI,IAAI;QAC7C,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,IAAI,IAAI;QAC3C,YAAY,EAAE,MAAM,EAAE,qBAAqB,EAAE,EAAE,IAAI,IAAI;QACvD,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,IAAI;QACrC,QAAQ,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,IAAI,IAAI;QAC/C,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,IAAI;QACrC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,IAAI,IAAI;QACvC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,IAAI,IAAI;KAC7C,CAAC;AAAA,CACF;AAED,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAK/D,SAAS,eAAe,GAA4C;IACnE,OAAQ,UAAsC,CAAC,oBAAoB,CAA4C,CAAC;AAAA,CAChH;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,KAAY,EAAU;IAC9D,MAAM,KAAK,GAAG,CAAC,CAAC;IAChB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5E,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,MAAM,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAG,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,OAAO,IAAI,GAAG,IAAI,CAAC;AAAA,CACnB;AACD,wEAAwE;AACxE,SAAS,kBAAkB,GAAuB;IACjD,OAAO,wBAAwB,EAAE,EAAE,OAAO,EAAE,CAAC;AAAA,CAC7C;AACD,MAAM,UAAU,eAAe,CAAC,KAAwB,EAAU;IACjE,MAAM,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC;IACnD,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAAA,CAChC;AAQD,uEAAuE;AACvE,MAAM,UAAU,kBAAkB,CAAC,KAAoB,EAAU;IAChE,QAAQ,KAAK,EAAE,CAAC;QACf,KAAK,KAAK;YACT,OAAO,aAAa,CAAC;QACtB,KAAK,SAAS;YACb,OAAO,iBAAiB,CAAC;QAC1B,KAAK,KAAK;YACT,OAAO,aAAa,CAAC;QACtB,KAAK,QAAQ;YACZ,OAAO,gBAAgB,CAAC;QACzB,KAAK,MAAM;YACV,OAAO,cAAc,CAAC;QACvB,KAAK,OAAO;YACX,OAAO,eAAe,CAAC;QACxB,KAAK,KAAK;YACT,OAAO,aAAa,CAAC;QACtB;YACC,OAAO,aAAa,CAAC;IACvB,CAAC;AAAA,CACD;AAED,yFAAuF;AACvF,MAAM,UAAU,gBAAgB,CAAC,KAAoB,EAAU;IAC9D,OAAO,KAAK,CAAC;AAAA,CACb;AAmID,8EAA8E;AAC9E,gDAAgD;AAChD,EAAE;AACF,4EAA4E;AAC5E,+EAA6E;AAC7E,+EAA+E;AAC/E,2EAA2E;AAC3E,gFAAgF;AAChF,6EAA6E;AAC7E,8EAA4E;AAC5E,iFAA+E;AAC/E,iEAAiE;AACjE,8EAA8E;AAE9E,SAAS,QAAQ,CAAC,GAAW,EAAE,GAAW,EAAU;IACnD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACrC,mCAAmC;IACnC,IAAI,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YAC/C,CAAC,EAAE,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,iCAAiC;IAC3D,CAAC;IACD,iFAA6E;IAC7E,8EAA8E;IAC9E,wDAAwD;IACxD,IACC,IAAI,KAAK,IAAI,CAAC,OAAO;QACrB,IAAI,KAAK,IAAI,CAAC,OAAO;QACrB,IAAI,KAAK,IAAI,CAAC,OAAO;QACrB,IAAI,KAAK,IAAI,CAAC,OAAO;QACrB,IAAI,KAAK,IAAI,CAAC,OAAO,EACpB,CAAC;QACF,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YAC7C,IAAI,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,OAAO;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;YAC7E,CAAC,EAAE,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,iCAAiC;IAC3D,CAAC;IACD,2EAA2E;IAC3E,uEAAuE;IACvE,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CAClC;AAED,SAAS,MAAM,CAAC,EAAU,EAAW;IACpC,OAAO,CACN,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC;QAC9B,CAAC,EAAE,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,CAAC;QAChC,CAAC,EAAE,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,CAAC,CAChC,CAAC;AAAA,CACF;AAED,SAAS,SAAS,CAAC,EAAU,EAAU;IACtC,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,MAAM;QAAE,OAAO,CAAC,CAAC;IAChG,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CAC1B;AAED,2DAA2D;AAC3D,SAAS,YAAY,CAAC,GAAW,EAAU;IAC1C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9B,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACd,CAAC,IAAI,IAAI,CAAC;YACV,SAAS;QACV,CAAC;QACD,MAAM,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,CAAC,CAAC;AAAA,CACT;AAED,sEAAsE;AACtE,SAAS,QAAQ,CAAC,IAAY,EAAE,KAAa,EAAU;IACtD,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,KAAK;QAAE,OAAO,IAAI,CAAC;IAC5B,OAAO,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;AAAA,CACpC;AAED,wEAAwE;AACxE,SAAS,aAAa,CAAC,IAAY,EAAE,QAAgB,EAAU;IAC9D,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7B,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IAChD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ;YAAE,MAAM;QAC7B,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,IAAI,EAAE,CAAC;QACR,CAAC,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED;oEACoE;AACpE,SAAS,eAAe,CAAC,IAAY,EAAE,QAAgB,EAAE,QAAQ,GAAG,EAAE,EAAU;IAC/E,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7B,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IAChD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/B,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACd,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;YAC/B,CAAC,IAAI,IAAI,CAAC;YACV,SAAS;QACV,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM;YAAE,MAAM;QAC3B,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC,IAAI,EAAE,CAAC;QACR,CAAC,IAAI,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IACD,GAAG,IAAI,SAAS,CAAC;IACjB,OAAO,GAAG,GAAG,QAAQ,CAAC;AAAA,CACtB;AAED,2EAA2E;AAC3E,SAAS,UAAU,CAAC,KAAe,EAAE,KAAa,EAAY;IAC7D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAAA,CACvF;AAED,iEAAiE;AACjE,SAAS,KAAK,CAAC,KAAwB,EAAE,KAAa,EAAE,IAAY,EAAU;IAC7E,IAAI,CAAC;QACJ,OAAO,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AAAA,CACD;AAED,oFAAoF;AACpF,SAAS,SAAS,CAAC,CAAS,EAAU;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAAA,CACxC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;uCAEmC;AACnC,SAAS,WAAW,CAAC,KAAa,EAAU;IAC3C,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC1C,IAAI,KAAK,GAAG,KAAK;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1D,IAAI,KAAK,GAAG,OAAO;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC;IAC3D,IAAI,KAAK,GAAG,QAAQ;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAChE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC;AAAA,CACzC;AAED,+EAA+E;AAC/E,SAAS,cAAc,CAAC,GAAyB,EAK/C;IACD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,kBAAsC,CAAC;IAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,EAAE,IAAI,GAAG,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC;IAC5F,KAAK,MAAM,KAAK,IAAI,OAAkC,EAAE,CAAC;QACxD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QACvC,MAAM,CAAC,GAAG,KAAK,CAAC,OAA2C,CAAC;QAC5D,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QAC3C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAClB,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QAChC,MAAM,cAAc,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC;QACxC,MAAM,eAAe,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;QAC1C,KAAK,IAAI,UAAU,CAAC;QACpB,MAAM,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;QACxB,SAAS,IAAI,cAAc,CAAC;QAC5B,UAAU,IAAI,eAAe,CAAC;QAC9B,MAAM,YAAY,GAAG,UAAU,GAAG,cAAc,GAAG,eAAe,CAAC;QACnE,kBAAkB,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3F,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,GAAG,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,kBAAkB,EAAE,CAAC;AAAA,CAC7F;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,sEAAsE;AACtE,iEAAiE;AACjE,8EAA8E;AAE9E,SAAS,mBAAmB,CAAC,QAA4B,EAAU;IAClE,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,KAAK,GAA2B;QACrC,SAAS,EAAE,WAAW;QACtB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,QAAQ;QAChB,cAAc,EAAE,cAAc;QAC9B,MAAM,EAAE,QAAQ;QAChB,cAAc,EAAE,QAAQ;QACxB,OAAO,EAAE,SAAS;KAClB,CAAC;IACF,OAAO,CACN,KAAK,CAAC,QAAQ,CAAC;QACf,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CACvE,CAAC;AAAA,CACF;AAED,8EAA8E;AAC9E,0CAAwC;AACxC,8EAA8E;AAE9E,SAAS,WAAW,CAAC,KAAwB,EAAE,KAAoB,EAAE,IAAY,EAAU;IAC1F,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1C,IAAI,KAAK,KAAK,aAAa,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED,SAAS,SAAS,CAAC,GAAyB,EAAE,EAAgB,EAA0D;IACvH,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,UAAU,CAAC;IAC5C,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC;IACrC,MAAM,aAAa,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,QAAQ,KAAK,cAAc,IAAI,mBAAmB,EAAE,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,UAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1G,MAAM,KAAK,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,OAAM,aAAa,MAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAAA,CAC1E;AAED,8EAA8E;AAC9E,0DAAwD;AACxD,8EAA8E;AAE9E,MAAM,OAAO,aAAc,SAAQ,YAAY;IACtC,GAAG,CAAuB;IAC1B,EAAE,CAAe;IAEzB,IAAI,CAAC,GAAyB,EAAE,EAAgB,EAAQ;QACvD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IAAA,CACb;IAED,gFAAgF;IAChF,MAAM,GAAS;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI,CACR;YACC,IAAI,EAAE,KAAK;YACX,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK;YACrB,cAAc,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE;YACxC,eAAe,EAAE,GAAG,EAAE,CAAC,SAAS;YAChC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,kBAAkB,GAAG,EAAC,CAAC,EAAE,SAAS,GAAG,EAAC,CAAC,EAAE;SAC1E,EACD,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,EAAC,CAAC,EAAE,CAC1C,CAAC;IAAA,CACF;IAED,YACC,GAAc,EACd,KAAsB,EACtB,WAA4B,EAC5B,GAAyB,EACzB,EAAgB,EACf;QACD,yEAAyE;QACzE,yEAAyE;QACzE,KAAK,CAAC,GAAuB,EAAE,KAAyB,EAAE,WAA+B,EAAE;YAC1F,QAAQ,EAAE,CAAC;SACX,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,iFAA+E;QAC/E,oDAAkD;IAFrC,CAGb;IAEO,KAAK,CAAC,KAAa,EAAE,IAAY,EAAU;QAClD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAAA,CAC9C;IAEQ,MAAM,CAAC,KAAa,EAAY;QACxC,kEAAgE;QAChE,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;YAChB,OAAO,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QAED,gEAA4D;QAC5D,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAEtC,0EAA0E;QAC1E,2EAA2E;QAC3E,oEAAoE;QACpE,qDAAqD;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAI,IAA+D,CAAC,gBAAgB,CAAC;QACjG,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC9D,IAAI,CAAC;gBACJ,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,GAAG,CAAC,CAAC;YACb,CAAC;QACF,CAAC;QAED,2EAAyE;QACzE,8EAA0E;QAC1E,8EAA8E;QAC9E,4EAA4E;QAC5E,2EAA2E;QAC3E,qEAAqE;QACrE,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,IAAI,OAAO,GAAa,EAAE,CAAC;QAC3B,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC3C,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;YAC9C,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;QAChD,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC3E,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAE7C,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAE1D,8BAAoB;QACpB,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;QAErE,4EAAwE;QACxE,2EAA2E;QAC3E,4DAA4D;QAC5D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAU,EAAE,CAAS,EAAE,EAAE,CAAC;YACrD,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACzE,OAAO,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QAAA,CACjF,CAAC,CAAC;QAEH,wEAA4D;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAE9C,OAAO,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC;IAAA,CAC/C;IAEO,kBAAkB,CAAC,KAAa,EAAU;QACjD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;QACxC,MAAM,QAAQ,GAAG,CAAC,CAAC;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;QAChD,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACpE,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,CAAC,CAAC;QACxD,sEAAsE;QACtE,qDAAqD;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;QAE3C,MAAM,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC;QAC1D,MAAM,KAAK,GAAG,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,QAAQ,CAAC;QAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC;QACjC,sEAAoE;QACpE,8EAA8E;QAC9E,MAAM,IAAI,GAAG,SAAS;YACrB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACnF,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAAA,CAC3C;CACD;AAED,8EAA8E;AAC9E,+DAA6D;AAC7D,8EAA8E;AAE9E,MAAM,UAAU,eAAe,CAC9B,KAAa,EACb,GAAyB,EACzB,KAAY,EACZ,UAAsC,EAC3B;IACX,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,8FAA4F;IACxI,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,wEAAsE;IACtE,qFAAqF;IACrF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,8EAA4E;IAC5E,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC;IAClC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;SAChF,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,MAAM;QAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,0DAAwD;IAEnJ,gFAAgF;IAChF,MAAM,aAAa,GAAG,iBAAiB,EAAE,CAAC;IAE1C,uEAAuE;IACvE,wEAAwE;IACxE,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,UAAU,CAAC,oBAAoB,EAAE,EAAE,CAAC;IACrD,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACnC,mEAAmE;QACnE,uDAAuD;QACvD,qEAAqE;QACrE,oEAAoE;QACpE,8DAA8D;QAC9D,MAAM,QAAQ,GAAa,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC;QACD,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,IAAI,aAAa,CAAC,GAAG;YAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,aAAa,CAAC,GAAG;YAAE,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACzD,IAAI,aAAa,CAAC,GAAG;YAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7C,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,+FAA+F;YAC/F,IAAI,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,yDAAuD;QAChH,CAAC;IACF,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAK,CAAC,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,oEAAoE;IACpE,IAAI,aAAa,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,EAAE,EAAE,CAAC;QAC3C,IAAI,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3C,IAAI,MAAM,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3C,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;gBACtD,MAAM;oBACL,IAAI,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YAC/F,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IAED,iFAAiF;IACjF,IAAI,aAAa,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC;QACrC,IAAI,QAAQ,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;YAChC,KAAK,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;YAC5B,MAAM,GAAG,GAAG,KAAK,EAAE,aAAa,EAAE,CAAC,QAAQ,CAAC,CAAC;YAC7C,IAAI,GAAG,EAAE,CAAC;gBACT,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC;gBAC9C,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC/F,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtF,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;YACxF,CAAC;QACF,CAAC;IACF,CAAC;IAED,iEAAiE;IACjE,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,EAAE,aAAa,IAAI,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;QAClE,MAAM,GAAG,GAAG,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAC3E,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5C,MAAM,EAAE,GAAG,KAAK,EAAE,OAAO,IAAI,CAAC,CAAC;QAC/B,IAAI,EAAE,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;aAClD,IAAI,EAAE,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;;YACzD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,0DAAwD;IACzG,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAEnC,+DAA2D;IAC3D,IAAI,aAAa,CAAC,MAAM,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,sDAAoD;IAClK,CAAC;IAED,iEAAiE;IACjE,IAAI,aAAa,CAAC,YAAY,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACnG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,4EAA4E;IAC5E,oFAAoF;IACpF,+DAA+D;IAE/D,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,YAAY,CAAC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC;QAChC,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC;AAAA,CACd;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,MAAM,cAAc,GAAG,IAAI,OAAO,EAA4B,CAAC;AAE/D,gGAAgG;AAChG,MAAM,UAAU,gBAAgB,CAC/B,GAAc,EACd,KAAsB,EACtB,WAA4B,EAC5B,GAAyB,EACzB,EAAgB,EACA;IAChB,IAAI,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;SAC5B,CAAC;QACL,MAAM,GAAG,IAAI,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7D,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,aAAa,CACrB,GAAyB,EACzB,EAAgB,EAChB,YAAqC,EACV;IAC3B,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC,kBAAkB,KAAK,UAAU;QAAE,OAAO;IAC5D,IAAI,MAAiC,CAAC;IACtC,MAAM,OAAO,GAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;QACjE,YAAY,CAAC,GAAG,EAAE,CAAC;YAClB,IAAI,CAAC;gBACJ,GAAG,CAAC,aAAa,EAAE,CAAC;YACrB,CAAC;YAAC,MAAM,CAAC;gBACR,YAAY;YACb,CAAC;QAAA,CACD,CAAC,CAAC;QACH,MAAM,GAAG,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QAC9D,OAAO,MAAM,CAAC;IAAA,CACd,CAAC;IACF,GAAG,CAAC,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;AAAA,CAC9B;AAED,SAAS,aAAa,CACrB,GAAyB,EACzB,YAAqC,EAC9B;IACP,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC,SAAS,KAAK,UAAU;QAAE,OAAO;IACnD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,OAAO,GAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,CAAC;QAChE,YAAY,CAAC,GAAG,EAAE,CAAC;YAClB,IAAI,CAAC;gBACJ,GAAG,CAAC,aAAa,EAAE,CAAC;YACrB,CAAC;YAAC,MAAM,CAAC;gBACR,YAAY;YACb,CAAC;QAAA,CACD,CAAC,CAAC;QACH,OAAO;YACN,UAAU,GAAS;gBAClB,iBAAiB;YADE,CAEnB;YACD,OAAO,GAAS;gBACf,QAAQ,GAAG,IAAI,CAAC;YAAA,CAChB;YACD,MAAM,CAAC,KAAa,EAAY;gBAC/B,IAAI,QAAQ;oBAAE,OAAO,EAAE,CAAC;gBACxB,OAAO,eAAe,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;YAAA,CACxD;SACD,CAAC;IAAA,CACF,CAAC;IACF,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAAA,CAC1B;AAED,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAE9E,MAAM,CAAC,OAAO,WAAW,EAAgB,EAAQ;IAChD,IAAI,YAAsC,CAAC;IAC3C,IAAI,eAAe,GAA6B,SAAS,CAAC;IAC1D,MAAM,aAAa,GAAG,GAAS,EAAE,CAAC;QACjC,IAAI,CAAC;YACJ,eAAe,EAAE,EAAE,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACR,YAAY;QACb,CAAC;IAAA,CACD,CAAC;IAEF,EAAE,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QACvC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;YAAE,OAAO;QAC7C,YAAY,GAAG,aAAa,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YAC5C,eAAe,GAAG,CAAC,CAAC;QAAA,CACpB,CAAC,CAAC;QACH,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe;gBAAE,eAAe,GAAG,CAAC,CAAC;QAAA,CAC1C,CAAC,CAAC;IAAA,CACH,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QAC1C,YAAY,EAAE,EAAE,CAAC;QACjB,YAAY,GAAG,SAAS,CAAC;QACzB,IAAI,CAAC;YACJ,IAAI,OAAO,GAAG,CAAC,EAAE,EAAE,kBAAkB,KAAK,UAAU;gBAAE,GAAG,CAAC,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAC5F,CAAC;QAAC,MAAM,CAAC;YACR,YAAY;QACb,CAAC;QACD,IAAI,CAAC;YACJ,IAAI,OAAO,GAAG,CAAC,EAAE,EAAE,SAAS,KAAK,UAAU;gBAAE,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC1E,CAAC;QAAC,MAAM,CAAC;YACR,YAAY;QACb,CAAC;QACD,eAAe,GAAG,SAAS,CAAC;IAAA,CAC5B,CAAC,CAAC;IAEH,6EAA6E;IAC7E,sDAAsD;IACtD,MAAM,cAAc,GAAG;QACtB,cAAc;QACd,uBAAuB;QACvB,WAAW;QACX,aAAa;QACb,oBAAoB;QACpB,iBAAiB;KACjB,CAAC;IACF,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;QACjC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;IAClC,CAAC;AAAA,CACD","sourcesContent":["/**\n * ashxj-tui — a custom slim chatbox for pi.\n *\n * Replaces pi-zentui's prompt box + statusline with:\n * - A rounded prompt box that auto-expands as the typed message wraps to\n * multiple rows (the sides extend; height grows with content).\n * - A right-aligned chip on the box's BOTTOM border:\n * model · provider · effort (e.g. `glm-5.2 · Ollama Cloud · xhigh`)\n * - A slim stats line (extension statuses · context% · ↑↓; each segment\n * toggle-gated via the lunr customize bridge) BELOW the box, not wrapped\n * around the input.\n * - No session-mode indicator anywhere (pi has no such concept).\n *\n * Loaded by pi via jiti — no build step, plain TypeScript.\n *\n * NOTE on type imports (see `ashxj-thinking`/`simple-memory` for the convention):\n * This file declares structural types inline rather than importing them from\n * `@ashx-j/lunr` / `@ashx-j/lunr-tui`.\n * pi-coding-agent's `index.d.ts` re-exports from internal `.d.ts` files that\n * contain subpath imports like `@ashx-j/lunr-ai/compat`, which do not\n * resolve under `tsc` with a file argument. We keep the typecheck\n * self-contained with inline types and verify via the included `tsconfig.json`\n * (`moduleResolution: \"Bundler\"` + `skipLibCheck: true`).\n *\n * The ONE exception is `CustomEditor`, imported as a RUNTIME VALUE directly\n * from its defining module (`modes/interactive/components/custom-editor.ts`).\n * We must `extends` it to inherit pi's app keybindings (escape, ctrl+d, model\n * switching, extension shortcuts) — wrapping would lose those. It is imported\n * from the concrete module, NOT the package barrel, because the barrel\n * re-exports main.ts which imports this file — a circular import that crashes\n * under vite-node (`Class extends value undefined`).\n */\n\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.js\";\n\nconst CUSTOMIZE_BRIDGE = Symbol.for(\"@lunr/customize\");\nconst PERMISSION_MODE_BRIDGE = Symbol.for(\"@lunr/permission-mode\");\ninterface CustomizeBridgeForPrompt {\n\tgetOpenAIFastMode?(): boolean;\n\t// lunr: footer element toggles (added to the same bridge).\n\tgetFooterMcp?(): boolean;\n\tgetFooterLsp?(): boolean;\n\tgetFooterContext?(): boolean;\n\tgetFooterTokens?(): boolean;\n\tgetFooterCacheHitRate?(): boolean;\n\tgetFooterTps?(): boolean;\n\tgetFooterStatuses?(): boolean;\n\tgetFooterGit?(): boolean;\n\tgetFooterPlan?(): boolean;\n\tgetFooterPlanBar?(): boolean;\n}\ninterface PermissionModeBridgeForFooter {\n\tgetMode(): string | undefined;\n}\nfunction lunrCustomizeBridge(): CustomizeBridgeForPrompt | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE] as CustomizeBridgeForPrompt | undefined;\n}\nfunction lunrPermissionModeBridge(): PermissionModeBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[PERMISSION_MODE_BRIDGE] as PermissionModeBridgeForFooter | undefined;\n}\n// lunr: footer toggles, read at render time. Bridgeless / missing-getter fallback\n// matches the settings-manager defaults: MCP on, LSP off, everything else on.\nfunction lunrFooterToggles(): {\n\tmcp: boolean;\n\tlsp: boolean;\n\tcontext: boolean;\n\ttokens: boolean;\n\tcacheHitRate: boolean;\n\ttps: boolean;\n\tstatuses: boolean;\n\tgit: boolean;\n\tplan: boolean;\n\tplanBar: boolean;\n} {\n\tconst bridge = lunrCustomizeBridge();\n\treturn {\n\t\tmcp: bridge?.getFooterMcp?.() ?? true,\n\t\tlsp: bridge?.getFooterLsp?.() ?? false,\n\t\tcontext: bridge?.getFooterContext?.() ?? true,\n\t\ttokens: bridge?.getFooterTokens?.() ?? true,\n\t\tcacheHitRate: bridge?.getFooterCacheHitRate?.() ?? true,\n\t\ttps: bridge?.getFooterTps?.() ?? true,\n\t\tstatuses: bridge?.getFooterStatuses?.() ?? true,\n\t\tgit: bridge?.getFooterGit?.() ?? true,\n\t\tplan: bridge?.getFooterPlan?.() ?? true,\n\t\tplanBar: bridge?.getFooterPlanBar?.() ?? true,\n\t};\n}\n\nconst USAGE_SERVICE_BRIDGE = Symbol.for(\"@lunr/usage-service\");\ninterface UsageServiceBridgeForFooter {\n\tpickForFooter?(providerId: string): { label: string; usedPercent: number } | undefined;\n\tprefetch?(providerId: string): void;\n}\nfunction lunrUsageBridge(): UsageServiceBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE] as UsageServiceBridgeForFooter | undefined;\n}\n\nfunction compactPlanBar(percent: number, theme: Theme): string {\n\tconst cells = 8;\n\tconst clamped = Math.max(0, Math.min(100, percent));\n\tconst filled = Math.round((clamped / 100) * cells);\n\tconst token = clamped > 90 ? \"error\" : clamped > 70 ? \"warning\" : \"success\";\n\tconst fill = filled > 0 ? color(theme, token, \"█\".repeat(filled)) : \"\";\n\tconst rest = filled < cells ? color(theme, \"dim\", \"░\".repeat(cells - filled)) : \"\";\n\treturn fill + rest;\n}\n// lunr: permission mode for the footer safety indicator (always shown).\nfunction lunrPermissionMode(): string | undefined {\n\treturn lunrPermissionModeBridge()?.getMode();\n}\nexport function lunrPromptGlyph(theme: Theme | undefined): string {\n\tconst arrow = theme?.glyph?.(\"promptArrow\") ?? \">\";\n\treturn arrow ? `${arrow} ` : \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Minimal structural types (inline — see file header)\n// ---------------------------------------------------------------------------\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\n/** Theme token for the chatbox thinking-level border / effort chip. */\nexport function thinkingThemeToken(level: ThinkingLevel): string {\n\tswitch (level) {\n\t\tcase \"off\":\n\t\t\treturn \"thinkingOff\";\n\t\tcase \"minimal\":\n\t\t\treturn \"thinkingMinimal\";\n\t\tcase \"low\":\n\t\t\treturn \"thinkingLow\";\n\t\tcase \"medium\":\n\t\t\treturn \"thinkingMedium\";\n\t\tcase \"high\":\n\t\t\treturn \"thinkingHigh\";\n\t\tcase \"xhigh\":\n\t\t\treturn \"thinkingXhigh\";\n\t\tcase \"max\":\n\t\t\treturn \"thinkingMax\";\n\t\tdefault:\n\t\t\treturn \"thinkingOff\";\n\t}\n}\n\n/** Chip effort label — identity, locked so xhigh/max are never mapped down to high. */\nexport function formatChipEffort(level: ThinkingLevel): string {\n\treturn level;\n}\n\n/** Trimmed view of pi's `Theme` — only the methods we use. */\ninterface Theme {\n\tfg(token: string, text: string): string;\n\t/** lunr: prompt glyph tokens (optional for forward/backward compat). */\n\tglyph?(name: \"promptArrow\"): string;\n}\n\n/** Trimmed view of `pi-tui`'s `TUI` — only the method we use. */\ninterface TUIHandle {\n\trequestRender(force?: boolean): void;\n}\n\n/** Trimmed view of `pi-tui`'s `EditorTheme`. */\ninterface EditorThemeLike {\n\tborderColor: (str: string) => string;\n\tselectList: unknown;\n}\n\n/** Opaque keybindings manager. */\ninterface KeybindingsLike {\n\treadonly _?: unknown;\n}\n\n/** Trimmed view of an autocomplete list (the editor's private `autocompleteList`). */\ninterface AutocompleteListLike {\n\trender(width: number): string[];\n}\n\n/** Trimmed view of pi's `ReadonlyFooterDataProvider`. */\ninterface ReadonlyFooterDataProvider {\n\tgetGitBranch(): string | null;\n\tgetGitDiffstat?(): { added: number; removed: number } | null;\n\tgetExtensionStatuses(): ReadonlyMap<string, string>;\n\tgetAvailableProviderCount(): number;\n\tonBranchChange(callback: () => void): () => void;\n}\n\n/** Trimmed view of the `getContextUsage` return value. */\ninterface ContextUsage {\n\ttokens: number | null;\n\tcontextWindow: number;\n\tpercent: number | null;\n}\n\n/** Trimmed view of an assistant message's usage — the bits we render. */\ninterface AssistantUsage {\n\tinput: number;\n\toutput: number;\n\tcacheRead?: number;\n\tcacheWrite?: number;\n\tcost: { total: number };\n}\n\n/** Trimmed view of an assistant message. */\ninterface AssistantMessageLike {\n\trole: \"assistant\";\n\tusage: AssistantUsage;\n}\n\n/** Trimmed view of a session entry — only what we iterate over. */\ntype SessionEntry =\n\t| { type: \"message\"; message: AssistantMessageLike }\n\t| { type: string; message?: unknown };\n\n/** Trimmed view of a `ReadonlySessionManager`. */\ninterface ReadonlySessionManagerLike {\n\tgetEntries(): readonly SessionEntry[];\n\tgetBranch?(): readonly SessionEntry[];\n}\n\n/** Trimmed view of a `Model`. */\ninterface ModelLike {\n\tid?: string;\n\tprovider?: string;\n\tcontextWindow?: number;\n\treasoning?: boolean;\n\tthinkingLevelMap?: Record<string, string | null>;\n}\n\ninterface ExtensionUIContextLike {\n\tsetEditorComponent(factory: EditorFactoryLike | undefined): void;\n\tsetFooter(factory: FooterFactoryLike | undefined): void;\n\treadonly theme?: Theme;\n}\n\n/** Trimmed view of `ExtensionContext`. */\ninterface ExtensionContextLike {\n\tmode: \"tui\" | \"rpc\" | \"json\" | \"print\";\n\thasUI: boolean;\n\tmodel: ModelLike | undefined;\n\tsessionManager: ReadonlySessionManagerLike;\n\tgetContextUsage(): ContextUsage | undefined;\n\tui: ExtensionUIContextLike;\n}\n\n/** Trimmed view of `ExtensionAPI`. */\ninterface ExtensionAPI {\n\tgetThinkingLevel(): ThinkingLevel;\n\ton(event: string, handler: (event: unknown, ctx: ExtensionContextLike) => void): void;\n}\n\n/** `setEditorComponent` factory shape. */\ntype EditorFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n) => EditorComponentLike;\n\ninterface EditorComponentLike {\n\trender(width: number): string[];\n\tgetText(): string;\n\tsetText(text: string): void;\n\tinvalidate(): void;\n\thandleInput?(data: string): void;\n}\n\n/** `setFooter` factory shape. */\ntype FooterFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n) => FooterComponentLike;\n\ninterface FooterComponentLike {\n\trender(width: number): string[];\n\tdispose?(): void;\n\tinvalidate?(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Display-width helpers (ANSI-aware; CJK-aware)\n//\n// The editor (`Editor.render`) word-wraps to the given width using grapheme\n// width, so each returned line is ≤ that many visual columns. To right-pad a\n// line for our box we need a width model that matches closely enough: skip ALL\n// escape sequences (SGR color, OSC/DCS/APC/PM/SOS string sequences such as\n// pi-tui's `CURSOR_MARKER` `ESC _pi:c BEL`, and two-char escapes), count common\n// East-Asian wide ranges as 2, combining marks and variation selectors as 0.\n// Handling the string sequences as 0-width is what keeps the right `│` rail\n// aligned on the focused (cursor) line — the base editor embeds the marker and\n// the TUI strips it at flush time, so we must not count it here.\n// ---------------------------------------------------------------------------\n\nfunction skipAnsi(str: string, pos: number): number {\n\tif (str.charCodeAt(pos) !== 0x1b) return 0;\n\tconst next = str.charCodeAt(pos + 1);\n\t// CSI: ESC [ ... <final 0x40-0x7e>\n\tif (next === 0x5b /* [ */) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c >= 0x40 && c <= 0x7e) return j + 1 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// String sequences — OSC (]), DCS (P), APC (_), PM (^), SOS (X) — terminated\n\t// by BEL (0x07) or ST (ESC \\). pi-tui's CURSOR_MARKER `ESC _pi:c BEL` is APC;\n\t// OSC color queries are OSC. All are zero visual width.\n\tif (\n\t\tnext === 0x5d /* ] */ ||\n\t\tnext === 0x50 /* P */ ||\n\t\tnext === 0x5f /* _ */ ||\n\t\tnext === 0x5e /* ^ */ ||\n\t\tnext === 0x58 /* X */\n\t) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c === 0x07 /* BEL */) return j + 1 - pos;\n\t\t\tif (c === 0x1b && str.charCodeAt(j + 1) === 0x5c /* \\ */) return j + 2 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// Any other ESC sequence: consume ESC + one final byte (e.g. ESC c, ESC \\,\n\t// ESC ( B). A lone trailing ESC with no following byte is 0 width too.\n\treturn Number.isNaN(next) ? 1 : 2;\n}\n\nfunction isWide(cp: number): boolean {\n\treturn (\n\t\t(cp >= 0x1100 && cp <= 0x115f) ||\n\t\t(cp >= 0x2e80 && cp <= 0x303e) ||\n\t\t(cp >= 0x3041 && cp <= 0x33ff) ||\n\t\t(cp >= 0x3400 && cp <= 0x4dbf) ||\n\t\t(cp >= 0x4e00 && cp <= 0x9fff) ||\n\t\t(cp >= 0xa000 && cp <= 0xa4cf) ||\n\t\t(cp >= 0xac00 && cp <= 0xd7a3) ||\n\t\t(cp >= 0xf900 && cp <= 0xfaff) ||\n\t\t(cp >= 0xfe30 && cp <= 0xfe4f) ||\n\t\t(cp >= 0xff00 && cp <= 0xff60) ||\n\t\t(cp >= 0xffe0 && cp <= 0xffe6) ||\n\t\t(cp >= 0x1f300 && cp <= 0x1faff) ||\n\t\t(cp >= 0x20000 && cp <= 0x3fffd)\n\t);\n}\n\nfunction charWidth(cp: number): number {\n\tif (cp >= 0x20 && cp < 0x7f) return 1;\n\tif ((cp >= 0x0300 && cp <= 0x036f) || (cp >= 0xfe00 && cp <= 0xfe0f) || cp === 0x200d) return 0;\n\treturn isWide(cp) ? 2 : 1;\n}\n\n/** Visible width of a string, ignoring SGR color codes. */\nfunction displayWidth(str: string): number {\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < str.length) {\n\t\tconst skip = skipAnsi(str, i);\n\t\tif (skip > 0) {\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst cp = str.codePointAt(i) ?? 0;\n\t\tw += charWidth(cp);\n\t\ti += cp > 0xffff ? 2 : 1;\n\t}\n\treturn w;\n}\n\n/** Right-pad a (possibly colored) line to `width` visible columns. */\nfunction padRight(line: string, width: number): string {\n\tconst w = displayWidth(line);\n\tif (w >= width) return line;\n\treturn line + \" \".repeat(width - w);\n}\n\n/** Truncate a plain (non-ANSI) string to `maxWidth` visible columns. */\nfunction truncatePlain(text: string, maxWidth: number): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length) {\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > maxWidth) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\treturn out;\n}\n\n/** Truncate a (possibly ANSI-colored) string to `maxWidth` visible columns,\n * re-emitting an SGR reset at the cut so styling doesn't bleed. */\nfunction truncateToWidth(text: string, maxWidth: number, ellipsis = \"\"): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tconst target = Math.max(0, maxWidth - displayWidth(ellipsis));\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length && w < target) {\n\t\tconst skip = skipAnsi(text, i);\n\t\tif (skip > 0) {\n\t\t\tout += text.slice(i, i + skip);\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > target) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\tout += \"\\x1b[0m\";\n\treturn out + ellipsis;\n}\n\n/** Clamp each rendered line to `width` visible columns (fallback path). */\nfunction clampLines(lines: string[], width: number): string[] {\n\treturn lines.map((l) => (displayWidth(l) > width ? truncateToWidth(l, width, \"\") : l));\n}\n\n/** Apply a theme `fg` token safely; falls back to plain text. */\nfunction color(theme: Theme | undefined, token: string, text: string): string {\n\ttry {\n\t\treturn theme?.fg?.(token, text) ?? text;\n\t} catch {\n\t\treturn text;\n\t}\n}\n\n// lunr: strip ANSI escape sequences so footer statuses can be re-colored uniformly.\nfunction stripAnsi(s: string): string {\n\treturn s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Stats formatting\n// ---------------------------------------------------------------------------\n\n/** Compact token-count formatter: `999`, `1.2k`, `15k`, `1.2M`, `15M`.\n * Matches pi's FooterComponent / the captured zentui examples\n * (`↑9.0M ↓112k`, `20%/1.0M`). */\nfunction formatCount(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\n/** Sum session token totals and derive the latest request's cache-hit rate. */\nfunction getUsageTotals(ctx: ExtensionContextLike): {\n\tinput: number;\n\toutput: number;\n\tcacheActivity: boolean;\n\tlatestCacheHitRate: number | undefined;\n} {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cacheRead = 0;\n\tlet cacheWrite = 0;\n\tlet latestCacheHitRate: number | undefined;\n\tconst entries = ctx.sessionManager.getEntries?.() ?? ctx.sessionManager.getBranch?.() ?? [];\n\tfor (const entry of entries as readonly SessionEntry[]) {\n\t\tif (entry.type !== \"message\") continue;\n\t\tconst m = entry.message as AssistantMessageLike | undefined;\n\t\tif (!m || m.role !== \"assistant\") continue;\n\t\tconst u = m.usage;\n\t\tif (!u) continue;\n\t\tconst usageInput = u.input ?? 0;\n\t\tconst usageCacheRead = u.cacheRead ?? 0;\n\t\tconst usageCacheWrite = u.cacheWrite ?? 0;\n\t\tinput += usageInput;\n\t\toutput += u.output ?? 0;\n\t\tcacheRead += usageCacheRead;\n\t\tcacheWrite += usageCacheWrite;\n\t\tconst promptTokens = usageInput + usageCacheRead + usageCacheWrite;\n\t\tlatestCacheHitRate = promptTokens > 0 ? (usageCacheRead / promptTokens) * 100 : undefined;\n\t}\n\treturn { input, output, cacheActivity: cacheRead > 0 || cacheWrite > 0, latestCacheHitRate };\n}\n\n// ---------------------------------------------------------------------------\n// Provider display label\n//\n// `ctx.model.provider` is a ProviderId string (e.g. `\"ollama-cloud\"`), NOT the\n// human label. `BUILT_IN_PROVIDER_DISPLAY_NAMES` exists in pi core but is not\n// re-exported to extensions, so we derive the label (mirrors zentui's\n// `formatProviderLabel`, with an explicit `ollama-cloud` entry).\n// ---------------------------------------------------------------------------\n\nfunction formatProviderLabel(provider: string | undefined): string {\n\tif (!provider) return \"Unknown\";\n\tconst known: Record<string, string> = {\n\t\tanthropic: \"Anthropic\",\n\t\tgemini: \"Google\",\n\t\tgoogle: \"Google\",\n\t\tollama: \"Ollama\",\n\t\t\"ollama-cloud\": \"Ollama Cloud\",\n\t\topenai: \"OpenAI\",\n\t\t\"openai-codex\": \"OpenAI\",\n\t\tmistral: \"Mistral\",\n\t};\n\treturn (\n\t\tknown[provider] ??\n\t\tprovider.replace(/[-_]/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase())\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// The chip: `model · provider · effort`\n// ---------------------------------------------------------------------------\n\nfunction colorEffort(theme: Theme | undefined, level: ThinkingLevel, text: string): string {\n\tconst token = thinkingThemeToken(level);\n\tconst painted = color(theme, token, text);\n\tif (token === \"thinkingMax\" && painted === text) {\n\t\treturn color(theme, \"thinkingXhigh\", text);\n\t}\n\treturn painted;\n}\n\nfunction buildChip(ctx: ExtensionContextLike, pi: ExtensionAPI): { left: string; effort: string; level: ThinkingLevel } {\n\tconst modelId = ctx.model?.id ?? \"no-model\";\n\tconst provider = ctx.model?.provider;\n\tconst providerLabel = formatProviderLabel(provider);\n\tconst fast = provider === \"openai-codex\" && lunrCustomizeBridge()?.getOpenAIFastMode?.() ? \" · fast\" : \"\";\n\tconst level = pi.getThinkingLevel();\n\tconst effort = formatChipEffort(level);\n\treturn { left: `${modelId}${fast} · ${providerLabel} · `, effort, level };\n}\n\n// ---------------------------------------------------------------------------\n// The prompt box — `ChatboxEditor extends CustomEditor`\n// ---------------------------------------------------------------------------\n\nexport class ChatboxEditor extends CustomEditor {\n\tprivate ctx: ExtensionContextLike;\n\tprivate pi: ExtensionAPI;\n\n\tbind(ctx: ExtensionContextLike, pi: ExtensionAPI): void {\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t}\n\n\t/** Keep the displayed values while /new or /resume replaces the old runtime. */\n\tunbind(): void {\n\t\tconst level = this.pi.getThinkingLevel();\n\t\tthis.bind(\n\t\t\t{\n\t\t\t\tmode: \"tui\",\n\t\t\t\thasUI: true,\n\t\t\t\tmodel: this.ctx.model,\n\t\t\t\tsessionManager: { getEntries: () => [] },\n\t\t\t\tgetContextUsage: () => undefined,\n\t\t\t\tui: { theme: this.ctx.ui?.theme, setEditorComponent() {}, setFooter() {} },\n\t\t\t},\n\t\t\t{ getThinkingLevel: () => level, on() {} },\n\t\t);\n\t}\n\n\tconstructor(\n\t\ttui: TUIHandle,\n\t\ttheme: EditorThemeLike,\n\t\tkeybindings: KeybindingsLike,\n\t\tctx: ExtensionContextLike,\n\t\tpi: ExtensionAPI,\n\t) {\n\t\t// CustomEditor ctor: (tui, theme, keybindings, options?: EditorOptions).\n\t\t// Casts keep the inline types from leaking into the real base signature.\n\t\tsuper(tui as unknown as never, theme as unknown as never, keybindings as unknown as never, {\n\t\t\tpaddingX: 0,\n\t\t});\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t\t// lunr: do not clobber borderColor — InteractiveMode.updateEditorBorderColor()\n\t\t// owns it (thinkingOff…thinkingMax, or bashMode).\n\t}\n\n\tprivate color(token: string, text: string): string {\n\t\treturn color(this.ctx.ui?.theme, token, text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// Too narrow to draw a box — defer to the base editor, clamped.\n\t\tif (width <= 4) {\n\t\t\treturn clampLines(super.render(width), width);\n\t\t}\n\n\t\t// Rails: `│ ` (left) + ` │` (right) => 4 columns of chrome.\n\t\tconst glyph = lunrPromptGlyph(this.ctx.ui?.theme);\n\t\tconst glyphW = displayWidth(glyph);\n\t\tconst innerWidth = Math.max(1, width - 4 - glyphW);\n\t\tconst base = super.render(innerWidth);\n\n\t\t// The base editor appends the autocomplete menu lines (if any) to the END\n\t\t// of its render output. Split them off so the body sits inside the box and\n\t\t// the autocomplete renders BELOW the bottom border (preserves slash\n\t\t// commands). Mirrors zentui's `renderPolishedFrame`.\n\t\tconst showing = this.isShowingAutocomplete();\n\t\tconst acList = (this as unknown as { autocompleteList?: AutocompleteListLike }).autocompleteList;\n\t\tlet acCount = 0;\n\t\tif (showing && acList && typeof acList.render === \"function\") {\n\t\t\ttry {\n\t\t\t\tacCount = acList.render(innerWidth).length;\n\t\t\t} catch {\n\t\t\t\tacCount = 0;\n\t\t\t}\n\t\t}\n\n\t\t// `super.render` returns [base top ─ border, ...wrapped text lines, base\n\t\t// bottom ─ border, ...autocomplete lines] — the base editor draws its OWN\n\t\t// straight borders and (when active) appends the autocomplete menu. Split the\n\t\t// autocomplete off the end, then STRIP the base's first/last lines (its own\n\t\t// borders) so we don't render them a second time inside our rounded frame.\n\t\t// Mirrors zentui's `editorFrame.slice(1, -1)` (renderPolishedFrame).\n\t\tlet frame = base;\n\t\tlet acLines: string[] = [];\n\t\tif (acCount > 0 && acCount < frame.length) {\n\t\t\tacLines = frame.slice(frame.length - acCount);\n\t\t\tframe = frame.slice(0, frame.length - acCount);\n\t\t}\n\t\tconst inner = frame.length >= 2 ? frame.slice(1, frame.length - 1) : frame;\n\t\tconst body = inner.length > 0 ? inner : [\"\"];\n\n\t\tconst border = (s: string): string => this.borderColor(s);\n\n\t\t// Top border: ╭─…─╮\n\t\tconst top = border(\"\\u256d\" + \"\\u2500\".repeat(width - 2) + \"\\u256e\");\n\n\t\t// Body: │ <padded line> │ (auto-grows with the number of wrapped lines)\n\t\t// lunr: prefix the first body line with the theme-controlled prompt arrow.\n\t\t// A same-width blank gutter keeps subsequent lines aligned.\n\t\tconst gutter = glyphW > 0 ? \" \".repeat(glyphW) : \"\";\n\t\tconst bodyLines = body.map((ln: string, i: number) => {\n\t\t\tconst prefix = i === 0 && glyphW > 0 ? this.color(\"dim\", glyph) : gutter;\n\t\t\treturn border(\"\\u2502 \") + prefix + padRight(ln, innerWidth) + border(\" \\u2502\");\n\t\t});\n\n\t\t// Bottom border with the right-aligned chip: ╰─…─ <chip> ─╯\n\t\tconst bottom = this.renderBottomBorder(width);\n\n\t\treturn [top, ...bodyLines, bottom, ...acLines];\n\t}\n\n\tprivate renderBottomBorder(width: number): string {\n\t\tconst border = (s: string): string => this.borderColor(s);\n\t\tconst parts = buildChip(this.ctx, this.pi);\n\t\tconst plain = parts.left + parts.effort;\n\t\tconst overhead = 4;\n\t\tconst maxChip = Math.max(0, width - overhead);\n\t\tconst truncated = displayWidth(plain) > maxChip;\n\t\tconst chipPlain = truncated ? truncatePlain(plain, maxChip) : plain;\n\t\tconst chipW = displayWidth(chipPlain);\n\t\tconst dashTotal = Math.max(0, width - overhead - chipW);\n\t\t// Right-align the chip: a single trailing dash before the corner, the\n\t\t// rest lead (right-aligns the chip near the corner).\n\t\tconst rightDashes = Math.min(dashTotal, 1);\n\t\tconst leftDashes = dashTotal - rightDashes;\n\n\t\tconst left = \"\\u2570\" + \"\\u2500\".repeat(leftDashes) + \" \";\n\t\tconst right = \" \" + \"\\u2500\".repeat(rightDashes) + \"\\u256f\";\n\t\tconst theme = this.ctx.ui?.theme;\n\t\t// Truncated chips may have lost the effort token — paint all white.\n\t\t// Otherwise model/provider stay white and the effort uses the thinking token.\n\t\tconst chip = truncated\n\t\t\t? this.color(\"white\", chipPlain)\n\t\t\t: this.color(\"white\", parts.left) + colorEffort(theme, parts.level, parts.effort);\n\t\treturn border(left) + chip + border(right);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// The stats line (footer) — slim, single line, BELOW the box\n// ---------------------------------------------------------------------------\n\nexport function renderStatsLine(\n\twidth: number,\n\tctx: ExtensionContextLike,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n): string[] {\n\tconst sep = color(theme, \"accent2\", \" | \"); // lunr: theme-polish — separator uses subtle accent2 blue (was bright-black plain fallback)\n\tconst parts: string[] = [];\n\n\t// lunr: mode zone — permission mode + agent-mode statuses (plan/goal)\n\t// render as ONE segment (dim middot-separated), not scattered across piped sections.\n\tconst modeZone: string[] = [];\n\n\t// lunr: permission mode safety indicator — always shown (not toggle-gated).\n\tconst mode = lunrPermissionMode();\n\tif (mode === \"yolo\" || mode === \"auto\") modeZone.push(color(theme, \"warning\", mode));\n\telse if (mode === \"manual\" || mode === \"plan\") modeZone.push(color(theme, \"white\", mode)); // lunr: theme-polish — manual/plan read white (was dim)\n\n\t// lunr: footer element toggles from the customize bridge (read at render time).\n\tconst footerToggles = lunrFooterToggles();\n\n\t// 1) Extension statuses published by other extensions (rendered as-is,\n\t// already styled): LSP (`pi-lsp-extension`), MCP (`pi-mcp-adapter`),\n\t// throughput/tokens (`pi-tps-was-taken`). These are NOT on `ctx` directly.\n\tconst statuses = footerData.getExtensionStatuses?.();\n\tif (statuses && statuses.size > 0) {\n\t\t// lunr: status segments are toggle-gated via the customize bridge:\n\t\t// footerStatuses gates plan/goal, footerTps gates tps,\n\t\t// footerMcp gates mcp/mcp-auth, footerLsp gates lsp. Publishers keep\n\t\t// calling ctx.ui.setStatus harmlessly when their segment is hidden.\n\t\t// lunr: plan/goal join the mode zone; tps/mcp/lsp stay piped.\n\t\tconst modeKeys: string[] = footerToggles.statuses ? [\"plan\", \"goal\"] : [];\n\t\tfor (const key of modeKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\tif (v) modeZone.push(color(theme, \"white\", stripAnsi(v)));\n\t\t}\n\t\tconst pipedKeys: string[] = [];\n\t\tif (footerToggles.tps) pipedKeys.push(\"tps\");\n\t\tif (footerToggles.mcp) pipedKeys.push(\"mcp\", \"mcp-auth\");\n\t\tif (footerToggles.lsp) pipedKeys.push(\"lsp\");\n\t\tfor (const key of pipedKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\t// lunr: unify footer status colors (white, was dim) so the whole stats line reads as one tone.\n\t\t\tif (v) parts.push(color(theme, \"white\", stripAnsi(v))); // lunr: theme-polish — status segments white (was dim)\n\t\t}\n\t}\n\tif (modeZone.length > 0) {\n\t\tparts.unshift(modeZone.join(color(theme, \"dim\", \" · \")));\n\t}\n\n\t// lunr: git branch + working-tree +/- vs HEAD (gated on footerGit).\n\tif (footerToggles.git) {\n\t\tconst branch = footerData.getGitBranch?.();\n\t\tif (branch) {\n\t\t\tconst diff = footerData.getGitDiffstat?.();\n\t\t\tlet gitSeg = color(theme, \"white\", branch);\n\t\t\tif (diff && (diff.added !== 0 || diff.removed !== 0)) {\n\t\t\t\tgitSeg +=\n\t\t\t\t\t` ${color(theme, \"success\", `+${diff.added}`)} ${color(theme, \"error\", `-${diff.removed}`)}`;\n\t\t\t}\n\t\t\tparts.push(gitSeg);\n\t\t}\n\t}\n\n\t// lunr: live subscription window bar (gated on footerPlan). Hidden with no plan.\n\tif (footerToggles.plan) {\n\t\tconst provider = ctx.model?.provider;\n\t\tif (provider) {\n\t\t\tconst usage = lunrUsageBridge();\n\t\t\tusage?.prefetch?.(provider);\n\t\t\tconst seg = usage?.pickForFooter?.(provider);\n\t\t\tif (seg) {\n\t\t\t\tconst pct = `${Math.round(seg.usedPercent)}%`;\n\t\t\t\tconst barColor = seg.usedPercent > 90 ? \"error\" : seg.usedPercent > 70 ? \"warning\" : \"success\";\n\t\t\t\tconst bar = footerToggles.planBar ? `${compactPlanBar(seg.usedPercent, theme)} ` : \"\";\n\t\t\t\tparts.push(color(theme, \"white\", seg.label) + \" \" + bar + color(theme, barColor, pct));\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2) Context usage: `pct/window` (lunr: gated on footerContext).\n\tif (footerToggles.context) {\n\t\tconst usage = ctx.getContextUsage();\n\t\tconst win = ctx.model?.contextWindow ?? usage?.contextWindow ?? 0;\n\t\tconst pct = usage?.percent == null ? \"?\" : `${Math.round(usage.percent)}%`;\n\t\tconst ctxSeg = `${pct}/${formatCount(win)}`;\n\t\tconst pv = usage?.percent ?? 0;\n\t\tif (pv > 90) parts.push(color(theme, \"error\", ctxSeg));\n\t\telse if (pv > 70) parts.push(color(theme, \"warning\", ctxSeg));\n\t\telse parts.push(color(theme, \"white\", ctxSeg)); // lunr: theme-polish — normal context % white (was dim)\n\t}\n\n\tconst totals = getUsageTotals(ctx);\n\n\t// 3) Token totals: ↑in ↓out (lunr: gated on footerTokens).\n\tif (footerToggles.tokens) {\n\t\tparts.push(color(theme, \"white\", `\\u2191${formatCount(totals.input)} \\u2193${formatCount(totals.output)}`)); // lunr: theme-polish — token totals white (was dim)\n\t}\n\n\t// 4) Latest prompt cache hit rate (gated on footerCacheHitRate).\n\tif (footerToggles.cacheHitRate && totals.cacheActivity && totals.latestCacheHitRate !== undefined) {\n\t\tparts.push(color(theme, \"white\", `CH${totals.latestCacheHitRate.toFixed(1)}%`));\n\t}\n\n\t// lunr: cost/usage counter segment removed entirely (both the $x.xxx dollar\n\t// counter for API-key providers and the plan-usage limit bar for OAuth/subscription\n\t// providers). Segments 1-3 (statuses, context, tokens) remain.\n\n\tlet line = parts.join(sep);\n\tif (displayWidth(line) > width) {\n\t\tline = truncateToWidth(line, width, \"\");\n\t}\n\treturn [line];\n}\n\n// ---------------------------------------------------------------------------\n// Install / teardown\n// ---------------------------------------------------------------------------\n\nconst chatboxEditors = new WeakMap<TUIHandle, ChatboxEditor>();\n\n/** The startup view and extension bind the same editor, preserving its complete draft state. */\nexport function getChatboxEditor(\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n): ChatboxEditor {\n\tlet editor = chatboxEditors.get(tui);\n\tif (editor) editor.bind(ctx, pi);\n\telse {\n\t\teditor = new ChatboxEditor(tui, theme, keybindings, ctx, pi);\n\t\tchatboxEditors.set(tui, editor);\n\t}\n\treturn editor;\n}\n\nfunction installEditor(\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n\tsetRequestor: (r: () => void) => void,\n): (() => void) | undefined {\n\tif (typeof ctx.ui.setEditorComponent !== \"function\") return;\n\tlet editor: ChatboxEditor | undefined;\n\tconst factory: EditorFactoryLike = (tui, _theme, _keybindings) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\teditor = getChatboxEditor(tui, _theme, _keybindings, ctx, pi);\n\t\treturn editor;\n\t};\n\tctx.ui.setEditorComponent(factory);\n\treturn () => editor?.unbind();\n}\n\nfunction installFooter(\n\tctx: ExtensionContextLike,\n\tsetRequestor: (r: () => void) => void,\n): void {\n\tif (typeof ctx.ui.setFooter !== \"function\") return;\n\tlet disposed = false;\n\tconst factory: FooterFactoryLike = (tui, _theme, _footerData) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tinvalidate(): void {\n\t\t\t\t// render is pure\n\t\t\t},\n\t\t\tdispose(): void {\n\t\t\t\tdisposed = true;\n\t\t\t},\n\t\t\trender(width: number): string[] {\n\t\t\t\tif (disposed) return [];\n\t\t\t\treturn renderStatsLine(width, ctx, _theme, _footerData);\n\t\t\t},\n\t\t};\n\t};\n\tctx.ui.setFooter(factory);\n}\n\n// ---------------------------------------------------------------------------\n// Extension entry point\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\tlet unbindEditor: (() => void) | undefined;\n\tlet renderRequestor: (() => void) | undefined = undefined;\n\tconst requestRender = (): void => {\n\t\ttry {\n\t\t\trenderRequestor?.();\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t};\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tif (!ctx.hasUI || ctx.mode !== \"tui\") return;\n\t\tunbindEditor = installEditor(ctx, pi, (r) => {\n\t\t\trenderRequestor = r;\n\t\t});\n\t\tinstallFooter(ctx, (r) => {\n\t\t\tif (!renderRequestor) renderRequestor = r;\n\t\t});\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tunbindEditor?.();\n\t\tunbindEditor = undefined;\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setEditorComponent === \"function\") ctx.ui.setEditorComponent(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setFooter === \"function\") ctx.ui.setFooter(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\trenderRequestor = undefined;\n\t});\n\n\t// Re-render triggers: model/provider + effort (chip), and token/cost/context\n\t// (stats line). Event names match those zentui wires.\n\tconst reRenderEvents = [\n\t\t\"model_select\",\n\t\t\"thinking_level_select\",\n\t\t\"agent_end\",\n\t\t\"message_end\",\n\t\t\"tool_execution_end\",\n\t\t\"session_compact\",\n\t];\n\tfor (const ev of reRenderEvents) {\n\t\tpi.on(ev, () => requestRender());\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ashxj-tui.js","sourceRoot":"","sources":["../../src/builtin-extensions/ashxj-tui.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ashxj-tui — a custom slim chatbox for pi.\n *\n * Replaces pi-zentui's prompt box + statusline with:\n * - A rounded prompt box that auto-expands as the typed message wraps.\n * Top and bottom rules only; no side rails.\n * - A right-aligned chip on the box's BOTTOM border:\n * model · provider · effort (e.g. `glm-5.2 · Ollama Cloud · xhigh`)\n * - A slim stats line (extension statuses · context% · ↑↓; each segment\n * toggle-gated via the lunr customize bridge) BELOW the box, not wrapped\n * around the input.\n * - No session-mode indicator anywhere (pi has no such concept).\n *\n * Loaded by pi via jiti — no build step, plain TypeScript.\n *\n * NOTE on type imports (see `ashxj-thinking`/`simple-memory` for the convention):\n * This file declares structural types inline rather than importing them from\n * `@ashx-j/lunr` / `@ashx-j/lunr-tui`.\n * pi-coding-agent's `index.d.ts` re-exports from internal `.d.ts` files that\n * contain subpath imports like `@ashx-j/lunr-ai/compat`, which do not\n * resolve under `tsc` with a file argument. We keep the typecheck\n * self-contained with inline types and verify via the included `tsconfig.json`\n * (`moduleResolution: \"Bundler\"` + `skipLibCheck: true`).\n *\n * The ONE exception is `CustomEditor`, imported as a RUNTIME VALUE directly\n * from its defining module (`modes/interactive/components/custom-editor.ts`).\n * We must `extends` it to inherit pi's app keybindings (escape, ctrl+d, model\n * switching, extension shortcuts) — wrapping would lose those. It is imported\n * from the concrete module, NOT the package barrel, because the barrel\n * re-exports main.ts which imports this file — a circular import that crashes\n * under vite-node (`Class extends value undefined`).\n */\n\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.js\";\n\nconst CUSTOMIZE_BRIDGE = Symbol.for(\"@lunr/customize\");\nconst PERMISSION_MODE_BRIDGE = Symbol.for(\"@lunr/permission-mode\");\ninterface CustomizeBridgeForPrompt {\n\tgetOpenAIFastMode?(): boolean;\n\t// lunr: footer element toggles (added to the same bridge).\n\tgetFooterMcp?(): boolean;\n\tgetFooterLsp?(): boolean;\n\tgetFooterContext?(): boolean;\n\tgetFooterTokens?(): boolean;\n\tgetFooterCacheHitRate?(): boolean;\n\tgetFooterTps?(): boolean;\n\tgetFooterStatuses?(): boolean;\n\tgetFooterGit?(): boolean;\n\tgetFooterPlan?(): boolean;\n\tgetFooterPlanBar?(): boolean;\n}\ninterface PermissionModeBridgeForFooter {\n\tgetMode(): string | undefined;\n}\nfunction lunrCustomizeBridge(): CustomizeBridgeForPrompt | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE] as CustomizeBridgeForPrompt | undefined;\n}\nfunction lunrPermissionModeBridge(): PermissionModeBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[PERMISSION_MODE_BRIDGE] as PermissionModeBridgeForFooter | undefined;\n}\n// lunr: footer toggles, read at render time. Bridgeless / missing-getter fallback\n// matches the settings-manager defaults: MCP on, LSP off, everything else on.\nfunction lunrFooterToggles(): {\n\tmcp: boolean;\n\tlsp: boolean;\n\tcontext: boolean;\n\ttokens: boolean;\n\tcacheHitRate: boolean;\n\ttps: boolean;\n\tstatuses: boolean;\n\tgit: boolean;\n\tplan: boolean;\n\tplanBar: boolean;\n} {\n\tconst bridge = lunrCustomizeBridge();\n\treturn {\n\t\tmcp: bridge?.getFooterMcp?.() ?? true,\n\t\tlsp: bridge?.getFooterLsp?.() ?? false,\n\t\tcontext: bridge?.getFooterContext?.() ?? true,\n\t\ttokens: bridge?.getFooterTokens?.() ?? true,\n\t\tcacheHitRate: bridge?.getFooterCacheHitRate?.() ?? true,\n\t\ttps: bridge?.getFooterTps?.() ?? true,\n\t\tstatuses: bridge?.getFooterStatuses?.() ?? true,\n\t\tgit: bridge?.getFooterGit?.() ?? true,\n\t\tplan: bridge?.getFooterPlan?.() ?? true,\n\t\tplanBar: bridge?.getFooterPlanBar?.() ?? true,\n\t};\n}\n\nconst USAGE_SERVICE_BRIDGE = Symbol.for(\"@lunr/usage-service\");\ninterface UsageServiceBridgeForFooter {\n\tpickForFooter?(providerId: string): { label: string; usedPercent: number } | undefined;\n\tprefetch?(providerId: string): void;\n}\nfunction lunrUsageBridge(): UsageServiceBridgeForFooter | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[USAGE_SERVICE_BRIDGE] as UsageServiceBridgeForFooter | undefined;\n}\n\nfunction compactPlanBar(percent: number, theme: Theme): string {\n\tconst cells = 8;\n\tconst clamped = Math.max(0, Math.min(100, percent));\n\tconst filled = Math.round((clamped / 100) * cells);\n\tconst token = clamped > 90 ? \"error\" : clamped > 70 ? \"warning\" : \"success\";\n\tconst fill = filled > 0 ? color(theme, token, \"█\".repeat(filled)) : \"\";\n\tconst rest = filled < cells ? color(theme, \"dim\", \"░\".repeat(cells - filled)) : \"\";\n\treturn fill + rest;\n}\n// lunr: permission mode for the footer safety indicator (always shown).\nfunction lunrPermissionMode(): string | undefined {\n\treturn lunrPermissionModeBridge()?.getMode();\n}\nexport function lunrPromptGlyph(theme: Theme | undefined): string {\n\tconst arrow = theme?.glyph?.(\"promptArrow\") ?? \">\";\n\treturn arrow ? `${arrow} ` : \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Minimal structural types (inline — see file header)\n// ---------------------------------------------------------------------------\n\ntype ThinkingLevel = \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n\n/** Theme token for the chatbox thinking-level border / effort chip. */\nexport function thinkingThemeToken(level: ThinkingLevel): string {\n\tswitch (level) {\n\t\tcase \"off\":\n\t\t\treturn \"thinkingOff\";\n\t\tcase \"minimal\":\n\t\t\treturn \"thinkingMinimal\";\n\t\tcase \"low\":\n\t\t\treturn \"thinkingLow\";\n\t\tcase \"medium\":\n\t\t\treturn \"thinkingMedium\";\n\t\tcase \"high\":\n\t\t\treturn \"thinkingHigh\";\n\t\tcase \"xhigh\":\n\t\t\treturn \"thinkingXhigh\";\n\t\tcase \"max\":\n\t\t\treturn \"thinkingMax\";\n\t\tdefault:\n\t\t\treturn \"thinkingOff\";\n\t}\n}\n\n/** Chip effort label — identity, locked so xhigh/max are never mapped down to high. */\nexport function formatChipEffort(level: ThinkingLevel): string {\n\treturn level;\n}\n\n/** Trimmed view of pi's `Theme` — only the methods we use. */\ninterface Theme {\n\tfg(token: string, text: string): string;\n\t/** lunr: prompt glyph tokens (optional for forward/backward compat). */\n\tglyph?(name: \"promptArrow\"): string;\n}\n\n/** Trimmed view of `pi-tui`'s `TUI` — only the method we use. */\ninterface TUIHandle {\n\trequestRender(force?: boolean): void;\n}\n\n/** Trimmed view of `pi-tui`'s `EditorTheme`. */\ninterface EditorThemeLike {\n\tborderColor: (str: string) => string;\n\tselectList: unknown;\n}\n\n/** Opaque keybindings manager. */\ninterface KeybindingsLike {\n\treadonly _?: unknown;\n}\n\n/** Trimmed view of an autocomplete list (the editor's private `autocompleteList`). */\ninterface AutocompleteListLike {\n\trender(width: number): string[];\n}\n\n/** Trimmed view of pi's `ReadonlyFooterDataProvider`. */\ninterface ReadonlyFooterDataProvider {\n\tgetGitBranch(): string | null;\n\tgetGitDiffstat?(): { added: number; removed: number } | null;\n\tgetExtensionStatuses(): ReadonlyMap<string, string>;\n\tgetAvailableProviderCount(): number;\n\tonBranchChange(callback: () => void): () => void;\n}\n\n/** Trimmed view of the `getContextUsage` return value. */\ninterface ContextUsage {\n\ttokens: number | null;\n\tcontextWindow: number;\n\tpercent: number | null;\n}\n\n/** Trimmed view of an assistant message's usage — the bits we render. */\ninterface AssistantUsage {\n\tinput: number;\n\toutput: number;\n\tcacheRead?: number;\n\tcacheWrite?: number;\n\tcost: { total: number };\n}\n\n/** Trimmed view of an assistant message. */\ninterface AssistantMessageLike {\n\trole: \"assistant\";\n\tusage: AssistantUsage;\n}\n\n/** Trimmed view of a session entry — only what we iterate over. */\ntype SessionEntry =\n\t| { type: \"message\"; message: AssistantMessageLike }\n\t| { type: string; message?: unknown };\n\n/** Trimmed view of a `ReadonlySessionManager`. */\ninterface ReadonlySessionManagerLike {\n\tgetEntries(): readonly SessionEntry[];\n\tgetBranch?(): readonly SessionEntry[];\n}\n\n/** Trimmed view of a `Model`. */\ninterface ModelLike {\n\tid?: string;\n\tprovider?: string;\n\tcontextWindow?: number;\n\treasoning?: boolean;\n\tthinkingLevelMap?: Record<string, string | null>;\n}\n\ninterface ExtensionUIContextLike {\n\tsetEditorComponent(factory: EditorFactoryLike | undefined): void;\n\tsetFooter(factory: FooterFactoryLike | undefined): void;\n\treadonly theme?: Theme;\n}\n\n/** Trimmed view of `ExtensionContext`. */\ninterface ExtensionContextLike {\n\tmode: \"tui\" | \"rpc\" | \"json\" | \"print\";\n\thasUI: boolean;\n\tmodel: ModelLike | undefined;\n\tsessionManager: ReadonlySessionManagerLike;\n\tgetContextUsage(): ContextUsage | undefined;\n\tui: ExtensionUIContextLike;\n}\n\n/** Trimmed view of `ExtensionAPI`. */\ninterface ExtensionAPI {\n\tgetThinkingLevel(): ThinkingLevel;\n\ton(event: string, handler: (event: unknown, ctx: ExtensionContextLike) => void): void;\n}\n\n/** `setEditorComponent` factory shape. */\ntype EditorFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n) => EditorComponentLike;\n\ninterface EditorComponentLike {\n\trender(width: number): string[];\n\tgetText(): string;\n\tsetText(text: string): void;\n\tinvalidate(): void;\n\thandleInput?(data: string): void;\n}\n\n/** `setFooter` factory shape. */\ntype FooterFactoryLike = (\n\ttui: TUIHandle,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n) => FooterComponentLike;\n\ninterface FooterComponentLike {\n\trender(width: number): string[];\n\tdispose?(): void;\n\tinvalidate?(): void;\n}\n\n// ---------------------------------------------------------------------------\n// Display-width helpers (ANSI-aware; CJK-aware)\n//\n// The editor (`Editor.render`) word-wraps to the given width using grapheme\n// width, so each returned line is ≤ that many visual columns. To right-pad a\n// line for our box we need a width model that matches closely enough: skip ALL\n// escape sequences (SGR color, OSC/DCS/APC/PM/SOS string sequences such as\n// pi-tui's `CURSOR_MARKER` `ESC _pi:c BEL`, and two-char escapes), count common\n// East-Asian wide ranges as 2, combining marks and variation selectors as 0.\n// Handling the string sequences as 0-width keeps body padding aligned with the\n// top/bottom rules on the focused (cursor) line. The base editor embeds the\n// marker and the TUI strips it at flush time, so we must not count it here.\n// ---------------------------------------------------------------------------\n\nfunction skipAnsi(str: string, pos: number): number {\n\tif (str.charCodeAt(pos) !== 0x1b) return 0;\n\tconst next = str.charCodeAt(pos + 1);\n\t// CSI: ESC [ ... <final 0x40-0x7e>\n\tif (next === 0x5b /* [ */) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c >= 0x40 && c <= 0x7e) return j + 1 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// String sequences — OSC (]), DCS (P), APC (_), PM (^), SOS (X) — terminated\n\t// by BEL (0x07) or ST (ESC \\). pi-tui's CURSOR_MARKER `ESC _pi:c BEL` is APC;\n\t// OSC color queries are OSC. All are zero visual width.\n\tif (\n\t\tnext === 0x5d /* ] */ ||\n\t\tnext === 0x50 /* P */ ||\n\t\tnext === 0x5f /* _ */ ||\n\t\tnext === 0x5e /* ^ */ ||\n\t\tnext === 0x58 /* X */\n\t) {\n\t\tlet j = pos + 2;\n\t\twhile (j < str.length) {\n\t\t\tconst c = str.charCodeAt(j);\n\t\t\tif (c === 0x07 /* BEL */) return j + 1 - pos;\n\t\t\tif (c === 0x1b && str.charCodeAt(j + 1) === 0x5c /* \\ */) return j + 2 - pos;\n\t\t\tj++;\n\t\t}\n\t\treturn str.length - pos; // unterminated; consume the rest\n\t}\n\t// Any other ESC sequence: consume ESC + one final byte (e.g. ESC c, ESC \\,\n\t// ESC ( B). A lone trailing ESC with no following byte is 0 width too.\n\treturn Number.isNaN(next) ? 1 : 2;\n}\n\nfunction isWide(cp: number): boolean {\n\treturn (\n\t\t(cp >= 0x1100 && cp <= 0x115f) ||\n\t\t(cp >= 0x2e80 && cp <= 0x303e) ||\n\t\t(cp >= 0x3041 && cp <= 0x33ff) ||\n\t\t(cp >= 0x3400 && cp <= 0x4dbf) ||\n\t\t(cp >= 0x4e00 && cp <= 0x9fff) ||\n\t\t(cp >= 0xa000 && cp <= 0xa4cf) ||\n\t\t(cp >= 0xac00 && cp <= 0xd7a3) ||\n\t\t(cp >= 0xf900 && cp <= 0xfaff) ||\n\t\t(cp >= 0xfe30 && cp <= 0xfe4f) ||\n\t\t(cp >= 0xff00 && cp <= 0xff60) ||\n\t\t(cp >= 0xffe0 && cp <= 0xffe6) ||\n\t\t(cp >= 0x1f300 && cp <= 0x1faff) ||\n\t\t(cp >= 0x20000 && cp <= 0x3fffd)\n\t);\n}\n\nfunction charWidth(cp: number): number {\n\tif (cp >= 0x20 && cp < 0x7f) return 1;\n\tif ((cp >= 0x0300 && cp <= 0x036f) || (cp >= 0xfe00 && cp <= 0xfe0f) || cp === 0x200d) return 0;\n\treturn isWide(cp) ? 2 : 1;\n}\n\n/** Visible width of a string, ignoring SGR color codes. */\nfunction displayWidth(str: string): number {\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < str.length) {\n\t\tconst skip = skipAnsi(str, i);\n\t\tif (skip > 0) {\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst cp = str.codePointAt(i) ?? 0;\n\t\tw += charWidth(cp);\n\t\ti += cp > 0xffff ? 2 : 1;\n\t}\n\treturn w;\n}\n\n/** Right-pad a (possibly colored) line to `width` visible columns. */\nfunction padRight(line: string, width: number): string {\n\tconst w = displayWidth(line);\n\tif (w >= width) return line;\n\treturn line + \" \".repeat(width - w);\n}\n\n/** Truncate a plain (non-ANSI) string to `maxWidth` visible columns. */\nfunction truncatePlain(text: string, maxWidth: number): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length) {\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > maxWidth) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\treturn out;\n}\n\n/** Truncate a (possibly ANSI-colored) string to `maxWidth` visible columns,\n * re-emitting an SGR reset at the cut so styling doesn't bleed. */\nfunction truncateToWidth(text: string, maxWidth: number, ellipsis = \"\"): string {\n\tif (maxWidth <= 0) return \"\";\n\tif (displayWidth(text) <= maxWidth) return text;\n\tconst target = Math.max(0, maxWidth - displayWidth(ellipsis));\n\tlet out = \"\";\n\tlet w = 0;\n\tlet i = 0;\n\twhile (i < text.length && w < target) {\n\t\tconst skip = skipAnsi(text, i);\n\t\tif (skip > 0) {\n\t\t\tout += text.slice(i, i + skip);\n\t\t\ti += skip;\n\t\t\tcontinue;\n\t\t}\n\t\tconst code = text.codePointAt(i) ?? 0;\n\t\tconst cw = charWidth(code);\n\t\tif (w + cw > target) break;\n\t\tout += String.fromCodePoint(code);\n\t\tw += cw;\n\t\ti += code > 0xffff ? 2 : 1;\n\t}\n\tout += \"\\x1b[0m\";\n\treturn out + ellipsis;\n}\n\n/** Clamp each rendered line to `width` visible columns (fallback path). */\nfunction clampLines(lines: string[], width: number): string[] {\n\treturn lines.map((l) => (displayWidth(l) > width ? truncateToWidth(l, width, \"\") : l));\n}\n\n/** Apply a theme `fg` token safely; falls back to plain text. */\nfunction color(theme: Theme | undefined, token: string, text: string): string {\n\ttry {\n\t\treturn theme?.fg?.(token, text) ?? text;\n\t} catch {\n\t\treturn text;\n\t}\n}\n\n// lunr: strip ANSI escape sequences so footer statuses can be re-colored uniformly.\nfunction stripAnsi(s: string): string {\n\treturn s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n// ---------------------------------------------------------------------------\n// Stats formatting\n// ---------------------------------------------------------------------------\n\n/** Compact token-count formatter: `999`, `1.2k`, `15k`, `1.2M`, `15M`.\n * Matches pi's FooterComponent / the captured zentui examples\n * (`↑9.0M ↓112k`, `20%/1.0M`). */\nfunction formatCount(count: number): string {\n\tif (count < 1000) return count.toString();\n\tif (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n\tif (count < 1000000) return `${Math.round(count / 1000)}k`;\n\tif (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n\treturn `${Math.round(count / 1000000)}M`;\n}\n\n/** Sum session token totals and derive the latest request's cache-hit rate. */\nfunction getUsageTotals(ctx: ExtensionContextLike): {\n\tinput: number;\n\toutput: number;\n\tcacheActivity: boolean;\n\tlatestCacheHitRate: number | undefined;\n} {\n\tlet input = 0;\n\tlet output = 0;\n\tlet cacheRead = 0;\n\tlet cacheWrite = 0;\n\tlet latestCacheHitRate: number | undefined;\n\tconst entries = ctx.sessionManager.getEntries?.() ?? ctx.sessionManager.getBranch?.() ?? [];\n\tfor (const entry of entries as readonly SessionEntry[]) {\n\t\tif (entry.type !== \"message\") continue;\n\t\tconst m = entry.message as AssistantMessageLike | undefined;\n\t\tif (!m || m.role !== \"assistant\") continue;\n\t\tconst u = m.usage;\n\t\tif (!u) continue;\n\t\tconst usageInput = u.input ?? 0;\n\t\tconst usageCacheRead = u.cacheRead ?? 0;\n\t\tconst usageCacheWrite = u.cacheWrite ?? 0;\n\t\tinput += usageInput;\n\t\toutput += u.output ?? 0;\n\t\tcacheRead += usageCacheRead;\n\t\tcacheWrite += usageCacheWrite;\n\t\tconst promptTokens = usageInput + usageCacheRead + usageCacheWrite;\n\t\tlatestCacheHitRate = promptTokens > 0 ? (usageCacheRead / promptTokens) * 100 : undefined;\n\t}\n\treturn { input, output, cacheActivity: cacheRead > 0 || cacheWrite > 0, latestCacheHitRate };\n}\n\n// ---------------------------------------------------------------------------\n// Provider display label\n//\n// `ctx.model.provider` is a ProviderId string (e.g. `\"ollama-cloud\"`), NOT the\n// human label. `BUILT_IN_PROVIDER_DISPLAY_NAMES` exists in pi core but is not\n// re-exported to extensions, so we derive the label (mirrors zentui's\n// `formatProviderLabel`, with an explicit `ollama-cloud` entry).\n// ---------------------------------------------------------------------------\n\nfunction formatProviderLabel(provider: string | undefined): string {\n\tif (!provider) return \"Unknown\";\n\tconst known: Record<string, string> = {\n\t\tanthropic: \"Anthropic\",\n\t\tgemini: \"Google\",\n\t\tgoogle: \"Google\",\n\t\tollama: \"Ollama\",\n\t\t\"ollama-cloud\": \"Ollama Cloud\",\n\t\topenai: \"OpenAI\",\n\t\t\"openai-codex\": \"OpenAI\",\n\t\tmistral: \"Mistral\",\n\t};\n\treturn (\n\t\tknown[provider] ??\n\t\tprovider.replace(/[-_]/g, \" \").replace(/\\b\\w/g, (c) => c.toUpperCase())\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// The chip: `model · provider · effort`\n// ---------------------------------------------------------------------------\n\nfunction colorEffort(theme: Theme | undefined, level: ThinkingLevel, text: string): string {\n\tconst token = thinkingThemeToken(level);\n\tconst painted = color(theme, token, text);\n\tif (token === \"thinkingMax\" && painted === text) {\n\t\treturn color(theme, \"thinkingXhigh\", text);\n\t}\n\treturn painted;\n}\n\nfunction buildChip(ctx: ExtensionContextLike, pi: ExtensionAPI): { left: string; effort: string; level: ThinkingLevel } {\n\tconst modelId = ctx.model?.id ?? \"no-model\";\n\tconst provider = ctx.model?.provider;\n\tconst providerLabel = formatProviderLabel(provider);\n\tconst fast = provider === \"openai-codex\" && lunrCustomizeBridge()?.getOpenAIFastMode?.() ? \" · fast\" : \"\";\n\tconst level = pi.getThinkingLevel();\n\tconst effort = formatChipEffort(level);\n\treturn { left: `${modelId}${fast} · ${providerLabel} · `, effort, level };\n}\n\n// ---------------------------------------------------------------------------\n// The prompt box — `ChatboxEditor extends CustomEditor`\n// ---------------------------------------------------------------------------\n\nexport class ChatboxEditor extends CustomEditor {\n\tprivate ctx: ExtensionContextLike;\n\tprivate pi: ExtensionAPI;\n\n\tbind(ctx: ExtensionContextLike, pi: ExtensionAPI): void {\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t}\n\n\t/** Keep the displayed values while /new or /resume replaces the old runtime. */\n\tunbind(): void {\n\t\tconst level = this.pi.getThinkingLevel();\n\t\tthis.bind(\n\t\t\t{\n\t\t\t\tmode: \"tui\",\n\t\t\t\thasUI: true,\n\t\t\t\tmodel: this.ctx.model,\n\t\t\t\tsessionManager: { getEntries: () => [] },\n\t\t\t\tgetContextUsage: () => undefined,\n\t\t\t\tui: { theme: this.ctx.ui?.theme, setEditorComponent() {}, setFooter() {} },\n\t\t\t},\n\t\t\t{ getThinkingLevel: () => level, on() {} },\n\t\t);\n\t}\n\n\tconstructor(\n\t\ttui: TUIHandle,\n\t\ttheme: EditorThemeLike,\n\t\tkeybindings: KeybindingsLike,\n\t\tctx: ExtensionContextLike,\n\t\tpi: ExtensionAPI,\n\t) {\n\t\t// CustomEditor ctor: (tui, theme, keybindings, options?: EditorOptions).\n\t\t// Casts keep the inline types from leaking into the real base signature.\n\t\tsuper(tui as unknown as never, theme as unknown as never, keybindings as unknown as never, {\n\t\t\tpaddingX: 0,\n\t\t});\n\t\tthis.ctx = ctx;\n\t\tthis.pi = pi;\n\t\t// lunr: do not clobber borderColor — InteractiveMode.updateEditorBorderColor()\n\t\t// owns it (thinkingOff…thinkingMax, or bashMode).\n\t}\n\n\tprivate color(token: string, text: string): string {\n\t\treturn color(this.ctx.ui?.theme, token, text);\n\t}\n\n\toverride render(width: number): string[] {\n\t\t// Too narrow to draw a box — defer to the base editor, clamped.\n\t\tif (width <= 4) {\n\t\t\treturn clampLines(super.render(width), width);\n\t\t}\n\n\t\tconst glyph = lunrPromptGlyph(this.ctx.ui?.theme);\n\t\tconst glyphW = displayWidth(glyph);\n\t\tconst innerWidth = Math.max(1, width - glyphW);\n\t\tconst base = super.render(innerWidth);\n\n\t\t// The base editor appends the autocomplete menu lines (if any) to the END\n\t\t// of its render output. Split them off so the body sits inside the box and\n\t\t// the autocomplete renders BELOW the bottom border (preserves slash\n\t\t// commands). Mirrors zentui's `renderPolishedFrame`.\n\t\tconst showing = this.isShowingAutocomplete();\n\t\tconst acList = (this as unknown as { autocompleteList?: AutocompleteListLike }).autocompleteList;\n\t\tlet acCount = 0;\n\t\tif (showing && acList && typeof acList.render === \"function\") {\n\t\t\ttry {\n\t\t\t\tacCount = acList.render(innerWidth).length;\n\t\t\t} catch {\n\t\t\t\tacCount = 0;\n\t\t\t}\n\t\t}\n\n\t\t// `super.render` returns [base top ─ border, ...wrapped text lines, base\n\t\t// bottom ─ border, ...autocomplete lines] — the base editor draws its OWN\n\t\t// straight borders and (when active) appends the autocomplete menu. Split the\n\t\t// autocomplete off the end, then STRIP the base's first/last lines (its own\n\t\t// borders) so we don't render them a second time inside our rounded frame.\n\t\t// Mirrors zentui's `editorFrame.slice(1, -1)` (renderPolishedFrame).\n\t\tlet frame = base;\n\t\tlet acLines: string[] = [];\n\t\tif (acCount > 0 && acCount < frame.length) {\n\t\t\tacLines = frame.slice(frame.length - acCount);\n\t\t\tframe = frame.slice(0, frame.length - acCount);\n\t\t}\n\t\tconst inner = frame.length >= 2 ? frame.slice(1, frame.length - 1) : frame;\n\t\tconst body = inner.length > 0 ? inner : [\"\"];\n\n\t\tconst border = (s: string): string => this.borderColor(s);\n\n\t\t// Top border: ╭─…─╮\n\t\tconst top = border(\"\\u256d\" + \"\\u2500\".repeat(width - 2) + \"\\u256e\");\n\n\t\t// Body: prompt glyph + padded line. No side rails. Height grows with wrap.\n\t\tconst gutter = glyphW > 0 ? \" \".repeat(glyphW) : \"\";\n\t\tconst bodyLines = body.map((ln: string, i: number) => {\n\t\t\tconst prefix = i === 0 && glyphW > 0 ? this.color(\"dim\", glyph) : gutter;\n\t\t\treturn prefix + padRight(ln, innerWidth);\n\t\t});\n\n\t\t// Bottom border with the right-aligned chip: ╰─…─ <chip> ─╯\n\t\tconst bottom = this.renderBottomBorder(width);\n\n\t\treturn [top, ...bodyLines, bottom, ...acLines];\n\t}\n\n\tprivate renderBottomBorder(width: number): string {\n\t\tconst border = (s: string): string => this.borderColor(s);\n\t\tconst parts = buildChip(this.ctx, this.pi);\n\t\tconst plain = parts.left + parts.effort;\n\t\tconst overhead = 4;\n\t\tconst maxChip = Math.max(0, width - overhead);\n\t\tconst truncated = displayWidth(plain) > maxChip;\n\t\tconst chipPlain = truncated ? truncatePlain(plain, maxChip) : plain;\n\t\tconst chipW = displayWidth(chipPlain);\n\t\tconst dashTotal = Math.max(0, width - overhead - chipW);\n\t\t// Right-align the chip: a single trailing dash before the corner, the\n\t\t// rest lead (right-aligns the chip near the corner).\n\t\tconst rightDashes = Math.min(dashTotal, 1);\n\t\tconst leftDashes = dashTotal - rightDashes;\n\n\t\tconst left = \"\\u2570\" + \"\\u2500\".repeat(leftDashes) + \" \";\n\t\tconst right = \" \" + \"\\u2500\".repeat(rightDashes) + \"\\u256f\";\n\t\tconst theme = this.ctx.ui?.theme;\n\t\t// Truncated chips may have lost the effort token — paint all white.\n\t\t// Otherwise model/provider stay white and the effort uses the thinking token.\n\t\tconst chip = truncated\n\t\t\t? this.color(\"white\", chipPlain)\n\t\t\t: this.color(\"white\", parts.left) + colorEffort(theme, parts.level, parts.effort);\n\t\treturn border(left) + chip + border(right);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// The stats line (footer) — slim, single line, BELOW the box\n// ---------------------------------------------------------------------------\n\nexport function renderStatsLine(\n\twidth: number,\n\tctx: ExtensionContextLike,\n\ttheme: Theme,\n\tfooterData: ReadonlyFooterDataProvider,\n): string[] {\n\tconst sep = color(theme, \"accent2\", \" | \"); // lunr: theme-polish — separator uses subtle accent2 blue (was bright-black plain fallback)\n\tconst parts: string[] = [];\n\n\t// lunr: mode zone — permission mode + agent-mode statuses (plan/goal)\n\t// render as ONE segment (dim middot-separated), not scattered across piped sections.\n\tconst modeZone: string[] = [];\n\n\t// lunr: permission mode safety indicator — always shown (not toggle-gated).\n\tconst mode = lunrPermissionMode();\n\tif (mode === \"yolo\" || mode === \"auto\") modeZone.push(color(theme, \"warning\", mode));\n\telse if (mode === \"manual\" || mode === \"plan\") modeZone.push(color(theme, \"white\", mode)); // lunr: theme-polish — manual/plan read white (was dim)\n\n\t// lunr: footer element toggles from the customize bridge (read at render time).\n\tconst footerToggles = lunrFooterToggles();\n\n\t// 1) Extension statuses published by other extensions (rendered as-is,\n\t// already styled): LSP (`pi-lsp-extension`), MCP (`pi-mcp-adapter`),\n\t// throughput/tokens (`pi-tps-was-taken`). These are NOT on `ctx` directly.\n\tconst statuses = footerData.getExtensionStatuses?.();\n\tif (statuses && statuses.size > 0) {\n\t\t// lunr: status segments are toggle-gated via the customize bridge:\n\t\t// footerStatuses gates plan/goal, footerTps gates tps,\n\t\t// footerMcp gates mcp/mcp-auth, footerLsp gates lsp. Publishers keep\n\t\t// calling ctx.ui.setStatus harmlessly when their segment is hidden.\n\t\t// lunr: plan/goal join the mode zone; tps/mcp/lsp stay piped.\n\t\tconst modeKeys: string[] = footerToggles.statuses ? [\"plan\", \"goal\"] : [];\n\t\tfor (const key of modeKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\tif (v) modeZone.push(color(theme, \"white\", stripAnsi(v)));\n\t\t}\n\t\tconst pipedKeys: string[] = [];\n\t\tif (footerToggles.tps) pipedKeys.push(\"tps\");\n\t\tif (footerToggles.mcp) pipedKeys.push(\"mcp\", \"mcp-auth\");\n\t\tif (footerToggles.lsp) pipedKeys.push(\"lsp\");\n\t\tfor (const key of pipedKeys) {\n\t\t\tconst v = statuses.get(key);\n\t\t\t// lunr: unify footer status colors (white, was dim) so the whole stats line reads as one tone.\n\t\t\tif (v) parts.push(color(theme, \"white\", stripAnsi(v))); // lunr: theme-polish — status segments white (was dim)\n\t\t}\n\t}\n\tif (modeZone.length > 0) {\n\t\tparts.unshift(modeZone.join(color(theme, \"dim\", \" · \")));\n\t}\n\n\t// lunr: git branch + working-tree +/- vs HEAD (gated on footerGit).\n\tif (footerToggles.git) {\n\t\tconst branch = footerData.getGitBranch?.();\n\t\tif (branch) {\n\t\t\tconst diff = footerData.getGitDiffstat?.();\n\t\t\tlet gitSeg = color(theme, \"white\", branch);\n\t\t\tif (diff && (diff.added !== 0 || diff.removed !== 0)) {\n\t\t\t\tgitSeg +=\n\t\t\t\t\t` ${color(theme, \"success\", `+${diff.added}`)} ${color(theme, \"error\", `-${diff.removed}`)}`;\n\t\t\t}\n\t\t\tparts.push(gitSeg);\n\t\t}\n\t}\n\n\t// lunr: live subscription window bar (gated on footerPlan). Hidden with no plan.\n\tif (footerToggles.plan) {\n\t\tconst provider = ctx.model?.provider;\n\t\tif (provider) {\n\t\t\tconst usage = lunrUsageBridge();\n\t\t\tusage?.prefetch?.(provider);\n\t\t\tconst seg = usage?.pickForFooter?.(provider);\n\t\t\tif (seg) {\n\t\t\t\tconst pct = `${Math.round(seg.usedPercent)}%`;\n\t\t\t\tconst barColor = seg.usedPercent > 90 ? \"error\" : seg.usedPercent > 70 ? \"warning\" : \"success\";\n\t\t\t\tconst bar = footerToggles.planBar ? `${compactPlanBar(seg.usedPercent, theme)} ` : \"\";\n\t\t\t\tparts.push(color(theme, \"white\", seg.label) + \" \" + bar + color(theme, barColor, pct));\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2) Context usage: `pct/window` (lunr: gated on footerContext).\n\tif (footerToggles.context) {\n\t\tconst usage = ctx.getContextUsage();\n\t\tconst win = ctx.model?.contextWindow ?? usage?.contextWindow ?? 0;\n\t\tconst pct = usage?.percent == null ? \"?\" : `${Math.round(usage.percent)}%`;\n\t\tconst ctxSeg = `${pct}/${formatCount(win)}`;\n\t\tconst pv = usage?.percent ?? 0;\n\t\tif (pv > 90) parts.push(color(theme, \"error\", ctxSeg));\n\t\telse if (pv > 70) parts.push(color(theme, \"warning\", ctxSeg));\n\t\telse parts.push(color(theme, \"white\", ctxSeg)); // lunr: theme-polish — normal context % white (was dim)\n\t}\n\n\tconst totals = getUsageTotals(ctx);\n\n\t// 3) Token totals: ↑in ↓out (lunr: gated on footerTokens).\n\tif (footerToggles.tokens) {\n\t\tparts.push(color(theme, \"white\", `\\u2191${formatCount(totals.input)} \\u2193${formatCount(totals.output)}`)); // lunr: theme-polish — token totals white (was dim)\n\t}\n\n\t// 4) Latest prompt cache hit rate (gated on footerCacheHitRate).\n\tif (footerToggles.cacheHitRate && totals.cacheActivity && totals.latestCacheHitRate !== undefined) {\n\t\tparts.push(color(theme, \"white\", `CH${totals.latestCacheHitRate.toFixed(1)}%`));\n\t}\n\n\t// lunr: cost/usage counter segment removed entirely (both the $x.xxx dollar\n\t// counter for API-key providers and the plan-usage limit bar for OAuth/subscription\n\t// providers). Segments 1-3 (statuses, context, tokens) remain.\n\n\tlet line = parts.join(sep);\n\tif (displayWidth(line) > width) {\n\t\tline = truncateToWidth(line, width, \"\");\n\t}\n\treturn [line];\n}\n\n// ---------------------------------------------------------------------------\n// Install / teardown\n// ---------------------------------------------------------------------------\n\nconst chatboxEditors = new WeakMap<TUIHandle, ChatboxEditor>();\n\n/** The startup view and extension bind the same editor, preserving its complete draft state. */\nexport function getChatboxEditor(\n\ttui: TUIHandle,\n\ttheme: EditorThemeLike,\n\tkeybindings: KeybindingsLike,\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n): ChatboxEditor {\n\tlet editor = chatboxEditors.get(tui);\n\tif (editor) editor.bind(ctx, pi);\n\telse {\n\t\teditor = new ChatboxEditor(tui, theme, keybindings, ctx, pi);\n\t\tchatboxEditors.set(tui, editor);\n\t}\n\treturn editor;\n}\n\nfunction installEditor(\n\tctx: ExtensionContextLike,\n\tpi: ExtensionAPI,\n\tsetRequestor: (r: () => void) => void,\n): (() => void) | undefined {\n\tif (typeof ctx.ui.setEditorComponent !== \"function\") return;\n\tlet editor: ChatboxEditor | undefined;\n\tconst factory: EditorFactoryLike = (tui, _theme, _keybindings) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\teditor = getChatboxEditor(tui, _theme, _keybindings, ctx, pi);\n\t\treturn editor;\n\t};\n\tctx.ui.setEditorComponent(factory);\n\treturn () => editor?.unbind();\n}\n\nfunction installFooter(\n\tctx: ExtensionContextLike,\n\tsetRequestor: (r: () => void) => void,\n): void {\n\tif (typeof ctx.ui.setFooter !== \"function\") return;\n\tlet disposed = false;\n\tconst factory: FooterFactoryLike = (tui, _theme, _footerData) => {\n\t\tsetRequestor(() => {\n\t\t\ttry {\n\t\t\t\ttui.requestRender();\n\t\t\t} catch {\n\t\t\t\t/* ignore */\n\t\t\t}\n\t\t});\n\t\treturn {\n\t\t\tinvalidate(): void {\n\t\t\t\t// render is pure\n\t\t\t},\n\t\t\tdispose(): void {\n\t\t\t\tdisposed = true;\n\t\t\t},\n\t\t\trender(width: number): string[] {\n\t\t\t\tif (disposed) return [];\n\t\t\t\treturn renderStatsLine(width, ctx, _theme, _footerData);\n\t\t\t},\n\t\t};\n\t};\n\tctx.ui.setFooter(factory);\n}\n\n// ---------------------------------------------------------------------------\n// Extension entry point\n// ---------------------------------------------------------------------------\n\nexport default function (pi: ExtensionAPI): void {\n\tlet unbindEditor: (() => void) | undefined;\n\tlet renderRequestor: (() => void) | undefined = undefined;\n\tconst requestRender = (): void => {\n\t\ttry {\n\t\t\trenderRequestor?.();\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t};\n\n\tpi.on(\"session_start\", (_event, ctx) => {\n\t\tif (!ctx.hasUI || ctx.mode !== \"tui\") return;\n\t\tunbindEditor = installEditor(ctx, pi, (r) => {\n\t\t\trenderRequestor = r;\n\t\t});\n\t\tinstallFooter(ctx, (r) => {\n\t\t\tif (!renderRequestor) renderRequestor = r;\n\t\t});\n\t});\n\n\tpi.on(\"session_shutdown\", (_event, ctx) => {\n\t\tunbindEditor?.();\n\t\tunbindEditor = undefined;\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setEditorComponent === \"function\") ctx.ui.setEditorComponent(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\ttry {\n\t\t\tif (typeof ctx.ui?.setFooter === \"function\") ctx.ui.setFooter(undefined);\n\t\t} catch {\n\t\t\t/* ignore */\n\t\t}\n\t\trenderRequestor = undefined;\n\t});\n\n\t// Re-render triggers: model/provider + effort (chip), and token/cost/context\n\t// (stats line). Event names match those zentui wires.\n\tconst reRenderEvents = [\n\t\t\"model_select\",\n\t\t\"thinking_level_select\",\n\t\t\"agent_end\",\n\t\t\"message_end\",\n\t\t\"tool_execution_end\",\n\t\t\"session_compact\",\n\t];\n\tfor (const ev of reRenderEvents) {\n\t\tpi.on(ev, () => requestRender());\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/builtin-extensions/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAwBrF,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,EAAE,eAAe,EAWnD,CAAC;AAiBF,eAAO,MAAM,gCAAgC,UAAsD,CAAC;AAEpG,6FAA6F;AAC7F,eAAO,MAAM,sBAAsB,yBAA0B,CAAC;AAE9D,6EAA6E;AAC7E,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAQhF;AAED,yFAAyF;AACzF,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAE3E;AAED,qFAAqF;AACrF,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAA2B,CAAC","sourcesContent":["/**\n * Built-in extensions for lunR.\n *\n * Light factories stay on the first-paint graph. Heavy factories are imported\n * only when attachDeferredBuiltinExtensions() runs after the TUI is up, or\n * immediately for print/RPC/gateway where there is no first-paint window.\n */\n\nimport type { ExtensionFactory, InlineExtension } from \"../core/extensions/types.ts\";\nimport { measureStartup } from \"../core/timings.ts\";\n\nimport simplePiMemory from \"./simple-pi-memory.ts\";\nimport piTps from \"./pi-tps.ts\";\nimport ashxjTui from \"./ashxj-tui.ts\";\nimport ashxjSpinners from \"./ashxj-spinners.ts\";\nimport ashxjThinking from \"./ashxj-thinking.ts\";\nimport lunrLocalProviders from \"./lunr-local-providers/index.ts\";\nimport lunrTodos from \"./lunr-todos.ts\";\nimport lunrPlanTools from \"./lunr-plan-tools.ts\";\nimport lunrSkillCreator from \"./lunr-skill-creator/index.ts\";\nimport lunrSettingsTools from \"./lunr-settings-tools.ts\";\n\n/**\n * Wrap a raw factory function as a named InlineExtension.\n * The cast bridges the gap between the source-level ExtensionFactory type\n * (used here) and the dist-level type that extensions import via the package\n * name. The underlying function signatures are structurally identical.\n */\nfunction ext(name: string, factory: unknown): InlineExtension {\n\treturn { name, factory: factory as ExtensionFactory };\n}\n\n/** UI, local providers, and small lunR-native factories. Safe to import at CLI start. */\nexport const lightBuiltinExtensions: InlineExtension[] = [\n\text(\"simple-pi-memory\", simplePiMemory),\n\text(\"pi-tps\", piTps),\n\text(\"ashxj-tui\", ashxjTui),\n\text(\"ashxj-spinners\", ashxjSpinners),\n\text(\"ashxj-thinking\", ashxjThinking),\n\text(\"lunr-local-providers\", lunrLocalProviders),\n\text(\"lunr-todos\", lunrTodos),\n\text(\"lunr-plan-tools\", lunrPlanTools),\n\text(\"lunr-skill-creator\", lunrSkillCreator),\n\text(\"lunr-settings-tools\", lunrSettingsTools),\n];\n\nconst DEFERRED_BUILTIN_LOADERS: Array<{\n\tname: string;\n\tload: () => Promise<{ default: unknown }>;\n}> = [\n\t{ name: \"pi-ollama-cloud\", load: () => import(\"./pi-ollama-cloud/index.ts\") },\n\t{ name: \"narumiruna-pi-goal\", load: () => import(\"./narumiruna-pi-goal/src/goal.ts\") },\n\t{ name: \"lunr-cron\", load: () => import(\"./lunr-cron.ts\") },\n\t{ name: \"pi-intercom\", load: () => import(\"./pi-intercom/index.ts\") },\n\t{ name: \"pi-prompt-template-model\", load: () => import(\"./pi-prompt-template-model/index.ts\") },\n\t{ name: \"pi-subagents\", load: () => import(\"./pi-subagents/index.ts\") },\n\t{ name: \"pi-web-access\", load: () => import(\"./pi-web-access/index.ts\") },\n\t{ name: \"pi-lsp-extension\", load: () => import(\"./pi-lsp-extension/src/index.ts\") },\n\t{ name: \"pi-mcp-adapter\", load: () => import(\"./pi-mcp-adapter/index.ts\") },\n];\n\nexport const DEFERRED_BUILTIN_EXTENSION_NAMES = DEFERRED_BUILTIN_LOADERS.map((entry) => entry.name);\n\n/** Flags registered only after deferred builtins attach. Do not fail CLI parse for these. */\nexport const DEFERRED_BUILTIN_FLAGS = [\"mcp-config\"] as const;\n\n/** Import MCP / LSP / web-access / intercom / subagents only when needed. */\nexport async function loadDeferredBuiltinExtensions(): Promise<InlineExtension[]> {\n\tconst loaded = await Promise.all(\n\t\tDEFERRED_BUILTIN_LOADERS.map(async ({ name, load }) => {\n\t\t\tconst module = await measureStartup(name, load, \"imports\");\n\t\t\treturn ext(name, module.default);\n\t\t}),\n\t);\n\treturn loaded;\n}\n\n/** Full roster. Print / RPC / gateway still need every factory before the first turn. */\nexport async function loadAllBuiltinExtensions(): Promise<InlineExtension[]> {\n\treturn [...lightBuiltinExtensions, ...(await loadDeferredBuiltinExtensions())];\n}\n\n/** Eager full roster. Prefer loadAllBuiltinExtensions() so CLI start stays light. */\nexport const builtinExtensions: InlineExtension[] = lightBuiltinExtensions;\n"]}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* only when attachDeferredBuiltinExtensions() runs after the TUI is up, or
|
|
6
6
|
* immediately for print/RPC/gateway where there is no first-paint window.
|
|
7
7
|
*/
|
|
8
|
+
import { measureStartup } from "../core/timings.js";
|
|
8
9
|
import simplePiMemory from "./simple-pi-memory.js";
|
|
9
10
|
import piTps from "./pi-tps.js";
|
|
10
11
|
import ashxjTui from "./ashxj-tui.js";
|
|
@@ -54,7 +55,7 @@ export const DEFERRED_BUILTIN_FLAGS = ["mcp-config"];
|
|
|
54
55
|
/** Import MCP / LSP / web-access / intercom / subagents only when needed. */
|
|
55
56
|
export async function loadDeferredBuiltinExtensions() {
|
|
56
57
|
const loaded = await Promise.all(DEFERRED_BUILTIN_LOADERS.map(async ({ name, load }) => {
|
|
57
|
-
const module = await load
|
|
58
|
+
const module = await measureStartup(name, load, "imports");
|
|
58
59
|
return ext(name, module.default);
|
|
59
60
|
}));
|
|
60
61
|
return loaded;
|