@ken-jo/agent-connector 0.4.0 → 0.4.1

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 (182) hide show
  1. package/README.md +8 -8
  2. package/dist/{action-PLZW5BGX.js → action-WT7GVRCC.js} +11 -10
  3. package/dist/{action-PLZW5BGX.js.map → action-WT7GVRCC.js.map} +1 -1
  4. package/dist/amazon-q-COAL3764.js +276 -0
  5. package/dist/amazon-q-COAL3764.js.map +1 -0
  6. package/dist/{amp-B524U6LO.js → amp-4U33CU7E.js} +3 -3
  7. package/dist/{antigravity-ANDKF3K7.js → antigravity-AMKKKHS4.js} +4 -4
  8. package/dist/{antigravity-cli-LLRPDDOT.js → antigravity-cli-XERXEH5W.js} +4 -4
  9. package/dist/{chunk-KGJWE6A2.js → chunk-24IDL5RW.js} +2 -2
  10. package/dist/{chunk-CIRDOY2V.js → chunk-2AVLX7GH.js} +3 -3
  11. package/dist/{chunk-ADTHT2FN.js → chunk-4ENJK5S2.js} +10 -173
  12. package/dist/chunk-4ENJK5S2.js.map +1 -0
  13. package/dist/{chunk-BHUCB6LY.js → chunk-5OWS5CMA.js} +8 -7
  14. package/dist/{chunk-BHUCB6LY.js.map → chunk-5OWS5CMA.js.map} +1 -1
  15. package/dist/{chunk-IW77FFNX.js → chunk-CPLK7GTE.js} +41 -5
  16. package/dist/chunk-CPLK7GTE.js.map +1 -0
  17. package/dist/chunk-DCKFYWGM.js +237 -0
  18. package/dist/chunk-DCKFYWGM.js.map +1 -0
  19. package/dist/{chunk-J3D5W5T2.js → chunk-EGCBZ2DC.js} +2 -2
  20. package/dist/{chunk-22Y24V7O.js → chunk-F5RX62T7.js} +2 -2
  21. package/dist/chunk-FAHIMJRU.js +177 -0
  22. package/dist/chunk-FAHIMJRU.js.map +1 -0
  23. package/dist/{chunk-BXGFUENQ.js → chunk-I5MLE6S7.js} +14 -1
  24. package/dist/{chunk-BXGFUENQ.js.map → chunk-I5MLE6S7.js.map} +1 -1
  25. package/dist/{chunk-LL4OBGRU.js → chunk-LQRAPXS4.js} +3 -3
  26. package/dist/{chunk-KGXDYGNJ.js → chunk-O5TWCIJN.js} +19 -19
  27. package/dist/{chunk-KGXDYGNJ.js.map → chunk-O5TWCIJN.js.map} +1 -1
  28. package/dist/{chunk-MAH6QQTO.js → chunk-QREL7LZJ.js} +5 -4
  29. package/dist/chunk-QREL7LZJ.js.map +1 -0
  30. package/dist/{chunk-G3ER4SY5.js → chunk-RIMVWCZY.js} +9 -9
  31. package/dist/{chunk-6XHB6BE3.js → chunk-SCVBYSF7.js} +1 -1
  32. package/dist/{chunk-KGGBNKI4.js → chunk-URHQMFB3.js} +90 -13
  33. package/dist/chunk-URHQMFB3.js.map +1 -0
  34. package/dist/chunk-WZA4CSGJ.js +28 -0
  35. package/dist/chunk-WZA4CSGJ.js.map +1 -0
  36. package/dist/{chunk-76FUSVIA.js → chunk-XJ4S47CT.js} +6 -5
  37. package/dist/chunk-XJ4S47CT.js.map +1 -0
  38. package/dist/{claude-code-MLWS7CW6.js → claude-code-W4PUFZL5.js} +20 -30
  39. package/dist/claude-code-W4PUFZL5.js.map +1 -0
  40. package/dist/cli/sdk.js +5 -4
  41. package/dist/cli/sdk.js.map +1 -1
  42. package/dist/cli.js +1 -1
  43. package/dist/cline-WRYMNS7Z.js +442 -0
  44. package/dist/cline-WRYMNS7Z.js.map +1 -0
  45. package/dist/{codebuff-SH2S3QAN.js → codebuff-DH5Y7GAT.js} +8 -4
  46. package/dist/codebuff-DH5Y7GAT.js.map +1 -0
  47. package/dist/{codex-BXA4FIF4.js → codex-DDHIV767.js} +43 -11
  48. package/dist/codex-DDHIV767.js.map +1 -0
  49. package/dist/continue-K43SUHLQ.js +790 -0
  50. package/dist/continue-K43SUHLQ.js.map +1 -0
  51. package/dist/{copilot-cli-ROIBTTDT.js → copilot-cli-Q3SSPT4V.js} +70 -12
  52. package/dist/copilot-cli-Q3SSPT4V.js.map +1 -0
  53. package/dist/{crush-QLEFLHUC.js → crush-MBEH2R3I.js} +130 -6
  54. package/dist/crush-MBEH2R3I.js.map +1 -0
  55. package/dist/{cursor-ASJPWZ4R.js → cursor-TMBXDYR4.js} +119 -19
  56. package/dist/cursor-TMBXDYR4.js.map +1 -0
  57. package/dist/{detect-ZIIS55LD.js → detect-KG5FG3EV.js} +5 -4
  58. package/dist/{detect-ZIIS55LD.js.map → detect-KG5FG3EV.js.map} +1 -1
  59. package/dist/{doctor-TJUGSQ5C.js → doctor-FLZF34Y3.js} +221 -95
  60. package/dist/doctor-FLZF34Y3.js.map +1 -0
  61. package/dist/{droid-NCSS3B5Y.js → droid-JC2NT6S4.js} +135 -13
  62. package/dist/droid-JC2NT6S4.js.map +1 -0
  63. package/dist/{gemini-cli-SLVWLXJW.js → gemini-cli-ILR7M5X3.js} +62 -10
  64. package/dist/gemini-cli-ILR7M5X3.js.map +1 -0
  65. package/dist/{goose-PBA7KTE5.js → goose-SFO5BBGW.js} +15 -8
  66. package/dist/goose-SFO5BBGW.js.map +1 -0
  67. package/dist/{hermes-ONDCECP2.js → hermes-3N7WN4WS.js} +329 -15
  68. package/dist/hermes-3N7WN4WS.js.map +1 -0
  69. package/dist/{hook-OU522ABV.js → hook-XR3Z45FB.js} +14 -11
  70. package/dist/hook-XR3Z45FB.js.map +1 -0
  71. package/dist/index.d.ts +2 -2
  72. package/dist/index.js +3 -2
  73. package/dist/{install-UDCBL7HP.js → install-BSR62UHJ.js} +11 -10
  74. package/dist/{install-UDCBL7HP.js.map → install-BSR62UHJ.js.map} +1 -1
  75. package/dist/{introspect-DuZSPSHB.d.ts → introspect-Nw8hTReX.d.ts} +1 -1
  76. package/dist/{jetbrains-copilot-YABZ3HFA.js → jetbrains-copilot-NRZHI5PC.js} +85 -18
  77. package/dist/jetbrains-copilot-NRZHI5PC.js.map +1 -0
  78. package/dist/{kilo-F3ZDZKCT.js → kilo-5NWOXVSD.js} +16 -16
  79. package/dist/kilo-5NWOXVSD.js.map +1 -0
  80. package/dist/{kilo-cli-3HWPWBY4.js → kilo-cli-UZ7R5UOP.js} +3 -3
  81. package/dist/{kimi-NV72FVAO.js → kimi-2YFK2GBA.js} +87 -25
  82. package/dist/kimi-2YFK2GBA.js.map +1 -0
  83. package/dist/{kiro-C5W6AGDR.js → kiro-YL6AWUYG.js} +3 -3
  84. package/dist/{leaderboard-TIBVONVT.js → leaderboard-MJG24O35.js} +3 -3
  85. package/dist/{mimo-code-IMM5YM3M.js → mimo-code-FTMGSKMQ.js} +41 -5
  86. package/dist/mimo-code-FTMGSKMQ.js.map +1 -0
  87. package/dist/{mux-DSSH4AFS.js → mux-5XZFB44C.js} +156 -6
  88. package/dist/mux-5XZFB44C.js.map +1 -0
  89. package/dist/{nemoclaw-3EVNKD3I.js → nemoclaw-W5KEJ3WX.js} +4 -4
  90. package/dist/{omp-Z6FRNDPN.js → omp-2QMEY6HD.js} +138 -18
  91. package/dist/omp-2QMEY6HD.js.map +1 -0
  92. package/dist/{openclaw-7G437NT7.js → openclaw-EXJEFNZI.js} +4 -4
  93. package/dist/{opencode-Q6KBSAKW.js → opencode-WNXYJR4X.js} +84 -27
  94. package/dist/opencode-WNXYJR4X.js.map +1 -0
  95. package/dist/{package-RMPN57YZ.js → package-ACZXJHWB.js} +8 -7
  96. package/dist/{package-RMPN57YZ.js.map → package-ACZXJHWB.js.map} +1 -1
  97. package/dist/{pi-LZT6WWAZ.js → pi-PVVPVWKG.js} +3 -2
  98. package/dist/{pi-LZT6WWAZ.js.map → pi-PVVPVWKG.js.map} +1 -1
  99. package/dist/{qwen-code-WQBKRPWJ.js → qwen-code-G4CXKUHR.js} +426 -10
  100. package/dist/qwen-code-G4CXKUHR.js.map +1 -0
  101. package/dist/{roo-code-GWSNU3OW.js → roo-code-67TYJIQR.js} +3 -3
  102. package/dist/runtime/index.d.ts +1 -1
  103. package/dist/runtime/index.js +9 -8
  104. package/dist/sdk/index.d.ts +3 -3
  105. package/dist/sdk/index.js +4 -3
  106. package/dist/sdk/index.js.map +1 -1
  107. package/dist/sdk/test.d.ts +2 -2
  108. package/dist/sdk/test.js +6 -5
  109. package/dist/sdk/test.js.map +1 -1
  110. package/dist/{serve-D3GO36UT.js → serve-GER7URPR.js} +11 -10
  111. package/dist/{serve-D3GO36UT.js.map → serve-GER7URPR.js.map} +1 -1
  112. package/dist/{status-KOSKCETC.js → status-LAJE3BM5.js} +7 -6
  113. package/dist/{status-KOSKCETC.js.map → status-LAJE3BM5.js.map} +1 -1
  114. package/dist/{statusline-ZNTCL5YC.js → statusline-L376ZPZU.js} +10 -9
  115. package/dist/{statusline-ZNTCL5YC.js.map → statusline-L376ZPZU.js.map} +1 -1
  116. package/dist/{telemetry-XIKUUGTQ.js → telemetry-B3DX3PWU.js} +6 -5
  117. package/dist/{telemetry-XIKUUGTQ.js.map → telemetry-B3DX3PWU.js.map} +1 -1
  118. package/dist/{trae-NWT3TMSZ.js → trae-7CZZGOGI.js} +3 -3
  119. package/dist/{types-BEKsAium.d.ts → types-CRVrFWeU.d.ts} +64 -22
  120. package/dist/{uninstall-2LBLQVFA.js → uninstall-ZYTW7YMZ.js} +11 -10
  121. package/dist/{uninstall-2LBLQVFA.js.map → uninstall-ZYTW7YMZ.js.map} +1 -1
  122. package/dist/{upgrade-ZC2S7VRN.js → upgrade-4LUEEOZW.js} +11 -10
  123. package/dist/{upgrade-ZC2S7VRN.js.map → upgrade-4LUEEOZW.js.map} +1 -1
  124. package/dist/{usage-E2A4O2CY.js → usage-ZFBVQF3H.js} +3 -3
  125. package/dist/{usage-event-JKMC4QC4.js → usage-event-GZ32AGEB.js} +10 -9
  126. package/dist/{usage-event-JKMC4QC4.js.map → usage-event-GZ32AGEB.js.map} +1 -1
  127. package/dist/{vscode-copilot-ALV45XF6.js → vscode-copilot-MF2CDNMT.js} +23 -10
  128. package/dist/vscode-copilot-MF2CDNMT.js.map +1 -0
  129. package/dist/{warp-H6IX4U3J.js → warp-VKG55TAT.js} +55 -4
  130. package/dist/warp-VKG55TAT.js.map +1 -0
  131. package/dist/windsurf-FU5G4SHF.js +443 -0
  132. package/dist/windsurf-FU5G4SHF.js.map +1 -0
  133. package/dist/{zed-RH34TNSW.js → zed-SFUHL3GS.js} +3 -3
  134. package/package.json +2 -2
  135. package/dist/chunk-3PFFTFCU.js +0 -190
  136. package/dist/chunk-3PFFTFCU.js.map +0 -1
  137. package/dist/chunk-76FUSVIA.js.map +0 -1
  138. package/dist/chunk-ADTHT2FN.js.map +0 -1
  139. package/dist/chunk-IW77FFNX.js.map +0 -1
  140. package/dist/chunk-KGGBNKI4.js.map +0 -1
  141. package/dist/chunk-MAH6QQTO.js.map +0 -1
  142. package/dist/claude-code-MLWS7CW6.js.map +0 -1
  143. package/dist/codebuff-SH2S3QAN.js.map +0 -1
  144. package/dist/codex-BXA4FIF4.js.map +0 -1
  145. package/dist/copilot-cli-ROIBTTDT.js.map +0 -1
  146. package/dist/crush-QLEFLHUC.js.map +0 -1
  147. package/dist/cursor-ASJPWZ4R.js.map +0 -1
  148. package/dist/doctor-TJUGSQ5C.js.map +0 -1
  149. package/dist/droid-NCSS3B5Y.js.map +0 -1
  150. package/dist/gemini-cli-SLVWLXJW.js.map +0 -1
  151. package/dist/goose-PBA7KTE5.js.map +0 -1
  152. package/dist/hermes-ONDCECP2.js.map +0 -1
  153. package/dist/hook-OU522ABV.js.map +0 -1
  154. package/dist/jetbrains-copilot-YABZ3HFA.js.map +0 -1
  155. package/dist/kilo-F3ZDZKCT.js.map +0 -1
  156. package/dist/kimi-NV72FVAO.js.map +0 -1
  157. package/dist/mimo-code-IMM5YM3M.js.map +0 -1
  158. package/dist/mux-DSSH4AFS.js.map +0 -1
  159. package/dist/omp-Z6FRNDPN.js.map +0 -1
  160. package/dist/opencode-Q6KBSAKW.js.map +0 -1
  161. package/dist/qwen-code-WQBKRPWJ.js.map +0 -1
  162. package/dist/vscode-copilot-ALV45XF6.js.map +0 -1
  163. package/dist/warp-H6IX4U3J.js.map +0 -1
  164. /package/dist/{amp-B524U6LO.js.map → amp-4U33CU7E.js.map} +0 -0
  165. /package/dist/{antigravity-ANDKF3K7.js.map → antigravity-AMKKKHS4.js.map} +0 -0
  166. /package/dist/{antigravity-cli-LLRPDDOT.js.map → antigravity-cli-XERXEH5W.js.map} +0 -0
  167. /package/dist/{chunk-KGJWE6A2.js.map → chunk-24IDL5RW.js.map} +0 -0
  168. /package/dist/{chunk-CIRDOY2V.js.map → chunk-2AVLX7GH.js.map} +0 -0
  169. /package/dist/{chunk-J3D5W5T2.js.map → chunk-EGCBZ2DC.js.map} +0 -0
  170. /package/dist/{chunk-22Y24V7O.js.map → chunk-F5RX62T7.js.map} +0 -0
  171. /package/dist/{chunk-LL4OBGRU.js.map → chunk-LQRAPXS4.js.map} +0 -0
  172. /package/dist/{chunk-G3ER4SY5.js.map → chunk-RIMVWCZY.js.map} +0 -0
  173. /package/dist/{chunk-6XHB6BE3.js.map → chunk-SCVBYSF7.js.map} +0 -0
  174. /package/dist/{kilo-cli-3HWPWBY4.js.map → kilo-cli-UZ7R5UOP.js.map} +0 -0
  175. /package/dist/{kiro-C5W6AGDR.js.map → kiro-YL6AWUYG.js.map} +0 -0
  176. /package/dist/{leaderboard-TIBVONVT.js.map → leaderboard-MJG24O35.js.map} +0 -0
  177. /package/dist/{nemoclaw-3EVNKD3I.js.map → nemoclaw-W5KEJ3WX.js.map} +0 -0
  178. /package/dist/{openclaw-7G437NT7.js.map → openclaw-EXJEFNZI.js.map} +0 -0
  179. /package/dist/{roo-code-GWSNU3OW.js.map → roo-code-67TYJIQR.js.map} +0 -0
  180. /package/dist/{trae-NWT3TMSZ.js.map → trae-7CZZGOGI.js.map} +0 -0
  181. /package/dist/{usage-E2A4O2CY.js.map → usage-ZFBVQF3H.js.map} +0 -0
  182. /package/dist/{zed-RH34TNSW.js.map → zed-SFUHL3GS.js.map} +0 -0
