@ken-jo/agent-connector 0.4.97 → 0.4.99

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.
Files changed (387) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +6 -6
  3. package/README.md +604 -596
  4. package/dist/{action-IPFDPOZU.js → action-5OEM3QC4.js} +17 -16
  5. package/dist/action-5OEM3QC4.js.map +1 -0
  6. package/dist/{amazon-q-IT44LEWV.js → amazon-q-7DPVJXJN.js} +6 -6
  7. package/dist/amazon-q-7DPVJXJN.js.map +1 -0
  8. package/dist/{amp-CEWOSWQO.js → amp-BQZOL5GR.js} +4 -4
  9. package/dist/amp-BQZOL5GR.js.map +1 -0
  10. package/dist/{amp-P35FRU2Z.js → amp-VYXZWHXW.js} +7 -7
  11. package/dist/amp-VYXZWHXW.js.map +1 -0
  12. package/dist/{antigravity-LHFEFNMC.js → antigravity-EA4L225L.js} +5 -5
  13. package/dist/antigravity-EA4L225L.js.map +1 -0
  14. package/dist/antigravity-VXHL6ZPM.js +18 -0
  15. package/dist/{antigravity-cli-MOKFSWOU.js → antigravity-cli-B2HXZFYQ.js} +5 -5
  16. package/dist/antigravity-cli-B2HXZFYQ.js.map +1 -0
  17. package/dist/{antigravity-cli-MPE27LPI.js → antigravity-cli-JHQ7JGNX.js} +10 -9
  18. package/dist/antigravity-cli-JHQ7JGNX.js.map +1 -0
  19. package/dist/{audit-3E5JAOP2.js → audit-BO7JQYIH.js} +8 -8
  20. package/dist/{chunk-7C2IPIIB.js → chunk-2Y2MZRLP.js} +3 -3
  21. package/dist/chunk-2Y2MZRLP.js.map +1 -0
  22. package/dist/{chunk-GZZCHJDP.js → chunk-4KIXXJ7B.js} +2 -2
  23. package/dist/chunk-4KIXXJ7B.js.map +1 -0
  24. package/dist/chunk-4NFDNY3C.js +34 -0
  25. package/dist/chunk-4NFDNY3C.js.map +1 -0
  26. package/dist/{chunk-C63AAXK7.js → chunk-4QXCNZMD.js} +5 -5
  27. package/dist/chunk-4QXCNZMD.js.map +1 -0
  28. package/dist/{chunk-Q7PR2WGT.js → chunk-6TF7MHG5.js} +2 -2
  29. package/dist/chunk-6TF7MHG5.js.map +1 -0
  30. package/dist/{chunk-7ZFK2WEO.js → chunk-6WN37NVN.js} +113 -10
  31. package/dist/chunk-6WN37NVN.js.map +1 -0
  32. package/dist/{chunk-GCPEPUD7.js → chunk-6XMV2OOA.js} +6 -6
  33. package/dist/chunk-6XMV2OOA.js.map +1 -0
  34. package/dist/{chunk-XXLCMSD3.js → chunk-BEFVJ2OE.js} +1 -1
  35. package/dist/chunk-BEFVJ2OE.js.map +1 -0
  36. package/dist/{chunk-N4ENLZEU.js → chunk-BV5WK6VQ.js} +19 -19
  37. package/dist/chunk-BV5WK6VQ.js.map +1 -0
  38. package/dist/{chunk-WPTNMYYM.js → chunk-BXPSDNIB.js} +6 -6
  39. package/dist/chunk-BXPSDNIB.js.map +1 -0
  40. package/dist/{chunk-Q4ISQHUQ.js → chunk-FBJQGRET.js} +1 -1
  41. package/dist/chunk-FBJQGRET.js.map +1 -0
  42. package/dist/{chunk-THI4PI4H.js → chunk-FJCUKXGX.js} +2 -2
  43. package/dist/chunk-FJCUKXGX.js.map +1 -0
  44. package/dist/{chunk-L2C5UMKW.js → chunk-FKW5A6HE.js} +23 -7
  45. package/dist/chunk-FKW5A6HE.js.map +1 -0
  46. package/dist/{chunk-NDMNMAKP.js → chunk-G5HAIYRM.js} +43 -43
  47. package/dist/chunk-G5HAIYRM.js.map +1 -0
  48. package/dist/{chunk-SLJI5BOM.js → chunk-GDIAHWNY.js} +2 -2
  49. package/dist/chunk-GDIAHWNY.js.map +1 -0
  50. package/dist/{chunk-QYOUQCC6.js → chunk-GZGLCCEE.js} +1 -1
  51. package/dist/chunk-GZGLCCEE.js.map +1 -0
  52. package/dist/{chunk-PSGTHJQU.js → chunk-H53QZQJI.js} +1 -1
  53. package/dist/chunk-H53QZQJI.js.map +1 -0
  54. package/dist/{chunk-7HHW23AC.js → chunk-IRUYJD23.js} +29 -29
  55. package/dist/chunk-IRUYJD23.js.map +1 -0
  56. package/dist/{chunk-IOJDZJ72.js → chunk-IVAWP6HH.js} +2 -2
  57. package/dist/chunk-IVAWP6HH.js.map +1 -0
  58. package/dist/{chunk-3FINQ2ZF.js → chunk-JTN3AKZO.js} +30 -20
  59. package/dist/chunk-JTN3AKZO.js.map +1 -0
  60. package/dist/{chunk-4GH2KA7V.js → chunk-KHO5WNTP.js} +1 -1
  61. package/dist/chunk-KHO5WNTP.js.map +1 -0
  62. package/dist/{chunk-MLU7NDAZ.js → chunk-KLZBRNFP.js} +12 -12
  63. package/dist/chunk-KLZBRNFP.js.map +1 -0
  64. package/dist/{chunk-3EP5V2F4.js → chunk-M6OS4OLU.js} +3 -3
  65. package/dist/chunk-M6OS4OLU.js.map +1 -0
  66. package/dist/{chunk-UZZTWWGG.js → chunk-MQPNU2CY.js} +1 -1
  67. package/dist/chunk-MQPNU2CY.js.map +1 -0
  68. package/dist/{chunk-LQ55E7QI.js → chunk-N4STCQGP.js} +7 -7
  69. package/dist/chunk-N4STCQGP.js.map +1 -0
  70. package/dist/{chunk-KFPSJRHR.js → chunk-NBYKLUF6.js} +2 -2
  71. package/dist/chunk-NBYKLUF6.js.map +1 -0
  72. package/dist/{chunk-KM2YXO6V.js → chunk-O7SDRBVB.js} +1 -1
  73. package/dist/chunk-O7SDRBVB.js.map +1 -0
  74. package/dist/{chunk-LFWYYWLV.js → chunk-OP4KBXUO.js} +1 -1
  75. package/dist/chunk-OP4KBXUO.js.map +1 -0
  76. package/dist/{chunk-XN7S44U4.js → chunk-OPXAP3AC.js} +1 -1
  77. package/dist/chunk-OPXAP3AC.js.map +1 -0
  78. package/dist/{chunk-TGZFDXNH.js → chunk-PWCBWAM4.js} +6 -4
  79. package/dist/chunk-PWCBWAM4.js.map +1 -0
  80. package/dist/{chunk-Y3K6KJMS.js → chunk-QSY74NAP.js} +2 -2
  81. package/dist/chunk-QSY74NAP.js.map +1 -0
  82. package/dist/{chunk-ZSOS2KOR.js → chunk-RK6VBLXP.js} +1 -1
  83. package/dist/chunk-RK6VBLXP.js.map +1 -0
  84. package/dist/{chunk-FHYR5Q5T.js → chunk-SFY6YLVK.js} +19 -12
  85. package/dist/chunk-SFY6YLVK.js.map +1 -0
  86. package/dist/{chunk-C747DYNT.js → chunk-UM5S7DKK.js} +1 -1
  87. package/dist/chunk-UM5S7DKK.js.map +1 -0
  88. package/dist/{chunk-ILWHLGIC.js → chunk-UMQ6NBQR.js} +2 -2
  89. package/dist/chunk-UMQ6NBQR.js.map +1 -0
  90. package/dist/{chunk-7PSNXUFK.js → chunk-XD7MY6HB.js} +1 -1
  91. package/dist/chunk-XD7MY6HB.js.map +1 -0
  92. package/dist/{chunk-XVEJAFKW.js → chunk-XY3N2U6L.js} +5 -5
  93. package/dist/chunk-XY3N2U6L.js.map +1 -0
  94. package/dist/{chunk-XZWMJLIT.js → chunk-YT43MUSJ.js} +1 -1
  95. package/dist/chunk-YT43MUSJ.js.map +1 -0
  96. package/dist/{claude-code-QBWDT5RT.js → claude-code-LJ6DVXWQ.js} +24 -14
  97. package/dist/claude-code-LJ6DVXWQ.js.map +1 -0
  98. package/dist/{claude-code-FS42PXZO.js → claude-code-NMRKTAP7.js} +4 -4
  99. package/dist/claude-code-NMRKTAP7.js.map +1 -0
  100. package/dist/cli/sdk.js +7 -7
  101. package/dist/cli/sdk.js.map +1 -1
  102. package/dist/cli.js +1 -1
  103. package/dist/cli.js.map +1 -1
  104. package/dist/{cline-JKEAYWVR.js → cline-JAPJNOZQ.js} +6 -6
  105. package/dist/cline-JAPJNOZQ.js.map +1 -0
  106. package/dist/{codebuddy-EB6EYPC3.js → codebuddy-GC7VAE2Y.js} +7 -7
  107. package/dist/codebuddy-GC7VAE2Y.js.map +1 -0
  108. package/dist/{codebuff-5RSXFU6G.js → codebuff-3VODFPD4.js} +6 -6
  109. package/dist/codebuff-3VODFPD4.js.map +1 -0
  110. package/dist/{codebuff-6KWBW6CT.js → codebuff-ETYT5UBL.js} +4 -4
  111. package/dist/codebuff-ETYT5UBL.js.map +1 -0
  112. package/dist/{codex-ART46CDD.js → codex-RXIS5BHM.js} +9 -9
  113. package/dist/codex-RXIS5BHM.js.map +1 -0
  114. package/dist/{codex-DKBAAUCO.js → codex-YAORPCOD.js} +4 -4
  115. package/dist/codex-YAORPCOD.js.map +1 -0
  116. package/dist/{continue-JHZCMSPH.js → continue-MECVDV4Z.js} +8 -8
  117. package/dist/continue-MECVDV4Z.js.map +1 -0
  118. package/dist/{copilot-cli-CLBJACQ5.js → copilot-cli-MZTAWMPW.js} +4 -4
  119. package/dist/copilot-cli-MZTAWMPW.js.map +1 -0
  120. package/dist/{copilot-cli-QVAU5CFM.js → copilot-cli-WVWAWNSM.js} +7 -7
  121. package/dist/copilot-cli-WVWAWNSM.js.map +1 -0
  122. package/dist/{crush-A5C5USRL.js → crush-QBXLNN7T.js} +4 -4
  123. package/dist/crush-QBXLNN7T.js.map +1 -0
  124. package/dist/{crush-7TORBYUL.js → crush-YB3SK6NK.js} +7 -7
  125. package/dist/crush-YB3SK6NK.js.map +1 -0
  126. package/dist/{cursor-D5SWDVSW.js → cursor-DIW43TRZ.js} +3 -3
  127. package/dist/cursor-DIW43TRZ.js.map +1 -0
  128. package/dist/cursor-RSLHA2CY.js +22 -0
  129. package/dist/{define-connector-DTWb46UB.d.ts → define-connector-odRHEC4H.d.ts} +1 -1
  130. package/dist/{detect-JHSA3G3U.js → detect-ALP4G7WG.js} +4 -4
  131. package/dist/detect-ALP4G7WG.js.map +1 -0
  132. package/dist/{devin-SSR7S4WX.js → devin-WPDN3MXE.js} +7 -7
  133. package/dist/devin-WPDN3MXE.js.map +1 -0
  134. package/dist/{doctor-CQJ7TZPA.js → doctor-YEQWCWZJ.js} +27 -26
  135. package/dist/doctor-YEQWCWZJ.js.map +1 -0
  136. package/dist/{droid-45PJ7JGF.js → droid-HS6MX3IL.js} +10 -8
  137. package/dist/droid-HS6MX3IL.js.map +1 -0
  138. package/dist/{droid-PFQ2PZSF.js → droid-U3ZBLQFO.js} +4 -4
  139. package/dist/droid-U3ZBLQFO.js.map +1 -0
  140. package/dist/{gemini-cli-Y6RJMU24.js → gemini-cli-NMVVBO3K.js} +4 -4
  141. package/dist/gemini-cli-NMVVBO3K.js.map +1 -0
  142. package/dist/{gemini-cli-24PFDK7D.js → gemini-cli-VJ6X5DNF.js} +8 -8
  143. package/dist/gemini-cli-VJ6X5DNF.js.map +1 -0
  144. package/dist/{goose-U5D3LCPC.js → goose-3X7ID7YW.js} +9 -9
  145. package/dist/goose-3X7ID7YW.js.map +1 -0
  146. package/dist/{goose-K2HKUTBK.js → goose-64V46Y2W.js} +4 -4
  147. package/dist/goose-64V46Y2W.js.map +1 -0
  148. package/dist/{grok-cli-L2MHAPBY.js → grok-cli-4VFVF2CQ.js} +7 -7
  149. package/dist/grok-cli-4VFVF2CQ.js.map +1 -0
  150. package/dist/{hermes-2S5JUTTJ.js → hermes-AIVUE7LX.js} +10 -8
  151. package/dist/hermes-AIVUE7LX.js.map +1 -0
  152. package/dist/{hermes-MF3NX4ZY.js → hermes-F3EGTK6N.js} +4 -4
  153. package/dist/hermes-F3EGTK6N.js.map +1 -0
  154. package/dist/{hook-VHICXHXL.js → hook-F63I3SD5.js} +17 -16
  155. package/dist/hook-F63I3SD5.js.map +1 -0
  156. package/dist/index.d.ts +3 -3
  157. package/dist/index.js +5 -5
  158. package/dist/{install-WLENR4KF.js → install-23WRRFBY.js} +21 -21
  159. package/dist/install-23WRRFBY.js.map +1 -0
  160. package/dist/{introspect-dNekqPDY.d.ts → introspect-gTx6GzpW.d.ts} +1 -1
  161. package/dist/{jetbrains-copilot-Z4FC3RM3.js → jetbrains-copilot-XBO2JZRO.js} +6 -6
  162. package/dist/jetbrains-copilot-XBO2JZRO.js.map +1 -0
  163. package/dist/{junie-ULGJJIHB.js → junie-UCOS6Q37.js} +6 -6
  164. package/dist/junie-UCOS6Q37.js.map +1 -0
  165. package/dist/{kilo-SMHPOHJ5.js → kilo-SW7BH6EG.js} +4 -4
  166. package/dist/kilo-SW7BH6EG.js.map +1 -0
  167. package/dist/{kilo-WWIJOVWD.js → kilo-T4OXNUYY.js} +8 -8
  168. package/dist/kilo-T4OXNUYY.js.map +1 -0
  169. package/dist/{kilo-cli-QKE2EQLS.js → kilo-cli-I2S3W245.js} +8 -8
  170. package/dist/kilo-cli-I2S3W245.js.map +1 -0
  171. package/dist/{kilo-cli-T2SRRRJS.js → kilo-cli-ZF272ZHN.js} +5 -5
  172. package/dist/kilo-cli-ZF272ZHN.js.map +1 -0
  173. package/dist/{kimi-MSIDEMCI.js → kimi-5FHEXGZD.js} +4 -4
  174. package/dist/kimi-5FHEXGZD.js.map +1 -0
  175. package/dist/{kimi-JMUFTVSF.js → kimi-VLSUFLYV.js} +7 -7
  176. package/dist/kimi-VLSUFLYV.js.map +1 -0
  177. package/dist/{kiro-UWUCRKR3.js → kiro-AQFXGOJX.js} +10 -8
  178. package/dist/kiro-AQFXGOJX.js.map +1 -0
  179. package/dist/{kiro-NYRRBIKW.js → kiro-WGOI5CGT.js} +4 -4
  180. package/dist/kiro-WGOI5CGT.js.map +1 -0
  181. package/dist/{leaderboard-NJWKGMXP.js → leaderboard-YBD3IKC2.js} +7 -7
  182. package/dist/leaderboard-YBD3IKC2.js.map +1 -0
  183. package/dist/{mimo-code-BPNYYIVM.js → mimo-code-KETL7W7D.js} +7 -7
  184. package/dist/mimo-code-KETL7W7D.js.map +1 -0
  185. package/dist/{mistral-vibe-LT3DAJ3L.js → mistral-vibe-3AU7N2CA.js} +6 -6
  186. package/dist/mistral-vibe-3AU7N2CA.js.map +1 -0
  187. package/dist/{mux-AHNUAY5Z.js → mux-BO2L5CTW.js} +6 -6
  188. package/dist/mux-BO2L5CTW.js.map +1 -0
  189. package/dist/{mux-7PIJ7HUQ.js → mux-XM6AP35L.js} +4 -4
  190. package/dist/mux-XM6AP35L.js.map +1 -0
  191. package/dist/{nemoclaw-RE5RZASZ.js → nemoclaw-WA7RSKF2.js} +7 -7
  192. package/dist/nemoclaw-WA7RSKF2.js.map +1 -0
  193. package/dist/{omp-D2EXEPH7.js → omp-UDYJ2PYY.js} +9 -7
  194. package/dist/omp-UDYJ2PYY.js.map +1 -0
  195. package/dist/{open-interpreter-SSGBEUKX.js → open-interpreter-WMBNM4MQ.js} +6 -6
  196. package/dist/open-interpreter-WMBNM4MQ.js.map +1 -0
  197. package/dist/openclaw-3DHVHX5P.js +17 -0
  198. package/dist/{openclaw-KAFTNLR2.js → openclaw-5EQFGOWL.js} +4 -4
  199. package/dist/openclaw-5EQFGOWL.js.map +1 -0
  200. package/dist/{opencode-YKUKZY3J.js → opencode-IKMI3RI7.js} +7 -7
  201. package/dist/opencode-IKMI3RI7.js.map +1 -0
  202. package/dist/{opencode-Z65JYILL.js → opencode-QGP4ALQY.js} +4 -4
  203. package/dist/opencode-QGP4ALQY.js.map +1 -0
  204. package/dist/{openhands-SEZMCUC3.js → openhands-QGXMQR6I.js} +7 -7
  205. package/dist/openhands-QGXMQR6I.js.map +1 -0
  206. package/dist/{package-JECVQEFT.js → package-TAUTPP7Z.js} +15 -15
  207. package/dist/package-TAUTPP7Z.js.map +1 -0
  208. package/dist/{pi-YPYV2ULH.js → pi-A2HCGRJG.js} +9 -7
  209. package/dist/pi-A2HCGRJG.js.map +1 -0
  210. package/dist/{pi-DLKCPOJE.js → pi-GGDQREVG.js} +4 -4
  211. package/dist/pi-GGDQREVG.js.map +1 -0
  212. package/dist/{qwen-code-ZHCLCYMC.js → qwen-code-DNQTGJOF.js} +35 -17
  213. package/dist/qwen-code-DNQTGJOF.js.map +1 -0
  214. package/dist/{qwen-code-26CSFDX6.js → qwen-code-GQILBJ5B.js} +4 -4
  215. package/dist/qwen-code-GQILBJ5B.js.map +1 -0
  216. package/dist/{roo-code-HSAE2CJU.js → roo-code-SUWI4BBN.js} +4 -4
  217. package/dist/roo-code-SUWI4BBN.js.map +1 -0
  218. package/dist/{roo-code-7F4HYB34.js → roo-code-VI2ZKTZC.js} +6 -6
  219. package/dist/roo-code-VI2ZKTZC.js.map +1 -0
  220. package/dist/runtime/index.d.ts +9 -8
  221. package/dist/runtime/index.js +15 -14
  222. package/dist/sdk/index.d.ts +4 -4
  223. package/dist/sdk/index.js +6 -6
  224. package/dist/sdk/index.js.map +1 -1
  225. package/dist/sdk/test.d.ts +2 -2
  226. package/dist/sdk/test.js +12 -11
  227. package/dist/{serve-LYSBH43G.js → serve-6MDLRQS2.js} +17 -16
  228. package/dist/serve-6MDLRQS2.js.map +1 -0
  229. package/dist/{status-PHKKGEW5.js → status-IUP75XHP.js} +11 -11
  230. package/dist/status-IUP75XHP.js.map +1 -0
  231. package/dist/{statusline-ZDD4OZ4F.js → statusline-PRODZV2J.js} +16 -15
  232. package/dist/statusline-PRODZV2J.js.map +1 -0
  233. package/dist/{synthetic-LUT6V6SD.js → synthetic-6FRA7P5Q.js} +4 -4
  234. package/dist/synthetic-6FRA7P5Q.js.map +1 -0
  235. package/dist/{telemetry-HDGMI2BK.js → telemetry-X4PLZEDB.js} +10 -10
  236. package/dist/telemetry-X4PLZEDB.js.map +1 -0
  237. package/dist/{trae-SIQI3C66.js → trae-CPPYASR2.js} +4 -4
  238. package/dist/trae-CPPYASR2.js.map +1 -0
  239. package/dist/{trae-Y67HSDOW.js → trae-VOJXUYRN.js} +6 -6
  240. package/dist/trae-VOJXUYRN.js.map +1 -0
  241. package/dist/{types-JyhpJHJa.d.ts → types-DWXnnx-N.d.ts} +96 -22
  242. package/dist/{uninstall-RWO2GM2I.js → uninstall-BSIJ4QXN.js} +21 -21
  243. package/dist/uninstall-BSIJ4QXN.js.map +1 -0
  244. package/dist/{upgrade-YJCXNUEE.js → upgrade-ZSICU3NE.js} +21 -21
  245. package/dist/upgrade-ZSICU3NE.js.map +1 -0
  246. package/dist/{usage-IWO4RQN6.js → usage-EQUNVSCT.js} +4 -4
  247. package/dist/usage-EQUNVSCT.js.map +1 -0
  248. package/dist/{usage-event-AFFKCLHE.js → usage-event-J5CQ6LNT.js} +16 -15
  249. package/dist/usage-event-J5CQ6LNT.js.map +1 -0
  250. package/dist/{vscode-copilot-5CI5B3X6.js → vscode-copilot-ZBXRPKGG.js} +7 -7
  251. package/dist/vscode-copilot-ZBXRPKGG.js.map +1 -0
  252. package/dist/{warp-5YBSP7FP.js → warp-NRBBJQR2.js} +4 -4
  253. package/dist/warp-NRBBJQR2.js.map +1 -0
  254. package/dist/{warp-INAKVGBV.js → warp-S444B2S3.js} +9 -7
  255. package/dist/warp-S444B2S3.js.map +1 -0
  256. package/dist/{windsurf-4HM57QAY.js → windsurf-R6D2JUTN.js} +6 -6
  257. package/dist/windsurf-R6D2JUTN.js.map +1 -0
  258. package/dist/{zed-YN5X37PQ.js → zed-DQV3ZUCU.js} +10 -8
  259. package/dist/zed-DQV3ZUCU.js.map +1 -0
  260. package/dist/{zed-XXCNYOIN.js → zed-XJFOOKCO.js} +4 -4
  261. package/dist/zed-XJFOOKCO.js.map +1 -0
  262. package/package.json +88 -88
  263. package/dist/action-IPFDPOZU.js.map +0 -1
  264. package/dist/amazon-q-IT44LEWV.js.map +0 -1
  265. package/dist/amp-CEWOSWQO.js.map +0 -1
  266. package/dist/amp-P35FRU2Z.js.map +0 -1
  267. package/dist/antigravity-LHFEFNMC.js.map +0 -1
  268. package/dist/antigravity-TWIWXTQH.js +0 -18
  269. package/dist/antigravity-cli-MOKFSWOU.js.map +0 -1
  270. package/dist/antigravity-cli-MPE27LPI.js.map +0 -1
  271. package/dist/chunk-3EP5V2F4.js.map +0 -1
  272. package/dist/chunk-3FINQ2ZF.js.map +0 -1
  273. package/dist/chunk-4GH2KA7V.js.map +0 -1
  274. package/dist/chunk-7C2IPIIB.js.map +0 -1
  275. package/dist/chunk-7HHW23AC.js.map +0 -1
  276. package/dist/chunk-7PSNXUFK.js.map +0 -1
  277. package/dist/chunk-7ZFK2WEO.js.map +0 -1
  278. package/dist/chunk-C63AAXK7.js.map +0 -1
  279. package/dist/chunk-C747DYNT.js.map +0 -1
  280. package/dist/chunk-FHYR5Q5T.js.map +0 -1
  281. package/dist/chunk-GCPEPUD7.js.map +0 -1
  282. package/dist/chunk-GZZCHJDP.js.map +0 -1
  283. package/dist/chunk-ILWHLGIC.js.map +0 -1
  284. package/dist/chunk-IOJDZJ72.js.map +0 -1
  285. package/dist/chunk-KFPSJRHR.js.map +0 -1
  286. package/dist/chunk-KM2YXO6V.js.map +0 -1
  287. package/dist/chunk-L2C5UMKW.js.map +0 -1
  288. package/dist/chunk-LFWYYWLV.js.map +0 -1
  289. package/dist/chunk-LQ55E7QI.js.map +0 -1
  290. package/dist/chunk-MLU7NDAZ.js.map +0 -1
  291. package/dist/chunk-N4ENLZEU.js.map +0 -1
  292. package/dist/chunk-NDMNMAKP.js.map +0 -1
  293. package/dist/chunk-PSGTHJQU.js.map +0 -1
  294. package/dist/chunk-Q4ISQHUQ.js.map +0 -1
  295. package/dist/chunk-Q7PR2WGT.js.map +0 -1
  296. package/dist/chunk-QYOUQCC6.js.map +0 -1
  297. package/dist/chunk-SLJI5BOM.js.map +0 -1
  298. package/dist/chunk-TGZFDXNH.js.map +0 -1
  299. package/dist/chunk-THI4PI4H.js.map +0 -1
  300. package/dist/chunk-UZZTWWGG.js.map +0 -1
  301. package/dist/chunk-WPTNMYYM.js.map +0 -1
  302. package/dist/chunk-XN7S44U4.js.map +0 -1
  303. package/dist/chunk-XVEJAFKW.js.map +0 -1
  304. package/dist/chunk-XXLCMSD3.js.map +0 -1
  305. package/dist/chunk-XZWMJLIT.js.map +0 -1
  306. package/dist/chunk-Y3K6KJMS.js.map +0 -1
  307. package/dist/chunk-ZSOS2KOR.js.map +0 -1
  308. package/dist/claude-code-FS42PXZO.js.map +0 -1
  309. package/dist/claude-code-QBWDT5RT.js.map +0 -1
  310. package/dist/cline-JKEAYWVR.js.map +0 -1
  311. package/dist/codebuddy-EB6EYPC3.js.map +0 -1
  312. package/dist/codebuff-5RSXFU6G.js.map +0 -1
  313. package/dist/codebuff-6KWBW6CT.js.map +0 -1
  314. package/dist/codex-ART46CDD.js.map +0 -1
  315. package/dist/codex-DKBAAUCO.js.map +0 -1
  316. package/dist/continue-JHZCMSPH.js.map +0 -1
  317. package/dist/copilot-cli-CLBJACQ5.js.map +0 -1
  318. package/dist/copilot-cli-QVAU5CFM.js.map +0 -1
  319. package/dist/crush-7TORBYUL.js.map +0 -1
  320. package/dist/crush-A5C5USRL.js.map +0 -1
  321. package/dist/cursor-D5SWDVSW.js.map +0 -1
  322. package/dist/cursor-W7I4QUFO.js +0 -22
  323. package/dist/detect-JHSA3G3U.js.map +0 -1
  324. package/dist/devin-SSR7S4WX.js.map +0 -1
  325. package/dist/doctor-CQJ7TZPA.js.map +0 -1
  326. package/dist/droid-45PJ7JGF.js.map +0 -1
  327. package/dist/droid-PFQ2PZSF.js.map +0 -1
  328. package/dist/gemini-cli-24PFDK7D.js.map +0 -1
  329. package/dist/gemini-cli-Y6RJMU24.js.map +0 -1
  330. package/dist/goose-K2HKUTBK.js.map +0 -1
  331. package/dist/goose-U5D3LCPC.js.map +0 -1
  332. package/dist/grok-cli-L2MHAPBY.js.map +0 -1
  333. package/dist/hermes-2S5JUTTJ.js.map +0 -1
  334. package/dist/hermes-MF3NX4ZY.js.map +0 -1
  335. package/dist/hook-VHICXHXL.js.map +0 -1
  336. package/dist/install-WLENR4KF.js.map +0 -1
  337. package/dist/jetbrains-copilot-Z4FC3RM3.js.map +0 -1
  338. package/dist/junie-ULGJJIHB.js.map +0 -1
  339. package/dist/kilo-SMHPOHJ5.js.map +0 -1
  340. package/dist/kilo-WWIJOVWD.js.map +0 -1
  341. package/dist/kilo-cli-QKE2EQLS.js.map +0 -1
  342. package/dist/kilo-cli-T2SRRRJS.js.map +0 -1
  343. package/dist/kimi-JMUFTVSF.js.map +0 -1
  344. package/dist/kimi-MSIDEMCI.js.map +0 -1
  345. package/dist/kiro-NYRRBIKW.js.map +0 -1
  346. package/dist/kiro-UWUCRKR3.js.map +0 -1
  347. package/dist/leaderboard-NJWKGMXP.js.map +0 -1
  348. package/dist/mimo-code-BPNYYIVM.js.map +0 -1
  349. package/dist/mistral-vibe-LT3DAJ3L.js.map +0 -1
  350. package/dist/mux-7PIJ7HUQ.js.map +0 -1
  351. package/dist/mux-AHNUAY5Z.js.map +0 -1
  352. package/dist/nemoclaw-RE5RZASZ.js.map +0 -1
  353. package/dist/omp-D2EXEPH7.js.map +0 -1
  354. package/dist/open-interpreter-SSGBEUKX.js.map +0 -1
  355. package/dist/openclaw-IJ33K45M.js +0 -17
  356. package/dist/openclaw-KAFTNLR2.js.map +0 -1
  357. package/dist/opencode-YKUKZY3J.js.map +0 -1
  358. package/dist/opencode-Z65JYILL.js.map +0 -1
  359. package/dist/openhands-SEZMCUC3.js.map +0 -1
  360. package/dist/package-JECVQEFT.js.map +0 -1
  361. package/dist/pi-DLKCPOJE.js.map +0 -1
  362. package/dist/pi-YPYV2ULH.js.map +0 -1
  363. package/dist/qwen-code-26CSFDX6.js.map +0 -1
  364. package/dist/qwen-code-ZHCLCYMC.js.map +0 -1
  365. package/dist/roo-code-7F4HYB34.js.map +0 -1
  366. package/dist/roo-code-HSAE2CJU.js.map +0 -1
  367. package/dist/serve-LYSBH43G.js.map +0 -1
  368. package/dist/status-PHKKGEW5.js.map +0 -1
  369. package/dist/statusline-ZDD4OZ4F.js.map +0 -1
  370. package/dist/synthetic-LUT6V6SD.js.map +0 -1
  371. package/dist/telemetry-HDGMI2BK.js.map +0 -1
  372. package/dist/trae-SIQI3C66.js.map +0 -1
  373. package/dist/trae-Y67HSDOW.js.map +0 -1
  374. package/dist/uninstall-RWO2GM2I.js.map +0 -1
  375. package/dist/upgrade-YJCXNUEE.js.map +0 -1
  376. package/dist/usage-IWO4RQN6.js.map +0 -1
  377. package/dist/usage-event-AFFKCLHE.js.map +0 -1
  378. package/dist/vscode-copilot-5CI5B3X6.js.map +0 -1
  379. package/dist/warp-5YBSP7FP.js.map +0 -1
  380. package/dist/warp-INAKVGBV.js.map +0 -1
  381. package/dist/windsurf-4HM57QAY.js.map +0 -1
  382. package/dist/zed-XXCNYOIN.js.map +0 -1
  383. package/dist/zed-YN5X37PQ.js.map +0 -1
  384. /package/dist/{antigravity-TWIWXTQH.js.map → antigravity-VXHL6ZPM.js.map} +0 -0
  385. /package/dist/{audit-3E5JAOP2.js.map → audit-BO7JQYIH.js.map} +0 -0
  386. /package/dist/{cursor-W7I4QUFO.js.map → cursor-RSLHA2CY.js.map} +0 -0
  387. /package/dist/{openclaw-IJ33K45M.js.map → openclaw-3DHVHX5P.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/usage/readers/synthetic.ts"],"sourcesContent":["/**\n * usage/readers/synthetic — Synthetic.new (Octofriend / HF gateway) usage reader.\n *\n * Faithful port of tokscale sessions/synthetic.rs (parse_octofriend_sqlite). The\n * Octofriend client persists usage in a single SQLite database. Per the tokscale\n * scanner (scanner.rs), the db lives at:\n * ${XDG_DATA_HOME:-~/.local/share}/octofriend/sqlite.db\n * (an AGENT_CONNECTOR_SYNTHETIC_DIR override is honored first — verbatim,\n * non-empty — mirroring the paths.ts env-override contract; `synthetic` is not\n * yet wired into paths.ts hostRoots, so the path is resolved here.)\n *\n * Octofriend historically stored only input_history (no token data), so the\n * parser is future-proofed: it first checks sqlite_master for any of the\n * token-tracking tables ('messages', 'sessions', 'token_usage'); when none\n * exist it yields []. When present it parses the `messages` table (the full\n * schema with cache + reasoning + cost), falling back to the simpler\n * `token_usage` table only when `messages` produced no rows.\n *\n * messages table (port of the primary SELECT):\n * SELECT id, model, input_tokens, output_tokens, cache_read_tokens,\n * cache_write_tokens, reasoning_tokens, cost, timestamp, session_id,\n * provider\n * FROM messages\n * WHERE input_tokens IS NOT NULL OR output_tokens IS NOT NULL\n * → input/output/cacheRead/cacheWrite/reasoning each clamped ≥ 0; a row whose\n * 5-dimension sum is 0 is skipped; cost ≥ 0; provider column (fallback\n * \"synthetic\" when missing/empty); dedup_key = id.\n *\n * token_usage fallback (only when messages yielded nothing):\n * SELECT id, model, input_tokens, output_tokens, timestamp, session_id\n * FROM token_usage\n * WHERE input_tokens > 0 OR output_tokens > 0\n * → only input/output (cache + reasoning = 0); provider hardcoded \"synthetic\";\n * cost = 0; dedup_key = id.\n *\n * Model normalization (port of normalize_synthetic_model): strips synthetic.new\n * gateway prefixes for a clean grouping id:\n * \"hf:deepseek-ai/DeepSeek-V3-0324\" → \"deepseek-v3-0324\"\n * \"accounts/fireworks/models/deepseek-v3-0324\" → \"deepseek-v3-0324\"\n * Provider is inferProvider() of the cleaned model, falling back to the row's\n * provider column (or \"synthetic\"). Timestamp is the f64 `timestamp` column:\n * values > 1e12 are already ms, smaller values are seconds (×1000). No project\n * attribution exists in the Octofriend schema. Confidence is host-reported, but\n * the spec rates this source medium (the schema is still emergent/future-proofed),\n * so rows are marked \"host-estimated\" to label that honestly.\n *\n * Fail-open: db missing/locked/unreadable / non-sqlite → openSqlite returns null\n * → []; a bad row is skipped, never thrown.\n */\n\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\n\nimport type { UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { inferProvider } from \"../normalize.js\";\nimport { expandHome } from \"../paths.js\";\nimport { openSqlite } from \"../sqlite.js\";\n\nconst PLATFORM_ID = \"synthetic\" as const;\nconst DEFAULT_PROVIDER = \"synthetic\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Octofriend db-path resolution (port of scanner.rs synthetic_db discovery).\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Read an env override, treating empty/blank as unset (mirrors the paths.ts\n * envOverride contract: an empty override must NOT resolve to \"\"). Relative\n * paths resolve against the process CWD; a leading \"~\" is expanded.\n */\nfunction envOverride(name: string): string | undefined {\n const raw = process.env[name];\n if (raw == null || raw.trim() === \"\") return undefined;\n const expanded = expandHome(raw.trim());\n return isAbsolute(expanded) ? expanded : resolve(expanded);\n}\n\n/** $XDG_DATA_HOME (when set & non-empty) else ~/.local/share — as in paths.ts. */\nfunction xdgDataHome(): string {\n const xdg = process.env.XDG_DATA_HOME;\n if (xdg && xdg.trim() !== \"\") return resolve(expandHome(xdg.trim()));\n return join(homedir(), \".local\", \"share\");\n}\n\n/**\n * Resolve the Octofriend sqlite.db path. Honors AGENT_CONNECTOR_SYNTHETIC_DIR\n * first (treated as the octofriend directory: `<dir>/sqlite.db`), else the\n * tokscale default `${XDG_DATA_HOME:-~/.local/share}/octofriend/sqlite.db`.\n */\nfunction octofriendDbPath(): string {\n const override = envOverride(\"AGENT_CONNECTOR_SYNTHETIC_DIR\");\n if (override !== undefined) return join(override, \"sqlite.db\");\n return join(xdgDataHome(), \"octofriend\", \"sqlite.db\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Model normalization (port of normalize_synthetic_model).\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Normalize a synthetic.new model id to a standard form, lowercased:\n * \"hf:<org>/<model>\" → \"<model>\"\n * \"hf:<model>\" → \"<model>\"\n * \"accounts/<provider>/models/<model>\" → \"<model>\"\n * Any other id passes through lowercased. Mirrors the Rust strip_prefix /\n * split_once chain exactly.\n */\nfunction normalizeSyntheticModel(modelId: string): string {\n const lower = modelId.toLowerCase();\n\n // Strip \"hf:\" prefix and (optional) org name.\n if (lower.startsWith(\"hf:\")) {\n const rest = lower.slice(\"hf:\".length);\n const slash = rest.indexOf(\"/\");\n if (slash >= 0) return rest.slice(slash + 1);\n return rest;\n }\n\n // Strip \"accounts/<provider>/models/\" prefix.\n if (lower.startsWith(\"accounts/\")) {\n const rest = lower.slice(\"accounts/\".length);\n const marker = \"/models/\";\n const idx = rest.indexOf(marker);\n if (idx >= 0) return rest.slice(idx + marker.length);\n }\n\n return lower;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Cell coercion & timestamp.\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Coerce a SQLite cell to an integer (Rust get::<i64>().unwrap_or(0)), no clamp. */\nfunction toInt(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n)) return 0;\n return Math.trunc(n);\n}\n\n/** Coerce a SQLite cell to a float (Rust get::<f64>().unwrap_or(0.0)). */\nfunction toFloat(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n return Number.isFinite(n) ? n : 0;\n}\n\n/** Coerce to a non-empty trimmed string, or undefined. */\nfunction toStr(v: unknown): string | undefined {\n if (typeof v !== \"string\") return undefined;\n return v;\n}\n\n/**\n * Convert the f64 `timestamp` column to epoch ms (port of the Rust branch):\n * values > 1e12 are already milliseconds (cast); smaller values are seconds\n * (×1000). Truncating, matching the Rust `as i64`.\n */\nfunction timestampToMs(timestamp: number): number {\n return timestamp > 1e12 ? Math.trunc(timestamp) : Math.trunc(timestamp * 1000);\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Table presence check (port of the sqlite_master count).\n// ─────────────────────────────────────────────────────────────────────────\n\nconst TABLE_CHECK_SQL = `\n SELECT count(*) AS n\n FROM sqlite_master\n WHERE type='table' AND name IN ('messages', 'sessions', 'token_usage')\n`;\n\n/** Row shape for the primary `messages` SELECT (all cells optional / unknown). */\ninterface MessagesRow {\n id?: unknown;\n model?: unknown;\n input_tokens?: unknown;\n output_tokens?: unknown;\n cache_read_tokens?: unknown;\n cache_write_tokens?: unknown;\n reasoning_tokens?: unknown;\n cost?: unknown;\n timestamp?: unknown;\n session_id?: unknown;\n provider?: unknown;\n}\n\nconst MESSAGES_SQL = `\n SELECT id, model, input_tokens, output_tokens, cache_read_tokens,\n cache_write_tokens, reasoning_tokens, cost, timestamp, session_id, provider\n FROM messages\n WHERE input_tokens IS NOT NULL OR output_tokens IS NOT NULL\n`;\n\n/** Row shape for the `token_usage` fallback SELECT. */\ninterface TokenUsageRow {\n id?: unknown;\n model?: unknown;\n input_tokens?: unknown;\n output_tokens?: unknown;\n timestamp?: unknown;\n session_id?: unknown;\n}\n\nconst TOKEN_USAGE_SQL = `\n SELECT id, model, input_tokens, output_tokens, timestamp, session_id\n FROM token_usage\n WHERE input_tokens > 0 OR output_tokens > 0\n`;\n\n// ─────────────────────────────────────────────────────────────────────────\n// Reader\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The Synthetic.new (Octofriend) usage reader singleton. */\nconst syntheticReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"local\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n const dbPath = octofriendDbPath();\n\n const db = await openSqlite(dbPath);\n if (db === null) return []; // missing / locked / unreadable / non-sqlite → fail-open\n\n try {\n // Future-proofing: only parse when a token-tracking table exists.\n const tableCheck = db.all(TABLE_CHECK_SQL);\n const tableCount = tableCheck.length > 0 ? toInt(tableCheck[0]?.n) : 0;\n if (tableCount <= 0) return [];\n\n const records: UsageRecord[] = [];\n\n // Primary schema: the `messages` table (full token breakdown + cost).\n const messageRows = db.all(MESSAGES_SQL); // bad SQL / schema mismatch → []\n for (const raw of messageRows) {\n const row = raw as MessagesRow;\n\n const id = toStr(row.id);\n if (id === undefined) continue; // Rust requires id (row.get(0)? bails otherwise)\n\n const rawModel = toStr(row.model) ?? \"\";\n const input = Math.max(0, toInt(row.input_tokens));\n const output = Math.max(0, toInt(row.output_tokens));\n const cacheRead = Math.max(0, toInt(row.cache_read_tokens));\n const cacheWrite = Math.max(0, toInt(row.cache_write_tokens));\n const reasoning = Math.max(0, toInt(row.reasoning_tokens));\n\n // Skip zero-token rows (Rust: total == 0 → continue), using raw (signed) sums.\n const total =\n toInt(row.input_tokens) +\n toInt(row.output_tokens) +\n toInt(row.cache_read_tokens) +\n toInt(row.cache_write_tokens) +\n toInt(row.reasoning_tokens);\n if (total === 0) continue;\n\n const cost = Math.max(0, toFloat(row.cost));\n const ts = timestampToMs(toFloat(row.timestamp));\n if (sinceMs !== undefined && ts < sinceMs) continue;\n\n const sessionId = toStr(row.session_id) ?? \"unknown\";\n // Provider: row column when present, else \"synthetic\" (Rust unwrap_or).\n const rowProvider = toStr(row.provider);\n const columnProvider =\n rowProvider !== undefined && rowProvider !== \"\" ? rowProvider : DEFAULT_PROVIDER;\n\n const modelId = normalizeSyntheticModel(rawModel);\n const providerId = inferProvider(modelId) ?? columnProvider;\n\n const tokens = emptyTokens();\n tokens.input = input;\n tokens.output = output;\n tokens.cacheRead = cacheRead;\n tokens.cacheWrite = cacheWrite;\n tokens.reasoning = reasoning;\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId,\n providerId,\n sessionId,\n tokens,\n ts,\n messageCount: 1,\n dedupKey: id, // messages.id → one record per row\n confidence: \"host-estimated\", // spec rates this source medium\n };\n if (cost > 0) record.cost = cost;\n records.push(record);\n }\n\n // Fallback schema: only when `messages` produced nothing.\n if (records.length === 0) {\n const tokenRows = db.all(TOKEN_USAGE_SQL);\n for (const raw of tokenRows) {\n const row = raw as TokenUsageRow;\n\n const id = toStr(row.id);\n if (id === undefined) continue;\n\n const rawModel = toStr(row.model) ?? \"\";\n const input = Math.max(0, toInt(row.input_tokens));\n const output = Math.max(0, toInt(row.output_tokens));\n\n const ts = timestampToMs(toFloat(row.timestamp));\n if (sinceMs !== undefined && ts < sinceMs) continue;\n\n const sessionId = toStr(row.session_id) ?? \"unknown\";\n const modelId = normalizeSyntheticModel(rawModel);\n const providerId = inferProvider(modelId) ?? DEFAULT_PROVIDER;\n\n const tokens = emptyTokens();\n tokens.input = input;\n tokens.output = output;\n // cacheRead / cacheWrite / reasoning stay 0 (token_usage has no such columns).\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId,\n providerId,\n sessionId,\n tokens,\n ts,\n messageCount: 1,\n dedupKey: id,\n confidence: \"host-estimated\",\n };\n records.push(record);\n }\n }\n\n return records;\n } finally {\n db.close();\n }\n },\n};\n\nexport default syntheticReader;\n"],"mappings":"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","names":[]}
@@ -8,25 +8,25 @@ import {
8
8
  mcpLeaderboard,
9
9
  surfaceLeaderboard,
10
10
  toolLeaderboard
11
- } from "./chunk-Q7PR2WGT.js";
11
+ } from "./chunk-6TF7MHG5.js";
12
12
  import {
13
13
  fail,
14
14
  print
15
- } from "./chunk-N4ENLZEU.js";
15
+ } from "./chunk-BV5WK6VQ.js";
16
16
  import {
17
17
  openStore
18
- } from "./chunk-IOJDZJ72.js";
18
+ } from "./chunk-IVAWP6HH.js";
19
19
  import {
20
20
  connectorFromMeta,
21
21
  listRegisteredConnectors,
22
22
  loadRegisteredConnector,
23
23
  readRegisteredMeta
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";
24
+ } from "./chunk-M6OS4OLU.js";
25
+ import "./chunk-6WN37NVN.js";
26
+ import "./chunk-G5HAIYRM.js";
27
+ import "./chunk-NBYKLUF6.js";
28
+ import "./chunk-UMQ6NBQR.js";
29
+ import "./chunk-GZGLCCEE.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-HDGMI2BK.js.map
352
+ //# sourceMappingURL=telemetry-X4PLZEDB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/telemetry.ts","../src/telemetry/report.ts"],"sourcesContent":["/**\n * cli/commands/telemetry — inspect the local per-tool token telemetry store.\n *\n * Subcommands:\n * report --by tool|session|project (default tool) --since 7d|24h|… --connector <id> [--json]\n * → summarize(openStore({}), …) + formatReport (the aligned table).\n * export --format csv|json (default json) --out <file> [--since/--connector …]\n * → toCSV / toJSONExport of the raw records.\n *\n * Telemetry rows are aggregate counts only (never raw arguments/results).\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { parseArgs } from \"node:util\";\n\nimport type { QueryFilter } from \"../../telemetry/types.js\";\nimport type { RollupDimension } from \"../../telemetry/report.js\";\nimport { openStore } from \"../../telemetry/store.js\";\nimport { summarize, toCSV, toJSONExport } from \"../../telemetry/report.js\";\nimport {\n formatMcpLeaderboard,\n formatSurfaceLeaderboard,\n formatToolLeaderboard,\n isScopeFilter,\n mcpLeaderboard,\n SCOPE_FILTER_VALUES,\n surfaceLeaderboard,\n toolLeaderboard,\n type LeaderboardOptions,\n type ScopeFilter,\n type SurfaceLeaderboardOptions,\n} from \"../../telemetry/leaderboard.js\";\nimport {\n connectorFromMeta,\n listRegisteredConnectors,\n loadRegisteredConnector,\n readRegisteredMeta,\n} from \"../../core/load-connector.js\";\nimport type { ResolvedConnector } from \"../../core/types.js\";\nimport { fail, print } from \"../app.js\";\n\n/**\n * Parse a relative duration (`Ns`/`Nm`/`Nh`/`Nd`) to a lower-bound epoch ms.\n * Returns undefined for an empty input and null for a malformed one.\n */\nexport function parseSince(since: string | undefined): number | null | undefined {\n if (since == null || since.trim() === \"\") return undefined;\n const m = since.trim().match(/^(\\d+)\\s*([smhd])$/i);\n if (!m || !m[1] || !m[2]) return null;\n const n = Number(m[1]);\n const unitMs: Record<string, number> = {\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n };\n const factor = unitMs[m[2].toLowerCase()];\n if (factor == null) return null;\n return Date.now() - n * factor;\n}\n\n/** Build a QueryFilter from the shared --since / --connector flags. */\nfunction buildFilter(\n since: string | undefined,\n connectorId: string | undefined,\n): QueryFilter | null {\n const sinceMs = parseSince(since);\n if (sinceMs === null) return null;\n const filter: QueryFilter = {};\n if (sinceMs !== undefined) filter.sinceMs = sinceMs;\n if (connectorId && connectorId.trim() !== \"\") filter.connectorId = connectorId;\n return filter;\n}\n\nfunction runReport(argv: string[]): number {\n const { values } = parseArgs({\n args: argv,\n options: {\n by: { type: \"string\", default: \"tool\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const by = values.by;\n if (by !== \"tool\" && by !== \"session\" && by !== \"project\") {\n return fail(`invalid --by \"${by}\" (use tool|session|project)`);\n }\n const dimension: RollupDimension = by;\n\n const filter = buildFilter(values.since, values.connector);\n if (filter === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n const store = openStore({});\n try {\n const { rows, text } = summarize(store, { by: dimension, filter });\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n } else {\n print(text);\n }\n } finally {\n store.close();\n }\n return 0;\n}\n\nfunction runExport(argv: string[]): number {\n const { values } = parseArgs({\n args: argv,\n options: {\n format: { type: \"string\", default: \"json\" },\n out: { type: \"string\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n },\n allowPositionals: false,\n });\n\n const format = values.format;\n if (format !== \"csv\" && format !== \"json\") {\n return fail(`invalid --format \"${format}\" (use csv|json)`);\n }\n\n const filter = buildFilter(values.since, values.connector);\n if (filter === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n const store = openStore({});\n let serialized: string;\n try {\n const records = store.query(filter);\n serialized = format === \"csv\" ? toCSV(records) : toJSONExport(records);\n } finally {\n store.close();\n }\n\n if (values.out && values.out.trim() !== \"\") {\n writeFileSync(values.out, serialized, \"utf8\");\n print(`wrote ${format.toUpperCase()} export → ${values.out}`);\n } else {\n print(serialized);\n }\n return 0;\n}\n\n/**\n * `telemetry leaderboard` — rank the per-MCP telemetry by connector (--by mcp,\n * the default and signature \"which MCP server costs the most\" metric), by tool\n * (--by tool), or by developer-axis surface (--by surface — the FIVE surfaces:\n * server + hook runtime rows plus static command/skill/subagent footprints).\n * Honors --since / --connector and the scope slice (--scope).\n */\nasync function runLeaderboard(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n by: { type: \"string\", default: \"mcp\" },\n since: { type: \"string\" },\n connector: { type: \"string\" },\n scope: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const by = values.by;\n if (by !== \"mcp\" && by !== \"tool\" && by !== \"surface\") {\n return fail(`invalid --by \"${by}\" (use mcp|tool|surface)`);\n }\n\n const sinceMs = parseSince(values.since);\n if (sinceMs === null) {\n return fail(`invalid --since \"${values.since}\" (use forms like 30s, 15m, 24h, 7d)`);\n }\n\n let scope: ScopeFilter | undefined;\n if (values.scope !== undefined && values.scope.trim() !== \"\") {\n const s = values.scope.trim();\n if (!isScopeFilter(s)) {\n return fail(`invalid --scope \"${s}\" (use ${SCOPE_FILTER_VALUES.join(\"|\")})`);\n }\n scope = s;\n }\n\n const opts: LeaderboardOptions = {};\n if (sinceMs !== undefined) opts.sinceMs = sinceMs;\n if (values.connector && values.connector.trim() !== \"\") {\n opts.connectorId = values.connector.trim();\n }\n if (scope !== undefined) opts.scope = scope;\n\n if (by === \"tool\") {\n const rows = toolLeaderboard(opts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatToolLeaderboard(rows));\n } else if (by === \"surface\") {\n // The per-surface view folds the STATIC command/skill/subagent footprints of\n // the registered connector(s) into the runtime server/hook rows.\n const connectorId = values.connector?.trim();\n const surfaceOpts: SurfaceLeaderboardOptions = {\n ...opts,\n connectors: await gatherConnectors(connectorId),\n };\n const rows = surfaceLeaderboard(surfaceOpts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatSurfaceLeaderboard(rows));\n } else {\n const rows = mcpLeaderboard(opts);\n print(values.json ? JSON.stringify(rows, null, 2) : formatMcpLeaderboard(rows));\n }\n return 0;\n}\n\n/**\n * Gather the registered connector(s) whose STATIC command/skill/subagent\n * footprints feed the per-surface view. When `connectorId` is given, prefer the\n * LIVE module (freshest content) and fall back to the persisted meta record;\n * otherwise enumerate every registered connector from its meta. Best-effort: a\n * connector that cannot be loaded is skipped (the surface view still renders the\n * runtime rows it can read from the store).\n */\nasync function gatherConnectors(\n connectorId: string | undefined,\n): Promise<ResolvedConnector[]> {\n if (connectorId !== undefined && connectorId !== \"\") {\n try {\n return [await loadRegisteredConnector(connectorId)];\n } catch {\n const meta = readRegisteredMetaSafe(connectorId);\n return meta ? [connectorFromMeta(meta)] : [];\n }\n }\n return listRegisteredConnectors();\n}\n\n/** readRegisteredMeta wrapped so a missing/corrupt record never throws here. */\nfunction readRegisteredMetaSafe(id: string): ReturnType<typeof readRegisteredMeta> {\n try {\n return readRegisteredMeta(id);\n } catch {\n return null;\n }\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const sub = argv[0];\n const rest = argv.slice(1);\n\n switch (sub) {\n case \"report\":\n return runReport(rest);\n case \"export\":\n return runExport(rest);\n case \"leaderboard\":\n return await runLeaderboard(rest);\n case undefined:\n case \"--help\":\n case \"-h\":\n print(\"usage: agent-connector telemetry <report|export|leaderboard> [flags]\");\n print(\" report --by tool|session|project --since 7d --connector <id> --json\");\n print(\" export --format csv|json --out <file> --since 7d --connector <id>\");\n print(\" leaderboard --by mcp|tool|surface --since 7d --connector <id> --scope <slice> --json\");\n return sub === undefined ? 1 : 0;\n default:\n return fail(`unknown telemetry subcommand \"${sub}\" (use report|export|leaderboard)`);\n }\n}\n","/**\n * telemetry/report — CLI-facing formatting for telemetry rollups and exports.\n *\n * Pure functions: take store output (rollup rows / raw records) and render text,\n * CSV, or JSON. No IO except {@link summarize}, which reads through a passed-in\n * {@link TelemetryStore}. Confidence is surfaced verbatim so heuristic/approx\n * numbers are never mistaken for exact host-reported usage.\n */\n\nimport type { TelemetryStore } from \"./types.js\";\nimport type {\n ConfidenceSource,\n QueryFilter,\n RollupRow,\n ToolEventRecord,\n} from \"./types.js\";\n\n/** Grouping dimension, mirrored from {@link TelemetryStore.rollup}. */\nexport type RollupDimension = \"tool\" | \"session\" | \"project\";\n\n/** Human label for the leading KEY column, per grouping dimension. */\nconst KEY_HEADER: Record<RollupDimension, string> = {\n tool: \"TOOL\",\n session: \"SESSION\",\n project: \"PROJECT\",\n};\n\n/**\n * Sources whose counts are estimates (vs. real / host-reported numbers).\n * `tokenizer-calibrated` is still an estimate — an approximation nudged toward\n * truth by a sampled Anthropic count_tokens factor — so it belongs here too.\n */\nconst ESTIMATE_SOURCES: ReadonlySet<ConfidenceSource> = new Set<ConfidenceSource>([\n \"heuristic\",\n \"tokenizer-approx\",\n \"tokenizer-calibrated\",\n]);\n\n/** Compact, fixed-width integer formatting with thousands separators. */\nfunction fmtInt(n: number): string {\n return n.toLocaleString(\"en-US\");\n}\n\n/** Pad a cell to a column width (right-pad text, used for left-aligned cols). */\nfunction padRight(s: string, width: number): string {\n return s.length >= width ? s : s + \" \".repeat(width - s.length);\n}\n\n/** Pad a cell to a column width (left-pad, used for right-aligned numbers). */\nfunction padLeft(s: string, width: number): string {\n return s.length >= width ? s : \" \".repeat(width - s.length) + s;\n}\n\n/**\n * Render an aligned text table of rollup rows, sorted by total tokens desc, with\n * a TOTAL footer and a short legend noting which confidence labels are estimates.\n */\nexport function formatReport(rows: RollupRow[], by: RollupDimension): string {\n const keyHeader = KEY_HEADER[by];\n const headers = [keyHeader, \"CALLS\", \"IN\", \"OUT\", \"TOTAL\", \"CONFIDENCE\"];\n\n const sorted = [...rows].sort((a, b) => b.totalTokens - a.totalTokens);\n\n // Build the data matrix (string cells) first so we can measure widths.\n const dataRows = sorted.map((r) => [\n r.key,\n fmtInt(r.calls),\n fmtInt(r.inputTokens),\n fmtInt(r.outputTokens),\n fmtInt(r.totalTokens),\n r.confidence,\n ]);\n\n // Totals footer. Confidence is the worst (least-confident) across all rows.\n const totals = sorted.reduce(\n (acc, r) => {\n acc.calls += r.calls;\n acc.inputTokens += r.inputTokens;\n acc.outputTokens += r.outputTokens;\n acc.totalTokens += r.totalTokens;\n return acc;\n },\n { calls: 0, inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n );\n const totalRow = [\n \"TOTAL\",\n fmtInt(totals.calls),\n fmtInt(totals.inputTokens),\n fmtInt(totals.outputTokens),\n fmtInt(totals.totalTokens),\n \"\",\n ];\n\n // Column widths: max over header, every data cell, and the totals row.\n const widths = headers.map((h, col) => {\n let w = h.length;\n for (const row of dataRows) w = Math.max(w, (row[col] ?? \"\").length);\n w = Math.max(w, (totalRow[col] ?? \"\").length);\n return w;\n });\n\n // Column 0 (KEY) is left-aligned; numeric/label columns are right-aligned.\n const renderRow = (cells: string[]): string =>\n cells\n .map((c, col) =>\n col === 0\n ? padRight(c, widths[col] ?? 0)\n : padLeft(c, widths[col] ?? 0),\n )\n .join(\" \")\n .trimEnd();\n\n const ruleWidth = widths.reduce((a, b) => a + b, 0) + 2 * (widths.length - 1);\n const rule = \"-\".repeat(ruleWidth);\n\n const lines: string[] = [];\n lines.push(renderRow(headers));\n lines.push(rule);\n if (dataRows.length === 0) {\n lines.push(\"(no telemetry recorded)\");\n } else {\n for (const row of dataRows) lines.push(renderRow(row));\n }\n lines.push(rule);\n lines.push(renderRow(totalRow));\n\n // Legend — honest labeling of which confidence values are estimates.\n const hasEstimate = sorted.some((r) => ESTIMATE_SOURCES.has(r.confidence));\n if (hasEstimate) {\n lines.push(\"\");\n lines.push(\n \"note: heuristic and tokenizer-approx token counts are estimates, \" +\n \"not exact host-reported usage.\",\n );\n if (sorted.some((r) => r.confidence === \"tokenizer-calibrated\")) {\n lines.push(\n \"note: tokenizer-calibrated = local approx adjusted by a sampled \" +\n \"Anthropic count_tokens factor (opt-in; content sampled off-box only \" +\n \"when AGENT_CONNECTOR_CALIBRATE=anthropic).\",\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Ordered columns for {@link toCSV}, matching the {@link ToolEventRecord} shape. */\nconst CSV_COLUMNS = [\n \"id\",\n \"ts\",\n \"connectorId\",\n \"toolName\",\n \"scope\",\n \"hostPlatform\",\n \"sessionId\",\n \"projectKey\",\n \"projectDir\",\n \"inputTokens\",\n \"outputTokens\",\n \"confidenceSource\",\n \"isError\",\n // installScope / launchMethod mirror the JSON export so the scope dimension is\n // not silently dropped from CSV; absent on a record → an empty cell.\n \"installScope\",\n \"launchMethod\",\n] as const satisfies ReadonlyArray<keyof ToolEventRecord>;\n\n/** RFC-4180-ish CSV escaping: quote when the cell holds a comma, quote, or newline. */\nfunction csvCell(value: unknown): string {\n // An absent field (optional column like installScope/launchMethod) renders as\n // an empty cell rather than the literal \"undefined\" — the JSON export omits\n // the key entirely, so the CSV should likewise carry no value.\n if (value === undefined || value === null) return \"\";\n const s = String(value);\n if (/[\",\\n\\r]/.test(s)) {\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n }\n return s;\n}\n\n/** Serialize raw records to CSV (header + one line per record, CRLF-terminated). */\nexport function toCSV(records: ToolEventRecord[]): string {\n const lines: string[] = [];\n lines.push(CSV_COLUMNS.join(\",\"));\n for (const record of records) {\n lines.push(CSV_COLUMNS.map((col) => csvCell(record[col])).join(\",\"));\n }\n return lines.join(\"\\r\\n\");\n}\n\n/** Serialize raw records to a pretty-printed JSON array string. */\nexport function toJSONExport(records: ToolEventRecord[]): string {\n return JSON.stringify(records, null, 2);\n}\n\n/** Options for {@link summarize}. */\nexport interface SummarizeOptions {\n /** Grouping dimension. Default \"tool\". */\n by?: RollupDimension;\n /** Query filter forwarded to the store. Default: no filter (all records). */\n filter?: QueryFilter;\n}\n\n/**\n * Roll up a store and render it in one call. Returns the structured rows (for\n * machine use) alongside the formatted text table (for the CLI).\n */\nexport function summarize(\n store: TelemetryStore,\n opts?: SummarizeOptions,\n): { rows: RollupRow[]; text: string } {\n const by = opts?.by ?? \"tool\";\n const filter = opts?.filter ?? {};\n const rows = store.rollup(by, filter);\n return { rows, text: formatReport(rows, by) };\n}\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-ZSOS2KOR.js";
4
+ } from "./chunk-RK6VBLXP.js";
5
5
  import {
6
6
  firstExistingRoot,
7
7
  walkFiles
8
- } from "./chunk-KM2YXO6V.js";
8
+ } from "./chunk-O7SDRBVB.js";
9
9
  import {
10
10
  emptyTokens
11
- } from "./chunk-7PSNXUFK.js";
11
+ } from "./chunk-XD7MY6HB.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-SIQI3C66.js.map
157
+ //# sourceMappingURL=trae-CPPYASR2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/usage/readers/trae.ts"],"sourcesContent":["/**\n * usage/readers/trae — Trae / ByteDance AI IDE usage reader (SYNCED platform).\n *\n * Faithful port of tokscale sessions/trae.rs. Trae's per-session token usage\n * lives behind the Trae usage REST API; tokscale authenticates, paginates, and\n * caches the JSON responses under ~/.config/tokscale/trae-cache/. THIS reader\n * never authenticates and never calls that API — it only parses the cached\n * artifacts when a tokscale run has already produced them. Hence kind:\"synced\":\n * - cache present → parse the JSON array(s) and emit one record per session;\n * - cache absent → return [] (the scan layer notes \"requires sync, skipped\").\n *\n * Cache layout (per docs/research/usage-readers.json + design §3d):\n * ~/.config/tokscale/trae-cache/sessions/usage-*.json (cached API artifacts)\n * ~/.config/tokscale/trae-cache/manifest.json (sync bookkeeping — ignored here)\n * paths.ts resolves the cache dir (env override AGENT_CONNECTOR_TOKSCALE_DIR\n * first, the tokscale ~/.config/tokscale default second). We walk for the\n * `usage-*.json` artifacts directly rather than reading the manifest: the\n * artifacts are self-describing and a manifest mismatch must never drop real data.\n *\n * Artifact format (mirrors parse_trae_file exactly): each file is a JSON array of\n * session objects. Per-session fields:\n * model_name — display name (may be \"\" for auto-mode);\n * mode — interaction mode (e.g. \"Auto\");\n * session_id — required; records without it cannot dedup correctly → dropped;\n * usage_time — epoch SECONDS, required & > 0 → ms = usage_time × 1000;\n * dollar_float — cost in USD;\n * extra_info — { input_token, output_token, cache_read_token, cache_write_token }.\n *\n * Token math (port of parse_session): the API returns exact counts, so each\n * dimension maps straight through; reasoning is always 0 (Trae does not report\n * it). A row whose four token dimensions sum to 0 is skipped.\n *\n * Model / provider (port of normalize_trae_model + provider_for_model):\n * - a known display name maps to a tiktoken-style id (e.g. \"GPT-5.4\" →\n * \"gpt-5.4\", \"Claude Sonnet 4.6\" → \"claude-sonnet-4.6\"); an unknown name\n * passes through verbatim;\n * - an empty model_name (auto-mode) buckets under \"trae-<mode>\" (e.g.\n * \"trae-auto\"); empty model AND empty mode → \"trae-unknown\" so the cost is\n * still attributed instead of vanishing into an empty Model cell;\n * - provider is inferred by substring on the display name: GPT→openai,\n * Claude→anthropic, Gemini→google, GLM→zhipu, else \"trae\".\n *\n * Dedup (design §6 / §220): Trae's API returns cumulative deltas and overlapping\n * syncs can write the same (session_id, usage_time) into multiple artifacts —\n * latest-per-(session_id, usage_time) wins. The dedupKey is\n * `trae:{session_id}:{usage_time}`. Because the global aggregate backstop keeps\n * the FIRST occurrence per key, this reader collapses duplicates itself, keeping\n * the LAST artifact row seen per key (walk order), so the emitted set is already\n * unique and the global filter is a no-op. Confidence is \"host-reported\" — the\n * cached data carries real, exact host token counts (spec lists it as medium for\n * the source overall; the per-row provenance is host-reported).\n *\n * Overflow guard (port of the checked_mul in Rust): a crafted usage_time near\n * the safe-integer ceiling would overflow when multiplied by 1000 — reject the\n * record rather than emit a garbage timestamp.\n *\n * Fail-open: no cache dir → []; unreadable/malformed file → skipped; a session\n * missing session_id / usage_time, with non-positive or overflowing usage_time,\n * or with all-zero tokens → skipped. No project scope (account-level usage).\n */\n\nimport type { TokenBreakdown, UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { readJsonFile } from \"../jsonl.js\";\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\n\nconst PLATFORM_ID = \"trae\" as const;\nconst DEFAULT_PROVIDER = \"trae\";\n\n/** Multiplying usage_time (s) by 1000 must stay a safe integer (port of checked_mul). */\nconst MAX_SAFE_USAGE_TIME_S = Math.floor(Number.MAX_SAFE_INTEGER / 1000);\n\n/** The fields we read off a cached Trae session object (everything optional / unknown). */\ninterface TraeSession {\n model_name?: unknown;\n mode?: unknown;\n session_id?: unknown;\n usage_time?: unknown;\n dollar_float?: unknown;\n extra_info?: {\n input_token?: unknown;\n output_token?: unknown;\n cache_read_token?: unknown;\n cache_write_token?: unknown;\n };\n}\n\n/**\n * Known mapping from Trae display names to tiktoken-style model ids (port of\n * normalize_trae_model). Unknown names fall through to the raw `model_name`\n * (mixed-case, space-separated) so a future model is still attributed.\n */\nfunction normalizeTraeModel(name: string): string {\n switch (name) {\n case \"GPT-5.4\":\n return \"gpt-5.4\";\n case \"GPT-5.3-Codex\":\n case \"GPT-5.3 Codex\":\n return \"gpt-5.3-codex\";\n case \"GPT-5.3\":\n return \"gpt-5.3\";\n case \"GPT-5.2-Codex\":\n case \"GPT-5.2 Codex\":\n return \"gpt-5.2-codex\";\n case \"GPT-5.2\":\n return \"gpt-5.2\";\n case \"GPT-5.1-Codex\":\n case \"GPT-5.1 Codex\":\n return \"gpt-5.1-codex\";\n case \"GPT-5.1\":\n return \"gpt-5.1\";\n case \"Gemini 3.1 Pro\":\n return \"gemini-3.1-pro\";\n case \"Gemini 3.1\":\n return \"gemini-3.1\";\n case \"GLM 5.1\":\n case \"GLM-5.1\":\n return \"glm-5.1\";\n case \"Claude Sonnet 4.6\":\n case \"Claude-Sonnet-4.6\":\n return \"claude-sonnet-4.6\";\n case \"Claude Sonnet 4.5\":\n case \"Claude-Sonnet-4.5\":\n return \"claude-sonnet-4.5\";\n default:\n return name;\n }\n}\n\n/**\n * Infer the provider from the display name (port of provider_for_model).\n * Substring matching, first match wins; falls back to \"trae\". Trae-specific so it\n * does not route through normalize.ts inferProvider (which knows nothing of GLM).\n */\nfunction providerForModel(name: string): string {\n if (name.includes(\"GPT\") || name.includes(\"gpt\")) return \"openai\";\n if (name.includes(\"Claude\") || name.includes(\"claude\")) return \"anthropic\";\n if (name.includes(\"Gemini\") || name.includes(\"gemini\")) return \"google\";\n if (name.includes(\"GLM\") || name.includes(\"glm\")) return \"zhipu\";\n return DEFAULT_PROVIDER;\n}\n\n/** Coerce an unknown to a non-negative integer (0 on absence/garbage). */\nfunction toNonNegInt(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.trunc(n));\n}\n\n/** Coerce an unknown to a finite number (0 on absence/garbage) — for the cost field. */\nfunction toNumber(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n return Number.isFinite(n) ? n : 0;\n}\n\n/**\n * Coerce an unknown to a positive integer epoch-seconds value, or null when it is\n * absent / non-positive / not an integer (port of the as_i64()? + ≤0 checks).\n */\nfunction toUsageTimeSeconds(v: unknown): number | null {\n let n: number;\n if (typeof v === \"number\") n = v;\n else if (typeof v === \"string\") n = Number(v);\n else return null;\n if (!Number.isFinite(n) || !Number.isInteger(n)) return null;\n if (n <= 0) return null;\n return n;\n}\n\n/** Parse one cached Trae session object into a usage record (port of parse_session). */\nfunction parseSession(session: TraeSession): UsageRecord | null {\n const modelRaw = typeof session.model_name === \"string\" ? session.model_name : \"\";\n const mode = typeof session.mode === \"string\" ? session.mode : \"\";\n\n // Auto-mode sessions return model_name \"\" (the system picks a model per turn).\n // Bucket them under \"trae-<mode>\" so the cost is still attributed.\n let modelId: string;\n if (modelRaw !== \"\") modelId = normalizeTraeModel(modelRaw);\n else if (mode !== \"\") modelId = `trae-${mode.toLowerCase()}`;\n else modelId = \"trae-unknown\";\n\n // Provider is inferred from the raw display name (the model_id may already be a\n // bucket like \"trae-auto\"); fall back to the model_id when no raw name exists.\n const providerId = providerForModel(modelRaw !== \"\" ? modelRaw : modelId);\n\n // Records without a real session_id cannot be deduplicated correctly (every\n // \"missing-id\" record would collide on the same key); records without a\n // positive usage_time would land at epoch 0. Drop them rather than fabricating.\n const sessionId =\n typeof session.session_id === \"string\" && session.session_id !== \"\" ? session.session_id : null;\n if (sessionId === null) return null;\n\n const usageTime = toUsageTimeSeconds(session.usage_time);\n if (usageTime === null) return null;\n\n // Overflow guard: a crafted usage_time would overflow × 1000 → reject it.\n if (usageTime > MAX_SAFE_USAGE_TIME_S) return null;\n const ts = usageTime * 1000;\n\n const cost = toNumber(session.dollar_float);\n\n const extra = session.extra_info ?? {};\n const input = toNonNegInt(extra.input_token);\n const output = toNonNegInt(extra.output_token);\n const cacheRead = toNonNegInt(extra.cache_read_token);\n const cacheWrite = toNonNegInt(extra.cache_write_token);\n\n if (input + output + cacheRead + cacheWrite === 0) return null;\n\n const tokens: TokenBreakdown = emptyTokens();\n tokens.input = input;\n tokens.output = output;\n tokens.cacheRead = cacheRead;\n tokens.cacheWrite = cacheWrite;\n // reasoning stays 0 (Trae does not report it).\n\n return {\n platformId: PLATFORM_ID,\n modelId,\n providerId,\n sessionId,\n tokens,\n cost,\n ts,\n messageCount: 1,\n dedupKey: `trae:${sessionId}:${usageTime}`,\n confidence: \"host-reported\",\n };\n}\n\n/**\n * Parse one cached artifact file (a JSON array of sessions) into usage records\n * (port of parse_trae_file). A non-array / unreadable / malformed file yields [].\n */\nfunction parseTraeFile(path: string): UsageRecord[] {\n const value = readJsonFile(path);\n if (!Array.isArray(value)) return [];\n\n const out: UsageRecord[] = [];\n for (const raw of value) {\n if (typeof raw !== \"object\" || raw === null) continue;\n const record = parseSession(raw as TraeSession);\n if (record !== null) out.push(record);\n }\n return out;\n}\n\n/** The Trae synced usage reader singleton. */\nconst traeReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"synced\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n // The cache dir is ~/.config/tokscale/trae-cache (env override first).\n // Absent → [] so the scan layer reports \"requires sync, skipped\".\n const root = firstExistingRoot(PLATFORM_ID);\n if (root === undefined) return [];\n\n // Enumerate cached artifacts: sessions/usage-*.json (walkFiles recurses, so\n // a flat or nested layout both work). Match the artifact name shape.\n const files = walkFiles(root, (name) => {\n const lower = name.toLowerCase();\n return lower.startsWith(\"usage-\") && lower.endsWith(\".json\");\n });\n\n // Trae returns cumulative deltas and overlapping syncs can repeat a\n // (session_id, usage_time) across artifacts — latest wins. Collapse to one\n // record per dedupKey, keeping the LAST seen (walk order), so the emitted set\n // is already unique (the global aggregate backstop keeps FIRST, not last).\n const byKey = new Map<string, UsageRecord>();\n for (const file of files) {\n for (const row of parseTraeFile(file)) {\n const key = row.dedupKey ?? `${row.sessionId}:${row.ts}`;\n byKey.set(key, row); // later artifact overwrites earlier → latest wins\n }\n }\n\n const records: UsageRecord[] = [];\n for (const row of byKey.values()) {\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\n records.push(row);\n }\n return records;\n },\n};\n\nexport default traeReader;\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-XXLCMSD3.js";
4
+ } from "./chunk-BEFVJ2OE.js";
5
5
  import {
6
6
  BaseAdapter,
7
7
  renderSkillMd
8
- } from "./chunk-3FINQ2ZF.js";
8
+ } from "./chunk-JTN3AKZO.js";
9
9
  import {
10
10
  buildWrappedStdio,
11
11
  isHomeBinHookCommand
12
- } from "./chunk-Y3K6KJMS.js";
13
- import "./chunk-ILWHLGIC.js";
14
- import "./chunk-QYOUQCC6.js";
12
+ } from "./chunk-QSY74NAP.js";
13
+ import "./chunk-UMQ6NBQR.js";
14
+ import "./chunk-GZGLCCEE.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-Y67HSDOW.js.map
274
+ //# sourceMappingURL=trae-VOJXUYRN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/trae/index.ts"],"sourcesContent":["/**\n * adapters/trae — Trae (ByteDance) platform adapter for agent-connector.\n *\n * Trae is an **mcp-only** host for our purposes: it exposes MCP servers as its\n * extensibility mechanism but has no lifecycle hook system we can register\n * against. This adapter therefore installs only the MCP server and reports hooks\n * as unavailable, mirroring the Warp reference path that validates the\n * `mcp-only` paradigm end-to-end.\n *\n * MCP config (medium-confidence path — still implemented; doctor reports presence):\n * - user scope → ~/.trae/mcp.json\n * - project scope → <projectDir>/.trae/mcp.json\n * Both are JSON, root key \"mcpServers\", and are the SAME file used for the\n * (non-existent) hook registration — there is no separate hook file here.\n *\n * A stdio server entry uses the standard Claude/Cursor shape:\n * { command, args, env } (object-keyed by connector id).\n *\n * Trae documents no native `${env:VAR}` interpolation token, so env/header/url\n * refs are resolved to literals at install time (the no-native-token path).\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, InstallContext } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n ServerDef,\n Transport,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildWrappedStdio,\n isHomeBinHookCommand,\n} from \"../../core/spawn.js\";\nimport { renderSkillMd } from \"../claude-code/render.js\";\n\nconst HOST: PlatformId = \"trae\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/** Native MCP server entry shapes Trae accepts under `mcpServers`. */\ninterface TraeStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\ninterface TraeHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\nexport class TraeAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Trae\";\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\n supportsMemory: true,\n // Trae has no lifecycle hook system we can target — every hook capability\n // is false.\n preToolUse: false,\n postToolUse: false,\n preCompact: false,\n sessionStart: false,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: false,\n // Trae registers stdio, SSE, and Streamable HTTP MCP servers.\n transports: [\"stdio\", \"sse\", \"http\"],\n // Content surfaces: Trae reads Agent Skills (SKILL.md) from\n // user scope → ~/.trae/skills/<name>/SKILL.md\n // project scope → <projectDir>/.trae/skills/<name>/SKILL.md\n // BOTH scopes are documented-writable. Commands/subagents have no native\n // file surface here, so only skills is enabled.\n supportsSkills: true,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".trae\");\n const userMcp = join(userDir, \"mcp.json\");\n const projDir = join(projectDir, \".trae\");\n const projMcp = join(projDir, \"mcp.json\");\n\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projMcp : userMcp;\n\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? `found Trae config (${scope})`\n : `no Trae config at ${userDir} or ${projDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".trae\")\n : join(homedir(), \".trae\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n /**\n * Trae has no hook file — hooks are not a thing here. The hook \"config path\"\n * is the same mcp.json so the generic doctor/backup behave sensibly.\n */\n getHookConfigPath(ctx: InstallContext): string {\n return this.getServerConfigPath(ctx);\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for trae\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Trae's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): TraeStdioServer | TraeHttpServer {\n const transport: Transport = server.transport;\n\n if (transport === \"stdio\") {\n let command = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n // Transparent telemetry wrapping: route the real command through\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\n ({ command, args } = buildWrappedStdio(ctx, server, this.id, command, args));\n\n // Trae has no documented native interpolation token, so resolve every\n // ${env:VAR} to a literal at install time.\n const entry: TraeStdioServer = { command: resolveEnvRefsDeep(command) };\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // sse / http (and any other remote transport) — Trae registers a URL.\n const entry: TraeHttpServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Trae documents no native interpolation token, so\n * resolve `${env:VAR}` references to literals at install time.\n */\n private renderEnv(\n env: Record<string, string> | undefined,\n ): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n return resolveEnvRefsDeep({ ...env });\n }\n\n // ── Hooks (unavailable — Trae is mcp-only) ───────────────────────────────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Trae is mcp-only)\",\n },\n ];\n }\n\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Trae is mcp-only)\",\n },\n ];\n }\n\n /**\n * True when a hook command references our home binary AND this connector id\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand).\n * Trae installs no hooks, but this guard keeps any future shared-file edit\n * from removing another connector's entries.\n */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Content surfaces: skills ─────────────────────────────────────────────\n // CONTENT-ONLY: pure native-file writers. No runtime dispatch, no home-bin\n // pointer, no telemetry wrap. Idempotent (byte-identical → skip) via\n // writeContentFile and reversible via removeContentFile. Honors\n // platforms[\"trae\"].skills === false to skip. BOTH user and project scopes\n // are documented-writable, so there is no scope guard.\n //\n // Native location:\n // skill → <configDir>/skills/<name>/SKILL.md (+ bundled resources)\n // user → ~/.trae/skills/<name>/SKILL.md\n // project → <projectDir>/.trae/skills/<name>/SKILL.md\n\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.getConfigDir(ctx), \"skills\", name);\n }\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for trae\" }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), renderSkillMd(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: mcp.json present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: server entry registered`,\n check: () => {\n // Only assert what the connector declares: a server-less connector —\n // e.g. a catalog-only bundle of agents/skills/commands — never writes\n // an mcpServers entry, so its absence is healthy.\n if (!ctx.connector.server) {\n return { status: \"OK\", detail: \"no MCP server declared\" };\n }\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\n }\n return connectorId in bucket\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\n : {\n status: \"FAIL\",\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\n };\n },\n },\n ];\n\n // Content-surface checks: assert presence only for skills this connector\n // declares (the SKILL.md lands under <configDir>/skills/<name>/).\n for (const skill of ctx.connector.skills) {\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\n checks.push({\n name: `${this.name}: skill ${skill.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n return checks;\n }\n}\n\nexport const adapter = new TraeAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
@@ -430,6 +430,12 @@ interface ConfigPatchDef {
430
430
  /** Docs link appended to the manual-edit fallback printed on skip/conflict. */
431
431
  docsUrl?: string;
432
432
  }
