@ken-jo/agent-connector 0.4.95 → 0.4.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -202
- package/NOTICE +6 -6
- package/README.md +605 -599
- package/dist/{action-Q7GGO4PA.js → action-IPFDPOZU.js} +16 -16
- package/dist/action-IPFDPOZU.js.map +1 -0
- package/dist/{amazon-q-ETMAGY3D.js → amazon-q-IT44LEWV.js} +6 -6
- package/dist/amazon-q-IT44LEWV.js.map +1 -0
- package/dist/{amp-BQZOL5GR.js → amp-CEWOSWQO.js} +4 -4
- package/dist/amp-CEWOSWQO.js.map +1 -0
- package/dist/{amp-67BZONGF.js → amp-P35FRU2Z.js} +7 -7
- package/dist/amp-P35FRU2Z.js.map +1 -0
- package/dist/{antigravity-EA4L225L.js → antigravity-LHFEFNMC.js} +5 -5
- package/dist/antigravity-LHFEFNMC.js.map +1 -0
- package/dist/antigravity-TWIWXTQH.js +18 -0
- package/dist/{antigravity-cli-B2HXZFYQ.js → antigravity-cli-MOKFSWOU.js} +5 -5
- package/dist/antigravity-cli-MOKFSWOU.js.map +1 -0
- package/dist/{antigravity-cli-OM6SC3PE.js → antigravity-cli-MPE27LPI.js} +9 -9
- package/dist/antigravity-cli-MPE27LPI.js.map +1 -0
- package/dist/audit-3E5JAOP2.js +311 -0
- package/dist/audit-3E5JAOP2.js.map +1 -0
- package/dist/{chunk-PW42ZXCB.js → chunk-3EP5V2F4.js} +3 -3
- package/dist/chunk-3EP5V2F4.js.map +1 -0
- package/dist/{chunk-MGTDQLJJ.js → chunk-3FINQ2ZF.js} +4 -4
- package/dist/chunk-3FINQ2ZF.js.map +1 -0
- package/dist/{chunk-KHO5WNTP.js → chunk-4GH2KA7V.js} +1 -1
- package/dist/chunk-4GH2KA7V.js.map +1 -0
- package/dist/{chunk-2Y2MZRLP.js → chunk-7C2IPIIB.js} +3 -3
- package/dist/chunk-7C2IPIIB.js.map +1 -0
- package/dist/{chunk-NLE2J5P4.js → chunk-7HHW23AC.js} +29 -29
- package/dist/chunk-7HHW23AC.js.map +1 -0
- package/dist/{chunk-XD7MY6HB.js → chunk-7PSNXUFK.js} +1 -1
- package/dist/chunk-7PSNXUFK.js.map +1 -0
- package/dist/{chunk-5IOTP7LQ.js → chunk-7ZFK2WEO.js} +7 -5
- package/dist/chunk-7ZFK2WEO.js.map +1 -0
- package/dist/{chunk-XC5SJ35F.js → chunk-C63AAXK7.js} +5 -5
- package/dist/chunk-C63AAXK7.js.map +1 -0
- package/dist/{chunk-UM5S7DKK.js → chunk-C747DYNT.js} +1 -1
- package/dist/chunk-C747DYNT.js.map +1 -0
- package/dist/{chunk-YPAXJ7EW.js → chunk-FHYR5Q5T.js} +13 -13
- package/dist/chunk-FHYR5Q5T.js.map +1 -0
- package/dist/{chunk-I5UXHIDT.js → chunk-GCPEPUD7.js} +8 -8
- package/dist/chunk-GCPEPUD7.js.map +1 -0
- package/dist/{chunk-ISEJWBFF.js → chunk-GZZCHJDP.js} +2 -2
- package/dist/chunk-GZZCHJDP.js.map +1 -0
- package/dist/{chunk-UMQ6NBQR.js → chunk-ILWHLGIC.js} +2 -2
- package/dist/chunk-ILWHLGIC.js.map +1 -0
- package/dist/{chunk-IVAWP6HH.js → chunk-IOJDZJ72.js} +2 -2
- package/dist/chunk-IOJDZJ72.js.map +1 -0
- package/dist/{chunk-NBYKLUF6.js → chunk-KFPSJRHR.js} +2 -2
- package/dist/chunk-KFPSJRHR.js.map +1 -0
- package/dist/{chunk-O7SDRBVB.js → chunk-KM2YXO6V.js} +1 -1
- package/dist/chunk-KM2YXO6V.js.map +1 -0
- package/dist/{chunk-7F5KHLEP.js → chunk-L2C5UMKW.js} +4 -4
- package/dist/chunk-L2C5UMKW.js.map +1 -0
- package/dist/{chunk-OP4KBXUO.js → chunk-LFWYYWLV.js} +1 -1
- package/dist/chunk-LFWYYWLV.js.map +1 -0
- package/dist/{chunk-APZDTY76.js → chunk-LQ55E7QI.js} +7 -7
- package/dist/chunk-LQ55E7QI.js.map +1 -0
- package/dist/{chunk-PAPMUAR5.js → chunk-MLU7NDAZ.js} +12 -12
- package/dist/chunk-MLU7NDAZ.js.map +1 -0
- package/dist/{chunk-H33M77DD.js → chunk-N4ENLZEU.js} +22 -19
- package/dist/chunk-N4ENLZEU.js.map +1 -0
- package/dist/{chunk-D4ELPBB5.js → chunk-NDMNMAKP.js} +43 -43
- package/dist/chunk-NDMNMAKP.js.map +1 -0
- package/dist/{chunk-H53QZQJI.js → chunk-PSGTHJQU.js} +1 -1
- package/dist/chunk-PSGTHJQU.js.map +1 -0
- package/dist/{chunk-FBJQGRET.js → chunk-Q4ISQHUQ.js} +1 -1
- package/dist/chunk-Q4ISQHUQ.js.map +1 -0
- package/dist/{chunk-6TF7MHG5.js → chunk-Q7PR2WGT.js} +2 -2
- package/dist/chunk-Q7PR2WGT.js.map +1 -0
- package/dist/{chunk-GZGLCCEE.js → chunk-QYOUQCC6.js} +1 -1
- package/dist/chunk-QYOUQCC6.js.map +1 -0
- package/dist/{chunk-Z2MRSS2I.js → chunk-SLJI5BOM.js} +2 -2
- package/dist/chunk-SLJI5BOM.js.map +1 -0
- package/dist/{chunk-JKKU2WKG.js → chunk-TGZFDXNH.js} +4 -4
- package/dist/chunk-TGZFDXNH.js.map +1 -0
- package/dist/{chunk-FJCUKXGX.js → chunk-THI4PI4H.js} +2 -2
- package/dist/chunk-THI4PI4H.js.map +1 -0
- package/dist/{chunk-MQPNU2CY.js → chunk-UZZTWWGG.js} +1 -1
- package/dist/chunk-UZZTWWGG.js.map +1 -0
- package/dist/{chunk-3NH2ARIS.js → chunk-WPTNMYYM.js} +2 -2
- package/dist/chunk-WPTNMYYM.js.map +1 -0
- package/dist/{chunk-OPXAP3AC.js → chunk-XN7S44U4.js} +1 -1
- package/dist/chunk-XN7S44U4.js.map +1 -0
- package/dist/{chunk-6WZODR3Z.js → chunk-XVEJAFKW.js} +5 -5
- package/dist/chunk-XVEJAFKW.js.map +1 -0
- package/dist/{chunk-BEFVJ2OE.js → chunk-XXLCMSD3.js} +1 -1
- package/dist/chunk-XXLCMSD3.js.map +1 -0
- package/dist/{chunk-YT43MUSJ.js → chunk-XZWMJLIT.js} +1 -1
- package/dist/chunk-XZWMJLIT.js.map +1 -0
- package/dist/{chunk-4NHXLXSD.js → chunk-Y3K6KJMS.js} +2 -2
- package/dist/chunk-Y3K6KJMS.js.map +1 -0
- package/dist/{chunk-RK6VBLXP.js → chunk-ZSOS2KOR.js} +1 -1
- package/dist/chunk-ZSOS2KOR.js.map +1 -0
- package/dist/{claude-code-NMRKTAP7.js → claude-code-FS42PXZO.js} +4 -4
- package/dist/claude-code-FS42PXZO.js.map +1 -0
- package/dist/{claude-code-GRWO6XBZ.js → claude-code-QBWDT5RT.js} +11 -11
- package/dist/claude-code-QBWDT5RT.js.map +1 -0
- package/dist/cli/sdk.js +9 -8
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/{cline-25KW25IN.js → cline-JKEAYWVR.js} +6 -6
- package/dist/cline-JKEAYWVR.js.map +1 -0
- package/dist/{codebuddy-ZNYQACMF.js → codebuddy-EB6EYPC3.js} +7 -7
- package/dist/codebuddy-EB6EYPC3.js.map +1 -0
- package/dist/{codebuff-VR6JUDIY.js → codebuff-5RSXFU6G.js} +6 -6
- package/dist/codebuff-5RSXFU6G.js.map +1 -0
- package/dist/{codebuff-ETYT5UBL.js → codebuff-6KWBW6CT.js} +4 -4
- package/dist/codebuff-6KWBW6CT.js.map +1 -0
- package/dist/{codex-CPNKTXG3.js → codex-ART46CDD.js} +9 -9
- package/dist/codex-ART46CDD.js.map +1 -0
- package/dist/{codex-YAORPCOD.js → codex-DKBAAUCO.js} +4 -4
- package/dist/codex-DKBAAUCO.js.map +1 -0
- package/dist/{continue-WU2IB5KS.js → continue-JHZCMSPH.js} +8 -8
- package/dist/continue-JHZCMSPH.js.map +1 -0
- package/dist/{copilot-cli-MZTAWMPW.js → copilot-cli-CLBJACQ5.js} +4 -4
- package/dist/copilot-cli-CLBJACQ5.js.map +1 -0
- package/dist/{copilot-cli-PAP377OM.js → copilot-cli-QVAU5CFM.js} +7 -7
- package/dist/copilot-cli-QVAU5CFM.js.map +1 -0
- package/dist/{crush-3AVQA4YU.js → crush-7TORBYUL.js} +7 -7
- package/dist/crush-7TORBYUL.js.map +1 -0
- package/dist/{crush-QBXLNN7T.js → crush-A5C5USRL.js} +4 -4
- package/dist/crush-A5C5USRL.js.map +1 -0
- package/dist/{cursor-DIW43TRZ.js → cursor-D5SWDVSW.js} +3 -3
- package/dist/cursor-D5SWDVSW.js.map +1 -0
- package/dist/cursor-W7I4QUFO.js +22 -0
- package/dist/{detect-6V4LC3MA.js → detect-JHSA3G3U.js} +4 -4
- package/dist/detect-JHSA3G3U.js.map +1 -0
- package/dist/{devin-QMEM3OFA.js → devin-SSR7S4WX.js} +7 -7
- package/dist/devin-SSR7S4WX.js.map +1 -0
- package/dist/{doctor-2YDUVSAU.js → doctor-CQJ7TZPA.js} +26 -26
- package/dist/doctor-CQJ7TZPA.js.map +1 -0
- package/dist/{droid-MOKV53J4.js → droid-45PJ7JGF.js} +7 -7
- package/dist/droid-45PJ7JGF.js.map +1 -0
- package/dist/{droid-U3ZBLQFO.js → droid-PFQ2PZSF.js} +4 -4
- package/dist/droid-PFQ2PZSF.js.map +1 -0
- package/dist/{gemini-cli-47ZHCOZR.js → gemini-cli-24PFDK7D.js} +8 -8
- package/dist/gemini-cli-24PFDK7D.js.map +1 -0
- package/dist/{gemini-cli-NMVVBO3K.js → gemini-cli-Y6RJMU24.js} +4 -4
- package/dist/gemini-cli-Y6RJMU24.js.map +1 -0
- package/dist/{goose-64V46Y2W.js → goose-K2HKUTBK.js} +4 -4
- package/dist/goose-K2HKUTBK.js.map +1 -0
- package/dist/{goose-4EI5MYTI.js → goose-U5D3LCPC.js} +9 -9
- package/dist/goose-U5D3LCPC.js.map +1 -0
- package/dist/{grok-cli-QYQPDSVB.js → grok-cli-L2MHAPBY.js} +7 -7
- package/dist/grok-cli-L2MHAPBY.js.map +1 -0
- package/dist/{hermes-F75OSK3Y.js → hermes-2S5JUTTJ.js} +7 -7
- package/dist/hermes-2S5JUTTJ.js.map +1 -0
- package/dist/{hermes-F3EGTK6N.js → hermes-MF3NX4ZY.js} +4 -4
- package/dist/hermes-MF3NX4ZY.js.map +1 -0
- package/dist/{hook-OEVRDMXD.js → hook-VHICXHXL.js} +16 -16
- package/dist/hook-VHICXHXL.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/{install-5NMCUDG5.js → install-WLENR4KF.js} +192 -28
- package/dist/install-WLENR4KF.js.map +1 -0
- package/dist/{jetbrains-copilot-ZGIWI6YV.js → jetbrains-copilot-Z4FC3RM3.js} +6 -6
- package/dist/jetbrains-copilot-Z4FC3RM3.js.map +1 -0
- package/dist/{junie-DIFN2P22.js → junie-ULGJJIHB.js} +6 -6
- package/dist/junie-ULGJJIHB.js.map +1 -0
- package/dist/{kilo-SW7BH6EG.js → kilo-SMHPOHJ5.js} +4 -4
- package/dist/kilo-SMHPOHJ5.js.map +1 -0
- package/dist/{kilo-EMZJBEBB.js → kilo-WWIJOVWD.js} +8 -8
- package/dist/kilo-WWIJOVWD.js.map +1 -0
- package/dist/{kilo-cli-S3GXBPAE.js → kilo-cli-QKE2EQLS.js} +8 -8
- package/dist/kilo-cli-QKE2EQLS.js.map +1 -0
- package/dist/{kilo-cli-ZF272ZHN.js → kilo-cli-T2SRRRJS.js} +5 -5
- package/dist/kilo-cli-T2SRRRJS.js.map +1 -0
- package/dist/{kimi-IQJOIY6B.js → kimi-JMUFTVSF.js} +7 -7
- package/dist/kimi-JMUFTVSF.js.map +1 -0
- package/dist/{kimi-5FHEXGZD.js → kimi-MSIDEMCI.js} +4 -4
- package/dist/kimi-MSIDEMCI.js.map +1 -0
- package/dist/{kiro-WGOI5CGT.js → kiro-NYRRBIKW.js} +4 -4
- package/dist/kiro-NYRRBIKW.js.map +1 -0
- package/dist/{kiro-BYX4HEAJ.js → kiro-UWUCRKR3.js} +7 -7
- package/dist/kiro-UWUCRKR3.js.map +1 -0
- package/dist/{leaderboard-XEKS7B3H.js → leaderboard-NJWKGMXP.js} +7 -7
- package/dist/leaderboard-NJWKGMXP.js.map +1 -0
- package/dist/{mimo-code-7R53QDHB.js → mimo-code-BPNYYIVM.js} +7 -7
- package/dist/mimo-code-BPNYYIVM.js.map +1 -0
- package/dist/{mistral-vibe-LHJ55FSB.js → mistral-vibe-LT3DAJ3L.js} +6 -6
- package/dist/mistral-vibe-LT3DAJ3L.js.map +1 -0
- package/dist/{mux-XM6AP35L.js → mux-7PIJ7HUQ.js} +4 -4
- package/dist/mux-7PIJ7HUQ.js.map +1 -0
- package/dist/{mux-NYCNGL43.js → mux-AHNUAY5Z.js} +6 -6
- package/dist/mux-AHNUAY5Z.js.map +1 -0
- package/dist/{nemoclaw-WSIPSE7U.js → nemoclaw-RE5RZASZ.js} +7 -7
- package/dist/nemoclaw-RE5RZASZ.js.map +1 -0
- package/dist/{omp-562NK5BJ.js → omp-D2EXEPH7.js} +7 -7
- package/dist/omp-D2EXEPH7.js.map +1 -0
- package/dist/{open-interpreter-I2CNOEXY.js → open-interpreter-SSGBEUKX.js} +6 -6
- package/dist/open-interpreter-SSGBEUKX.js.map +1 -0
- package/dist/openclaw-IJ33K45M.js +17 -0
- package/dist/{openclaw-5EQFGOWL.js → openclaw-KAFTNLR2.js} +4 -4
- package/dist/openclaw-KAFTNLR2.js.map +1 -0
- package/dist/{opencode-YS4WX2E2.js → opencode-YKUKZY3J.js} +7 -7
- package/dist/opencode-YKUKZY3J.js.map +1 -0
- package/dist/{opencode-QGP4ALQY.js → opencode-Z65JYILL.js} +4 -4
- package/dist/opencode-Z65JYILL.js.map +1 -0
- package/dist/{openhands-QMYIKNOS.js → openhands-SEZMCUC3.js} +7 -7
- package/dist/openhands-SEZMCUC3.js.map +1 -0
- package/dist/{package-G25GVTH2.js → package-JECVQEFT.js} +15 -15
- package/dist/package-JECVQEFT.js.map +1 -0
- package/dist/{pi-GGDQREVG.js → pi-DLKCPOJE.js} +4 -4
- package/dist/pi-DLKCPOJE.js.map +1 -0
- package/dist/{pi-644FIN3A.js → pi-YPYV2ULH.js} +6 -6
- package/dist/pi-YPYV2ULH.js.map +1 -0
- package/dist/{qwen-code-GQILBJ5B.js → qwen-code-26CSFDX6.js} +4 -4
- package/dist/qwen-code-26CSFDX6.js.map +1 -0
- package/dist/{qwen-code-STDMX7EM.js → qwen-code-ZHCLCYMC.js} +9 -9
- package/dist/qwen-code-ZHCLCYMC.js.map +1 -0
- package/dist/{roo-code-DLPIHHQ6.js → roo-code-7F4HYB34.js} +6 -6
- package/dist/roo-code-7F4HYB34.js.map +1 -0
- package/dist/{roo-code-SUWI4BBN.js → roo-code-HSAE2CJU.js} +4 -4
- package/dist/roo-code-HSAE2CJU.js.map +1 -0
- package/dist/runtime/index.js +14 -14
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/test.js +11 -11
- package/dist/{serve-XTMIUHKK.js → serve-LYSBH43G.js} +16 -16
- package/dist/serve-LYSBH43G.js.map +1 -0
- package/dist/{status-VJAGO4Z7.js → status-PHKKGEW5.js} +11 -11
- package/dist/status-PHKKGEW5.js.map +1 -0
- package/dist/{statusline-EY2E2UGF.js → statusline-ZDD4OZ4F.js} +15 -15
- package/dist/statusline-ZDD4OZ4F.js.map +1 -0
- package/dist/{synthetic-6FRA7P5Q.js → synthetic-LUT6V6SD.js} +4 -4
- package/dist/synthetic-LUT6V6SD.js.map +1 -0
- package/dist/{telemetry-OLZQBADT.js → telemetry-HDGMI2BK.js} +10 -10
- package/dist/telemetry-HDGMI2BK.js.map +1 -0
- package/dist/{trae-CPPYASR2.js → trae-SIQI3C66.js} +4 -4
- package/dist/trae-SIQI3C66.js.map +1 -0
- package/dist/{trae-UOYD6JZZ.js → trae-Y67HSDOW.js} +6 -6
- package/dist/trae-Y67HSDOW.js.map +1 -0
- package/dist/{uninstall-AZEUPAND.js → uninstall-RWO2GM2I.js} +21 -21
- package/dist/uninstall-RWO2GM2I.js.map +1 -0
- package/dist/{upgrade-CAUUHSSC.js → upgrade-YJCXNUEE.js} +21 -21
- package/dist/upgrade-YJCXNUEE.js.map +1 -0
- package/dist/{usage-3KHZ4RYZ.js → usage-IWO4RQN6.js} +4 -4
- package/dist/usage-IWO4RQN6.js.map +1 -0
- package/dist/{usage-event-TZWOZPRJ.js → usage-event-AFFKCLHE.js} +15 -15
- package/dist/usage-event-AFFKCLHE.js.map +1 -0
- package/dist/{vscode-copilot-NIMH2DGU.js → vscode-copilot-5CI5B3X6.js} +7 -7
- package/dist/vscode-copilot-5CI5B3X6.js.map +1 -0
- package/dist/{warp-NRBBJQR2.js → warp-5YBSP7FP.js} +4 -4
- package/dist/warp-5YBSP7FP.js.map +1 -0
- package/dist/{warp-QYJGKURM.js → warp-INAKVGBV.js} +6 -6
- package/dist/warp-INAKVGBV.js.map +1 -0
- package/dist/{windsurf-75LLZ37C.js → windsurf-4HM57QAY.js} +6 -6
- package/dist/windsurf-4HM57QAY.js.map +1 -0
- package/dist/{zed-XJFOOKCO.js → zed-XXCNYOIN.js} +4 -4
- package/dist/zed-XXCNYOIN.js.map +1 -0
- package/dist/{zed-HKAZXEJW.js → zed-YN5X37PQ.js} +7 -7
- package/dist/zed-YN5X37PQ.js.map +1 -0
- package/package.json +92 -88
- package/dist/action-Q7GGO4PA.js.map +0 -1
- package/dist/amazon-q-ETMAGY3D.js.map +0 -1
- package/dist/amp-67BZONGF.js.map +0 -1
- package/dist/amp-BQZOL5GR.js.map +0 -1
- package/dist/antigravity-EA4L225L.js.map +0 -1
- package/dist/antigravity-VXLDLTO7.js +0 -18
- package/dist/antigravity-cli-B2HXZFYQ.js.map +0 -1
- package/dist/antigravity-cli-OM6SC3PE.js.map +0 -1
- package/dist/chunk-2Y2MZRLP.js.map +0 -1
- package/dist/chunk-3NH2ARIS.js.map +0 -1
- package/dist/chunk-4NHXLXSD.js.map +0 -1
- package/dist/chunk-5IOTP7LQ.js.map +0 -1
- package/dist/chunk-6TF7MHG5.js.map +0 -1
- package/dist/chunk-6WZODR3Z.js.map +0 -1
- package/dist/chunk-7F5KHLEP.js.map +0 -1
- package/dist/chunk-APZDTY76.js.map +0 -1
- package/dist/chunk-BEFVJ2OE.js.map +0 -1
- package/dist/chunk-D4ELPBB5.js.map +0 -1
- package/dist/chunk-FBJQGRET.js.map +0 -1
- package/dist/chunk-FJCUKXGX.js.map +0 -1
- package/dist/chunk-GZGLCCEE.js.map +0 -1
- package/dist/chunk-H33M77DD.js.map +0 -1
- package/dist/chunk-H53QZQJI.js.map +0 -1
- package/dist/chunk-I5UXHIDT.js.map +0 -1
- package/dist/chunk-ISEJWBFF.js.map +0 -1
- package/dist/chunk-IVAWP6HH.js.map +0 -1
- package/dist/chunk-JKKU2WKG.js.map +0 -1
- package/dist/chunk-KHO5WNTP.js.map +0 -1
- package/dist/chunk-MGTDQLJJ.js.map +0 -1
- package/dist/chunk-MQPNU2CY.js.map +0 -1
- package/dist/chunk-NBYKLUF6.js.map +0 -1
- package/dist/chunk-NLE2J5P4.js.map +0 -1
- package/dist/chunk-O7SDRBVB.js.map +0 -1
- package/dist/chunk-OP4KBXUO.js.map +0 -1
- package/dist/chunk-OPXAP3AC.js.map +0 -1
- package/dist/chunk-PAPMUAR5.js.map +0 -1
- package/dist/chunk-PW42ZXCB.js.map +0 -1
- package/dist/chunk-RK6VBLXP.js.map +0 -1
- package/dist/chunk-UM5S7DKK.js.map +0 -1
- package/dist/chunk-UMQ6NBQR.js.map +0 -1
- package/dist/chunk-XC5SJ35F.js.map +0 -1
- package/dist/chunk-XD7MY6HB.js.map +0 -1
- package/dist/chunk-YPAXJ7EW.js.map +0 -1
- package/dist/chunk-YT43MUSJ.js.map +0 -1
- package/dist/chunk-Z2MRSS2I.js.map +0 -1
- package/dist/claude-code-GRWO6XBZ.js.map +0 -1
- package/dist/claude-code-NMRKTAP7.js.map +0 -1
- package/dist/cline-25KW25IN.js.map +0 -1
- package/dist/codebuddy-ZNYQACMF.js.map +0 -1
- package/dist/codebuff-ETYT5UBL.js.map +0 -1
- package/dist/codebuff-VR6JUDIY.js.map +0 -1
- package/dist/codex-CPNKTXG3.js.map +0 -1
- package/dist/codex-YAORPCOD.js.map +0 -1
- package/dist/continue-WU2IB5KS.js.map +0 -1
- package/dist/copilot-cli-MZTAWMPW.js.map +0 -1
- package/dist/copilot-cli-PAP377OM.js.map +0 -1
- package/dist/crush-3AVQA4YU.js.map +0 -1
- package/dist/crush-QBXLNN7T.js.map +0 -1
- package/dist/cursor-DIW43TRZ.js.map +0 -1
- package/dist/cursor-GSLUET3V.js +0 -22
- package/dist/detect-6V4LC3MA.js.map +0 -1
- package/dist/devin-QMEM3OFA.js.map +0 -1
- package/dist/doctor-2YDUVSAU.js.map +0 -1
- package/dist/droid-MOKV53J4.js.map +0 -1
- package/dist/droid-U3ZBLQFO.js.map +0 -1
- package/dist/gemini-cli-47ZHCOZR.js.map +0 -1
- package/dist/gemini-cli-NMVVBO3K.js.map +0 -1
- package/dist/goose-4EI5MYTI.js.map +0 -1
- package/dist/goose-64V46Y2W.js.map +0 -1
- package/dist/grok-cli-QYQPDSVB.js.map +0 -1
- package/dist/hermes-F3EGTK6N.js.map +0 -1
- package/dist/hermes-F75OSK3Y.js.map +0 -1
- package/dist/hook-OEVRDMXD.js.map +0 -1
- package/dist/install-5NMCUDG5.js.map +0 -1
- package/dist/jetbrains-copilot-ZGIWI6YV.js.map +0 -1
- package/dist/junie-DIFN2P22.js.map +0 -1
- package/dist/kilo-EMZJBEBB.js.map +0 -1
- package/dist/kilo-SW7BH6EG.js.map +0 -1
- package/dist/kilo-cli-S3GXBPAE.js.map +0 -1
- package/dist/kilo-cli-ZF272ZHN.js.map +0 -1
- package/dist/kimi-5FHEXGZD.js.map +0 -1
- package/dist/kimi-IQJOIY6B.js.map +0 -1
- package/dist/kiro-BYX4HEAJ.js.map +0 -1
- package/dist/kiro-WGOI5CGT.js.map +0 -1
- package/dist/leaderboard-XEKS7B3H.js.map +0 -1
- package/dist/mimo-code-7R53QDHB.js.map +0 -1
- package/dist/mistral-vibe-LHJ55FSB.js.map +0 -1
- package/dist/mux-NYCNGL43.js.map +0 -1
- package/dist/mux-XM6AP35L.js.map +0 -1
- package/dist/nemoclaw-WSIPSE7U.js.map +0 -1
- package/dist/omp-562NK5BJ.js.map +0 -1
- package/dist/open-interpreter-I2CNOEXY.js.map +0 -1
- package/dist/openclaw-5EQFGOWL.js.map +0 -1
- package/dist/openclaw-7EYBQS4R.js +0 -17
- package/dist/opencode-QGP4ALQY.js.map +0 -1
- package/dist/opencode-YS4WX2E2.js.map +0 -1
- package/dist/openhands-QMYIKNOS.js.map +0 -1
- package/dist/package-G25GVTH2.js.map +0 -1
- package/dist/pi-644FIN3A.js.map +0 -1
- package/dist/pi-GGDQREVG.js.map +0 -1
- package/dist/qwen-code-GQILBJ5B.js.map +0 -1
- package/dist/qwen-code-STDMX7EM.js.map +0 -1
- package/dist/roo-code-DLPIHHQ6.js.map +0 -1
- package/dist/roo-code-SUWI4BBN.js.map +0 -1
- package/dist/serve-XTMIUHKK.js.map +0 -1
- package/dist/status-VJAGO4Z7.js.map +0 -1
- package/dist/statusline-EY2E2UGF.js.map +0 -1
- package/dist/synthetic-6FRA7P5Q.js.map +0 -1
- package/dist/telemetry-OLZQBADT.js.map +0 -1
- package/dist/trae-CPPYASR2.js.map +0 -1
- package/dist/trae-UOYD6JZZ.js.map +0 -1
- package/dist/uninstall-AZEUPAND.js.map +0 -1
- package/dist/upgrade-CAUUHSSC.js.map +0 -1
- package/dist/usage-3KHZ4RYZ.js.map +0 -1
- package/dist/usage-event-TZWOZPRJ.js.map +0 -1
- package/dist/vscode-copilot-NIMH2DGU.js.map +0 -1
- package/dist/warp-NRBBJQR2.js.map +0 -1
- package/dist/warp-QYJGKURM.js.map +0 -1
- package/dist/windsurf-75LLZ37C.js.map +0 -1
- package/dist/zed-HKAZXEJW.js.map +0 -1
- package/dist/zed-XJFOOKCO.js.map +0 -1
- /package/dist/{antigravity-VXLDLTO7.js.map → antigravity-TWIWXTQH.js.map} +0 -0
- /package/dist/{cursor-GSLUET3V.js.map → cursor-W7I4QUFO.js.map} +0 -0
- /package/dist/{openclaw-7EYBQS4R.js.map → openclaw-IJ33K45M.js.map} +0 -0
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
marketplaceEvidence
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-7C2IPIIB.js";
|
|
5
|
+
import "./chunk-C747DYNT.js";
|
|
6
6
|
import {
|
|
7
7
|
fail,
|
|
8
8
|
parseScope,
|
|
9
9
|
print
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-N4ENLZEU.js";
|
|
11
11
|
import {
|
|
12
12
|
detectInstalledPlatforms
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-GZZCHJDP.js";
|
|
14
14
|
import {
|
|
15
15
|
findConnectorConfig,
|
|
16
16
|
listRegisteredConnectors,
|
|
17
17
|
loadConnectorFromPath
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import "./chunk-
|
|
18
|
+
} from "./chunk-3EP5V2F4.js";
|
|
19
|
+
import "./chunk-7ZFK2WEO.js";
|
|
20
20
|
import {
|
|
21
21
|
loadAdapter
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
22
|
+
} from "./chunk-NDMNMAKP.js";
|
|
23
|
+
import "./chunk-KFPSJRHR.js";
|
|
24
|
+
import "./chunk-ILWHLGIC.js";
|
|
25
25
|
import {
|
|
26
26
|
dataRoot,
|
|
27
27
|
homeBinPath
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-QYOUQCC6.js";
|
|
29
29
|
|
|
30
30
|
// src/cli/commands/status.ts
|
|
31
31
|
import { parseArgs } from "util";
|
|
@@ -139,4 +139,4 @@ async function run(argv) {
|
|
|
139
139
|
export {
|
|
140
140
|
run
|
|
141
141
|
};
|
|
142
|
-
//# sourceMappingURL=status-
|
|
142
|
+
//# sourceMappingURL=status-PHKKGEW5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/status.ts"],"sourcesContent":["/**\r\n * cli/commands/status — a light, glanceable install-state summary.\r\n *\r\n * There is NO MCP standard for \"which connectors are installed into which host\r\n * configs on this machine\" — distribution/wire standards (server.json, MCPB,\r\n * the lifecycle) cover publishing + the protocol, not local install state. So\r\n * `status` is purely agent-connector infrastructure, and we design it for the\r\n * everyday question it answers in one line per platform:\r\n *\r\n * \"which of my connectors are present on which hosts?\"\r\n *\r\n * It REUSES detect (host enumeration) + the adapters' own config-path resolvers\r\n * (a read-only presence check) — NO new adapter SPI methods. Unlike `doctor`\r\n * (deep health checks, non-zero exit on failure) and `doctor --probe` (a live\r\n * protocol probe that FAILs on a dead server), `status` ALWAYS exits 0: it\r\n * describes, it never gates. A connector being absent is informational.\r\n */\r\n\r\nimport { parseArgs } from \"node:util\";\r\nimport { readFileSync } from \"node:fs\";\r\n\r\nimport type { InstallScope, PlatformId, ResolvedConnector } from \"../../core/types.js\";\r\nimport type { InstallContext } from \"../../adapters/spi.js\";\r\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\r\nimport { loadAdapter } from \"../../adapters/registry.js\";\r\nimport {\r\n findConnectorConfig,\r\n listRegisteredConnectors,\r\n loadConnectorFromPath,\r\n} from \"../../core/load-connector.js\";\r\nimport { marketplaceEvidence } from \"../../core/marketplace-state.js\";\r\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\r\nimport { fail, parseScope, print } from \"../app.js\";\r\n\r\n/**\r\n * Resolve which connector(s) status reports on: an explicit --connector path or\r\n * a local config first, else every connector registered under the data-root\r\n * (what is actually installed). Empty array when none — status still lists the\r\n * detected platforms.\r\n */\r\nasync function resolveConnectors(\r\n connectorPath: string | undefined,\r\n projectDir: string,\r\n): Promise<ResolvedConnector[]> {\r\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\r\n if (configPath) {\r\n try {\r\n const { connector } = await loadConnectorFromPath(configPath);\r\n return [connector];\r\n } catch {\r\n /* fall through to the registry */\r\n }\r\n }\r\n return listRegisteredConnectors();\r\n}\r\n\r\nfunction buildContext(\r\n connector: ResolvedConnector,\r\n id: PlatformId,\r\n scope: InstallScope,\r\n projectDir: string,\r\n): InstallContext {\r\n return {\r\n connector,\r\n scope: connector.platforms[id]?.scope ?? scope,\r\n projectDir,\r\n homeBinPath: homeBinPath(),\r\n dataRoot: dataRoot(),\r\n dryRun: true,\r\n };\r\n}\r\n\r\n/** Read-only: does the file at `path` mention `needle`? Missing/unreadable → false. */\r\nfunction fileMentions(path: string, needle: string): boolean {\r\n try {\r\n return readFileSync(path, \"utf8\").includes(needle);\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\ninterface ConnStatus {\r\n id: string;\r\n serverPresent: boolean;\r\n hooksPresent: boolean;\r\n /**\r\n * Delivery method actually present on this host: `direct` (managed entries in\r\n * the host config), `marketplace` (the host's own plugin state / our install\r\n * record), `both` (the double-install invariant is VIOLATED — doctor FAILs\r\n * it), or null when absent.\r\n */\r\n method: \"direct\" | \"marketplace\" | \"both\" | null;\r\n}\r\ninterface StatusRow {\r\n platform: PlatformId;\r\n scope: InstallScope;\r\n configPath: string;\r\n connectors: ConnStatus[];\r\n}\r\n\r\nexport async function run(argv: string[]): Promise<number> {\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n scope: { type: \"string\", default: \"user\" },\r\n connector: { type: \"string\" },\r\n project: { type: \"string\" },\r\n json: { type: \"boolean\", default: false },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n const projectDir = values.project ?? process.cwd();\r\n const scope = parseScope(values.scope);\r\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\r\n\r\n const connectors = await resolveConnectors(values.connector, projectDir);\r\n const detected = await detectInstalledPlatforms(projectDir);\r\n\r\n const rows: StatusRow[] = [];\r\n for (const p of detected) {\r\n const adapter = await loadAdapter(p.id);\r\n if (!adapter) continue;\r\n const connStatuses: ConnStatus[] = connectors.map((connector) => {\r\n const ctx = buildContext(connector, p.id, scope, projectDir);\r\n let serverPath = \"\";\r\n let hookPath = \"\";\r\n try {\r\n serverPath = adapter.getServerConfigPath(ctx);\r\n } catch {\r\n /* adapter has no server config path */\r\n }\r\n try {\r\n hookPath = adapter.getHookConfigPath(ctx);\r\n } catch {\r\n /* adapter has no hook config path */\r\n }\r\n const serverPresent = serverPath\r\n ? fileMentions(serverPath, connector.id)\r\n : false;\r\n const hooksPresent = hookPath ? fileMentions(hookPath, connector.id) : false;\r\n const direct = serverPresent || hooksPresent;\r\n const viaMarketplace = marketplaceEvidence(connector.id, p.id) != null;\r\n return {\r\n id: connector.id,\r\n serverPresent,\r\n hooksPresent,\r\n method: direct && viaMarketplace\r\n ? (\"both\" as const)\r\n : direct\r\n ? (\"direct\" as const)\r\n : viaMarketplace\r\n ? (\"marketplace\" as const)\r\n : null,\r\n };\r\n });\r\n rows.push({\r\n platform: p.id,\r\n scope: p.scope,\r\n configPath: p.configPath,\r\n connectors: connStatuses,\r\n });\r\n }\r\n\r\n if (values.json) {\r\n print(JSON.stringify(rows, null, 2));\r\n return 0;\r\n }\r\n\r\n if (rows.length === 0) {\r\n print(\"status: no agent platforms detected.\");\r\n return 0;\r\n }\r\n if (connectors.length === 0) {\r\n print(\"status: no connectors found (pass --connector <path> or install one).\\n\");\r\n }\r\n\r\n for (const r of rows) {\r\n print(`${r.platform} [${r.scope}] ${r.configPath}`);\r\n if (r.connectors.length === 0) {\r\n print(\" (no connectors to check)\");\r\n } else {\r\n for (const c of r.connectors) {\r\n const mark = c.method != null ? \"[installed]\" : \"[absent ]\";\r\n const server = c.serverPresent ? \"server ✓\" : \"server ·\";\r\n const hooks = c.hooksPresent ? \"hooks ✓\" : \"hooks ·\";\r\n // `both(!)` flags a violated one-method-per-host invariant — doctor's\r\n // duplicate-registration check FAILs it with the fix.\r\n const method =\r\n c.method == null ? \"\" : c.method === \"both\" ? \" (both!)\" : ` (${c.method})`;\r\n print(` ${mark} ${c.id} ${server} ${hooks}${method}`);\r\n }\r\n }\r\n print(\"\");\r\n }\r\n\r\n // Always 0: status is descriptive (what is installed where), never a gate —\r\n // that contrast with doctor (non-zero on FAIL) is the reason it exists.\r\n return 0;\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runStatusline
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-FHYR5Q5T.js";
|
|
5
|
+
import "./chunk-LFWYYWLV.js";
|
|
6
|
+
import "./chunk-SLJI5BOM.js";
|
|
7
|
+
import "./chunk-GZZCHJDP.js";
|
|
8
|
+
import "./chunk-GCPEPUD7.js";
|
|
9
|
+
import "./chunk-IOJDZJ72.js";
|
|
10
|
+
import "./chunk-4GH2KA7V.js";
|
|
11
|
+
import "./chunk-3EP5V2F4.js";
|
|
12
|
+
import "./chunk-7ZFK2WEO.js";
|
|
13
|
+
import "./chunk-NDMNMAKP.js";
|
|
14
|
+
import "./chunk-KFPSJRHR.js";
|
|
15
|
+
import "./chunk-Y3K6KJMS.js";
|
|
16
|
+
import "./chunk-ILWHLGIC.js";
|
|
17
|
+
import "./chunk-QYOUQCC6.js";
|
|
18
18
|
|
|
19
19
|
// src/cli/commands/statusline.ts
|
|
20
20
|
import { parseArgs } from "util";
|
|
@@ -57,4 +57,4 @@ async function run(argv) {
|
|
|
57
57
|
export {
|
|
58
58
|
run
|
|
59
59
|
};
|
|
60
|
-
//# sourceMappingURL=statusline-
|
|
60
|
+
//# sourceMappingURL=statusline-ZDD4OZ4F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/statusline.ts"],"sourcesContent":["/**\r\n * cli/commands/statusline — the universal statusline (HUD) entrypoint.\r\n *\r\n * agent-connector statusline <platform> --connector <id>\r\n *\r\n * A statusline-supporting host points its status line config at the single stable\r\n * home binary (via core/spawn.buildHomeBinStatuslineCommand). This command reads\r\n * the ENTIRE host payload from stdin, dispatches through runStatusline, writes the\r\n * rendered line to stdout, and exits with the adapter's exit code.\r\n *\r\n * FAIL-SAFE is the runtime's contract: a status line must NEVER wedge the host or\r\n * spew an error into the status bar. runStatusline never rejects (always exits 0\r\n * with at most a rendered line), and even a malformed invocation here degrades to\r\n * exit 0 with no output — never the strict `fail()` non-zero used by other\r\n * commands.\r\n */\r\n\r\nimport { parseArgs } from \"node:util\";\r\n\r\nimport { runStatusline } from \"../../runtime/index.js\";\r\n\r\n/** Read all of a readable stream to a UTF-8 string. */\r\nasync function readAll(stream: NodeJS.ReadStream): Promise<string> {\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of stream) {\r\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\r\n }\r\n return Buffer.concat(chunks).toString(\"utf8\");\r\n}\r\n\r\nexport async function run(argv: string[]): Promise<number> {\r\n // strict:false so a future flag from a newer install can never make this throw\r\n // and surface a non-zero exit into the host's status bar.\r\n let platformId = \"\";\r\n let connectorId = \"\";\r\n try {\r\n const { values, positionals } = parseArgs({\r\n args: argv,\r\n options: { connector: { type: \"string\" } },\r\n allowPositionals: true,\r\n strict: false,\r\n });\r\n platformId = positionals[0] ?? \"\";\r\n connectorId = typeof values.connector === \"string\" ? values.connector : \"\";\r\n } catch {\r\n // A malformed invocation must still fail-safe (render nothing, exit 0).\r\n return 0;\r\n }\r\n\r\n // Drain stdin regardless — a host expects the command to consume its payload.\r\n const stdin = await readAll(process.stdin).catch(() => \"\");\r\n\r\n // Missing platform/connector → render nothing, exit 0 (never a non-zero exit).\r\n if (platformId === \"\" || connectorId === \"\") {\r\n return 0;\r\n }\r\n\r\n const reply = await runStatusline({ platformId, connectorId, stdin });\r\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\r\n process.stdout.write(reply.stdout);\r\n }\r\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\r\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\r\n }\r\n return reply.exitCode;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,SAAS,iBAAiB;AAK1B,eAAe,QAAQ,QAA4C;AACjE,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ;AAChC,WAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,EACpE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,eAAsB,IAAI,MAAiC;AAGzD,MAAI,aAAa;AACjB,MAAI,cAAc;AAClB,MAAI;AACF,UAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,MACxC,MAAM;AAAA,MACN,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,EAAE;AAAA,MACzC,kBAAkB;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AACD,iBAAa,YAAY,CAAC,KAAK;AAC/B,kBAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAAA,EAC1E,QAAQ;AAEN,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,MAAM,EAAE;AAGzD,MAAI,eAAe,MAAM,gBAAgB,IAAI;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,cAAc,EAAE,YAAY,aAAa,MAAM,CAAC;AACpE,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,MAAM;AAAA,EACnC;AACA,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AACA,SAAO,MAAM;AACf;","names":[]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
openSqlite
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XZWMJLIT.js";
|
|
5
5
|
import {
|
|
6
6
|
expandHome
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KM2YXO6V.js";
|
|
8
8
|
import {
|
|
9
9
|
emptyTokens,
|
|
10
10
|
inferProvider
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7PSNXUFK.js";
|
|
12
12
|
|
|
13
13
|
// src/usage/readers/synthetic.ts
|
|
14
14
|
import { homedir } from "os";
|
|
@@ -175,4 +175,4 @@ var synthetic_default = syntheticReader;
|
|
|
175
175
|
export {
|
|
176
176
|
synthetic_default as default
|
|
177
177
|
};
|
|
178
|
-
//# sourceMappingURL=synthetic-
|
|
178
|
+
//# sourceMappingURL=synthetic-LUT6V6SD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/synthetic.ts"],"sourcesContent":["/**\r\n * usage/readers/synthetic — Synthetic.new (Octofriend / HF gateway) usage reader.\r\n *\r\n * Faithful port of tokscale sessions/synthetic.rs (parse_octofriend_sqlite). The\r\n * Octofriend client persists usage in a single SQLite database. Per the tokscale\r\n * scanner (scanner.rs), the db lives at:\r\n * ${XDG_DATA_HOME:-~/.local/share}/octofriend/sqlite.db\r\n * (an AGENT_CONNECTOR_SYNTHETIC_DIR override is honored first — verbatim,\r\n * non-empty — mirroring the paths.ts env-override contract; `synthetic` is not\r\n * yet wired into paths.ts hostRoots, so the path is resolved here.)\r\n *\r\n * Octofriend historically stored only input_history (no token data), so the\r\n * parser is future-proofed: it first checks sqlite_master for any of the\r\n * token-tracking tables ('messages', 'sessions', 'token_usage'); when none\r\n * exist it yields []. When present it parses the `messages` table (the full\r\n * schema with cache + reasoning + cost), falling back to the simpler\r\n * `token_usage` table only when `messages` produced no rows.\r\n *\r\n * messages table (port of the primary SELECT):\r\n * SELECT id, model, input_tokens, output_tokens, cache_read_tokens,\r\n * cache_write_tokens, reasoning_tokens, cost, timestamp, session_id,\r\n * provider\r\n * FROM messages\r\n * WHERE input_tokens IS NOT NULL OR output_tokens IS NOT NULL\r\n * → input/output/cacheRead/cacheWrite/reasoning each clamped ≥ 0; a row whose\r\n * 5-dimension sum is 0 is skipped; cost ≥ 0; provider column (fallback\r\n * \"synthetic\" when missing/empty); dedup_key = id.\r\n *\r\n * token_usage fallback (only when messages yielded nothing):\r\n * SELECT id, model, input_tokens, output_tokens, timestamp, session_id\r\n * FROM token_usage\r\n * WHERE input_tokens > 0 OR output_tokens > 0\r\n * → only input/output (cache + reasoning = 0); provider hardcoded \"synthetic\";\r\n * cost = 0; dedup_key = id.\r\n *\r\n * Model normalization (port of normalize_synthetic_model): strips synthetic.new\r\n * gateway prefixes for a clean grouping id:\r\n * \"hf:deepseek-ai/DeepSeek-V3-0324\" → \"deepseek-v3-0324\"\r\n * \"accounts/fireworks/models/deepseek-v3-0324\" → \"deepseek-v3-0324\"\r\n * Provider is inferProvider() of the cleaned model, falling back to the row's\r\n * provider column (or \"synthetic\"). Timestamp is the f64 `timestamp` column:\r\n * values > 1e12 are already ms, smaller values are seconds (×1000). No project\r\n * attribution exists in the Octofriend schema. Confidence is host-reported, but\r\n * the spec rates this source medium (the schema is still emergent/future-proofed),\r\n * so rows are marked \"host-estimated\" to label that honestly.\r\n *\r\n * Fail-open: db missing/locked/unreadable / non-sqlite → openSqlite returns null\r\n * → []; a bad row is skipped, never thrown.\r\n */\r\n\r\nimport { homedir } from \"node:os\";\r\nimport { isAbsolute, join, resolve } from \"node:path\";\r\n\r\nimport type { UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { inferProvider } from \"../normalize.js\";\r\nimport { expandHome } from \"../paths.js\";\r\nimport { openSqlite } from \"../sqlite.js\";\r\n\r\nconst PLATFORM_ID = \"synthetic\" as const;\r\nconst DEFAULT_PROVIDER = \"synthetic\";\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Octofriend db-path resolution (port of scanner.rs synthetic_db discovery).\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Read an env override, treating empty/blank as unset (mirrors the paths.ts\r\n * envOverride contract: an empty override must NOT resolve to \"\"). Relative\r\n * paths resolve against the process CWD; a leading \"~\" is expanded.\r\n */\r\nfunction envOverride(name: string): string | undefined {\r\n const raw = process.env[name];\r\n if (raw == null || raw.trim() === \"\") return undefined;\r\n const expanded = expandHome(raw.trim());\r\n return isAbsolute(expanded) ? expanded : resolve(expanded);\r\n}\r\n\r\n/** $XDG_DATA_HOME (when set & non-empty) else ~/.local/share — as in paths.ts. */\r\nfunction xdgDataHome(): string {\r\n const xdg = process.env.XDG_DATA_HOME;\r\n if (xdg && xdg.trim() !== \"\") return resolve(expandHome(xdg.trim()));\r\n return join(homedir(), \".local\", \"share\");\r\n}\r\n\r\n/**\r\n * Resolve the Octofriend sqlite.db path. Honors AGENT_CONNECTOR_SYNTHETIC_DIR\r\n * first (treated as the octofriend directory: `<dir>/sqlite.db`), else the\r\n * tokscale default `${XDG_DATA_HOME:-~/.local/share}/octofriend/sqlite.db`.\r\n */\r\nfunction octofriendDbPath(): string {\r\n const override = envOverride(\"AGENT_CONNECTOR_SYNTHETIC_DIR\");\r\n if (override !== undefined) return join(override, \"sqlite.db\");\r\n return join(xdgDataHome(), \"octofriend\", \"sqlite.db\");\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Model normalization (port of normalize_synthetic_model).\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Normalize a synthetic.new model id to a standard form, lowercased:\r\n * \"hf:<org>/<model>\" → \"<model>\"\r\n * \"hf:<model>\" → \"<model>\"\r\n * \"accounts/<provider>/models/<model>\" → \"<model>\"\r\n * Any other id passes through lowercased. Mirrors the Rust strip_prefix /\r\n * split_once chain exactly.\r\n */\r\nfunction normalizeSyntheticModel(modelId: string): string {\r\n const lower = modelId.toLowerCase();\r\n\r\n // Strip \"hf:\" prefix and (optional) org name.\r\n if (lower.startsWith(\"hf:\")) {\r\n const rest = lower.slice(\"hf:\".length);\r\n const slash = rest.indexOf(\"/\");\r\n if (slash >= 0) return rest.slice(slash + 1);\r\n return rest;\r\n }\r\n\r\n // Strip \"accounts/<provider>/models/\" prefix.\r\n if (lower.startsWith(\"accounts/\")) {\r\n const rest = lower.slice(\"accounts/\".length);\r\n const marker = \"/models/\";\r\n const idx = rest.indexOf(marker);\r\n if (idx >= 0) return rest.slice(idx + marker.length);\r\n }\r\n\r\n return lower;\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Cell coercion & timestamp.\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** Coerce a SQLite cell to an integer (Rust get::<i64>().unwrap_or(0)), no clamp. */\r\nfunction toInt(v: unknown): number {\r\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\r\n if (!Number.isFinite(n)) return 0;\r\n return Math.trunc(n);\r\n}\r\n\r\n/** Coerce a SQLite cell to a float (Rust get::<f64>().unwrap_or(0.0)). */\r\nfunction toFloat(v: unknown): number {\r\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\r\n return Number.isFinite(n) ? n : 0;\r\n}\r\n\r\n/** Coerce to a non-empty trimmed string, or undefined. */\r\nfunction toStr(v: unknown): string | undefined {\r\n if (typeof v !== \"string\") return undefined;\r\n return v;\r\n}\r\n\r\n/**\r\n * Convert the f64 `timestamp` column to epoch ms (port of the Rust branch):\r\n * values > 1e12 are already milliseconds (cast); smaller values are seconds\r\n * (×1000). Truncating, matching the Rust `as i64`.\r\n */\r\nfunction timestampToMs(timestamp: number): number {\r\n return timestamp > 1e12 ? Math.trunc(timestamp) : Math.trunc(timestamp * 1000);\r\n}\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Table presence check (port of the sqlite_master count).\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\nconst TABLE_CHECK_SQL = `\r\n SELECT count(*) AS n\r\n FROM sqlite_master\r\n WHERE type='table' AND name IN ('messages', 'sessions', 'token_usage')\r\n`;\r\n\r\n/** Row shape for the primary `messages` SELECT (all cells optional / unknown). */\r\ninterface MessagesRow {\r\n id?: unknown;\r\n model?: unknown;\r\n input_tokens?: unknown;\r\n output_tokens?: unknown;\r\n cache_read_tokens?: unknown;\r\n cache_write_tokens?: unknown;\r\n reasoning_tokens?: unknown;\r\n cost?: unknown;\r\n timestamp?: unknown;\r\n session_id?: unknown;\r\n provider?: unknown;\r\n}\r\n\r\nconst MESSAGES_SQL = `\r\n SELECT id, model, input_tokens, output_tokens, cache_read_tokens,\r\n cache_write_tokens, reasoning_tokens, cost, timestamp, session_id, provider\r\n FROM messages\r\n WHERE input_tokens IS NOT NULL OR output_tokens IS NOT NULL\r\n`;\r\n\r\n/** Row shape for the `token_usage` fallback SELECT. */\r\ninterface TokenUsageRow {\r\n id?: unknown;\r\n model?: unknown;\r\n input_tokens?: unknown;\r\n output_tokens?: unknown;\r\n timestamp?: unknown;\r\n session_id?: unknown;\r\n}\r\n\r\nconst TOKEN_USAGE_SQL = `\r\n SELECT id, model, input_tokens, output_tokens, timestamp, session_id\r\n FROM token_usage\r\n WHERE input_tokens > 0 OR output_tokens > 0\r\n`;\r\n\r\n// ─────────────────────────────────────────────────────────────────────────\r\n// Reader\r\n// ─────────────────────────────────────────────────────────────────────────\r\n\r\n/** The Synthetic.new (Octofriend) usage reader singleton. */\r\nconst syntheticReader: UsageReader = {\r\n platformId: PLATFORM_ID,\r\n kind: \"local\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n const dbPath = octofriendDbPath();\r\n\r\n const db = await openSqlite(dbPath);\r\n if (db === null) return []; // missing / locked / unreadable / non-sqlite → fail-open\r\n\r\n try {\r\n // Future-proofing: only parse when a token-tracking table exists.\r\n const tableCheck = db.all(TABLE_CHECK_SQL);\r\n const tableCount = tableCheck.length > 0 ? toInt(tableCheck[0]?.n) : 0;\r\n if (tableCount <= 0) return [];\r\n\r\n const records: UsageRecord[] = [];\r\n\r\n // Primary schema: the `messages` table (full token breakdown + cost).\r\n const messageRows = db.all(MESSAGES_SQL); // bad SQL / schema mismatch → []\r\n for (const raw of messageRows) {\r\n const row = raw as MessagesRow;\r\n\r\n const id = toStr(row.id);\r\n if (id === undefined) continue; // Rust requires id (row.get(0)? bails otherwise)\r\n\r\n const rawModel = toStr(row.model) ?? \"\";\r\n const input = Math.max(0, toInt(row.input_tokens));\r\n const output = Math.max(0, toInt(row.output_tokens));\r\n const cacheRead = Math.max(0, toInt(row.cache_read_tokens));\r\n const cacheWrite = Math.max(0, toInt(row.cache_write_tokens));\r\n const reasoning = Math.max(0, toInt(row.reasoning_tokens));\r\n\r\n // Skip zero-token rows (Rust: total == 0 → continue), using raw (signed) sums.\r\n const total =\r\n toInt(row.input_tokens) +\r\n toInt(row.output_tokens) +\r\n toInt(row.cache_read_tokens) +\r\n toInt(row.cache_write_tokens) +\r\n toInt(row.reasoning_tokens);\r\n if (total === 0) continue;\r\n\r\n const cost = Math.max(0, toFloat(row.cost));\r\n const ts = timestampToMs(toFloat(row.timestamp));\r\n if (sinceMs !== undefined && ts < sinceMs) continue;\r\n\r\n const sessionId = toStr(row.session_id) ?? \"unknown\";\r\n // Provider: row column when present, else \"synthetic\" (Rust unwrap_or).\r\n const rowProvider = toStr(row.provider);\r\n const columnProvider =\r\n rowProvider !== undefined && rowProvider !== \"\" ? rowProvider : DEFAULT_PROVIDER;\r\n\r\n const modelId = normalizeSyntheticModel(rawModel);\r\n const providerId = inferProvider(modelId) ?? columnProvider;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.cacheWrite = cacheWrite;\r\n tokens.reasoning = reasoning;\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId,\r\n providerId,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n dedupKey: id, // messages.id → one record per row\r\n confidence: \"host-estimated\", // spec rates this source medium\r\n };\r\n if (cost > 0) record.cost = cost;\r\n records.push(record);\r\n }\r\n\r\n // Fallback schema: only when `messages` produced nothing.\r\n if (records.length === 0) {\r\n const tokenRows = db.all(TOKEN_USAGE_SQL);\r\n for (const raw of tokenRows) {\r\n const row = raw as TokenUsageRow;\r\n\r\n const id = toStr(row.id);\r\n if (id === undefined) continue;\r\n\r\n const rawModel = toStr(row.model) ?? \"\";\r\n const input = Math.max(0, toInt(row.input_tokens));\r\n const output = Math.max(0, toInt(row.output_tokens));\r\n\r\n const ts = timestampToMs(toFloat(row.timestamp));\r\n if (sinceMs !== undefined && ts < sinceMs) continue;\r\n\r\n const sessionId = toStr(row.session_id) ?? \"unknown\";\r\n const modelId = normalizeSyntheticModel(rawModel);\r\n const providerId = inferProvider(modelId) ?? DEFAULT_PROVIDER;\r\n\r\n const tokens = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n // cacheRead / cacheWrite / reasoning stay 0 (token_usage has no such columns).\r\n\r\n const record: UsageRecord = {\r\n platformId: PLATFORM_ID,\r\n modelId,\r\n providerId,\r\n sessionId,\r\n tokens,\r\n ts,\r\n messageCount: 1,\r\n dedupKey: id,\r\n confidence: \"host-estimated\",\r\n };\r\n records.push(record);\r\n }\r\n }\r\n\r\n return records;\r\n } finally {\r\n db.close();\r\n }\r\n },\r\n};\r\n\r\nexport default syntheticReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -8,25 +8,25 @@ import {
|
|
|
8
8
|
mcpLeaderboard,
|
|
9
9
|
surfaceLeaderboard,
|
|
10
10
|
toolLeaderboard
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-Q7PR2WGT.js";
|
|
12
12
|
import {
|
|
13
13
|
fail,
|
|
14
14
|
print
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-N4ENLZEU.js";
|
|
16
16
|
import {
|
|
17
17
|
openStore
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-IOJDZJ72.js";
|
|
19
19
|
import {
|
|
20
20
|
connectorFromMeta,
|
|
21
21
|
listRegisteredConnectors,
|
|
22
22
|
loadRegisteredConnector,
|
|
23
23
|
readRegisteredMeta
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-3EP5V2F4.js";
|
|
25
|
+
import "./chunk-7ZFK2WEO.js";
|
|
26
|
+
import "./chunk-NDMNMAKP.js";
|
|
27
|
+
import "./chunk-KFPSJRHR.js";
|
|
28
|
+
import "./chunk-ILWHLGIC.js";
|
|
29
|
+
import "./chunk-QYOUQCC6.js";
|
|
30
30
|
|
|
31
31
|
// src/cli/commands/telemetry.ts
|
|
32
32
|
import { writeFileSync } from "fs";
|
|
@@ -349,4 +349,4 @@ export {
|
|
|
349
349
|
parseSince,
|
|
350
350
|
run
|
|
351
351
|
};
|
|
352
|
-
//# sourceMappingURL=telemetry-
|
|
352
|
+
//# sourceMappingURL=telemetry-HDGMI2BK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/telemetry.ts","../src/telemetry/report.ts"],"sourcesContent":["/**\r\n * cli/commands/telemetry — inspect the local per-tool token telemetry store.\r\n *\r\n * Subcommands:\r\n * report --by tool|session|project (default tool) --since 7d|24h|… --connector <id> [--json]\r\n * → summarize(openStore({}), …) + formatReport (the aligned table).\r\n * export --format csv|json (default json) --out <file> [--since/--connector …]\r\n * → toCSV / toJSONExport of the raw records.\r\n *\r\n * Telemetry rows are aggregate counts only (never raw arguments/results).\r\n */\r\n\r\nimport { writeFileSync } from \"node:fs\";\r\nimport { parseArgs } from \"node:util\";\r\n\r\nimport type { QueryFilter } from \"../../telemetry/types.js\";\r\nimport type { RollupDimension } from \"../../telemetry/report.js\";\r\nimport { openStore } from \"../../telemetry/store.js\";\r\nimport { summarize, toCSV, toJSONExport } from \"../../telemetry/report.js\";\r\nimport {\r\n formatMcpLeaderboard,\r\n formatSurfaceLeaderboard,\r\n formatToolLeaderboard,\r\n isScopeFilter,\r\n mcpLeaderboard,\r\n SCOPE_FILTER_VALUES,\r\n surfaceLeaderboard,\r\n toolLeaderboard,\r\n type LeaderboardOptions,\r\n type ScopeFilter,\r\n type SurfaceLeaderboardOptions,\r\n} from \"../../telemetry/leaderboard.js\";\r\nimport {\r\n connectorFromMeta,\r\n listRegisteredConnectors,\r\n loadRegisteredConnector,\r\n readRegisteredMeta,\r\n} from \"../../core/load-connector.js\";\r\nimport type { ResolvedConnector } from \"../../core/types.js\";\r\nimport { fail, print } from \"../app.js\";\r\n\r\n/**\r\n * Parse a relative duration (`Ns`/`Nm`/`Nh`/`Nd`) to a lower-bound epoch ms.\r\n * Returns undefined for an empty input and null for a malformed one.\r\n */\r\nexport function parseSince(since: string | undefined): number | null | undefined {\r\n if (since == null || since.trim() === \"\") return undefined;\r\n const m = since.trim().match(/^(\\d+)\\s*([smhd])$/i);\r\n if (!m || !m[1] || !m[2]) return null;\r\n const n = Number(m[1]);\r\n const unitMs: Record<string, number> = {\r\n s: 1000,\r\n m: 60_000,\r\n h: 3_600_000,\r\n d: 86_400_000,\r\n };\r\n const factor = unitMs[m[2].toLowerCase()];\r\n if (factor == null) return null;\r\n return Date.now() - n * factor;\r\n}\r\n\r\n/** Build a QueryFilter from the shared --since / --connector flags. */\r\nfunction buildFilter(\r\n since: string | undefined,\r\n connectorId: string | undefined,\r\n): QueryFilter | null {\r\n const sinceMs = parseSince(since);\r\n if (sinceMs === null) return null;\r\n const filter: QueryFilter = {};\r\n if (sinceMs !== undefined) filter.sinceMs = sinceMs;\r\n if (connectorId && connectorId.trim() !== \"\") filter.connectorId = connectorId;\r\n return filter;\r\n}\r\n\r\nfunction runReport(argv: string[]): number {\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n by: { type: \"string\", default: \"tool\" },\r\n since: { type: \"string\" },\r\n connector: { type: \"string\" },\r\n json: { type: \"boolean\", default: false },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n const by = values.by;\r\n if (by !== \"tool\" && by !== \"session\" && by !== \"project\") {\r\n return fail(`invalid --by \"${by}\" (use tool|session|project)`);\r\n }\r\n const dimension: RollupDimension = by;\r\n\r\n const filter = buildFilter(values.since, values.connector);\r\n if (filter === null) {\r\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\r\n }\r\n\r\n const store = openStore({});\r\n try {\r\n const { rows, text } = summarize(store, { by: dimension, filter });\r\n if (values.json) {\r\n print(JSON.stringify(rows, null, 2));\r\n } else {\r\n print(text);\r\n }\r\n } finally {\r\n store.close();\r\n }\r\n return 0;\r\n}\r\n\r\nfunction runExport(argv: string[]): number {\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n format: { type: \"string\", default: \"json\" },\r\n out: { type: \"string\" },\r\n since: { type: \"string\" },\r\n connector: { type: \"string\" },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n const format = values.format;\r\n if (format !== \"csv\" && format !== \"json\") {\r\n return fail(`invalid --format \"${format}\" (use csv|json)`);\r\n }\r\n\r\n const filter = buildFilter(values.since, values.connector);\r\n if (filter === null) {\r\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\r\n }\r\n\r\n const store = openStore({});\r\n let serialized: string;\r\n try {\r\n const records = store.query(filter);\r\n serialized = format === \"csv\" ? toCSV(records) : toJSONExport(records);\r\n } finally {\r\n store.close();\r\n }\r\n\r\n if (values.out && values.out.trim() !== \"\") {\r\n writeFileSync(values.out, serialized, \"utf8\");\r\n print(`wrote ${format.toUpperCase()} export → ${values.out}`);\r\n } else {\r\n print(serialized);\r\n }\r\n return 0;\r\n}\r\n\r\n/**\r\n * `telemetry leaderboard` — rank the per-MCP telemetry by connector (--by mcp,\r\n * the default and signature \"which MCP server costs the most\" metric), by tool\r\n * (--by tool), or by developer-axis surface (--by surface — the FIVE surfaces:\r\n * server + hook runtime rows plus static command/skill/subagent footprints).\r\n * Honors --since / --connector and the scope slice (--scope).\r\n */\r\nasync function runLeaderboard(argv: string[]): Promise<number> {\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n by: { type: \"string\", default: \"mcp\" },\r\n since: { type: \"string\" },\r\n connector: { type: \"string\" },\r\n scope: { type: \"string\" },\r\n json: { type: \"boolean\", default: false },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n const by = values.by;\r\n if (by !== \"mcp\" && by !== \"tool\" && by !== \"surface\") {\r\n return fail(`invalid --by \"${by}\" (use mcp|tool|surface)`);\r\n }\r\n\r\n const sinceMs = parseSince(values.since);\r\n if (sinceMs === null) {\r\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\r\n }\r\n\r\n let scope: ScopeFilter | undefined;\r\n if (values.scope !== undefined && values.scope.trim() !== \"\") {\r\n const s = values.scope.trim();\r\n if (!isScopeFilter(s)) {\r\n return fail(`invalid --scope \"${s}\" (use ${SCOPE_FILTER_VALUES.join(\"|\")})`);\r\n }\r\n scope = s;\r\n }\r\n\r\n const opts: LeaderboardOptions = {};\r\n if (sinceMs !== undefined) opts.sinceMs = sinceMs;\r\n if (values.connector && values.connector.trim() !== \"\") {\r\n opts.connectorId = values.connector.trim();\r\n }\r\n if (scope !== undefined) opts.scope = scope;\r\n\r\n if (by === \"tool\") {\r\n const rows = toolLeaderboard(opts);\r\n print(values.json ? JSON.stringify(rows, null, 2) : formatToolLeaderboard(rows));\r\n } else if (by === \"surface\") {\r\n // The per-surface view folds the STATIC command/skill/subagent footprints of\r\n // the registered connector(s) into the runtime server/hook rows.\r\n const connectorId = values.connector?.trim();\r\n const surfaceOpts: SurfaceLeaderboardOptions = {\r\n ...opts,\r\n connectors: await gatherConnectors(connectorId),\r\n };\r\n const rows = surfaceLeaderboard(surfaceOpts);\r\n print(values.json ? JSON.stringify(rows, null, 2) : formatSurfaceLeaderboard(rows));\r\n } else {\r\n const rows = mcpLeaderboard(opts);\r\n print(values.json ? JSON.stringify(rows, null, 2) : formatMcpLeaderboard(rows));\r\n }\r\n return 0;\r\n}\r\n\r\n/**\r\n * Gather the registered connector(s) whose STATIC command/skill/subagent\r\n * footprints feed the per-surface view. When `connectorId` is given, prefer the\r\n * LIVE module (freshest content) and fall back to the persisted meta record;\r\n * otherwise enumerate every registered connector from its meta. Best-effort: a\r\n * connector that cannot be loaded is skipped (the surface view still renders the\r\n * runtime rows it can read from the store).\r\n */\r\nasync function gatherConnectors(\r\n connectorId: string | undefined,\r\n): Promise<ResolvedConnector[]> {\r\n if (connectorId !== undefined && connectorId !== \"\") {\r\n try {\r\n return [await loadRegisteredConnector(connectorId)];\r\n } catch {\r\n const meta = readRegisteredMetaSafe(connectorId);\r\n return meta ? [connectorFromMeta(meta)] : [];\r\n }\r\n }\r\n return listRegisteredConnectors();\r\n}\r\n\r\n/** readRegisteredMeta wrapped so a missing/corrupt record never throws here. */\r\nfunction readRegisteredMetaSafe(id: string): ReturnType<typeof readRegisteredMeta> {\r\n try {\r\n return readRegisteredMeta(id);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport async function run(argv: string[]): Promise<number> {\r\n const sub = argv[0];\r\n const rest = argv.slice(1);\r\n\r\n switch (sub) {\r\n case \"report\":\r\n return runReport(rest);\r\n case \"export\":\r\n return runExport(rest);\r\n case \"leaderboard\":\r\n return await runLeaderboard(rest);\r\n case undefined:\r\n case \"--help\":\r\n case \"-h\":\r\n print(\"usage: agent-connector telemetry <report|export|leaderboard> [flags]\");\r\n print(\" report --by tool|session|project --since 7d --connector <id> --json\");\r\n print(\" export --format csv|json --out <file> --since 7d --connector <id>\");\r\n print(\" leaderboard --by mcp|tool|surface --since 7d --connector <id> --scope <slice> --json\");\r\n return sub === undefined ? 1 : 0;\r\n default:\r\n return fail(`unknown telemetry subcommand \"${sub}\" (use report|export|leaderboard)`);\r\n }\r\n}\r\n","/**\r\n * telemetry/report — CLI-facing formatting for telemetry rollups and exports.\r\n *\r\n * Pure functions: take store output (rollup rows / raw records) and render text,\r\n * CSV, or JSON. No IO except {@link summarize}, which reads through a passed-in\r\n * {@link TelemetryStore}. Confidence is surfaced verbatim so heuristic/approx\r\n * numbers are never mistaken for exact host-reported usage.\r\n */\r\n\r\nimport type { TelemetryStore } from \"./types.js\";\r\nimport type {\r\n ConfidenceSource,\r\n QueryFilter,\r\n RollupRow,\r\n ToolEventRecord,\r\n} from \"./types.js\";\r\n\r\n/** Grouping dimension, mirrored from {@link TelemetryStore.rollup}. */\r\nexport type RollupDimension = \"tool\" | \"session\" | \"project\";\r\n\r\n/** Human label for the leading KEY column, per grouping dimension. */\r\nconst KEY_HEADER: Record<RollupDimension, string> = {\r\n tool: \"TOOL\",\r\n session: \"SESSION\",\r\n project: \"PROJECT\",\r\n};\r\n\r\n/**\r\n * Sources whose counts are estimates (vs. real / host-reported numbers).\r\n * `tokenizer-calibrated` is still an estimate — an approximation nudged toward\r\n * truth by a sampled Anthropic count_tokens factor — so it belongs here too.\r\n */\r\nconst ESTIMATE_SOURCES: ReadonlySet<ConfidenceSource> = new Set<ConfidenceSource>([\r\n \"heuristic\",\r\n \"tokenizer-approx\",\r\n \"tokenizer-calibrated\",\r\n]);\r\n\r\n/** Compact, fixed-width integer formatting with thousands separators. */\r\nfunction fmtInt(n: number): string {\r\n return n.toLocaleString(\"en-US\");\r\n}\r\n\r\n/** Pad a cell to a column width (right-pad text, used for left-aligned cols). */\r\nfunction padRight(s: string, width: number): string {\r\n return s.length >= width ? s : s + \" \".repeat(width - s.length);\r\n}\r\n\r\n/** Pad a cell to a column width (left-pad, used for right-aligned numbers). */\r\nfunction padLeft(s: string, width: number): string {\r\n return s.length >= width ? s : \" \".repeat(width - s.length) + s;\r\n}\r\n\r\n/**\r\n * Render an aligned text table of rollup rows, sorted by total tokens desc, with\r\n * a TOTAL footer and a short legend noting which confidence labels are estimates.\r\n */\r\nexport function formatReport(rows: RollupRow[], by: RollupDimension): string {\r\n const keyHeader = KEY_HEADER[by];\r\n const headers = [keyHeader, \"CALLS\", \"IN\", \"OUT\", \"TOTAL\", \"CONFIDENCE\"];\r\n\r\n const sorted = [...rows].sort((a, b) => b.totalTokens - a.totalTokens);\r\n\r\n // Build the data matrix (string cells) first so we can measure widths.\r\n const dataRows = sorted.map((r) => [\r\n r.key,\r\n fmtInt(r.calls),\r\n fmtInt(r.inputTokens),\r\n fmtInt(r.outputTokens),\r\n fmtInt(r.totalTokens),\r\n r.confidence,\r\n ]);\r\n\r\n // Totals footer. Confidence is the worst (least-confident) across all rows.\r\n const totals = sorted.reduce(\r\n (acc, r) => {\r\n acc.calls += r.calls;\r\n acc.inputTokens += r.inputTokens;\r\n acc.outputTokens += r.outputTokens;\r\n acc.totalTokens += r.totalTokens;\r\n return acc;\r\n },\r\n { calls: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0 },\r\n );\r\n const totalRow = [\r\n \"TOTAL\",\r\n fmtInt(totals.calls),\r\n fmtInt(totals.inputTokens),\r\n fmtInt(totals.outputTokens),\r\n fmtInt(totals.totalTokens),\r\n \"\",\r\n ];\r\n\r\n // Column widths: max over header, every data cell, and the totals row.\r\n const widths = headers.map((h, col) => {\r\n let w = h.length;\r\n for (const row of dataRows) w = Math.max(w, (row[col] ?? \"\").length);\r\n w = Math.max(w, (totalRow[col] ?? \"\").length);\r\n return w;\r\n });\r\n\r\n // Column 0 (KEY) is left-aligned; numeric/label columns are right-aligned.\r\n const renderRow = (cells: string[]): string =>\r\n cells\r\n .map((c, col) =>\r\n col === 0\r\n ? padRight(c, widths[col] ?? 0)\r\n : padLeft(c, widths[col] ?? 0),\r\n )\r\n .join(\" \")\r\n .trimEnd();\r\n\r\n const ruleWidth = widths.reduce((a, b) => a + b, 0) + 2 * (widths.length - 1);\r\n const rule = \"-\".repeat(ruleWidth);\r\n\r\n const lines: string[] = [];\r\n lines.push(renderRow(headers));\r\n lines.push(rule);\r\n if (dataRows.length === 0) {\r\n lines.push(\"(no telemetry recorded)\");\r\n } else {\r\n for (const row of dataRows) lines.push(renderRow(row));\r\n }\r\n lines.push(rule);\r\n lines.push(renderRow(totalRow));\r\n\r\n // Legend — honest labeling of which confidence values are estimates.\r\n const hasEstimate = sorted.some((r) => ESTIMATE_SOURCES.has(r.confidence));\r\n if (hasEstimate) {\r\n lines.push(\"\");\r\n lines.push(\r\n \"note: heuristic and tokenizer-approx token counts are estimates, \" +\r\n \"not exact host-reported usage.\",\r\n );\r\n if (sorted.some((r) => r.confidence === \"tokenizer-calibrated\")) {\r\n lines.push(\r\n \"note: tokenizer-calibrated = local approx adjusted by a sampled \" +\r\n \"Anthropic count_tokens factor (opt-in; content sampled off-box only \" +\r\n \"when AGENT_CONNECTOR_CALIBRATE=anthropic).\",\r\n );\r\n }\r\n }\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n\r\n/** Ordered columns for {@link toCSV}, matching the {@link ToolEventRecord} shape. */\r\nconst CSV_COLUMNS = [\r\n \"id\",\r\n \"ts\",\r\n \"connectorId\",\r\n \"toolName\",\r\n \"scope\",\r\n \"hostPlatform\",\r\n \"sessionId\",\r\n \"projectKey\",\r\n \"projectDir\",\r\n \"inputTokens\",\r\n \"outputTokens\",\r\n \"confidenceSource\",\r\n \"isError\",\r\n // installScope / launchMethod mirror the JSON export so the scope dimension is\r\n // not silently dropped from CSV; absent on a record → an empty cell.\r\n \"installScope\",\r\n \"launchMethod\",\r\n] as const satisfies ReadonlyArray<keyof ToolEventRecord>;\r\n\r\n/** RFC-4180-ish CSV escaping: quote when the cell holds a comma, quote, or newline. */\r\nfunction csvCell(value: unknown): string {\r\n // An absent field (optional column like installScope/launchMethod) renders as\r\n // an empty cell rather than the literal \"undefined\" — the JSON export omits\r\n // the key entirely, so the CSV should likewise carry no value.\r\n if (value === undefined || value === null) return \"\";\r\n const s = String(value);\r\n if (/[\",\\n\\r]/.test(s)) {\r\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n return s;\r\n}\r\n\r\n/** Serialize raw records to CSV (header + one line per record, CRLF-terminated). */\r\nexport function toCSV(records: ToolEventRecord[]): string {\r\n const lines: string[] = [];\r\n lines.push(CSV_COLUMNS.join(\",\"));\r\n for (const record of records) {\r\n lines.push(CSV_COLUMNS.map((col) => csvCell(record[col])).join(\",\"));\r\n }\r\n return lines.join(\"\\r\\n\");\r\n}\r\n\r\n/** Serialize raw records to a pretty-printed JSON array string. */\r\nexport function toJSONExport(records: ToolEventRecord[]): string {\r\n return JSON.stringify(records, null, 2);\r\n}\r\n\r\n/** Options for {@link summarize}. */\r\nexport interface SummarizeOptions {\r\n /** Grouping dimension. Default \"tool\". */\r\n by?: RollupDimension;\r\n /** Query filter forwarded to the store. Default: no filter (all records). */\r\n filter?: QueryFilter;\r\n}\r\n\r\n/**\r\n * Roll up a store and render it in one call. Returns the structured rows (for\r\n * machine use) alongside the formatted text table (for the CLI).\r\n */\r\nexport function summarize(\r\n store: TelemetryStore,\r\n opts?: SummarizeOptions,\r\n): { rows: RollupRow[]; text: string } {\r\n const by = opts?.by ?? \"tool\";\r\n const filter = opts?.filter ?? {};\r\n const rows = store.rollup(by, filter);\r\n return { rows, text: formatReport(rows, by) };\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
readJsonFile
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZSOS2KOR.js";
|
|
5
5
|
import {
|
|
6
6
|
firstExistingRoot,
|
|
7
7
|
walkFiles
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KM2YXO6V.js";
|
|
9
9
|
import {
|
|
10
10
|
emptyTokens
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7PSNXUFK.js";
|
|
12
12
|
|
|
13
13
|
// src/usage/readers/trae.ts
|
|
14
14
|
var PLATFORM_ID = "trae";
|
|
@@ -154,4 +154,4 @@ var trae_default = traeReader;
|
|
|
154
154
|
export {
|
|
155
155
|
trae_default as default
|
|
156
156
|
};
|
|
157
|
-
//# sourceMappingURL=trae-
|
|
157
|
+
//# sourceMappingURL=trae-SIQI3C66.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/usage/readers/trae.ts"],"sourcesContent":["/**\r\n * usage/readers/trae — Trae / ByteDance AI IDE usage reader (SYNCED platform).\r\n *\r\n * Faithful port of tokscale sessions/trae.rs. Trae's per-session token usage\r\n * lives behind the Trae usage REST API; tokscale authenticates, paginates, and\r\n * caches the JSON responses under ~/.config/tokscale/trae-cache/. THIS reader\r\n * never authenticates and never calls that API — it only parses the cached\r\n * artifacts when a tokscale run has already produced them. Hence kind:\"synced\":\r\n * - cache present → parse the JSON array(s) and emit one record per session;\r\n * - cache absent → return [] (the scan layer notes \"requires sync, skipped\").\r\n *\r\n * Cache layout (per docs/research/usage-readers.json + design §3d):\r\n * ~/.config/tokscale/trae-cache/sessions/usage-*.json (cached API artifacts)\r\n * ~/.config/tokscale/trae-cache/manifest.json (sync bookkeeping — ignored here)\r\n * paths.ts resolves the cache dir (env override AGENT_CONNECTOR_TOKSCALE_DIR\r\n * first, the tokscale ~/.config/tokscale default second). We walk for the\r\n * `usage-*.json` artifacts directly rather than reading the manifest: the\r\n * artifacts are self-describing and a manifest mismatch must never drop real data.\r\n *\r\n * Artifact format (mirrors parse_trae_file exactly): each file is a JSON array of\r\n * session objects. Per-session fields:\r\n * model_name — display name (may be \"\" for auto-mode);\r\n * mode — interaction mode (e.g. \"Auto\");\r\n * session_id — required; records without it cannot dedup correctly → dropped;\r\n * usage_time — epoch SECONDS, required & > 0 → ms = usage_time × 1000;\r\n * dollar_float — cost in USD;\r\n * extra_info — { input_token, output_token, cache_read_token, cache_write_token }.\r\n *\r\n * Token math (port of parse_session): the API returns exact counts, so each\r\n * dimension maps straight through; reasoning is always 0 (Trae does not report\r\n * it). A row whose four token dimensions sum to 0 is skipped.\r\n *\r\n * Model / provider (port of normalize_trae_model + provider_for_model):\r\n * - a known display name maps to a tiktoken-style id (e.g. \"GPT-5.4\" →\r\n * \"gpt-5.4\", \"Claude Sonnet 4.6\" → \"claude-sonnet-4.6\"); an unknown name\r\n * passes through verbatim;\r\n * - an empty model_name (auto-mode) buckets under \"trae-<mode>\" (e.g.\r\n * \"trae-auto\"); empty model AND empty mode → \"trae-unknown\" so the cost is\r\n * still attributed instead of vanishing into an empty Model cell;\r\n * - provider is inferred by substring on the display name: GPT→openai,\r\n * Claude→anthropic, Gemini→google, GLM→zhipu, else \"trae\".\r\n *\r\n * Dedup (design §6 / §220): Trae's API returns cumulative deltas and overlapping\r\n * syncs can write the same (session_id, usage_time) into multiple artifacts —\r\n * latest-per-(session_id, usage_time) wins. The dedupKey is\r\n * `trae:{session_id}:{usage_time}`. Because the global aggregate backstop keeps\r\n * the FIRST occurrence per key, this reader collapses duplicates itself, keeping\r\n * the LAST artifact row seen per key (walk order), so the emitted set is already\r\n * unique and the global filter is a no-op. Confidence is \"host-reported\" — the\r\n * cached data carries real, exact host token counts (spec lists it as medium for\r\n * the source overall; the per-row provenance is host-reported).\r\n *\r\n * Overflow guard (port of the checked_mul in Rust): a crafted usage_time near\r\n * the safe-integer ceiling would overflow when multiplied by 1000 — reject the\r\n * record rather than emit a garbage timestamp.\r\n *\r\n * Fail-open: no cache dir → []; unreadable/malformed file → skipped; a session\r\n * missing session_id / usage_time, with non-positive or overflowing usage_time,\r\n * or with all-zero tokens → skipped. No project scope (account-level usage).\r\n */\r\n\r\nimport type { TokenBreakdown, UsageReader, UsageRecord } from \"../types.js\";\r\nimport { emptyTokens } from \"../aggregate.js\";\r\nimport { readJsonFile } from \"../jsonl.js\";\r\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\r\n\r\nconst PLATFORM_ID = \"trae\" as const;\r\nconst DEFAULT_PROVIDER = \"trae\";\r\n\r\n/** Multiplying usage_time (s) by 1000 must stay a safe integer (port of checked_mul). */\r\nconst MAX_SAFE_USAGE_TIME_S = Math.floor(Number.MAX_SAFE_INTEGER / 1000);\r\n\r\n/** The fields we read off a cached Trae session object (everything optional / unknown). */\r\ninterface TraeSession {\r\n model_name?: unknown;\r\n mode?: unknown;\r\n session_id?: unknown;\r\n usage_time?: unknown;\r\n dollar_float?: unknown;\r\n extra_info?: {\r\n input_token?: unknown;\r\n output_token?: unknown;\r\n cache_read_token?: unknown;\r\n cache_write_token?: unknown;\r\n };\r\n}\r\n\r\n/**\r\n * Known mapping from Trae display names to tiktoken-style model ids (port of\r\n * normalize_trae_model). Unknown names fall through to the raw `model_name`\r\n * (mixed-case, space-separated) so a future model is still attributed.\r\n */\r\nfunction normalizeTraeModel(name: string): string {\r\n switch (name) {\r\n case \"GPT-5.4\":\r\n return \"gpt-5.4\";\r\n case \"GPT-5.3-Codex\":\r\n case \"GPT-5.3 Codex\":\r\n return \"gpt-5.3-codex\";\r\n case \"GPT-5.3\":\r\n return \"gpt-5.3\";\r\n case \"GPT-5.2-Codex\":\r\n case \"GPT-5.2 Codex\":\r\n return \"gpt-5.2-codex\";\r\n case \"GPT-5.2\":\r\n return \"gpt-5.2\";\r\n case \"GPT-5.1-Codex\":\r\n case \"GPT-5.1 Codex\":\r\n return \"gpt-5.1-codex\";\r\n case \"GPT-5.1\":\r\n return \"gpt-5.1\";\r\n case \"Gemini 3.1 Pro\":\r\n return \"gemini-3.1-pro\";\r\n case \"Gemini 3.1\":\r\n return \"gemini-3.1\";\r\n case \"GLM 5.1\":\r\n case \"GLM-5.1\":\r\n return \"glm-5.1\";\r\n case \"Claude Sonnet 4.6\":\r\n case \"Claude-Sonnet-4.6\":\r\n return \"claude-sonnet-4.6\";\r\n case \"Claude Sonnet 4.5\":\r\n case \"Claude-Sonnet-4.5\":\r\n return \"claude-sonnet-4.5\";\r\n default:\r\n return name;\r\n }\r\n}\r\n\r\n/**\r\n * Infer the provider from the display name (port of provider_for_model).\r\n * Substring matching, first match wins; falls back to \"trae\". Trae-specific so it\r\n * does not route through normalize.ts inferProvider (which knows nothing of GLM).\r\n */\r\nfunction providerForModel(name: string): string {\r\n if (name.includes(\"GPT\") || name.includes(\"gpt\")) return \"openai\";\r\n if (name.includes(\"Claude\") || name.includes(\"claude\")) return \"anthropic\";\r\n if (name.includes(\"Gemini\") || name.includes(\"gemini\")) return \"google\";\r\n if (name.includes(\"GLM\") || name.includes(\"glm\")) return \"zhipu\";\r\n return DEFAULT_PROVIDER;\r\n}\r\n\r\n/** Coerce an unknown to a non-negative integer (0 on absence/garbage). */\r\nfunction toNonNegInt(v: unknown): number {\r\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\r\n if (!Number.isFinite(n)) return 0;\r\n return Math.max(0, Math.trunc(n));\r\n}\r\n\r\n/** Coerce an unknown to a finite number (0 on absence/garbage) — for the cost field. */\r\nfunction toNumber(v: unknown): number {\r\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\r\n return Number.isFinite(n) ? n : 0;\r\n}\r\n\r\n/**\r\n * Coerce an unknown to a positive integer epoch-seconds value, or null when it is\r\n * absent / non-positive / not an integer (port of the as_i64()? + ≤0 checks).\r\n */\r\nfunction toUsageTimeSeconds(v: unknown): number | null {\r\n let n: number;\r\n if (typeof v === \"number\") n = v;\r\n else if (typeof v === \"string\") n = Number(v);\r\n else return null;\r\n if (!Number.isFinite(n) || !Number.isInteger(n)) return null;\r\n if (n <= 0) return null;\r\n return n;\r\n}\r\n\r\n/** Parse one cached Trae session object into a usage record (port of parse_session). */\r\nfunction parseSession(session: TraeSession): UsageRecord | null {\r\n const modelRaw = typeof session.model_name === \"string\" ? session.model_name : \"\";\r\n const mode = typeof session.mode === \"string\" ? session.mode : \"\";\r\n\r\n // Auto-mode sessions return model_name \"\" (the system picks a model per turn).\r\n // Bucket them under \"trae-<mode>\" so the cost is still attributed.\r\n let modelId: string;\r\n if (modelRaw !== \"\") modelId = normalizeTraeModel(modelRaw);\r\n else if (mode !== \"\") modelId = `trae-${mode.toLowerCase()}`;\r\n else modelId = \"trae-unknown\";\r\n\r\n // Provider is inferred from the raw display name (the model_id may already be a\r\n // bucket like \"trae-auto\"); fall back to the model_id when no raw name exists.\r\n const providerId = providerForModel(modelRaw !== \"\" ? modelRaw : modelId);\r\n\r\n // Records without a real session_id cannot be deduplicated correctly (every\r\n // \"missing-id\" record would collide on the same key); records without a\r\n // positive usage_time would land at epoch 0. Drop them rather than fabricating.\r\n const sessionId =\r\n typeof session.session_id === \"string\" && session.session_id !== \"\" ? session.session_id : null;\r\n if (sessionId === null) return null;\r\n\r\n const usageTime = toUsageTimeSeconds(session.usage_time);\r\n if (usageTime === null) return null;\r\n\r\n // Overflow guard: a crafted usage_time would overflow × 1000 → reject it.\r\n if (usageTime > MAX_SAFE_USAGE_TIME_S) return null;\r\n const ts = usageTime * 1000;\r\n\r\n const cost = toNumber(session.dollar_float);\r\n\r\n const extra = session.extra_info ?? {};\r\n const input = toNonNegInt(extra.input_token);\r\n const output = toNonNegInt(extra.output_token);\r\n const cacheRead = toNonNegInt(extra.cache_read_token);\r\n const cacheWrite = toNonNegInt(extra.cache_write_token);\r\n\r\n if (input + output + cacheRead + cacheWrite === 0) return null;\r\n\r\n const tokens: TokenBreakdown = emptyTokens();\r\n tokens.input = input;\r\n tokens.output = output;\r\n tokens.cacheRead = cacheRead;\r\n tokens.cacheWrite = cacheWrite;\r\n // reasoning stays 0 (Trae does not report it).\r\n\r\n return {\r\n platformId: PLATFORM_ID,\r\n modelId,\r\n providerId,\r\n sessionId,\r\n tokens,\r\n cost,\r\n ts,\r\n messageCount: 1,\r\n dedupKey: `trae:${sessionId}:${usageTime}`,\r\n confidence: \"host-reported\",\r\n };\r\n}\r\n\r\n/**\r\n * Parse one cached artifact file (a JSON array of sessions) into usage records\r\n * (port of parse_trae_file). A non-array / unreadable / malformed file yields [].\r\n */\r\nfunction parseTraeFile(path: string): UsageRecord[] {\r\n const value = readJsonFile(path);\r\n if (!Array.isArray(value)) return [];\r\n\r\n const out: UsageRecord[] = [];\r\n for (const raw of value) {\r\n if (typeof raw !== \"object\" || raw === null) continue;\r\n const record = parseSession(raw as TraeSession);\r\n if (record !== null) out.push(record);\r\n }\r\n return out;\r\n}\r\n\r\n/** The Trae synced usage reader singleton. */\r\nconst traeReader: UsageReader = {\r\n platformId: PLATFORM_ID,\r\n kind: \"synced\",\r\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\r\n // The cache dir is ~/.config/tokscale/trae-cache (env override first).\r\n // Absent → [] so the scan layer reports \"requires sync, skipped\".\r\n const root = firstExistingRoot(PLATFORM_ID);\r\n if (root === undefined) return [];\r\n\r\n // Enumerate cached artifacts: sessions/usage-*.json (walkFiles recurses, so\r\n // a flat or nested layout both work). Match the artifact name shape.\r\n const files = walkFiles(root, (name) => {\r\n const lower = name.toLowerCase();\r\n return lower.startsWith(\"usage-\") && lower.endsWith(\".json\");\r\n });\r\n\r\n // Trae returns cumulative deltas and overlapping syncs can repeat a\r\n // (session_id, usage_time) across artifacts — latest wins. Collapse to one\r\n // record per dedupKey, keeping the LAST seen (walk order), so the emitted set\r\n // is already unique (the global aggregate backstop keeps FIRST, not last).\r\n const byKey = new Map<string, UsageRecord>();\r\n for (const file of files) {\r\n for (const row of parseTraeFile(file)) {\r\n const key = row.dedupKey ?? `${row.sessionId}:${row.ts}`;\r\n byKey.set(key, row); // later artifact overwrites earlier → latest wins\r\n }\r\n }\r\n\r\n const records: UsageRecord[] = [];\r\n for (const row of byKey.values()) {\r\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\r\n records.push(row);\r\n }\r\n return records;\r\n },\r\n};\r\n\r\nexport default traeReader;\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
resolveEnvRefsDeep
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XXLCMSD3.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter,
|
|
7
7
|
renderSkillMd
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3FINQ2ZF.js";
|
|
9
9
|
import {
|
|
10
10
|
buildWrappedStdio,
|
|
11
11
|
isHomeBinHookCommand
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-Y3K6KJMS.js";
|
|
13
|
+
import "./chunk-ILWHLGIC.js";
|
|
14
|
+
import "./chunk-QYOUQCC6.js";
|
|
15
15
|
|
|
16
16
|
// src/adapters/trae/index.ts
|
|
17
17
|
import { existsSync } from "fs";
|
|
@@ -271,4 +271,4 @@ export {
|
|
|
271
271
|
adapter,
|
|
272
272
|
trae_default as default
|
|
273
273
|
};
|
|
274
|
-
//# sourceMappingURL=trae-
|
|
274
|
+
//# sourceMappingURL=trae-Y67HSDOW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/trae/index.ts"],"sourcesContent":["/**\r\n * adapters/trae — Trae (ByteDance) platform adapter for agent-connector.\r\n *\r\n * Trae is an **mcp-only** host for our purposes: it exposes MCP servers as its\r\n * extensibility mechanism but has no lifecycle hook system we can register\r\n * against. This adapter therefore installs only the MCP server and reports hooks\r\n * as unavailable, mirroring the Warp reference path that validates the\r\n * `mcp-only` paradigm end-to-end.\r\n *\r\n * MCP config (medium-confidence path — still implemented; doctor reports presence):\r\n * - user scope → ~/.trae/mcp.json\r\n * - project scope → <projectDir>/.trae/mcp.json\r\n * Both are JSON, root key \"mcpServers\", and are the SAME file used for the\r\n * (non-existent) hook registration — there is no separate hook file here.\r\n *\r\n * A stdio server entry uses the standard Claude/Cursor shape:\r\n * { command, args, env } (object-keyed by connector id).\r\n *\r\n * Trae documents no native `${env:VAR}` interpolation token, so env/header/url\r\n * refs are resolved to literals at install time (the no-native-token path).\r\n */\r\n\r\nimport { existsSync } from \"node:fs\";\r\nimport { homedir } from \"node:os\";\r\nimport { join } from \"node:path\";\r\n\r\nimport { BaseAdapter } from \"../base.js\";\r\nimport type { Adapter, InstallContext } from \"../spi.js\";\r\nimport type {\r\n ChangeRecord,\r\n DetectedPlatform,\r\n HealthCheck,\r\n HookParadigm,\r\n PlatformCapabilities,\r\n PlatformId,\r\n ServerDef,\r\n Transport,\r\n} from \"../../core/types.js\";\r\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\r\nimport {\r\n buildWrappedStdio,\r\n isHomeBinHookCommand,\r\n} from \"../../core/spawn.js\";\r\nimport { renderSkillMd } from \"../claude-code/render.js\";\r\n\r\nconst HOST: PlatformId = \"trae\";\r\nconst MCP_ROOT_KEY = \"mcpServers\";\r\n\r\n/** Native MCP server entry shapes Trae accepts under `mcpServers`. */\r\ninterface TraeStdioServer {\r\n command: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n}\r\ninterface TraeHttpServer {\r\n url: string;\r\n headers?: Record<string, string>;\r\n}\r\n\r\nexport class TraeAdapter extends BaseAdapter implements Adapter {\r\n readonly id: PlatformId = HOST;\r\n readonly name = \"Trae\";\r\n readonly paradigm: HookParadigm = \"mcp-only\";\r\n\r\n readonly capabilities: PlatformCapabilities = {\r\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\r\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\r\n supportsMemory: true,\r\n // Trae has no lifecycle hook system we can target — every hook capability\r\n // is false.\r\n preToolUse: false,\r\n postToolUse: false,\r\n preCompact: false,\r\n sessionStart: false,\r\n sessionEnd: false,\r\n userPromptSubmit: false,\r\n stop: false,\r\n notification: false,\r\n canModifyArgs: false,\r\n canModifyOutput: false,\r\n canInjectSessionContext: false,\r\n // Trae registers stdio, SSE, and Streamable HTTP MCP servers.\r\n transports: [\"stdio\", \"sse\", \"http\"],\r\n // Content surfaces: Trae reads Agent Skills (SKILL.md) from\r\n // user scope → ~/.trae/skills/<name>/SKILL.md\r\n // project scope → <projectDir>/.trae/skills/<name>/SKILL.md\r\n // BOTH scopes are documented-writable. Commands/subagents have no native\r\n // file surface here, so only skills is enabled.\r\n supportsSkills: true,\r\n };\r\n\r\n // ── Detection ────────────────────────────────────────────────────────────\r\n\r\n detectInstalled(projectDir: string): DetectedPlatform {\r\n const userDir = join(homedir(), \".trae\");\r\n const userMcp = join(userDir, \"mcp.json\");\r\n const projDir = join(projectDir, \".trae\");\r\n const projMcp = join(projDir, \"mcp.json\");\r\n\r\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\r\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\r\n const installed = userInstalled || projInstalled;\r\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\r\n const configPath = scope === \"project\" ? projMcp : userMcp;\r\n\r\n return {\r\n id: this.id,\r\n name: this.name,\r\n installed,\r\n paradigm: this.paradigm,\r\n capabilities: this.capabilities,\r\n configPath,\r\n scope,\r\n reason: installed\r\n ? `found Trae config (${scope})`\r\n : `no Trae config at ${userDir} or ${projDir}`,\r\n confidence: installed ? \"high\" : \"low\",\r\n };\r\n }\r\n\r\n // ── Native paths ─────────────────────────────────────────────────────────\r\n\r\n getConfigDir(ctx: InstallContext): string {\r\n return ctx.scope === \"project\"\r\n ? join(ctx.projectDir, \".trae\")\r\n : join(homedir(), \".trae\");\r\n }\r\n\r\n getServerConfigPath(ctx: InstallContext): string {\r\n return join(this.getConfigDir(ctx), \"mcp.json\");\r\n }\r\n\r\n /**\r\n * Trae has no hook file — hooks are not a thing here. The hook \"config path\"\r\n * is the same mcp.json so the generic doctor/backup behave sensibly.\r\n */\r\n getHookConfigPath(ctx: InstallContext): string {\r\n return this.getServerConfigPath(ctx);\r\n }\r\n\r\n // ── MCP server install / uninstall ───────────────────────────────────────\r\n\r\n installServer(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n const override = connector.platforms[HOST]?.server;\r\n if (!connector.server || override === false) {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: connector.server\r\n ? \"server registration disabled for trae\"\r\n : \"connector declares no MCP server\",\r\n },\r\n ];\r\n }\r\n\r\n // Shallow-merge any per-platform server override into the base ServerDef.\r\n const server: ServerDef =\r\n override && typeof override === \"object\"\r\n ? { ...connector.server, ...override }\r\n : connector.server;\r\n\r\n const serverPath = this.getServerConfigPath(ctx);\r\n const entry = this.renderServerEntry(ctx, server);\r\n\r\n return [\r\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\r\n ];\r\n }\r\n\r\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\r\n const serverPath = this.getServerConfigPath(ctx);\r\n return [\r\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\r\n ];\r\n }\r\n\r\n /** Render a normalized ServerDef into Trae's native mcpServers entry. */\r\n private renderServerEntry(\r\n ctx: InstallContext,\r\n server: ServerDef,\r\n ): TraeStdioServer | TraeHttpServer {\r\n const transport: Transport = server.transport;\r\n\r\n if (transport === \"stdio\") {\r\n let command = server.command ?? \"\";\r\n let args = [...(server.args ?? [])];\r\n\r\n // Transparent telemetry wrapping: route the real command through\r\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\r\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\r\n\r\n // Trae has no documented native interpolation token, so resolve every\r\n // ${env:VAR} to a literal at install time.\r\n const entry: TraeStdioServer = { command: resolveEnvRefsDeep(command) };\r\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\r\n const env = this.renderEnv(server.env);\r\n if (env) entry.env = env;\r\n return entry;\r\n }\r\n\r\n // sse / http (and any other remote transport) — Trae registers a URL.\r\n const entry: TraeHttpServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\r\n const headers = this.renderEnv(server.headers);\r\n if (headers) entry.headers = headers;\r\n return entry;\r\n }\r\n\r\n /**\r\n * Render env/header values. Trae documents no native interpolation token, so\r\n * resolve `${env:VAR}` references to literals at install time.\r\n */\r\n private renderEnv(\r\n env: Record<string, string> | undefined,\r\n ): Record<string, string> | undefined {\r\n if (!env || Object.keys(env).length === 0) return undefined;\r\n return resolveEnvRefsDeep({ ...env });\r\n }\r\n\r\n // ── Hooks (unavailable — Trae is mcp-only) ───────────────────────────────\r\n\r\n installHooks(_ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: \"hooks unavailable (Trae is mcp-only)\",\r\n },\r\n ];\r\n }\r\n\r\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\r\n return [\r\n {\r\n platform: this.id,\r\n action: \"skip\",\r\n detail: \"hooks unavailable (Trae is mcp-only)\",\r\n },\r\n ];\r\n }\r\n\r\n /**\r\n * True when a hook command references our home binary AND this connector id\r\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand).\r\n * Trae installs no hooks, but this guard keeps any future shared-file edit\r\n * from removing another connector's entries.\r\n */\r\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\r\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\r\n }\r\n\r\n // ── Content surfaces: skills ─────────────────────────────────────────────\r\n // CONTENT-ONLY: pure native-file writers. No runtime dispatch, no home-bin\r\n // pointer, no telemetry wrap. Idempotent (byte-identical → skip) via\r\n // writeContentFile and reversible via removeContentFile. Honors\r\n // platforms[\"trae\"].skills === false to skip. BOTH user and project scopes\r\n // are documented-writable, so there is no scope guard.\r\n //\r\n // Native location:\r\n // skill → <configDir>/skills/<name>/SKILL.md (+ bundled resources)\r\n // user → ~/.trae/skills/<name>/SKILL.md\r\n // project → <projectDir>/.trae/skills/<name>/SKILL.md\r\n\r\n private skillDir(ctx: InstallContext, name: string): string {\r\n return join(this.getConfigDir(ctx), \"skills\", name);\r\n }\r\n\r\n override installSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.platforms[HOST]?.skills === false) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for trae\" }];\r\n }\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n changes.push(\r\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\r\n );\r\n // Bundle any resource files beside SKILL.md (relative path → contents).\r\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\r\n // (config-time validation already rejects these, but never trust input).\r\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) {\r\n changes.push({\r\n platform: this.id,\r\n action: \"warn\",\r\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\r\n });\r\n continue;\r\n }\r\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\r\n }\r\n }\r\n return changes;\r\n }\r\n\r\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\r\n const { connector } = ctx;\r\n if (connector.skills.length === 0) {\r\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\r\n }\r\n const changes: ChangeRecord[] = [];\r\n for (const skill of connector.skills) {\r\n const dir = this.skillDir(ctx, skill.name);\r\n // Remove only the files we wrote (SKILL.md + declared resources), then the\r\n // skill dir itself when we own its full contents.\r\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\r\n for (const rel of Object.keys(skill.resources ?? {})) {\r\n const target = this.resolveWithin(dir, rel);\r\n if (target === null) continue; // never delete outside the skill dir\r\n changes.push(this.removeContentFile(target, ctx.dryRun));\r\n }\r\n // Only remove the skill dir when WE own its full contents — never rm -rf a\r\n // dir that still holds user-added / sibling-tool / shared files.\r\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\r\n }\r\n return changes;\r\n }\r\n\r\n // ── Diagnostics ──────────────────────────────────────────────────────────\r\n\r\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\r\n const mcpPath = this.getServerConfigPath(ctx);\r\n const connectorId = ctx.connector.id;\r\n const checks: HealthCheck[] = [\r\n {\r\n name: `${this.name}: mcp.json present`,\r\n check: () =>\r\n existsSync(mcpPath)\r\n ? { status: \"OK\", detail: mcpPath }\r\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\r\n },\r\n {\r\n name: `${this.name}: server entry registered`,\r\n check: () => {\r\n // Only assert what the connector declares: a server-less connector —\r\n // e.g. a catalog-only bundle of agents/skills/commands — never writes\r\n // an mcpServers entry, so its absence is healthy.\r\n if (!ctx.connector.server) {\r\n return { status: \"OK\", detail: \"no MCP server declared\" };\r\n }\r\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\r\n const bucket = cfg?.[MCP_ROOT_KEY];\r\n if (!cfg || !bucket) {\r\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\r\n }\r\n return connectorId in bucket\r\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\r\n : {\r\n status: \"FAIL\",\r\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\r\n };\r\n },\r\n },\r\n ];\r\n\r\n // Content-surface checks: assert presence only for skills this connector\r\n // declares (the SKILL.md lands under <configDir>/skills/<name>/).\r\n for (const skill of ctx.connector.skills) {\r\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\r\n checks.push({\r\n name: `${this.name}: skill ${skill.name} present`,\r\n check: () =>\r\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\r\n });\r\n }\r\n return checks;\r\n }\r\n}\r\n\r\nexport const adapter = new TraeAdapter();\r\nexport default adapter;\r\n"],"mappings":"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","names":["entry"]}
|
|
@@ -5,15 +5,15 @@ import {
|
|
|
5
5
|
resolveUninstallTargets,
|
|
6
6
|
uninstallConnector,
|
|
7
7
|
uninstallViaMarketplace
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-MLU7NDAZ.js";
|
|
9
|
+
import "./chunk-LQ55E7QI.js";
|
|
10
10
|
import {
|
|
11
11
|
marketplaceEvidence,
|
|
12
12
|
readMarketplaceInstalls
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-7C2IPIIB.js";
|
|
14
|
+
import "./chunk-C747DYNT.js";
|
|
15
|
+
import "./chunk-XVEJAFKW.js";
|
|
16
|
+
import "./chunk-XN7S44U4.js";
|
|
17
17
|
import {
|
|
18
18
|
buildConnectorSummary,
|
|
19
19
|
fail,
|
|
@@ -22,25 +22,25 @@ import {
|
|
|
22
22
|
parseTargets,
|
|
23
23
|
print,
|
|
24
24
|
renderInstallResult
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-N4ENLZEU.js";
|
|
26
|
+
import "./chunk-SLJI5BOM.js";
|
|
27
|
+
import "./chunk-GZZCHJDP.js";
|
|
28
|
+
import "./chunk-4GH2KA7V.js";
|
|
29
29
|
import {
|
|
30
30
|
findConnectorConfig,
|
|
31
31
|
loadConnectorFromPath
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
35
|
-
import "./chunk-
|
|
36
|
-
import "./chunk-
|
|
37
|
-
import "./chunk-
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-3EP5V2F4.js";
|
|
33
|
+
import "./chunk-7ZFK2WEO.js";
|
|
34
|
+
import "./chunk-NDMNMAKP.js";
|
|
35
|
+
import "./chunk-KFPSJRHR.js";
|
|
36
|
+
import "./chunk-PSGTHJQU.js";
|
|
37
|
+
import "./chunk-XXLCMSD3.js";
|
|
38
|
+
import "./chunk-3FINQ2ZF.js";
|
|
39
|
+
import "./chunk-Y3K6KJMS.js";
|
|
40
|
+
import "./chunk-ILWHLGIC.js";
|
|
41
41
|
import {
|
|
42
42
|
assertConnectorId
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-QYOUQCC6.js";
|
|
44
44
|
|
|
45
45
|
// src/cli/commands/uninstall.ts
|
|
46
46
|
import { parseArgs } from "util";
|
|
@@ -183,4 +183,4 @@ async function run(argv) {
|
|
|
183
183
|
export {
|
|
184
184
|
run
|
|
185
185
|
};
|
|
186
|
-
//# sourceMappingURL=uninstall-
|
|
186
|
+
//# sourceMappingURL=uninstall-RWO2GM2I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/uninstall.ts"],"sourcesContent":["/**\r\n * cli/commands/uninstall — strip a connector's registrations, method-aware.\r\n *\r\n * The connector id is taken from --connector-id, or inferred from the local\r\n * connector config (--connector <path> / findConnectorConfig).\r\n *\r\n * --method auto (default) reverses WHATEVER is actually there, per target:\r\n * targets with marketplace evidence (the state record, or the host's own plugin\r\n * state) get the HOST plugin uninstall; everything else gets the existing\r\n * direct adapter strip. Install chooses a method (a user decision); uninstall\r\n * reverses what exists (a state decision) — and since the double-install guard\r\n * enforces exactly one method per (connector, host, scope), auto is\r\n * unambiguous. Explicit --method direct|marketplace forces one path for every\r\n * target. Config removal vs plugin uninstall is therefore method-resolved:\r\n * never both, never neither.\r\n *\r\n * --purge additionally removes the framework-state this connector left behind:\r\n * its DATA-dir connector record (connectorDir(id)), the empty marketplace\r\n * staging root, and, when no connectors remain, the shared home-bin launcher.\r\n * Without --purge those linger so the connector can be re-synced without\r\n * re-registering.\r\n */\r\n\r\nimport { parseArgs } from \"node:util\";\r\n\r\nimport {\r\n purgeFrameworkState,\r\n resolveUninstallTargets,\r\n uninstallConnector,\r\n} from \"../../core/installer.js\";\r\nimport {\r\n marketplaceEvidence,\r\n parseUninstallMethod,\r\n uninstallViaMarketplace,\r\n} from \"../../core/marketplace.js\";\r\nimport { readMarketplaceInstalls } from \"../../core/marketplace-state.js\";\r\nimport { assertConnectorId } from \"../../core/ids.js\";\r\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\r\nimport type {\r\n ConnectorSummary,\r\n InstallResult,\r\n PlatformId,\r\n ResolvedConnector,\r\n} from \"../../core/types.js\";\r\nimport {\r\n buildConnectorSummary,\r\n fail,\r\n maybePrintBanner,\r\n parseScope,\r\n parseTargets,\r\n print,\r\n renderInstallResult,\r\n} from \"../app.js\";\r\n\r\n/**\r\n * Resolve the connector id from flags, then from a local config file. When the\r\n * id was inferred by LOADING a config, the resolved connector is returned too so\r\n * the caller can build a header summary; an explicit `--connector-id` yields no\r\n * connector (id-only uninstall), and the renderer degrades to an id-only header.\r\n */\r\nasync function resolveConnectorId(\r\n explicitId: string | undefined,\r\n connectorPath: string | undefined,\r\n projectDir: string,\r\n): Promise<{ id: string; connector?: ResolvedConnector } | null> {\r\n if (explicitId && explicitId.trim() !== \"\") return { id: explicitId };\r\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\r\n if (!configPath) return null;\r\n const { connector } = await loadConnectorFromPath(configPath);\r\n return { id: connector.id, connector };\r\n}\r\n\r\nexport async function run(argv: string[]): Promise<number> {\r\n const { values } = parseArgs({\r\n args: argv,\r\n options: {\r\n method: { type: \"string\", default: \"auto\" },\r\n scope: { type: \"string\", default: \"user\" },\r\n targets: { type: \"string\" },\r\n connector: { type: \"string\" },\r\n \"connector-id\": { type: \"string\" },\r\n project: { type: \"string\" },\r\n \"dry-run\": { type: \"boolean\", default: false },\r\n purge: { type: \"boolean\", default: false },\r\n // Decorative-banner suppressor (no effect on command output bytes).\r\n quiet: { type: \"boolean\", default: false },\r\n },\r\n allowPositionals: false,\r\n });\r\n\r\n maybePrintBanner({ quiet: values.quiet });\r\n\r\n const method = parseUninstallMethod(values.method);\r\n if (method == null) {\r\n return fail(`invalid --method \"${values.method}\" (use auto|direct|marketplace)`);\r\n }\r\n\r\n const projectDir = values.project ?? process.cwd();\r\n\r\n const scope = parseScope(values.scope);\r\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\r\n\r\n const resolved = await resolveConnectorId(\r\n values[\"connector-id\"],\r\n values.connector,\r\n projectDir,\r\n );\r\n if (!resolved) {\r\n return fail(\r\n \"could not determine connector id. Pass --connector-id <id>, \" +\r\n \"--connector <path>, or run inside a project with an agent-connector config.\",\r\n );\r\n }\r\n const connectorId = resolved.id;\r\n // Header summary when a connector config was actually loaded; id-only\r\n // (--connector-id) uninstalls have no connector → the renderer degrades to an\r\n // id-only header.\r\n const summary: ConnectorSummary | undefined = resolved.connector\r\n ? buildConnectorSummary(resolved.connector)\r\n : undefined;\r\n\r\n // Single choke-point: validate the id BEFORE any path is built or any delete\r\n // runs. Every branch below (explicit --method marketplace, --method auto, and\r\n // the direct strip) constructs record / staging-root paths from this id —\r\n // including the explicit --targets marketplace path, which reaches\r\n // driver.finishUninstall(id) → rmSync(join(stagingRoot, id)) without otherwise\r\n // routing the raw id through connectorDir's validation. Failing loud here closes\r\n // the `--connector-id ../../x` traversal window for ALL of them at once.\r\n try {\r\n assertConnectorId(connectorId);\r\n } catch (err) {\r\n return fail(err instanceof Error ? err.message : String(err));\r\n }\r\n\r\n const targets = parseTargets(values.targets);\r\n const dryRun = values[\"dry-run\"];\r\n\r\n // ── Explicit --method marketplace: every target goes to the marketplace path\r\n // (targets default to the recorded installs); framework purge runs here since\r\n // no direct pass follows.\r\n if (method === \"marketplace\") {\r\n const result = await uninstallViaMarketplace({\r\n connectorId,\r\n projectDir,\r\n dryRun,\r\n purge: values.purge,\r\n ...(targets ? { targets } : {}),\r\n });\r\n if (values.purge) purgeFrameworkState(connectorId, dryRun, result);\r\n result.connector = summary;\r\n print(renderInstallResult(result, \"uninstall\"));\r\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\r\n }\r\n\r\n // ── --method auto: partition the resolved targets by marketplace evidence.\r\n // (--method direct keeps every target on the adapter strip — today's path.)\r\n let marketplaceTargets: PlatformId[] = [];\r\n let directTargets: PlatformId[] = [];\r\n if (method === \"auto\") {\r\n const resolvedTargets = await resolveUninstallTargets(connectorId, targets, projectDir);\r\n // With no explicit --targets, recorded marketplace platforms are unioned\r\n // in: the state record IS the authority for what we installed, and host\r\n // detection can miss a host whose probe-able config dir was relocated.\r\n // An explicit --targets list is always respected as-is.\r\n const recorded = targets\r\n ? []\r\n : (Object.keys(readMarketplaceInstalls(connectorId)) as PlatformId[]);\r\n const candidates = [...new Set([...resolvedTargets, ...recorded])];\r\n marketplaceTargets = candidates.filter(\r\n (id) => marketplaceEvidence(connectorId, id) != null,\r\n );\r\n directTargets = resolvedTargets.filter((id) => !marketplaceTargets.includes(id));\r\n }\r\n\r\n // No marketplace evidence anywhere (or --method direct): exactly today's\r\n // single-orchestration path, byte-for-byte — zero behavior change for users\r\n // who never touched the marketplace method.\r\n if (marketplaceTargets.length === 0) {\r\n const result = await uninstallConnector({\r\n connectorId,\r\n scope,\r\n projectDir,\r\n dryRun,\r\n purge: values.purge,\r\n ...(targets ? { targets } : {}),\r\n });\r\n result.connector = summary;\r\n print(renderInstallResult(result, \"uninstall\"));\r\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\r\n }\r\n\r\n const results: InstallResult[] = [\r\n await uninstallViaMarketplace({\r\n connectorId,\r\n projectDir,\r\n targets: marketplaceTargets,\r\n dryRun,\r\n purge: values.purge,\r\n }),\r\n ];\r\n\r\n // The direct strip runs only for its partition (never both methods on one\r\n // target). When every target was marketplace-routed, --purge still runs the\r\n // framework purge (the marketplace records were just cleared, so it can\r\n // proceed to the connector record + home-bin).\r\n if (directTargets.length > 0) {\r\n results.push(\r\n await uninstallConnector({\r\n connectorId,\r\n scope,\r\n projectDir,\r\n dryRun,\r\n purge: values.purge,\r\n targets: directTargets,\r\n }),\r\n );\r\n } else if (values.purge) {\r\n const purgeResult: InstallResult = {\r\n connectorId,\r\n dryRun,\r\n changes: [],\r\n warnings: [],\r\n };\r\n if (dryRun) {\r\n // On a real run the marketplace records are removed BEFORE this purge;\r\n // calling purgeFrameworkState now would false-refuse on records that the\r\n // marketplace pass only PLANNED to remove. Report the plan instead.\r\n purgeResult.changes.push({\r\n platform: connectorId as PlatformId,\r\n action: \"remove\",\r\n detail:\r\n \"would purge framework state (connector record; home-bin when no connectors remain)\",\r\n });\r\n } else {\r\n purgeFrameworkState(connectorId, dryRun, purgeResult);\r\n }\r\n results.push(purgeResult);\r\n }\r\n\r\n const merged: InstallResult = {\r\n connectorId,\r\n dryRun,\r\n changes: results.flatMap((r) => r.changes),\r\n warnings: results.flatMap((r) => r.warnings),\r\n connector: summary,\r\n };\r\n print(renderInstallResult(merged, \"uninstall\"));\r\n return merged.changes.some((c) => c.action === \"warn\") ? 1 : 0;\r\n}\r\n"],"mappings":"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","names":[]}
|