@@ -6,19 +6,20 @@ import {
6
6
  fail,
7
7
  parseScope,
8
8
  print
9
- } from "./chunk-KGXDYGNJ.js";
9
+ } from "./chunk-O5TWCIJN.js";
10
10
  import {
11
11
  detectInstalledPlatforms
12
- } from "./chunk-J3D5W5T2.js";
12
+ } from "./chunk-EGCBZ2DC.js";
13
13
  import {
14
14
  findConnectorConfig,
15
15
  listRegisteredConnectors,
16
16
  loadConnectorFromPath
17
- } from "./chunk-KGJWE6A2.js";
18
- import "./chunk-ADTHT2FN.js";
17
+ } from "./chunk-24IDL5RW.js";
18
+ import "./chunk-4ENJK5S2.js";
19
19
  import {
20
20
  loadAdapter
21
- } from "./chunk-3PFFTFCU.js";
21
+ } from "./chunk-DCKFYWGM.js";
22
+ import "./chunk-FAHIMJRU.js";
22
23
  import "./chunk-N6HH7K6P.js";
23
24
  import {
24
25
  dataRoot,
@@ -137,4 +138,4 @@ async function run(argv) {
137
138
  export {
138
139
  run
139
140
  };
140
- //# sourceMappingURL=status-KOSKCETC.js.map
141
+ //# sourceMappingURL=status-LAJE3BM5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/commands/status.ts"],"sourcesContent":["/**\n * cli/commands/status — a light, glanceable install-state summary.\n *\n * There is NO MCP standard for \"which connectors are installed into which host\n * configs on this machine\" — distribution/wire standards (server.json, MCPB,\n * the lifecycle) cover publishing + the protocol, not local install state. So\n * `status` is purely agent-connector infrastructure, and we design it for the\n * everyday question it answers in one line per platform:\n *\n * \"which of my connectors are present on which hosts?\"\n *\n * It REUSES detect (host enumeration) + the adapters' own config-path resolvers\n * (a read-only presence check) — NO new adapter SPI methods. Unlike `doctor`\n * (deep health checks, non-zero exit on failure) and `doctor --probe` (a live\n * protocol probe that FAILs on a dead server), `status` ALWAYS exits 0: it\n * describes, it never gates. A connector being absent is informational.\n */\n\nimport { parseArgs } from \"node:util\";\nimport { readFileSync } from \"node:fs\";\n\nimport type { InstallScope, PlatformId, ResolvedConnector } from \"../../core/types.js\";\nimport type { InstallContext } from \"../../adapters/spi.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { loadAdapter } from \"../../adapters/registry.js\";\nimport {\n findConnectorConfig,\n listRegisteredConnectors,\n loadConnectorFromPath,\n} from \"../../core/load-connector.js\";\nimport { marketplaceEvidence } from \"../../core/marketplace-state.js\";\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\nimport { fail, parseScope, print } from \"../app.js\";\n\n/**\n * Resolve which connector(s) status reports on: an explicit --connector path or\n * a local config first, else every connector registered under the data-root\n * (what is actually installed). Empty array when none — status still lists the\n * detected platforms.\n */\nasync function resolveConnectors(\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<ResolvedConnector[]> {\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (configPath) {\n try {\n const { connector } = await loadConnectorFromPath(configPath);\n return [connector];\n } catch {\n /* fall through to the registry */\n }\n }\n return listRegisteredConnectors();\n}\n\nfunction buildContext(\n connector: ResolvedConnector,\n id: PlatformId,\n scope: InstallScope,\n projectDir: string,\n): InstallContext {\n return {\n connector,\n scope: connector.platforms[id]?.scope ?? scope,\n projectDir,\n homeBinPath: homeBinPath(),\n dataRoot: dataRoot(),\n dryRun: true,\n };\n}\n\n/** Read-only: does the file at `path` mention `needle`? Missing/unreadable → false. */\nfunction fileMentions(path: string, needle: string): boolean {\n try {\n return readFileSync(path, \"utf8\").includes(needle);\n } catch {\n return false;\n }\n}\n\ninterface ConnStatus {\n id: string;\n serverPresent: boolean;\n hooksPresent: boolean;\n /**\n * Delivery method actually present on this host: `direct` (managed entries in\n * the host config), `marketplace` (the host's own plugin state / our install\n * record), `both` (the double-install invariant is VIOLATED — doctor FAILs\n * it), or null when absent.\n */\n method: \"direct\" | \"marketplace\" | \"both\" | null;\n}\ninterface StatusRow {\n platform: PlatformId;\n scope: InstallScope;\n configPath: string;\n connectors: ConnStatus[];\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n scope: { type: \"string\", default: \"user\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectors = await resolveConnectors(values.connector, projectDir);\n const detected = await detectInstalledPlatforms(projectDir);\n\n const rows: StatusRow[] = [];\n for (const p of detected) {\n const adapter = await loadAdapter(p.id);\n if (!adapter) continue;\n const connStatuses: ConnStatus[] = connectors.map((connector) => {\n const ctx = buildContext(connector, p.id, scope, projectDir);\n let serverPath = \"\";\n let hookPath = \"\";\n try {\n serverPath = adapter.getServerConfigPath(ctx);\n } catch {\n /* adapter has no server config path */\n }\n try {\n hookPath = adapter.getHookConfigPath(ctx);\n } catch {\n /* adapter has no hook config path */\n }\n const serverPresent = serverPath\n ? fileMentions(serverPath, connector.id)\n : false;\n const hooksPresent = hookPath ? fileMentions(hookPath, connector.id) : false;\n const direct = serverPresent || hooksPresent;\n const viaMarketplace = marketplaceEvidence(connector.id, p.id) != null;\n return {\n id: connector.id,\n serverPresent,\n hooksPresent,\n method: direct && viaMarketplace\n ? (\"both\" as const)\n : direct\n ? (\"direct\" as const)\n : viaMarketplace\n ? (\"marketplace\" as const)\n : null,\n };\n });\n rows.push({\n platform: p.id,\n scope: p.scope,\n configPath: p.configPath,\n connectors: connStatuses,\n });\n }\n\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n return 0;\n }\n\n if (rows.length === 0) {\n print(\"status: no agent platforms detected.\");\n return 0;\n }\n if (connectors.length === 0) {\n print(\"status: no connectors found (pass --connector <path> or install one).\\n\");\n }\n\n for (const r of rows) {\n print(`${r.platform} [${r.scope}] ${r.configPath}`);\n if (r.connectors.length === 0) {\n print(\" (no connectors to check)\");\n } else {\n for (const c of r.connectors) {\n const mark = c.method != null ? \"[installed]\" : \"[absent ]\";\n const server = c.serverPresent ? \"server ✓\" : \"server ·\";\n const hooks = c.hooksPresent ? \"hooks ✓\" : \"hooks ·\";\n // `both(!)` flags a violated one-method-per-host invariant — doctor's\n // duplicate-registration check FAILs it with the fix.\n const method =\n c.method == null ? \"\" : c.method === \"both\" ? \" (both!)\" : ` (${c.method})`;\n print(` ${mark} ${c.id} ${server} ${hooks}${method}`);\n }\n }\n print(\"\");\n }\n\n // Always 0: status is descriptive (what is installed where), never a gate —\n // that contrast with doctor (non-zero on FAIL) is the reason it exists.\n return 0;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli/commands/status.ts"],"sourcesContent":["/**\n * cli/commands/status — a light, glanceable install-state summary.\n *\n * There is NO MCP standard for \"which connectors are installed into which host\n * configs on this machine\" — distribution/wire standards (server.json, MCPB,\n * the lifecycle) cover publishing + the protocol, not local install state. So\n * `status` is purely agent-connector infrastructure, and we design it for the\n * everyday question it answers in one line per platform:\n *\n * \"which of my connectors are present on which hosts?\"\n *\n * It REUSES detect (host enumeration) + the adapters' own config-path resolvers\n * (a read-only presence check) — NO new adapter SPI methods. Unlike `doctor`\n * (deep health checks, non-zero exit on failure) and `doctor --probe` (a live\n * protocol probe that FAILs on a dead server), `status` ALWAYS exits 0: it\n * describes, it never gates. A connector being absent is informational.\n */\n\nimport { parseArgs } from \"node:util\";\nimport { readFileSync } from \"node:fs\";\n\nimport type { InstallScope, PlatformId, ResolvedConnector } from \"../../core/types.js\";\nimport type { InstallContext } from \"../../adapters/spi.js\";\nimport { detectInstalledPlatforms } from \"../../adapters/detect.js\";\nimport { loadAdapter } from \"../../adapters/registry.js\";\nimport {\n findConnectorConfig,\n listRegisteredConnectors,\n loadConnectorFromPath,\n} from \"../../core/load-connector.js\";\nimport { marketplaceEvidence } from \"../../core/marketplace-state.js\";\nimport { dataRoot, homeBinPath } from \"../../core/paths.js\";\nimport { fail, parseScope, print } from \"../app.js\";\n\n/**\n * Resolve which connector(s) status reports on: an explicit --connector path or\n * a local config first, else every connector registered under the data-root\n * (what is actually installed). Empty array when none — status still lists the\n * detected platforms.\n */\nasync function resolveConnectors(\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<ResolvedConnector[]> {\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (configPath) {\n try {\n const { connector } = await loadConnectorFromPath(configPath);\n return [connector];\n } catch {\n /* fall through to the registry */\n }\n }\n return listRegisteredConnectors();\n}\n\nfunction buildContext(\n connector: ResolvedConnector,\n id: PlatformId,\n scope: InstallScope,\n projectDir: string,\n): InstallContext {\n return {\n connector,\n scope: connector.platforms[id]?.scope ?? scope,\n projectDir,\n homeBinPath: homeBinPath(),\n dataRoot: dataRoot(),\n dryRun: true,\n };\n}\n\n/** Read-only: does the file at `path` mention `needle`? Missing/unreadable → false. */\nfunction fileMentions(path: string, needle: string): boolean {\n try {\n return readFileSync(path, \"utf8\").includes(needle);\n } catch {\n return false;\n }\n}\n\ninterface ConnStatus {\n id: string;\n serverPresent: boolean;\n hooksPresent: boolean;\n /**\n * Delivery method actually present on this host: `direct` (managed entries in\n * the host config), `marketplace` (the host's own plugin state / our install\n * record), `both` (the double-install invariant is VIOLATED — doctor FAILs\n * it), or null when absent.\n */\n method: \"direct\" | \"marketplace\" | \"both\" | null;\n}\ninterface StatusRow {\n platform: PlatformId;\n scope: InstallScope;\n configPath: string;\n connectors: ConnStatus[];\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n scope: { type: \"string\", default: \"user\" },\n connector: { type: \"string\" },\n project: { type: \"string\" },\n json: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n const projectDir = values.project ?? process.cwd();\n const scope = parseScope(values.scope);\n if (scope == null) return fail(`invalid --scope \"${values.scope}\" (use user|project)`);\n\n const connectors = await resolveConnectors(values.connector, projectDir);\n const detected = await detectInstalledPlatforms(projectDir);\n\n const rows: StatusRow[] = [];\n for (const p of detected) {\n const adapter = await loadAdapter(p.id);\n if (!adapter) continue;\n const connStatuses: ConnStatus[] = connectors.map((connector) => {\n const ctx = buildContext(connector, p.id, scope, projectDir);\n let serverPath = \"\";\n let hookPath = \"\";\n try {\n serverPath = adapter.getServerConfigPath(ctx);\n } catch {\n /* adapter has no server config path */\n }\n try {\n hookPath = adapter.getHookConfigPath(ctx);\n } catch {\n /* adapter has no hook config path */\n }\n const serverPresent = serverPath\n ? fileMentions(serverPath, connector.id)\n : false;\n const hooksPresent = hookPath ? fileMentions(hookPath, connector.id) : false;\n const direct = serverPresent || hooksPresent;\n const viaMarketplace = marketplaceEvidence(connector.id, p.id) != null;\n return {\n id: connector.id,\n serverPresent,\n hooksPresent,\n method: direct && viaMarketplace\n ? (\"both\" as const)\n : direct\n ? (\"direct\" as const)\n : viaMarketplace\n ? (\"marketplace\" as const)\n : null,\n };\n });\n rows.push({\n platform: p.id,\n scope: p.scope,\n configPath: p.configPath,\n connectors: connStatuses,\n });\n }\n\n if (values.json) {\n print(JSON.stringify(rows, null, 2));\n return 0;\n }\n\n if (rows.length === 0) {\n print(\"status: no agent platforms detected.\");\n return 0;\n }\n if (connectors.length === 0) {\n print(\"status: no connectors found (pass --connector <path> or install one).\\n\");\n }\n\n for (const r of rows) {\n print(`${r.platform} [${r.scope}] ${r.configPath}`);\n if (r.connectors.length === 0) {\n print(\" (no connectors to check)\");\n } else {\n for (const c of r.connectors) {\n const mark = c.method != null ? \"[installed]\" : \"[absent ]\";\n const server = c.serverPresent ? \"server ✓\" : \"server ·\";\n const hooks = c.hooksPresent ? \"hooks ✓\" : \"hooks ·\";\n // `both(!)` flags a violated one-method-per-host invariant — doctor's\n // duplicate-registration check FAILs it with the fix.\n const method =\n c.method == null ? \"\" : c.method === \"both\" ? \" (both!)\" : ` (${c.method})`;\n print(` ${mark} ${c.id} ${server} ${hooks}${method}`);\n }\n }\n print(\"\");\n }\n\n // Always 0: status is descriptive (what is installed where), never a gate —\n // that contrast with doctor (non-zero on FAIL) is the reason it exists.\n return 0;\n}\n"],"mappings":"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","names":[]}
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runStatusline
4
- } from "./chunk-BHUCB6LY.js";
4
+ } from "./chunk-5OWS5CMA.js";
5
5
  import "./chunk-OP4KBXUO.js";