433
+ /** How a host exposes a status-line surface. */
434
+ type StatuslineMode = "command-stdin" | "preset";
435
+ /** How a host-native action affordance invokes the connector action verb. */
436
+ type ActionInvocationMode = "exec" | "exec-file" | "manual-hook" | "paste" | "plugin-command" | "task";
437
+ /** Where a host surfaces an action affordance to the user. */
438
+ type ActionAffordanceKind = "command-palette" | "extension-command" | "hook-panel" | "slash-command" | "task" | "workflow";
433
439
  /** What a given host can actually honor. The single-API layer degrades to it. */
434
440
  interface PlatformCapabilities {
435
441
  preToolUse: boolean;
@@ -525,19 +531,44 @@ interface PlatformCapabilities {
525
531
  * `<homeBin> statusline <host> --connector <id>`.
526
532
  */
527
533
  supportsStatusline?: boolean;
534
+ /**
535
+ * More precise statusline mode. `command-stdin` means the host runs the
536
+ * framework statusline command and pipes JSON on stdin. `preset` is reserved
537
+ * for hosts that only expose a built-in item picker/config and should NOT be
538
+ * treated as supporting {@link StatuslineDef.render}.
539
+ */
540
+ statuslineMode?: StatuslineMode;
541
+ /** Maximum rendered statusline rows the host documents, when known. */
542
+ statuslineMaxLines?: number;
543
+ /** The host can re-run command statuslines on a timer. */
544
+ statuslineSupportsRefreshInterval?: boolean;
545
+ /** The host can render ANSI color/style sequences in statusline output. */
546
+ statuslineSupportsAnsi?: boolean;
547
+ /** The host has a setting to preserve user command colors/styles. */
548
+ statuslineSupportsRespectUserColors?: boolean;
549
+ /** The host has a setting to hide its built-in context indicator. */
550
+ statuslineSupportsHideContextIndicator?: boolean;
528
551
  /**
529
552
  * Action-surface support — can this adapter EMIT a host affordance (slash
530
553
  * command / palette workflow / exec-file) bound to the universal
531
554
  * `<homeBin> action <host> <actionId> --connector <id>` verb? OPTIONAL, read
532
555
  * as `?? false` (supportsStatusline precedent). The dispatch BACKBONE shipped
533
- * first; the EMITTERS now ship on the hosts with a verifiable target: droid
534
- * (executable command file), hermes (quick_commands exec slash command), warp
535
- * (palette workflow pastes the command for the user to run). Hosts whose
536
- * slash commands are prompt templates that cannot run a shell verb, or whose
537
- * plugin APIs expose no command registration, leave this unset — every such
538
- * adapter's BaseAdapter install/uninstall defaults honestly skip-warn.
556
+ * first; the EMITTERS now ship only on hosts with a verifiable target: droid
557
+ * (executable command file), hermes (quick_commands exec slash command), kiro,
558
+ * omp, openclaw, pi, warp, zed, plus the nemoclaw fork. Hosts whose slash
559
+ * commands are prompt templates that cannot run a shell verb, or whose plugin
560
+ * APIs expose no command registration, leave this unset — every such adapter's
561
+ * BaseAdapter install/uninstall defaults honestly skip-warn.
539
562
  */
540
563
  supportsActions?: boolean;
564
+ /**
565
+ * Precise semantics for the emitted action affordance. This is intentionally
566
+ * separate from supportsActions because "supported" spans direct exec, task
567
+ * runners, generated plugin commands, and Warp-style paste workflows.
568
+ */
569
+ actionInvocationMode?: ActionInvocationMode;
570
+ /** The host UI surface where generated action affordances appear. */
571
+ actionAffordanceKind?: ActionAffordanceKind;
541
572
  }
542
573
  /** Tool access expressed once; adapters render to allowed-tools / tools[] / readonly. */
543
574
  interface SurfaceToolPolicy {
@@ -721,6 +752,29 @@ interface StatuslineContext extends HostCtx {
721
752
  /** The host's verbatim status payload (escape hatch). */
722
753
  raw: unknown;
723
754
  }
755
+ /** Shared statusline options adapters may honor when the host supports them. */
756
+ interface StatuslineOptions {
757
+ /**
758
+ * Re-run the host command every N seconds in addition to host-driven refreshes.
759
+ * Adapters only write this when the host supports it.
760
+ */
761
+ refreshInterval?: number;
762
+ /** Preserve ANSI colors/styles instead of forcing host styling, when supported. */
763
+ respectUserColors?: boolean;
764
+ /** Hide the host's built-in context indicator, when supported. */
765
+ hideContextIndicator?: boolean;
766
+ /**
767
+ * Clamp rendered output to at most N lines before handing it to the host.
768
+ * This is framework-enforced so one declaration behaves consistently.
769
+ */
770
+ maxLines?: number;
771
+ }
772
+ type StatuslineRenderer = (ctx: StatuslineContext) => string | Promise<string>;
773
+ /** Per-host statusline override: render function and/or host-specific options. */
774
+ interface StatuslineHostOverride {
775
+ render?: StatuslineRenderer;
776
+ options?: StatuslineOptions;
777
+ }
724
778
  /**
725
779
  * A connector's status line ("HUD"): a single handler that renders the line
726
780
  * text from the normalized {@link StatuslineContext}. The handler lives in the
@@ -745,7 +799,9 @@ interface StatuslineDef {
745
799
  * Renderer. Receives the normalized context; returns the status line text.
746
800
  * Re-imported at runtime via the connector module path (like hook handlers).
747
801
  */
748
- render: (ctx: StatuslineContext) => string | Promise<string>;
802
+ render: StatuslineRenderer;
803
+ /** Host-neutral options. Unsupported options are ignored by adapters. */
804
+ options?: StatuslineOptions;
749
805
  /**
750
806
  * Per-host render override. When rendering for host X, `hosts[X].render` WINS
751
807
  * over the top-level `render`; a host not listed here falls back to the
@@ -760,35 +816,55 @@ interface StatuslineDef {
760
816
  * statusline surface is inert (the runtime no-ops it), exactly as the surface
761
817
  * itself skip-warns there.
762
818
  */
763
- hosts?: Partial<Record<PlatformId, {
764
- render: StatuslineDef["render"];
765
- }>>;
819
+ hosts?: Partial<Record<PlatformId, StatuslineHostOverride>>;
766
820
  }
767
821
  /** What an action's run() returns. v1 minimal: an optional user-facing message. */
768
822
  interface ActionResult {
769
823
  message?: string;
770
824
  }
825
+ type ActionHandler = (ctx: HostCtx) => ActionResult | void | Promise<ActionResult | void>;
826
+ interface ActionConfirm {
827
+ title?: string;
828
+ message?: string;
829
+ }
830
+ type ActionPlacement = ActionAffordanceKind | "default" | (string & Record<never, never>);
831
+ /** Per-host action override: run function and/or host-specific UI metadata. */
832
+ interface ActionHostOverride {
833
+ run?: ActionHandler;
834
+ label?: string;
835
+ description?: string;
836
+ icon?: string;
837
+ placement?: ActionPlacement | ActionPlacement[];
838
+ confirm?: boolean | ActionConfirm;
839
+ }
771
840
  /**
772
- * A user-invokable action: an id + a run(ctx) handler. The connector binds it to
773
- * a host affordance (slash command / keybinding) in a LATER phase; v1 ships the
774
- * dispatch backbone (the `agent-connector action` verb runs run(ctx)). run
775
- * receives the shared {@link HostCtx} (host + capabilities; no stdin — an action
776
- * takes no host payload, unlike a hook or status line). The handler lives in the
777
- * connector module and is re-imported at runtime (like hook handlers /
778
- * statusline.render), so it must survive defineConnector resolution as a live
779
- * function.
841
+ * A user-invokable action: an id + a run(ctx) handler. Supporting adapters bind
842
+ * it to a host affordance, while every host can invoke the stable dispatch verb
843
+ * manually (`agent-connector action`). run receives the shared {@link HostCtx}
844
+ * (host + capabilities; no stdin — an action takes no host payload, unlike a
845
+ * hook or status line). The handler lives in the connector module and is
846
+ * re-imported at runtime (like hook handlers / statusline.render), so it must
847
+ * survive defineConnector resolution as a live function.
780
848
  */
781
849
  interface ActionDef {
782
850
  /** kebab-case id; unique within the connector. The verb's positional arg. */
783
851
  id: string;
852
+ /** Short display label for hosts that show action names. Defaults to description/id. */
853
+ label?: string;
784
854
  /** One-line "what this action does" — status/docs output only. */
785
855
  description?: string;
856
+ /** Optional icon name/string for hosts that can display one. */
857
+ icon?: string;
858
+ /** Optional preferred placement; adapters ignore unsupported placements. */
859
+ placement?: ActionPlacement | ActionPlacement[];
860
+ /** Optional confirmation metadata for hosts that can prompt before running. */
861
+ confirm?: boolean | ActionConfirm;
786
862
  /**
787
863
  * The action handler. Receives the normalized {@link HostCtx}; an optional
788
864
  * {@link ActionResult} return prints its `message` to the user. Re-imported at
789
865
  * runtime via the connector module path (like hook handlers).
790
866
  */
791
- run: (ctx: HostCtx) => ActionResult | void | Promise<ActionResult | void>;
867
+ run: ActionHandler;
792
868
  /**
793
869
  * Per-host run override. When dispatching for host X, `hosts[X].run` WINS over
794
870
  * the top-level `run`; a host not listed here falls back to the top-level run.
@@ -796,9 +872,7 @@ interface ActionDef {
796
872
  * platform ids and each entry's run MUST be a function (validated at
797
873
  * defineConnector). The top-level `run` is ALWAYS the mandatory fallback.
798
874
  */
799
- hosts?: Partial<Record<PlatformId, {
800
- run: ActionDef["run"];
801
- }>>;
875
+ hosts?: Partial<Record<PlatformId, ActionHostOverride>>;
802
876
  }
803
877
  /** Per-host memory tuning — the object form of {@link PlatformOverride.memory}. */
804
878
  interface PlatformMemoryOverride {
@@ -5,15 +5,15 @@ import {
5
5
  resolveUninstallTargets,
6
6
  uninstallConnector,
7
7
  uninstallViaMarketplace
8
- } from "./chunk-MLU7NDAZ.js";
9
- import "./chunk-LQ55E7QI.js";
8
+ } from "./chunk-KLZBRNFP.js";
9
+ import "./chunk-N4STCQGP.js";
10
10
  import {
11
11
  marketplaceEvidence,
12
12
  readMarketplaceInstalls
13
- } from "./chunk-7C2IPIIB.js";
14
- import "./chunk-C747DYNT.js";
15
- import "./chunk-XVEJAFKW.js";
16
- import "./chunk-XN7S44U4.js";
13
+ } from "./chunk-2Y2MZRLP.js";
14
+ import "./chunk-UM5S7DKK.js";
15
+ import "./chunk-XY3N2U6L.js";
16
+ import "./chunk-OPXAP3AC.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-N4ENLZEU.js";
26
- import "./chunk-SLJI5BOM.js";
27
- import "./chunk-GZZCHJDP.js";
28
- import "./chunk-4GH2KA7V.js";
25
+ } from "./chunk-BV5WK6VQ.js";
26
+ import "./chunk-GDIAHWNY.js";
27
+ import "./chunk-4KIXXJ7B.js";
28
+ import "./chunk-KHO5WNTP.js";
29
29
  import {
30
30
  findConnectorConfig,
31
31
  loadConnectorFromPath
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";
32
+ } from "./chunk-M6OS4OLU.js";
33
+ import "./chunk-6WN37NVN.js";
34
+ import "./chunk-G5HAIYRM.js";
35
+ import "./chunk-NBYKLUF6.js";
36
+ import "./chunk-H53QZQJI.js";
37
+ import "./chunk-BEFVJ2OE.js";
38
+ import "./chunk-JTN3AKZO.js";
39
+ import "./chunk-QSY74NAP.js";
40
+ import "./chunk-UMQ6NBQR.js";
41
41
  import {
42
42
  assertConnectorId
43
- } from "./chunk-QYOUQCC6.js";
43
+ } from "./chunk-GZGLCCEE.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-RWO2GM2I.js.map
186
+ //# sourceMappingURL=uninstall-BSIJ4QXN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/uninstall.ts"],"sourcesContent":["/**\n * cli/commands/uninstall — strip a connector's registrations, method-aware.\n *\n * The connector id is taken from --connector-id, or inferred from the local\n * connector config (--connector <path> / findConnectorConfig).\n *\n * --method auto (default) reverses WHATEVER is actually there, per target:\n * targets with marketplace evidence (the state record, or the host's own plugin\n * state) get the HOST plugin uninstall; everything else gets the existing\n * direct adapter strip. Install chooses a method (a user decision); uninstall\n * reverses what exists (a state decision) — and since the double-install guard\n * enforces exactly one method per (connector, host, scope), auto is\n * unambiguous. Explicit --method direct|marketplace forces one path for every\n * target. Config removal vs plugin uninstall is therefore method-resolved:\n * never both, never neither.\n *\n * --purge additionally removes the framework-state this connector left behind:\n * its DATA-dir connector record (connectorDir(id)), the empty marketplace\n * staging root, and, when no connectors remain, the shared home-bin launcher.\n * Without --purge those linger so the connector can be re-synced without\n * re-registering.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport {\n purgeFrameworkState,\n resolveUninstallTargets,\n uninstallConnector,\n} from \"../../core/installer.js\";\nimport {\n marketplaceEvidence,\n parseUninstallMethod,\n uninstallViaMarketplace,\n} from \"../../core/marketplace.js\";\nimport { readMarketplaceInstalls } from \"../../core/marketplace-state.js\";\nimport { assertConnectorId } from \"../../core/ids.js\";\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport type {\n ConnectorSummary,\n InstallResult,\n PlatformId,\n ResolvedConnector,\n} from \"../../core/types.js\";\nimport {\n buildConnectorSummary,\n fail,\n maybePrintBanner,\n parseScope,\n parseTargets,\n print,\n renderInstallResult,\n} from \"../app.js\";\n\n/**\n * Resolve the connector id from flags, then from a local config file. When the\n * id was inferred by LOADING a config, the resolved connector is returned too so\n * the caller can build a header summary; an explicit `--connector-id` yields no\n * connector (id-only uninstall), and the renderer degrades to an id-only header.\n */\nasync function resolveConnectorId(\n explicitId: string | undefined,\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<{ id: string; connector?: ResolvedConnector } | null> {\n if (explicitId && explicitId.trim() !== \"\") return { id: explicitId };\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (!configPath) return null;\n const { connector } = await loadConnectorFromPath(configPath);\n return { id: connector.id, connector };\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n method: { type: \"string\", default: \"auto\" },\n scope: { type: \"string\", default: \"user\" },\n targets: { type: \"string\" },\n connector: { type: \"string\" },\n \"connector-id\": { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n purge: { type: \"boolean\", default: false },\n // Decorative-banner suppressor (no effect on command output bytes).\n quiet: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n maybePrintBanner({ quiet: values.quiet });\n\n const method = parseUninstallMethod(values.method);\n if (method == null) {\n return fail(`invalid --method \"${values.method}\" (use auto|direct|marketplace)`);\n }\n\n const projectDir = values.project ?? process.cwd();\n\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const resolved = await resolveConnectorId(\n values[\"connector-id\"],\n values.connector,\n projectDir,\n );\n if (!resolved) {\n return fail(\n \"could not determine connector id. Pass --connector-id <id>, \" +\n \"--connector <path>, or run inside a project with an agent-connector config.\",\n );\n }\n const connectorId = resolved.id;\n // Header summary when a connector config was actually loaded; id-only\n // (--connector-id) uninstalls have no connector → the renderer degrades to an\n // id-only header.\n const summary: ConnectorSummary | undefined = resolved.connector\n ? buildConnectorSummary(resolved.connector)\n : undefined;\n\n // Single choke-point: validate the id BEFORE any path is built or any delete\n // runs. Every branch below (explicit --method marketplace, --method auto, and\n // the direct strip) constructs record / staging-root paths from this id —\n // including the explicit --targets marketplace path, which reaches\n // driver.finishUninstall(id) → rmSync(join(stagingRoot, id)) without otherwise\n // routing the raw id through connectorDir's validation. Failing loud here closes\n // the `--connector-id ../../x` traversal window for ALL of them at once.\n try {\n assertConnectorId(connectorId);\n } catch (err) {\n return fail(err instanceof Error ? err.message : String(err));\n }\n\n const targets = parseTargets(values.targets);\n const dryRun = values[\"dry-run\"];\n\n // ── Explicit --method marketplace: every target goes to the marketplace path\n // (targets default to the recorded installs); framework purge runs here since\n // no direct pass follows.\n if (method === \"marketplace\") {\n const result = await uninstallViaMarketplace({\n connectorId,\n projectDir,\n dryRun,\n purge: values.purge,\n ...(targets ? { targets } : {}),\n });\n if (values.purge) purgeFrameworkState(connectorId, dryRun, result);\n result.connector = summary;\n print(renderInstallResult(result, \"uninstall\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n }\n\n // ── --method auto: partition the resolved targets by marketplace evidence.\n // (--method direct keeps every target on the adapter strip — today's path.)\n let marketplaceTargets: PlatformId[] = [];\n let directTargets: PlatformId[] = [];\n if (method === \"auto\") {\n const resolvedTargets = await resolveUninstallTargets(connectorId, targets, projectDir);\n // With no explicit --targets, recorded marketplace platforms are unioned\n // in: the state record IS the authority for what we installed, and host\n // detection can miss a host whose probe-able config dir was relocated.\n // An explicit --targets list is always respected as-is.\n const recorded = targets\n ? []\n : (Object.keys(readMarketplaceInstalls(connectorId)) as PlatformId[]);\n const candidates = [...new Set([...resolvedTargets, ...recorded])];\n marketplaceTargets = candidates.filter(\n (id) => marketplaceEvidence(connectorId, id) != null,\n );\n directTargets = resolvedTargets.filter((id) => !marketplaceTargets.includes(id));\n }\n\n // No marketplace evidence anywhere (or --method direct): exactly today's\n // single-orchestration path, byte-for-byte — zero behavior change for users\n // who never touched the marketplace method.\n if (marketplaceTargets.length === 0) {\n const result = await uninstallConnector({\n connectorId,\n scope,\n projectDir,\n dryRun,\n purge: values.purge,\n ...(targets ? { targets } : {}),\n });\n result.connector = summary;\n print(renderInstallResult(result, \"uninstall\"));\n return result.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n }\n\n const results: InstallResult[] = [\n await uninstallViaMarketplace({\n connectorId,\n projectDir,\n targets: marketplaceTargets,\n dryRun,\n purge: values.purge,\n }),\n ];\n\n // The direct strip runs only for its partition (never both methods on one\n // target). When every target was marketplace-routed, --purge still runs the\n // framework purge (the marketplace records were just cleared, so it can\n // proceed to the connector record + home-bin).\n if (directTargets.length > 0) {\n results.push(\n await uninstallConnector({\n connectorId,\n scope,\n projectDir,\n dryRun,\n purge: values.purge,\n targets: directTargets,\n }),\n );\n } else if (values.purge) {\n const purgeResult: InstallResult = {\n connectorId,\n dryRun,\n changes: [],\n warnings: [],\n };\n if (dryRun) {\n // On a real run the marketplace records are removed BEFORE this purge;\n // calling purgeFrameworkState now would false-refuse on records that the\n // marketplace pass only PLANNED to remove. Report the plan instead.\n purgeResult.changes.push({\n platform: connectorId as PlatformId,\n action: \"remove\",\n detail:\n \"would purge framework state (connector record; home-bin when no connectors remain)\",\n });\n } else {\n purgeFrameworkState(connectorId, dryRun, purgeResult);\n }\n results.push(purgeResult);\n }\n\n const merged: InstallResult = {\n connectorId,\n dryRun,\n changes: results.flatMap((r) => r.changes),\n warnings: results.flatMap((r) => r.warnings),\n connector: summary,\n };\n print(renderInstallResult(merged, \"uninstall\"));\n return merged.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n"],"mappings":"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","names":[]}