6
- import "./chunk-22Y24V7O.js";
7
- import "./chunk-J3D5W5T2.js";
8
- import "./chunk-CIRDOY2V.js";
6
+ import "./chunk-F5RX62T7.js";
7
+ import "./chunk-EGCBZ2DC.js";
8
+ import "./chunk-2AVLX7GH.js";
9
9
  import "./chunk-BCHWFTV4.js";
10
10
  import "./chunk-KHO5WNTP.js";
11
- import "./chunk-KGJWE6A2.js";
12
- import "./chunk-ADTHT2FN.js";
13
- import "./chunk-3PFFTFCU.js";
14
- import "./chunk-BXGFUENQ.js";
11
+ import "./chunk-24IDL5RW.js";
12
+ import "./chunk-4ENJK5S2.js";
13
+ import "./chunk-DCKFYWGM.js";
14
+ import "./chunk-FAHIMJRU.js";
15
+ import "./chunk-I5MLE6S7.js";
15
16
  import "./chunk-N6HH7K6P.js";
16
17
  import "./chunk-TRQKHP7D.js";
17
18
 
@@ -56,4 +57,4 @@ async function run(argv) {
56
57
  export {
57
58
  run
58
59
  };
59
- //# sourceMappingURL=statusline-ZNTCL5YC.js.map
60
+ //# sourceMappingURL=statusline-L376ZPZU.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/commands/statusline.ts"],"sourcesContent":["/**\n * cli/commands/statusline — the universal statusline (HUD) entrypoint.\n *\n * agent-connector statusline <platform> --connector <id>\n *\n * A statusline-supporting host points its status line config at the single stable\n * home binary (via core/spawn.buildHomeBinStatuslineCommand). This command reads\n * the ENTIRE host payload from stdin, dispatches through runStatusline, writes the\n * rendered line to stdout, and exits with the adapter's exit code.\n *\n * FAIL-SAFE is the runtime's contract: a status line must NEVER wedge the host or\n * spew an error into the status bar. runStatusline never rejects (always exits 0\n * with at most a rendered line), and even a malformed invocation here degrades to\n * exit 0 with no output — never the strict `fail()` non-zero used by other\n * commands.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { runStatusline } from \"../../runtime/index.js\";\n\n/** Read all of a readable stream to a UTF-8 string. */\nasync function readAll(stream: NodeJS.ReadStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n // strict:false so a future flag from a newer install can never make this throw\n // and surface a non-zero exit into the host's status bar.\n let platformId = \"\";\n let connectorId = \"\";\n try {\n const { values, positionals } = parseArgs({\n args: argv,\n options: { connector: { type: \"string\" } },\n allowPositionals: true,\n strict: false,\n });\n platformId = positionals[0] ?? \"\";\n connectorId = typeof values.connector === \"string\" ? values.connector : \"\";\n } catch {\n // A malformed invocation must still fail-safe (render nothing, exit 0).\n return 0;\n }\n\n // Drain stdin regardless — a host expects the command to consume its payload.\n const stdin = await readAll(process.stdin).catch(() => \"\");\n\n // Missing platform/connector → render nothing, exit 0 (never a non-zero exit).\n if (platformId === \"\" || connectorId === \"\") {\n return 0;\n }\n\n const reply = await runStatusline({ platformId, connectorId, stdin });\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\n process.stdout.write(reply.stdout);\n }\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\n }\n return reply.exitCode;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiBA,SAAS,iBAAiB;AAK1B,eAAe,QAAQ,QAA4C;AACjE,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ;AAChC,WAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,EACpE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,eAAsB,IAAI,MAAiC;AAGzD,MAAI,aAAa;AACjB,MAAI,cAAc;AAClB,MAAI;AACF,UAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,MACxC,MAAM;AAAA,MACN,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,EAAE;AAAA,MACzC,kBAAkB;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AACD,iBAAa,YAAY,CAAC,KAAK;AAC/B,kBAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAAA,EAC1E,QAAQ;AAEN,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,MAAM,EAAE;AAGzD,MAAI,eAAe,MAAM,gBAAgB,IAAI;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,cAAc,EAAE,YAAY,aAAa,MAAM,CAAC;AACpE,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,MAAM;AAAA,EACnC;AACA,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AACA,SAAO,MAAM;AACf;","names":[]}
1
+ {"version":3,"sources":["../src/cli/commands/statusline.ts"],"sourcesContent":["/**\n * cli/commands/statusline — the universal statusline (HUD) entrypoint.\n *\n * agent-connector statusline <platform> --connector <id>\n *\n * A statusline-supporting host points its status line config at the single stable\n * home binary (via core/spawn.buildHomeBinStatuslineCommand). This command reads\n * the ENTIRE host payload from stdin, dispatches through runStatusline, writes the\n * rendered line to stdout, and exits with the adapter's exit code.\n *\n * FAIL-SAFE is the runtime's contract: a status line must NEVER wedge the host or\n * spew an error into the status bar. runStatusline never rejects (always exits 0\n * with at most a rendered line), and even a malformed invocation here degrades to\n * exit 0 with no output — never the strict `fail()` non-zero used by other\n * commands.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { runStatusline } from \"../../runtime/index.js\";\n\n/** Read all of a readable stream to a UTF-8 string. */\nasync function readAll(stream: NodeJS.ReadStream): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === \"string\" ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n // strict:false so a future flag from a newer install can never make this throw\n // and surface a non-zero exit into the host's status bar.\n let platformId = \"\";\n let connectorId = \"\";\n try {\n const { values, positionals } = parseArgs({\n args: argv,\n options: { connector: { type: \"string\" } },\n allowPositionals: true,\n strict: false,\n });\n platformId = positionals[0] ?? \"\";\n connectorId = typeof values.connector === \"string\" ? values.connector : \"\";\n } catch {\n // A malformed invocation must still fail-safe (render nothing, exit 0).\n return 0;\n }\n\n // Drain stdin regardless — a host expects the command to consume its payload.\n const stdin = await readAll(process.stdin).catch(() => \"\");\n\n // Missing platform/connector → render nothing, exit 0 (never a non-zero exit).\n if (platformId === \"\" || connectorId === \"\") {\n return 0;\n }\n\n const reply = await runStatusline({ platformId, connectorId, stdin });\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\n process.stdout.write(reply.stdout);\n }\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\n }\n return reply.exitCode;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAiBA,SAAS,iBAAiB;AAK1B,eAAe,QAAQ,QAA4C;AACjE,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ;AAChC,WAAO,KAAK,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI,KAAK;AAAA,EACpE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;AAEA,eAAsB,IAAI,MAAiC;AAGzD,MAAI,aAAa;AACjB,MAAI,cAAc;AAClB,MAAI;AACF,UAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,MACxC,MAAM;AAAA,MACN,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,EAAE;AAAA,MACzC,kBAAkB;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AACD,iBAAa,YAAY,CAAC,KAAK;AAC/B,kBAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAAA,EAC1E,QAAQ;AAEN,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,MAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,MAAM,EAAE;AAGzD,MAAI,eAAe,MAAM,gBAAgB,IAAI;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,MAAM,cAAc,EAAE,YAAY,aAAa,MAAM,CAAC;AACpE,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,MAAM;AAAA,EACnC;AACA,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AACA,SAAO,MAAM;AACf;","names":[]}
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  fail,
14
14
  print
15
- } from "./chunk-KGXDYGNJ.js";
15
+ } from "./chunk-O5TWCIJN.js";
16
16
  import {
17
17
  openStore
18
18
  } from "./chunk-BCHWFTV4.js";
@@ -21,9 +21,10 @@ import {
21
21
  listRegisteredConnectors,
22
22
  loadRegisteredConnector,
23
23
  readRegisteredMeta
24
- } from "./chunk-KGJWE6A2.js";
25
- import "./chunk-ADTHT2FN.js";
26
- import "./chunk-3PFFTFCU.js";
24
+ } from "./chunk-24IDL5RW.js";
25
+ import "./chunk-4ENJK5S2.js";
26
+ import "./chunk-DCKFYWGM.js";
27
+ import "./chunk-FAHIMJRU.js";
27
28
  import "./chunk-N6HH7K6P.js";
28
29
  import "./chunk-TRQKHP7D.js";
29
30
 
@@ -348,4 +349,4 @@ export {
348
349
  parseSince,
349
350
  run
350
351
  };
351
- //# sourceMappingURL=telemetry-XIKUUGTQ.js.map
352
+ //# sourceMappingURL=telemetry-B3DX3PWU.js.map
@@ -1 +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
+ {"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":[]}
@@ -4,13 +4,13 @@ import {
4
4
  } from "./chunk-DBQMX75U.js";
5
5
  import {
6
6
  BaseAdapter
7
- } from "./chunk-IW77FFNX.js";
7
+ } from "./chunk-CPLK7GTE.js";
8
8
  import "./chunk-7L6ITC4T.js";
9
9
  import {
10
10
  buildServeWrapperCommand,
11
11
  isHomeBinHookCommand,
12
12
  shouldWrapForTelemetry
13
- } from "./chunk-BXGFUENQ.js";
13
+ } from "./chunk-I5MLE6S7.js";
14
14
  import "./chunk-N6HH7K6P.js";
15
15
  import "./chunk-TRQKHP7D.js";
16
16
 
@@ -302,4 +302,4 @@ export {
302
302
  adapter,
303
303
  trae_default as default
304
304
  };
305
- //# sourceMappingURL=trae-NWT3TMSZ.js.map
305
+ //# sourceMappingURL=trae-7CZZGOGI.js.map
@@ -23,22 +23,22 @@
23
23
  * exposes no writable MCP config to install into. The registry-completeness test
24
24
  * (tests/adapters/registry-completeness.test.ts) allowlists it for this reason.
25
25
  */
26
- type PlatformId = "claude-code" | "codex" | "cursor" | "vscode-copilot" | "jetbrains-copilot" | "copilot-cli" | "gemini-cli" | "opencode" | "mimo-code" | "kilo" | "kilo-cli" | "warp" | "hermes" | "nemoclaw" | "openclaw" | "zed" | "antigravity" | "antigravity-cli" | "kiro" | "qwen-code" | "kimi" | "pi" | "omp" | "droid" | "roo-code" | "trae" | "amp" | "codebuff" | "mux" | "crush" | "goose" | "synthetic" | "unknown";
26
+ type PlatformId = "claude-code" | "codex" | "cursor" | "vscode-copilot" | "jetbrains-copilot" | "copilot-cli" | "gemini-cli" | "opencode" | "mimo-code" | "kilo" | "kilo-cli" | "warp" | "hermes" | "nemoclaw" | "openclaw" | "zed" | "antigravity" | "antigravity-cli" | "kiro" | "qwen-code" | "kimi" | "pi" | "omp" | "droid" | "roo-code" | "cline" | "trae" | "amp" | "codebuff" | "mux" | "crush" | "goose" | "amazon-q" | "continue" | "windsurf" | "synthetic" | "unknown";
27
27
  /**
28
28
  * Hook I/O paradigm — the deepest cross-platform divergence (report §4).
29
29
  * Canonical shipped sets (keep in sync with src/adapters/registry.ts — this
30
30
  * comment once drifted and seeded a docs-wide misclassification):
31
- * - "json-stdio" (16): host pipes JSON to a command on stdin, reads
31
+ * - "json-stdio" (17): host pipes JSON to a command on stdin, reads
32
32
  * JSON/exit-code back — Claude Code, Codex, Cursor, VS Code/JetBrains
33
33
  * Copilot, Copilot CLI, Gemini CLI, Qwen, Kiro, Kimi, Crush, Goose, Hermes,
34
- * Droid (Factory), Antigravity (+ the agy CLI). One universal entrypoint
35
- * binary handles all of them.
34
+ * Droid (Factory), Antigravity (+ the agy CLI), Continue. One universal
35
+ * entrypoint binary handles all of them.
36
36
  * - "ts-plugin" (7): host loads a JS/TS module exporting lifecycle functions
37
37
  * — OpenCode, MiMoCode (an OpenCode fork), Kilo CLI, Kilo, OMP, OpenClaw,
38
38
  * NemoClaw (an OpenClaw wrapper/fork). Framework generates the module.
39
- * - "mcp-only" (8): no hook layer at all — Warp, Roo Code, Trae, Zed,
40
- * Amp, Codebuff, Mux, Pi. Only the MCP server (or skills surface) is
41
- * installed; hooks are reported unavailable.
39
+ * - "mcp-only" (11): no hook layer at all — Warp, Roo Code, Cline, Trae, Zed,
40
+ * Amp, Codebuff, Mux, Pi, Amazon Q, Windsurf. Only the MCP server (or skills
41
+ * surface) is installed; hooks are reported unavailable.
42
42
  */
43
43
  type HookParadigm = "json-stdio" | "ts-plugin" | "mcp-only";
44
44
  /**
@@ -88,12 +88,14 @@ interface ServerDef {
88
88
  /**
89
89
  * Canonical, platform-agnostic lifecycle event names.
90
90
  *
91
- * The last four (PermissionRequest / PostToolUseFailure / SubagentStart /
92
- * SubagentStop) are newer additions with cross-host analogs; hosts without a
93
- * native analog mark them unsupported in capabilities and the install reports
94
- * a skip-warn — an event is never silently dropped.
91
+ * The newer additions (PermissionRequest / PostToolUseFailure / SubagentStart /
92
+ * SubagentStop and the trailing PostCompact) have cross-host analogs; hosts
93
+ * without a native analog mark them unsupported in capabilities and the install
94
+ * reports a skip-warn — an event is never silently dropped. PostCompact is
95
+ * observational only (the post-compaction sibling of PreCompact; cannot
96
+ * block/modify) and is appended LAST to keep the canonical order append-only.
95
97
  */
96
- type HookEventName = "SessionStart" | "SessionEnd" | "UserPromptSubmit" | "PreToolUse" | "PostToolUse" | "PreCompact" | "Stop" | "Notification" | "PermissionRequest" | "PostToolUseFailure" | "SubagentStart" | "SubagentStop";
98
+ type HookEventName = "SessionStart" | "SessionEnd" | "UserPromptSubmit" | "PreToolUse" | "PostToolUse" | "PreCompact" | "Stop" | "Notification" | "PermissionRequest" | "PostToolUseFailure" | "SubagentStart" | "SubagentStop" | "PostCompact";
97
99
  interface BaseEvent {
98
100
  /** Which host produced this event (from runtime detection). */
99
101
  hostPlatform: PlatformId;
@@ -139,6 +141,17 @@ interface UserPromptSubmitEvent extends BaseEvent {
139
141
  interface PreCompactEvent extends BaseEvent {
140
142
  trigger?: "auto" | "manual";
141
143
  }
144
+ /**
145
+ * PostCompact — the post-compaction sibling of {@link PreCompactEvent}. Fires
146
+ * AFTER the host finishes compacting/summarizing the conversation. Observational
147
+ * only: it cannot block or modify (compaction already happened), exactly like
148
+ * PreCompact's reply contract. The single normalized field is `trigger`
149
+ * (manual|auto); everything else rides on `raw`. Codex is the verified firing
150
+ * host (its hook system ships PreCompact AND PostCompact).
151
+ */
152
+ interface PostCompactEvent extends BaseEvent {
153
+ trigger?: "auto" | "manual";
154
+ }
142
155
  interface StopEvent extends BaseEvent {
143
156
  /** True when the stop hook itself was triggered during a previous stop hook. */
144
157
  stopHookActive?: boolean;
@@ -225,6 +238,7 @@ interface EventPayloadMap {
225
238
  PostToolUseFailure: PostToolUseFailureEvent;
226
239
  SubagentStart: SubagentStartEvent;
227
240
  SubagentStop: SubagentStopEvent;
241
+ PostCompact: PostCompactEvent;
228
242
  }
229
243
  /**
230
244
  * Normalized hook response. A handler returns a subset of these; the adapter
@@ -301,6 +315,7 @@ interface HooksConfig {
301
315
  PostToolUseFailure?: HookDefinition<"PostToolUseFailure">;
302
316
  SubagentStart?: HookDefinition<"SubagentStart">;
303
317
  SubagentStop?: HookDefinition<"SubagentStop">;
318
+ PostCompact?: HookDefinition<"PostCompact">;
304
319
  }
305
320
  /**
306
321
  * The payload a NATIVE (passthrough) hook handler receives. Unlike the
@@ -431,6 +446,14 @@ interface PlatformCapabilities {
431
446
  postToolUseFailure?: boolean;
432
447
  subagentStart?: boolean;
433
448
  subagentStop?: boolean;
449
+ /**
450
+ * PostCompact — observational post-compaction event (the sibling of
451
+ * preCompact). OPTIONAL, read as `?? false`: a host that leaves it unset does
452
+ * not fire PostCompact natively and a declared hook for it warn-skips at
453
+ * install. v1: codex only (its hook system ships both PreCompact and
454
+ * PostCompact).
455
+ */
456
+ postCompact?: boolean;
434
457
  /** Can a PreToolUse hook rewrite tool arguments? */
435
458
  canModifyArgs: boolean;
436
459
  /** Can a PostToolUse hook rewrite tool output? */
@@ -487,14 +510,15 @@ interface PlatformCapabilities {
487
510
  supportsStatusline?: boolean;
488
511
  /**
489
512
  * Action-surface support — can this adapter EMIT a host affordance (slash
490
- * command / keybinding / clickable element) bound to the universal
513
+ * command / palette workflow / exec-file) bound to the universal
491
514
  * `<homeBin> action <host> <actionId> --connector <id>` verb? OPTIONAL, read
492
- * as `?? false` (supportsStatusline precedent). v1 ships only the dispatch
493
- * BACKBONE no adapter sets this true, because the host-feasibility survey
494
- * found no verifiable CLI emission target (slash commands are prompt
495
- * templates that cannot run a shell verb; plugin APIs expose no command
496
- * registration). It is the flag a future affordance-emitter flips; until then
497
- * every adapter's BaseAdapter install/uninstall defaults honestly skip-warn.
515
+ * as `?? false` (supportsStatusline precedent). The dispatch BACKBONE shipped
516
+ * first; the EMITTERS now ship on the hosts with a verifiable target: droid
517
+ * (executable command file), hermes (quick_commands exec slash command), warp
518
+ * (palette workflow pastes the command for the user to run). Hosts whose
519
+ * slash commands are prompt templates that cannot run a shell verb, or whose
520
+ * plugin APIs expose no command registration, leave this unset — every such
521
+ * adapter's BaseAdapter install/uninstall defaults honestly skip-warn.
498
522
  */
499
523
  supportsActions?: boolean;
500
524
  }
@@ -556,7 +580,7 @@ interface SubagentDef {
556
580
  * writes it as a MANAGED BLOCK (marker-fenced, hash-stamped,
557
581
  * uninstall-reversible — see core/managed-block.ts) into the memory/rules file
558
582
  * that host actually reads: AGENTS.md wherever the host supports the agents.md
559
- * standard (29/31 hosts), the host's own file (CLAUDE.md / GEMINI.md)
583
+ * standard (29/35 hosts), the host's own file (CLAUDE.md / GEMINI.md)
560
584
  * otherwise. CONTENT-ONLY like commands/skills/subagents: no runtime dispatch,
561
585
  * no telemetry wrapping — a pure, surgical file edit that never touches bytes
562
586
  * outside its own marker pair.
@@ -655,6 +679,16 @@ interface StatuslineContext extends HostCtx {
655
679
  maxTokens?: number;
656
680
  percent?: number;
657
681
  };
682
+ /**
683
+ * THIS connector's OWN recorded MCP telemetry usage (token sums + call count),
684
+ * pre-computed by the runtime so render() can read it synchronously. ALL-TIME
685
+ * for the connector (every stored row) — NOT the host context-window (see
686
+ * `context`) and NOT session-scoped. When pre-computed it is always a real
687
+ * summary (zeros when there's no telemetry or it's switched off, never
688
+ * undefined); it is undefined only for a context that does not pre-compute it.
689
+ * render() can still `await ctx.telemetry?.()` to fetch a live or custom slice.
690
+ */
691
+ usage?: TelemetryUsageSummary;
658
692
  /** Path to the session transcript, when the host reports one. */
659
693
  transcriptPath?: string;
660
694
  /** The host's verbatim status payload (escape hatch). */
@@ -817,13 +851,13 @@ interface PlatformOverride {
817
851
  * VERBATIM. This immediately covers all 30 current Claude Code events (e.g.
818
852
  * TaskCreated, TaskCompleted, TeammateIdle, StopFailure, MessageDisplay,
819
853
  * WorktreeCreate/WorktreeRemove, Elicitation/ElicitationResult,
820
- * InstructionsLoaded, ConfigChange, FileChanged, PostCompact, …) and any
854
+ * InstructionsLoaded, ConfigChange, FileChanged, CwdChanged, …) and any
821
855
  * future event a host adds — with zero agent-connector releases.
822
856
  *
823
857
  * Scoping: per-platform-keyed, so a declaration only ever applies to the
824
858
  * platform it is declared under. Adapters without
825
859
  * {@link PlatformCapabilities.supportsNativeHooks} report a skip-warn
826
- * ChangeRecord at install (never silent). Declaring one of the 12 normalized
860
+ * ChangeRecord at install (never silent). Declaring one of the 13 normalized
827
861
  * event names here is a ConnectorConfigError — use the normalized `hooks`
828
862
  * API for those.
829
863
  *
@@ -859,6 +893,8 @@ interface PlatformOverride {
859
893
  memory?: boolean | PlatformMemoryOverride;
860
894
  /** false → do not wire the status line on this platform (no object form in v1). */
861
895
  statusline?: boolean;
896
+ /** false → do not emit the action affordance(s) on this platform (no object form in v1). */
897
+ actions?: boolean;
862
898
  /** Verbatim fields merged into the native config (reach platform-exclusive features). */
863
899
  extra?: Record<string, unknown>;
864
900
  }
@@ -1014,6 +1050,12 @@ interface DiagnosticResult {
1014
1050
  status: "pass" | "fail" | "warn";
1015
1051
  message: string;
1016
1052
  fix?: string;
1053
+ /**
1054
+ * true ⇒ a plain re-sync re-asserts this (the surface is simply absent and
1055
+ * agent-connector owns it). Omitted/false ⇒ heal must DEFER (drift we'd
1056
+ * clobber, external dep, or ambiguous ownership).
1057
+ */
1058
+ fixable?: boolean;
1017
1059
  }
1018
1060
 
1019
1061
  export type { ActionDef as A, SubagentDef as B, CommandDef as C, SubagentStartEvent as D, EventPayloadMap as E, SubagentStopEvent as F, SurfaceToolPolicy as G, HookDefinition as H, InstallScope as I, JsonValue as J, TelemetryConfig as K, TelemetryUsageSummary as L, MemoryDef as M, NativeHookDef as N, ToolFilter as O, PlatformId as P, Transport as Q, ResolvedConnector as R, ServerDef as S, TelemetryAccessor as T, UserPromptSubmitEvent as U, ChangeRecord as V, DetectedPlatform as W, DiagnosticResult as X, InstallResult as Y, ActionResult as a, AuthSpec as b, ConfigPatchDef as c, ConnectorConfig as d, HookEventName as e, HookParadigm as f, HookResponse as g, HooksConfig as h, HostCtx as i, NativeHookEvent as j, NotificationEvent as k, PermissionRequestEvent as l, PlatformCapabilities as m, PlatformMemoryOverride as n, PlatformOverride as o, PostToolUseEvent as p, PostToolUseFailureEvent as q, PreCompactEvent as r, PreToolUseEvent as s, PublishConfig as t, SessionEndEvent as u, SessionStartEvent as v, SkillDef as w, StatuslineContext as x, StatuslineDef as y, StopEvent as z };
@@ -5,8 +5,8 @@ import {
5
5
  resolveUninstallTargets,
6
6
  uninstallConnector,
7
7
  uninstallViaMarketplace
8
- } from "./chunk-G3ER4SY5.js";
9
- import "./chunk-MAH6QQTO.js";
8
+ } from "./chunk-RIMVWCZY.js";
9
+ import "./chunk-QREL7LZJ.js";
10
10
  import {
11
11
  marketplaceEvidence,
12
12
  readMarketplaceInstalls
@@ -17,19 +17,20 @@ import {
17
17
  parseTargets,
18
18
  print,
19
19
  renderInstallResult
20
- } from "./chunk-KGXDYGNJ.js";
21
- import "./chunk-22Y24V7O.js";
22
- import "./chunk-J3D5W5T2.js";
20
+ } from "./chunk-O5TWCIJN.js";
21
+ import "./chunk-F5RX62T7.js";
22
+ import "./chunk-EGCBZ2DC.js";
23
23
  import "./chunk-KHO5WNTP.js";
24
24
  import {
25
25
  findConnectorConfig,
26
26
  loadConnectorFromPath
27
- } from "./chunk-KGJWE6A2.js";
28
- import "./chunk-ADTHT2FN.js";
29
- import "./chunk-3PFFTFCU.js";
27
+ } from "./chunk-24IDL5RW.js";
28
+ import "./chunk-4ENJK5S2.js";
29
+ import "./chunk-DCKFYWGM.js";
30
+ import "./chunk-FAHIMJRU.js";
30
31
  import "./chunk-OPXAP3AC.js";
31
32
  import "./chunk-7L6ITC4T.js";
32
- import "./chunk-BXGFUENQ.js";
33
+ import "./chunk-I5MLE6S7.js";
33
34
  import "./chunk-N6HH7K6P.js";
34
35
  import "./chunk-TRQKHP7D.js";
35
36
 
@@ -161,4 +162,4 @@ async function run(argv) {
161
162
  export {
162
163
  run
163
164
  };
164
- //# sourceMappingURL=uninstall-2LBLQVFA.js.map
165
+ //# sourceMappingURL=uninstall-ZYTW7YMZ.js.map
@@ -1 +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 { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport type { InstallResult, PlatformId } from \"../../core/types.js\";\nimport { fail, parseScope, parseTargets, print, renderInstallResult } from \"../app.js\";\n\n/** Resolve the connector id from flags, then from a local config file. */\nasync function resolveConnectorId(\n explicitId: string | undefined,\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<string | null> {\n if (explicitId && explicitId.trim() !== \"\") return explicitId;\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (!configPath) return null;\n const { connector } = await loadConnectorFromPath(configPath);\n return connector.id;\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 },\n allowPositionals: false,\n });\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 connectorId = await resolveConnectorId(\n values[\"connector-id\"],\n values.connector,\n projectDir,\n );\n if (!connectorId) {\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\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 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 resolved = 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([...resolved, ...recorded])];\n marketplaceTargets = candidates.filter(\n (id) => marketplaceEvidence(connectorId, id) != null,\n );\n directTargets = resolved.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 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 };\n print(renderInstallResult(merged, \"uninstall\"));\n return merged.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,SAAS,iBAAiB;AAkB1B,eAAe,mBACb,YACA,eACA,YACwB;AACxB,MAAI,cAAc,WAAW,KAAK,MAAM,GAAI,QAAO;AACnD,QAAM,aAAa,iBAAiB,oBAAoB,UAAU;AAClE,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,EAAE,UAAU,IAAI,MAAM,sBAAsB,UAAU;AAC5D,SAAO,UAAU;AACnB;AAEA,eAAsB,IAAI,MAAiC;AACzD,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,MACP,QAAQ,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,MAC1C,OAAO,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,MACzC,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,gBAAgB,EAAE,MAAM,SAAS;AAAA,MACjC,SAAS,EAAE,MAAM,SAAS;AAAA,MAC1B,WAAW,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MAC7C,OAAO,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,IAC3C;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,SAAS,qBAAqB,OAAO,MAAM;AACjD,MAAI,UAAU,MAAM;AAClB,WAAO,KAAK,qBAAqB,OAAO,MAAM,iCAAiC;AAAA,EACjF;AAEA,QAAM,aAAa,OAAO,WAAW,QAAQ,IAAI;AAEjD,QAAM,QAAQ,WAAW,OAAO,KAAK;AACrC,MAAI,SAAS,KAAM,QAAO,KAAK,oBAAoB,OAAO,KAAK,sBAAsB;AAErF,QAAM,cAAc,MAAM;AAAA,IACxB,OAAO,cAAc;AAAA,IACrB,OAAO;AAAA,IACP;AAAA,EACF;AACA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,MACL;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,UAAU,aAAa,OAAO,OAAO;AAC3C,QAAM,SAAS,OAAO,SAAS;AAK/B,MAAI,WAAW,eAAe;AAC5B,UAAM,SAAS,MAAM,wBAAwB;AAAA,MAC3C;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,OAAO;AAAA,MACd,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC/B,CAAC;AACD,QAAI,OAAO,MAAO,qBAAoB,aAAa,QAAQ,MAAM;AACjE,UAAM,oBAAoB,QAAQ,WAAW,CAAC;AAC9C,WAAO,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,IAAI,IAAI;AAAA,EAC/D;AAIA,MAAI,qBAAmC,CAAC;AACxC,MAAI,gBAA8B,CAAC;AACnC,MAAI,WAAW,QAAQ;AACrB,UAAM,WAAW,MAAM,wBAAwB,aAAa,SAAS,UAAU;AAK/E,UAAM,WAAW,UACb,CAAC,IACA,OAAO,KAAK,wBAAwB,WAAW,CAAC;AACrD,UAAM,aAAa,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAC,CAAC;AAC1D,yBAAqB,WAAW;AAAA,MAC9B,CAAC,OAAO,oBAAoB,aAAa,EAAE,KAAK;AAAA,IAClD;AACA,oBAAgB,SAAS,OAAO,CAAC,OAAO,CAAC,mBAAmB,SAAS,EAAE,CAAC;AAAA,EAC1E;AAKA,MAAI,mBAAmB,WAAW,GAAG;AACnC,UAAM,SAAS,MAAM,mBAAmB;AAAA,MACtC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,OAAO;AAAA,MACd,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC/B,CAAC;AACD,UAAM,oBAAoB,QAAQ,WAAW,CAAC;AAC9C,WAAO,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,IAAI,IAAI;AAAA,EAC/D;AAEA,QAAM,UAA2B;AAAA,IAC/B,MAAM,wBAAwB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT;AAAA,MACA,OAAO,OAAO;AAAA,IAChB,CAAC;AAAA,EACH;AAMA,MAAI,cAAc,SAAS,GAAG;AAC5B,YAAQ;AAAA,MACN,MAAM,mBAAmB;AAAA,QACvB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,OAAO;AAAA,QACd,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,WAAW,OAAO,OAAO;AACvB,UAAM,cAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA,SAAS,CAAC;AAAA,MACV,UAAU,CAAC;AAAA,IACb;AACA,QAAI,QAAQ;AAIV,kBAAY,QAAQ,KAAK;AAAA,QACvB,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,QACE;AAAA,MACJ,CAAC;AAAA,IACH,OAAO;AACL,0BAAoB,aAAa,QAAQ,WAAW;AAAA,IACtD;AACA,YAAQ,KAAK,WAAW;AAAA,EAC1B;AAEA,QAAM,SAAwB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,SAAS,QAAQ,QAAQ,CAAC,MAAM,EAAE,OAAO;AAAA,IACzC,UAAU,QAAQ,QAAQ,CAAC,MAAM,EAAE,QAAQ;AAAA,EAC7C;AACA,QAAM,oBAAoB,QAAQ,WAAW,CAAC;AAC9C,SAAO,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,MAAM,IAAI,IAAI;AAC/D;","names":[]}
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 { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport type { InstallResult, PlatformId } from \"../../core/types.js\";\nimport { fail, parseScope, parseTargets, print, renderInstallResult } from \"../app.js\";\n\n/** Resolve the connector id from flags, then from a local config file. */\nasync function resolveConnectorId(\n explicitId: string | undefined,\n connectorPath: string | undefined,\n projectDir: string,\n): Promise<string | null> {\n if (explicitId && explicitId.trim() !== \"\") return explicitId;\n const configPath = connectorPath ?? findConnectorConfig(projectDir);\n if (!configPath) return null;\n const { connector } = await loadConnectorFromPath(configPath);\n return connector.id;\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 },\n allowPositionals: false,\n });\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 connectorId = await resolveConnectorId(\n values[\"connector-id\"],\n values.connector,\n projectDir,\n );\n if (!connectorId) {\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\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 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 resolved = 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([...resolved, ...recorded])];\n marketplaceTargets = candidates.filter(\n (id) => marketplaceEvidence(connectorId, id) != null,\n );\n directTargets = resolved.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 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 };\n print(renderInstallResult(merged, \"uninstall\"));\n return merged.changes.some((c) => c.action === \"warn\") ? 1 : 0;\n}\n"],"mappings":"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","names":[]}