@ken-jo/agent-connector 0.1.0 → 0.3.0

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 (174) hide show
  1. package/README.md +183 -24
  2. package/dist/{amp-QSFH2V7Y.js → amp-YGV66GJT.js} +9 -2
  3. package/dist/amp-YGV66GJT.js.map +1 -0
  4. package/dist/{antigravity-CX2YLSY7.js → antigravity-7IBYFO6P.js} +4 -3
  5. package/dist/{antigravity-cli-YQDFVV4U.js → antigravity-cli-JEOUP2VN.js} +4 -3
  6. package/dist/{antigravity-cli-YQDFVV4U.js.map → antigravity-cli-JEOUP2VN.js.map} +1 -1
  7. package/dist/{chunk-LTT56GI3.js → chunk-3JCRUROU.js} +18 -5
  8. package/dist/chunk-3JCRUROU.js.map +1 -0
  9. package/dist/chunk-44HUXXC6.js +284 -0
  10. package/dist/chunk-44HUXXC6.js.map +1 -0
  11. package/dist/{chunk-54EMKTTX.js → chunk-DS3LUFVN.js} +21 -21
  12. package/dist/chunk-DS3LUFVN.js.map +1 -0
  13. package/dist/chunk-GSGDG2BV.js +568 -0
  14. package/dist/chunk-GSGDG2BV.js.map +1 -0
  15. package/dist/{chunk-TRKWUNO4.js → chunk-KQSNDFBN.js} +13 -2
  16. package/dist/chunk-KQSNDFBN.js.map +1 -0
  17. package/dist/{chunk-KHO5WNTP.js → chunk-KVAAFYRR.js} +18 -2
  18. package/dist/chunk-KVAAFYRR.js.map +1 -0
  19. package/dist/chunk-N6HH7K6P.js +494 -0
  20. package/dist/chunk-N6HH7K6P.js.map +1 -0
  21. package/dist/{chunk-XUCWLJY5.js → chunk-NJU275US.js} +30 -30
  22. package/dist/{chunk-WCETQWWK.js → chunk-OP4KBXUO.js} +1 -17
  23. package/dist/chunk-OP4KBXUO.js.map +1 -0
  24. package/dist/{chunk-TIIP3RG2.js → chunk-PD4VFEBY.js} +342 -2
  25. package/dist/chunk-PD4VFEBY.js.map +1 -0
  26. package/dist/chunk-QADSG2JY.js +1989 -0
  27. package/dist/chunk-QADSG2JY.js.map +1 -0
  28. package/dist/{chunk-WV63X7IK.js → chunk-SCVBYSF7.js} +2 -2
  29. package/dist/chunk-SCVBYSF7.js.map +1 -0
  30. package/dist/{package-DLOVE2E4.js → chunk-WNREHWKL.js} +26 -115
  31. package/dist/chunk-WNREHWKL.js.map +1 -0
  32. package/dist/{chunk-YNZU6PAV.js → chunk-ZAM4M7LI.js} +74 -21
  33. package/dist/chunk-ZAM4M7LI.js.map +1 -0
  34. package/dist/claude-code-4275HQU4.js +1432 -0
  35. package/dist/claude-code-4275HQU4.js.map +1 -0
  36. package/dist/cli/sdk.js +4 -3
  37. package/dist/cli/sdk.js.map +1 -1
  38. package/dist/cli.js +1 -1
  39. package/dist/{codebuff-QX57FJDN.js → codebuff-LE3KBZGM.js} +9 -2
  40. package/dist/codebuff-LE3KBZGM.js.map +1 -0
  41. package/dist/{codex-JFQTS6LU.js → codex-4BY2ZJIW.js} +148 -7
  42. package/dist/codex-4BY2ZJIW.js.map +1 -0
  43. package/dist/{copilot-cli-MTCGHZ2T.js → copilot-cli-IPISKO3V.js} +109 -2
  44. package/dist/copilot-cli-IPISKO3V.js.map +1 -0
  45. package/dist/{crush-I7PK3FGI.js → crush-X3E25EQG.js} +31 -3
  46. package/dist/crush-X3E25EQG.js.map +1 -0
  47. package/dist/{cursor-4TMXKJOZ.js → cursor-UH3W622V.js} +66 -5
  48. package/dist/cursor-UH3W622V.js.map +1 -0
  49. package/dist/{detect-WIAGVYS4.js → detect-MNDHGLSV.js} +7 -3
  50. package/dist/detect-MNDHGLSV.js.map +1 -0
  51. package/dist/{doctor-EZW2K4NI.js → doctor-N5KZDD55.js} +45 -7
  52. package/dist/doctor-N5KZDD55.js.map +1 -0
  53. package/dist/{droid-KN6VRMMT.js → droid-T5VBRXZF.js} +32 -3
  54. package/dist/droid-T5VBRXZF.js.map +1 -0
  55. package/dist/{gemini-cli-Y35FFK4M.js → gemini-cli-ZSUK55UA.js} +51 -3
  56. package/dist/gemini-cli-ZSUK55UA.js.map +1 -0
  57. package/dist/{goose-ZTGTSUFJ.js → goose-M3RR3CZG.js} +63 -4
  58. package/dist/goose-M3RR3CZG.js.map +1 -0
  59. package/dist/{hermes-H2KV44GK.js → hermes-CUNKIAR5.js} +76 -3
  60. package/dist/hermes-CUNKIAR5.js.map +1 -0
  61. package/dist/{hook-YVDILAMZ.js → hook-7LUOKIXH.js} +28 -13
  62. package/dist/hook-7LUOKIXH.js.map +1 -0
  63. package/dist/index.d.ts +2 -2
  64. package/dist/index.js +3 -1
  65. package/dist/install-TQTT4F3I.js +89 -0
  66. package/dist/install-TQTT4F3I.js.map +1 -0
  67. package/dist/{jetbrains-copilot-HWA3DMH7.js → jetbrains-copilot-C3HDGGML.js} +16 -2
  68. package/dist/jetbrains-copilot-C3HDGGML.js.map +1 -0
  69. package/dist/kilo-PKAJCWPX.js +852 -0
  70. package/dist/kilo-PKAJCWPX.js.map +1 -0
  71. package/dist/{kilo-cli-EAQTHXUW.js → kilo-cli-QWUVXG2O.js} +186 -7
  72. package/dist/kilo-cli-QWUVXG2O.js.map +1 -0
  73. package/dist/{kimi-GQ7VXNYT.js → kimi-EVD7YKXS.js} +167 -9
  74. package/dist/kimi-EVD7YKXS.js.map +1 -0
  75. package/dist/{kiro-VQTT6LO2.js → kiro-UQRY6EIO.js} +98 -4
  76. package/dist/kiro-UQRY6EIO.js.map +1 -0
  77. package/dist/{leaderboard-K6ON3SWW.js → leaderboard-MUJ7DURM.js} +3 -3
  78. package/dist/{mux-T2TV4CIQ.js → mux-5CI5FP2W.js} +9 -2
  79. package/dist/mux-5CI5FP2W.js.map +1 -0
  80. package/dist/{omp-PB4VDKS6.js → omp-AXA7XY22.js} +13 -2
  81. package/dist/omp-AXA7XY22.js.map +1 -0
  82. package/dist/{openclaw-ETN2M63O.js → openclaw-UZ5BMCGQ.js} +101 -4
  83. package/dist/openclaw-UZ5BMCGQ.js.map +1 -0
  84. package/dist/{opencode-FZ33JKUZ.js → opencode-NZBRLJN3.js} +53 -7
  85. package/dist/opencode-NZBRLJN3.js.map +1 -0
  86. package/dist/package-SYPA5POO.js +130 -0
  87. package/dist/package-SYPA5POO.js.map +1 -0
  88. package/dist/{pi-CIU2QHT4.js → pi-WMTUX6ES.js} +106 -23
  89. package/dist/pi-WMTUX6ES.js.map +1 -0
  90. package/dist/{qwen-code-5POCNU6P.js → qwen-code-MRRIUQ3P.js} +187 -6
  91. package/dist/qwen-code-MRRIUQ3P.js.map +1 -0
  92. package/dist/{roo-code-IOIUXRDE.js → roo-code-NI5UU6JB.js} +26 -2
  93. package/dist/roo-code-NI5UU6JB.js.map +1 -0
  94. package/dist/runtime/index.d.ts +38 -4
  95. package/dist/runtime/index.js +11 -6
  96. package/dist/{serve-HVWWY4B6.js → serve-XJOSA7BY.js} +9 -8
  97. package/dist/{serve-HVWWY4B6.js.map → serve-XJOSA7BY.js.map} +1 -1
  98. package/dist/{status-FE7TECZD.js → status-DYSS6BOR.js} +19 -9
  99. package/dist/status-DYSS6BOR.js.map +1 -0
  100. package/dist/{telemetry-36GESKQQ.js → telemetry-IJ4GP2Q3.js} +5 -4
  101. package/dist/{telemetry-36GESKQQ.js.map → telemetry-IJ4GP2Q3.js.map} +1 -1
  102. package/dist/{trae-JSNDZFKL.js → trae-CQC72RHH.js} +9 -2
  103. package/dist/trae-CQC72RHH.js.map +1 -0
  104. package/dist/types-CNigfEuR.d.ts +757 -0
  105. package/dist/uninstall-3DXIBRCV.js +162 -0
  106. package/dist/uninstall-3DXIBRCV.js.map +1 -0
  107. package/dist/{upgrade-JV2VK242.js → upgrade-GJEB3ITY.js} +29 -10
  108. package/dist/upgrade-GJEB3ITY.js.map +1 -0
  109. package/dist/{usage-6ER6EMEY.js → usage-2BJLM3GJ.js} +3 -3
  110. package/dist/{usage-event-JKBI6XCF.js → usage-event-472X3DOY.js} +8 -7
  111. package/dist/{usage-event-JKBI6XCF.js.map → usage-event-472X3DOY.js.map} +1 -1
  112. package/dist/{vscode-copilot-CK3NO54M.js → vscode-copilot-4RVRTCKV.js} +53 -4
  113. package/dist/vscode-copilot-4RVRTCKV.js.map +1 -0
  114. package/dist/{warp-QNVDXOG4.js → warp-X6MB67NT.js} +110 -4
  115. package/dist/warp-X6MB67NT.js.map +1 -0
  116. package/dist/{zed-VRJKWYUR.js → zed-NTCYW4V2.js} +120 -5
  117. package/dist/zed-NTCYW4V2.js.map +1 -0
  118. package/package.json +4 -3
  119. package/dist/amp-QSFH2V7Y.js.map +0 -1
  120. package/dist/chunk-54EMKTTX.js.map +0 -1
  121. package/dist/chunk-7MSDGHJW.js +0 -316
  122. package/dist/chunk-7MSDGHJW.js.map +0 -1
  123. package/dist/chunk-KHO5WNTP.js.map +0 -1
  124. package/dist/chunk-LTT56GI3.js.map +0 -1
  125. package/dist/chunk-TIIP3RG2.js.map +0 -1
  126. package/dist/chunk-TRKWUNO4.js.map +0 -1
  127. package/dist/chunk-WCETQWWK.js.map +0 -1
  128. package/dist/chunk-WV63X7IK.js.map +0 -1
  129. package/dist/chunk-XNAM7F35.js +0 -276
  130. package/dist/chunk-XNAM7F35.js.map +0 -1
  131. package/dist/chunk-YNZU6PAV.js.map +0 -1
  132. package/dist/claude-code-HKDV7T32.js +0 -637
  133. package/dist/claude-code-HKDV7T32.js.map +0 -1
  134. package/dist/codebuff-QX57FJDN.js.map +0 -1
  135. package/dist/codex-JFQTS6LU.js.map +0 -1
  136. package/dist/copilot-cli-MTCGHZ2T.js.map +0 -1
  137. package/dist/crush-I7PK3FGI.js.map +0 -1
  138. package/dist/cursor-4TMXKJOZ.js.map +0 -1
  139. package/dist/detect-WIAGVYS4.js.map +0 -1
  140. package/dist/doctor-EZW2K4NI.js.map +0 -1
  141. package/dist/droid-KN6VRMMT.js.map +0 -1
  142. package/dist/gemini-cli-Y35FFK4M.js.map +0 -1
  143. package/dist/goose-ZTGTSUFJ.js.map +0 -1
  144. package/dist/hermes-H2KV44GK.js.map +0 -1
  145. package/dist/hook-YVDILAMZ.js.map +0 -1
  146. package/dist/install-HQRYZOQ2.js +0 -60
  147. package/dist/install-HQRYZOQ2.js.map +0 -1
  148. package/dist/jetbrains-copilot-HWA3DMH7.js.map +0 -1
  149. package/dist/kilo-QXJRCSLT.js +0 -384
  150. package/dist/kilo-QXJRCSLT.js.map +0 -1
  151. package/dist/kilo-cli-EAQTHXUW.js.map +0 -1
  152. package/dist/kimi-GQ7VXNYT.js.map +0 -1
  153. package/dist/kiro-VQTT6LO2.js.map +0 -1
  154. package/dist/mux-T2TV4CIQ.js.map +0 -1
  155. package/dist/omp-PB4VDKS6.js.map +0 -1
  156. package/dist/openclaw-ETN2M63O.js.map +0 -1
  157. package/dist/opencode-FZ33JKUZ.js.map +0 -1
  158. package/dist/package-DLOVE2E4.js.map +0 -1
  159. package/dist/pi-CIU2QHT4.js.map +0 -1
  160. package/dist/qwen-code-5POCNU6P.js.map +0 -1
  161. package/dist/roo-code-IOIUXRDE.js.map +0 -1
  162. package/dist/status-FE7TECZD.js.map +0 -1
  163. package/dist/trae-JSNDZFKL.js.map +0 -1
  164. package/dist/types-CYUB1OTr.d.ts +0 -427
  165. package/dist/uninstall-IGCKNOSF.js +0 -72
  166. package/dist/uninstall-IGCKNOSF.js.map +0 -1
  167. package/dist/upgrade-JV2VK242.js.map +0 -1
  168. package/dist/vscode-copilot-CK3NO54M.js.map +0 -1
  169. package/dist/warp-QNVDXOG4.js.map +0 -1
  170. package/dist/zed-VRJKWYUR.js.map +0 -1
  171. /package/dist/{antigravity-CX2YLSY7.js.map → antigravity-7IBYFO6P.js.map} +0 -0
  172. /package/dist/{chunk-XUCWLJY5.js.map → chunk-NJU275US.js.map} +0 -0
  173. /package/dist/{leaderboard-K6ON3SWW.js.map → leaderboard-MUJ7DURM.js.map} +0 -0
  174. /package/dist/{usage-6ER6EMEY.js.map → usage-2BJLM3GJ.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import { c as HookEventName, h as PlatformId } from '../types-CYUB1OTr.js';
1
+ import { c as HookEventName, k as PlatformId } from '../types-CNigfEuR.js';
2
2
 
3
3
  /**
4
4
  * runtime/hook-entrypoint — the universal json-stdio hook dispatcher.
@@ -16,8 +16,9 @@ import { c as HookEventName, h as PlatformId } from '../types-CYUB1OTr.js';
16
16
  *
17
17
  * Fail-open is the safety contract: ANY error degrades to exit 0 ("allow") so a
18
18
  * framework or handler bug can never wedge a host's tool call — EXCEPT when the
19
- * event is PreToolUse and the handler explicitly denied, in which case the deny
20
- * (a deliberate security decision) is preserved rather than swallowed.
19
+ * event is PreToolUse or PermissionRequest and the handler explicitly denied,
20
+ * in which case the deny (a deliberate security decision) is preserved rather
21
+ * than swallowed.
21
22
  */
22
23
 
23
24
  /** Flags + stdin the CLI hands to {@link runHook}. */
@@ -43,6 +44,39 @@ interface RunHookResult {
43
44
  * cleanly. See the module header for the fail-open contract.
44
45
  */
45
46
  declare function runHook(opts: RunHookOptions): Promise<RunHookResult>;
47
+ /** Flags + stdin for {@link runNativeHook}. `event` is HOST-NATIVE (non-union). */
48
+ interface RunNativeHookOptions {
49
+ /** Host platform id from the hook command (`hook <platformId> ...`). */
50
+ platformId: string;
51
+ /** Host-native event name, verbatim (e.g. "TaskCreated"). */
52
+ event: string;
53
+ /** Connector id from `--connector <id>`. */
54
+ connectorId: string;
55
+ /** Raw stdin payload (host-native JSON). Empty string is tolerated → `{}`. */
56
+ stdin: string;
57
+ }
58
+ /**
59
+ * True when the registered connector declares `event` under
60
+ * `platforms[platformId].nativeHooks` with a live handler. Used by the hook CLI
61
+ * to decide whether a non-union event name is accepted (declared → dispatch via
62
+ * {@link runNativeHook}) or rejected with the strict unknown-event error.
63
+ * Fail-safe: any load error reads as "not declared".
64
+ */
65
+ declare function isNativeHookDeclared(platformId: string, event: string, connectorId: string): Promise<boolean>;
66
+ /**
67
+ * Dispatch one NATIVE (passthrough) hook invocation. No normalized parse, no
68
+ * HookResponse mapping, no runtime matcher evaluation (the host's own matcher
69
+ * already filtered — the def's matcher string was written verbatim into the
70
+ * host config at install):
71
+ *
72
+ * stdin JSON → NativeHookEvent{raw} → handler → VERBATIM JSON stdout (exit 0).
73
+ *
74
+ * void/undefined return → exit 0 with no output. Fail-open: ANY throw degrades
75
+ * to exit 0 with no output — exit-2 blocking semantics are not modeled in v1.
76
+ * Telemetry: records the same scope:"hook" developer-axis row as normalized
77
+ * hooks, with the NATIVE event name as the per-item name.
78
+ */
79
+ declare function runNativeHook(opts: RunNativeHookOptions): Promise<RunHookResult>;
46
80
 
47
81
  /**
48
82
  * telemetry/types — runtime telemetry contracts.
@@ -154,4 +188,4 @@ interface RunUsageEventResult {
154
188
  */
155
189
  declare function runUsageEvent(opts: RunUsageEventOptions): Promise<RunUsageEventResult>;
156
190
 
157
- export { type RunHookOptions, type RunHookResult, type RunServeOptions, type RunUsageEventOptions, type RunUsageEventResult, runHook, runServe, runUsageEvent };
191
+ export { type RunHookOptions, type RunHookResult, type RunNativeHookOptions, type RunServeOptions, type RunUsageEventOptions, type RunUsageEventResult, isNativeHookDeclared, runHook, runNativeHook, runServe, runUsageEvent };
@@ -1,19 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ isNativeHookDeclared,
3
4
  runHook,
5
+ runNativeHook,
4
6
  runServe,
5
7
  runUsageEvent
6
- } from "../chunk-YNZU6PAV.js";
8
+ } from "../chunk-ZAM4M7LI.js";
7
9
  import "../chunk-BCHWFTV4.js";
8
- import "../chunk-KHO5WNTP.js";
9
- import "../chunk-WCETQWWK.js";
10
- import "../chunk-XUCWLJY5.js";
11
- import "../chunk-LTT56GI3.js";
12
- import "../chunk-XNAM7F35.js";
10
+ import "../chunk-OP4KBXUO.js";
11
+ import "../chunk-KVAAFYRR.js";
12
+ import "../chunk-NJU275US.js";
13
+ import "../chunk-3JCRUROU.js";
14
+ import "../chunk-GSGDG2BV.js";
13
15
  import "../chunk-MEH7GC7R.js";
16
+ import "../chunk-N6HH7K6P.js";
14
17
  import "../chunk-TRQKHP7D.js";
15
18
  export {
19
+ isNativeHookDeclared,
16
20
  runHook,
21
+ runNativeHook,
17
22
  runServe,
18
23
  runUsageEvent
19
24
  };
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  fail
4
- } from "./chunk-54EMKTTX.js";
4
+ } from "./chunk-DS3LUFVN.js";
5
5
  import {
6
6
  runServe
7
- } from "./chunk-YNZU6PAV.js";
7
+ } from "./chunk-ZAM4M7LI.js";
8
8
  import "./chunk-BCHWFTV4.js";
9
- import "./chunk-KHO5WNTP.js";
10
- import "./chunk-WCETQWWK.js";
11
- import "./chunk-XUCWLJY5.js";
12
- import "./chunk-LTT56GI3.js";
13
- import "./chunk-XNAM7F35.js";
9
+ import "./chunk-OP4KBXUO.js";
10
+ import "./chunk-KVAAFYRR.js";
11
+ import "./chunk-NJU275US.js";
12
+ import "./chunk-3JCRUROU.js";
13
+ import "./chunk-GSGDG2BV.js";
14
14
  import "./chunk-MEH7GC7R.js";
15
+ import "./chunk-N6HH7K6P.js";
15
16
  import "./chunk-TRQKHP7D.js";
16
17
 
17
18
  // src/cli/commands/serve.ts
@@ -62,4 +63,4 @@ async function run(argv) {
62
63
  export {
63
64
  run
64
65
  };
65
- //# sourceMappingURL=serve-HVWWY4B6.js.map
66
+ //# sourceMappingURL=serve-XJOSA7BY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/commands/serve.ts"],"sourcesContent":["/**\n * cli/commands/serve — the telemetry-wrapping MCP stdio proxy entrypoint.\n *\n * agent-connector serve --connector <id> [--scope <user|project>] [--host <platformId>] -- <realCommand> <realArgs...>\n *\n * A stdio MCP server that opts into transparent telemetry has its host config\n * rewritten to launch THIS instead of the server directly. We split argv at the\n * literal `--` separator: flags on the left, the real server command + args on\n * the right (taken verbatim). The optional `--scope` flag records the install\n * dimension (global user vs project-local) onto telemetry; it is absent for\n * configs written before scope plumbing existed → the runtime reads \"unknown\".\n * The optional `--host` flag carries the install TARGET platform id so the proxy\n * stamps hostPlatform correctly under a headless spawn; absent configs fall back\n * to runtime env detection.\n * runServe stands up the per-session telemetry context and proxies bytes both\n * ways, resolving with the child's exit code.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type { PlatformId } from \"../../core/types.js\";\nimport type { TelemetryInstallScope } from \"../../telemetry/types.js\";\nimport { runServe } from \"../../runtime/index.js\";\nimport { fail } from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n // Split at the FIRST literal \"--\": everything after it is the real server\n // invocation and must be passed through verbatim (never re-parsed as flags).\n const sepIndex = argv.indexOf(\"--\");\n if (sepIndex === -1) {\n return fail(\n \"usage: agent-connector serve --connector <id> [--scope <user|project>] [--host <platformId>] -- <command> [args...]\",\n );\n }\n const flagArgs = argv.slice(0, sepIndex);\n const serverInvocation = argv.slice(sepIndex + 1);\n\n // strict:false so an unknown FUTURE flag before `--` (written by a newer host\n // config) is ignored instead of throwing — a parse throw here would prevent the\n // real MCP server from ever spawning and wedge the host's tool call. We only\n // read the two flags we understand; everything else is tolerated.\n const { values } = parseArgs({\n args: flagArgs,\n options: {\n connector: { type: \"string\" },\n scope: { type: \"string\" },\n // `--host <platformId>` bakes the install TARGET platform into the wrapper\n // so the proxy stamps hostPlatform correctly under a headless spawn (where\n // runtime env markers are absent). Optional + tolerated (strict:false).\n host: { type: \"string\" },\n },\n allowPositionals: true,\n strict: false,\n });\n\n // With strict:false, parseArgs types each value as string | boolean; we only\n // accept the string form (a bare `--connector` flag with no value is invalid).\n const connectorId = typeof values.connector === \"string\" ? values.connector : undefined;\n if (!connectorId || connectorId.trim() === \"\") {\n return fail(\"serve requires --connector <id>\");\n }\n\n // `--scope` is optional and only ever \"user\" | \"project\" (the wrapper emits\n // exactly those). An unrecognized value is ignored rather than fatal so a\n // future/older wrapper can never break a real tool call over a flag mismatch.\n const rawScope = values.scope;\n const installScope: TelemetryInstallScope | undefined =\n rawScope === \"user\" || rawScope === \"project\" ? rawScope : undefined;\n\n // `--host` carries the install TARGET platform id (string only). runServe\n // validates it against the registry and falls back to runtime detection when\n // it is absent or unrecognized — so a future/older wrapper never breaks here.\n const hostPlatformOverride =\n typeof values.host === \"string\" ? (values.host as PlatformId) : undefined;\n\n const serverCommand = serverInvocation[0];\n if (!serverCommand) {\n return fail(\"serve requires a command after `--`\");\n }\n const serverArgs = serverInvocation.slice(1);\n\n const code = await runServe({\n connectorId,\n serverCommand,\n serverArgs,\n installScope,\n hostPlatformOverride,\n });\n process.exit(code);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,SAAS,iBAAiB;AAO1B,eAAsB,IAAI,MAAiC;AAGzD,QAAM,WAAW,KAAK,QAAQ,IAAI;AAClC,MAAI,aAAa,IAAI;AACnB,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,KAAK,MAAM,GAAG,QAAQ;AACvC,QAAM,mBAAmB,KAAK,MAAM,WAAW,CAAC;AAMhD,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,MACP,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,OAAO,EAAE,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA,MAIxB,MAAM,EAAE,MAAM,SAAS;AAAA,IACzB;AAAA,IACA,kBAAkB;AAAA,IAClB,QAAQ;AAAA,EACV,CAAC;AAID,QAAM,cAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAC9E,MAAI,CAAC,eAAe,YAAY,KAAK,MAAM,IAAI;AAC7C,WAAO,KAAK,iCAAiC;AAAA,EAC/C;AAKA,QAAM,WAAW,OAAO;AACxB,QAAM,eACJ,aAAa,UAAU,aAAa,YAAY,WAAW;AAK7D,QAAM,uBACJ,OAAO,OAAO,SAAS,WAAY,OAAO,OAAsB;AAElE,QAAM,gBAAgB,iBAAiB,CAAC;AACxC,MAAI,CAAC,eAAe;AAClB,WAAO,KAAK,qCAAqC;AAAA,EACnD;AACA,QAAM,aAAa,iBAAiB,MAAM,CAAC;AAE3C,QAAM,OAAO,MAAM,SAAS;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,UAAQ,KAAK,IAAI;AACnB;","names":[]}
1
+ {"version":3,"sources":["../src/cli/commands/serve.ts"],"sourcesContent":["/**\n * cli/commands/serve — the telemetry-wrapping MCP stdio proxy entrypoint.\n *\n * agent-connector serve --connector <id> [--scope <user|project>] [--host <platformId>] -- <realCommand> <realArgs...>\n *\n * A stdio MCP server that opts into transparent telemetry has its host config\n * rewritten to launch THIS instead of the server directly. We split argv at the\n * literal `--` separator: flags on the left, the real server command + args on\n * the right (taken verbatim). The optional `--scope` flag records the install\n * dimension (global user vs project-local) onto telemetry; it is absent for\n * configs written before scope plumbing existed → the runtime reads \"unknown\".\n * The optional `--host` flag carries the install TARGET platform id so the proxy\n * stamps hostPlatform correctly under a headless spawn; absent configs fall back\n * to runtime env detection.\n * runServe stands up the per-session telemetry context and proxies bytes both\n * ways, resolving with the child's exit code.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport type { PlatformId } from \"../../core/types.js\";\nimport type { TelemetryInstallScope } from \"../../telemetry/types.js\";\nimport { runServe } from \"../../runtime/index.js\";\nimport { fail } from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n // Split at the FIRST literal \"--\": everything after it is the real server\n // invocation and must be passed through verbatim (never re-parsed as flags).\n const sepIndex = argv.indexOf(\"--\");\n if (sepIndex === -1) {\n return fail(\n \"usage: agent-connector serve --connector <id> [--scope <user|project>] [--host <platformId>] -- <command> [args...]\",\n );\n }\n const flagArgs = argv.slice(0, sepIndex);\n const serverInvocation = argv.slice(sepIndex + 1);\n\n // strict:false so an unknown FUTURE flag before `--` (written by a newer host\n // config) is ignored instead of throwing — a parse throw here would prevent the\n // real MCP server from ever spawning and wedge the host's tool call. We only\n // read the two flags we understand; everything else is tolerated.\n const { values } = parseArgs({\n args: flagArgs,\n options: {\n connector: { type: \"string\" },\n scope: { type: \"string\" },\n // `--host <platformId>` bakes the install TARGET platform into the wrapper\n // so the proxy stamps hostPlatform correctly under a headless spawn (where\n // runtime env markers are absent). Optional + tolerated (strict:false).\n host: { type: \"string\" },\n },\n allowPositionals: true,\n strict: false,\n });\n\n // With strict:false, parseArgs types each value as string | boolean; we only\n // accept the string form (a bare `--connector` flag with no value is invalid).\n const connectorId = typeof values.connector === \"string\" ? values.connector : undefined;\n if (!connectorId || connectorId.trim() === \"\") {\n return fail(\"serve requires --connector <id>\");\n }\n\n // `--scope` is optional and only ever \"user\" | \"project\" (the wrapper emits\n // exactly those). An unrecognized value is ignored rather than fatal so a\n // future/older wrapper can never break a real tool call over a flag mismatch.\n const rawScope = values.scope;\n const installScope: TelemetryInstallScope | undefined =\n rawScope === \"user\" || rawScope === \"project\" ? rawScope : undefined;\n\n // `--host` carries the install TARGET platform id (string only). runServe\n // validates it against the registry and falls back to runtime detection when\n // it is absent or unrecognized — so a future/older wrapper never breaks here.\n const hostPlatformOverride =\n typeof values.host === \"string\" ? (values.host as PlatformId) : undefined;\n\n const serverCommand = serverInvocation[0];\n if (!serverCommand) {\n return fail(\"serve requires a command after `--`\");\n }\n const serverArgs = serverInvocation.slice(1);\n\n const code = await runServe({\n connectorId,\n serverCommand,\n serverArgs,\n installScope,\n hostPlatformOverride,\n });\n process.exit(code);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAS,iBAAiB;AAO1B,eAAsB,IAAI,MAAiC;AAGzD,QAAM,WAAW,KAAK,QAAQ,IAAI;AAClC,MAAI,aAAa,IAAI;AACnB,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,KAAK,MAAM,GAAG,QAAQ;AACvC,QAAM,mBAAmB,KAAK,MAAM,WAAW,CAAC;AAMhD,QAAM,EAAE,OAAO,IAAI,UAAU;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS;AAAA,MACP,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,OAAO,EAAE,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA,MAIxB,MAAM,EAAE,MAAM,SAAS;AAAA,IACzB;AAAA,IACA,kBAAkB;AAAA,IAClB,QAAQ;AAAA,EACV,CAAC;AAID,QAAM,cAAc,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAC9E,MAAI,CAAC,eAAe,YAAY,KAAK,MAAM,IAAI;AAC7C,WAAO,KAAK,iCAAiC;AAAA,EAC/C;AAKA,QAAM,WAAW,OAAO;AACxB,QAAM,eACJ,aAAa,UAAU,aAAa,YAAY,WAAW;AAK7D,QAAM,uBACJ,OAAO,OAAO,SAAS,WAAY,OAAO,OAAsB;AAElE,QAAM,gBAAgB,iBAAiB,CAAC;AACxC,MAAI,CAAC,eAAe;AAClB,WAAO,KAAK,qCAAqC;AAAA,EACnD;AACA,QAAM,aAAa,iBAAiB,MAAM,CAAC;AAE3C,QAAM,OAAO,MAAM,SAAS;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,UAAQ,KAAK,IAAI;AACnB;","names":[]}
@@ -1,19 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ marketplaceEvidence
4
+ } from "./chunk-44HUXXC6.js";
2
5
  import {
3
6
  fail,
4
7
  parseScope,
5
8
  print
6
- } from "./chunk-54EMKTTX.js";
9
+ } from "./chunk-DS3LUFVN.js";
7
10
  import {
8
11
  detectInstalledPlatforms,
9
12
  loadAdapter
10
- } from "./chunk-XUCWLJY5.js";
13
+ } from "./chunk-NJU275US.js";
11
14
  import {
12
15
  findConnectorConfig,
13
16
  listRegisteredConnectors,
14
17
  loadConnectorFromPath
15
- } from "./chunk-LTT56GI3.js";
16
- import "./chunk-XNAM7F35.js";
18
+ } from "./chunk-3JCRUROU.js";
19
+ import "./chunk-GSGDG2BV.js";
20
+ import "./chunk-N6HH7K6P.js";
17
21
  import {
18
22
  dataRoot,
19
23
  homeBinPath
@@ -82,10 +86,15 @@ async function run(argv) {
82
86
  hookPath = adapter.getHookConfigPath(ctx);
83
87
  } catch {
84
88
  }
89
+ const serverPresent = serverPath ? fileMentions(serverPath, connector.id) : false;
90
+ const hooksPresent = hookPath ? fileMentions(hookPath, connector.id) : false;
91
+ const direct = serverPresent || hooksPresent;
92
+ const viaMarketplace = marketplaceEvidence(connector.id, p.id) != null;
85
93
  return {
86
94
  id: connector.id,
87
- serverPresent: serverPath ? fileMentions(serverPath, connector.id) : false,
88
- hooksPresent: hookPath ? fileMentions(hookPath, connector.id) : false
95
+ serverPresent,
96
+ hooksPresent,
97
+ method: direct && viaMarketplace ? "both" : direct ? "direct" : viaMarketplace ? "marketplace" : null
89
98
  };
90
99
  });
91
100
  rows.push({
@@ -112,10 +121,11 @@ async function run(argv) {
112
121
  print(" (no connectors to check)");
113
122
  } else {
114
123
  for (const c of r.connectors) {
115
- const mark = c.serverPresent || c.hooksPresent ? "[installed]" : "[absent ]";
124
+ const mark = c.method != null ? "[installed]" : "[absent ]";
116
125
  const server = c.serverPresent ? "server \u2713" : "server \xB7";
117
126
  const hooks = c.hooksPresent ? "hooks \u2713" : "hooks \xB7";
118
- print(` ${mark} ${c.id} ${server} ${hooks}`);
127
+ const method = c.method == null ? "" : c.method === "both" ? " (both!)" : ` (${c.method})`;
128
+ print(` ${mark} ${c.id} ${server} ${hooks}${method}`);
119
129
  }
120
130
  }
121
131
  print("");
@@ -125,4 +135,4 @@ async function run(argv) {
125
135
  export {
126
136
  run
127
137
  };
128
- //# sourceMappingURL=status-FE7TECZD.js.map
138
+ //# sourceMappingURL=status-DYSS6BOR.js.map
@@ -0,0 +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":[]}
@@ -12,7 +12,7 @@ import {
12
12
  import {
13
13
  fail,
14
14
  print
15
- } from "./chunk-54EMKTTX.js";
15
+ } from "./chunk-DS3LUFVN.js";
16
16
  import {
17
17
  openStore
18
18
  } from "./chunk-BCHWFTV4.js";
@@ -21,8 +21,9 @@ import {
21
21
  listRegisteredConnectors,
22
22
  loadRegisteredConnector,
23
23
  readRegisteredMeta
24
- } from "./chunk-LTT56GI3.js";
25
- import "./chunk-XNAM7F35.js";
24
+ } from "./chunk-3JCRUROU.js";
25
+ import "./chunk-GSGDG2BV.js";
26
+ import "./chunk-N6HH7K6P.js";
26
27
  import "./chunk-TRQKHP7D.js";
27
28
 
28
29
  // src/cli/commands/telemetry.ts
@@ -346,4 +347,4 @@ export {
346
347
  parseSince,
347
348
  run
348
349
  };
349
- //# sourceMappingURL=telemetry-36GESKQQ.js.map
350
+ //# sourceMappingURL=telemetry-IJ4GP2Q3.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,14 @@ import {
4
4
  } from "./chunk-DBQMX75U.js";
5
5
  import {
6
6
  BaseAdapter
7
- } from "./chunk-TIIP3RG2.js";
7
+ } from "./chunk-PD4VFEBY.js";
8
8
  import "./chunk-7L6ITC4T.js";
9
9
  import {
10
10
  buildServeWrapperCommand,
11
11
  isHomeBinHookCommand,
12
12
  shouldWrapForTelemetry
13
13
  } from "./chunk-MEH7GC7R.js";
14
+ import "./chunk-N6HH7K6P.js";
14
15
  import "./chunk-TRQKHP7D.js";
15
16
 
16
17
  // src/adapters/trae/index.ts
@@ -24,6 +25,9 @@ var TraeAdapter = class extends BaseAdapter {
24
25
  name = "Trae";
25
26
  paradigm = "mcp-only";
26
27
  capabilities = {
28
+ // Memory surface: AGENTS.md-first managed block via the BaseAdapter default
29
+ // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).
30
+ supportsMemory: true,
27
31
  // Trae has no lifecycle hook system we can target — every hook capability
28
32
  // is false.
29
33
  preToolUse: false,
@@ -180,6 +184,9 @@ var TraeAdapter = class extends BaseAdapter {
180
184
  {
181
185
  name: `${this.name}: server entry registered`,
182
186
  check: () => {
187
+ if (!ctx.connector.server) {
188
+ return { status: "OK", detail: "no MCP server declared" };
189
+ }
183
190
  const cfg = this.readJson(mcpPath);
184
191
  const bucket = cfg?.[MCP_ROOT_KEY];
185
192
  if (!cfg || !bucket) {
@@ -201,4 +208,4 @@ export {
201
208
  adapter,
202
209
  trae_default as default
203
210
  };
204
- //# sourceMappingURL=trae-JSNDZFKL.js.map
211
+ //# sourceMappingURL=trae-CQC72RHH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/trae/index.ts"],"sourcesContent":["/**\n * adapters/trae — Trae (ByteDance) platform adapter for agent-connector.\n *\n * Trae is an **mcp-only** host for our purposes: it exposes MCP servers as its\n * extensibility mechanism but has no lifecycle hook system we can register\n * against. This adapter therefore installs only the MCP server and reports hooks\n * as unavailable, mirroring the Warp reference path that validates the\n * `mcp-only` paradigm end-to-end.\n *\n * MCP config (medium-confidence path — still implemented; doctor reports presence):\n * - user scope → ~/.trae/mcp.json\n * - project scope → <projectDir>/.trae/mcp.json\n * Both are JSON, root key \"mcpServers\", and are the SAME file used for the\n * (non-existent) hook registration — there is no separate hook file here.\n *\n * A stdio server entry uses the standard Claude/Cursor shape:\n * { command, args, env } (object-keyed by connector id).\n *\n * Trae documents no native `${env:VAR}` interpolation token, so env/header/url\n * refs are resolved to literals at install time (the no-native-token path).\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, InstallContext } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n ServerDef,\n Transport,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"trae\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/** Native MCP server entry shapes Trae accepts under `mcpServers`. */\ninterface TraeStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\ninterface TraeHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\nexport class TraeAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Trae\";\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\n supportsMemory: true,\n // Trae has no lifecycle hook system we can target — every hook capability\n // is false.\n preToolUse: false,\n postToolUse: false,\n preCompact: false,\n sessionStart: false,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: false,\n // Trae registers stdio, SSE, and Streamable HTTP MCP servers.\n transports: [\"stdio\", \"sse\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".trae\");\n const userMcp = join(userDir, \"mcp.json\");\n const projDir = join(projectDir, \".trae\");\n const projMcp = join(projDir, \"mcp.json\");\n\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projMcp : userMcp;\n\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? `found Trae config (${scope})`\n : `no Trae config at ${userDir} or ${projDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".trae\")\n : join(homedir(), \".trae\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n /**\n * Trae has no hook file — hooks are not a thing here. The hook \"config path\"\n * is the same mcp.json so the generic doctor/backup behave sensibly.\n */\n getHookConfigPath(ctx: InstallContext): string {\n return this.getServerConfigPath(ctx);\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for trae\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Trae's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): TraeStdioServer | TraeHttpServer {\n const transport: Transport = server.transport;\n\n if (transport === \"stdio\") {\n let command = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n // Transparent telemetry wrapping: route the real command through\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\n if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n // Trae has no documented native interpolation token, so resolve every\n // ${env:VAR} to a literal at install time.\n const entry: TraeStdioServer = { command: resolveEnvRefsDeep(command) };\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // sse / http (and any other remote transport) — Trae registers a URL.\n const entry: TraeHttpServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Trae documents no native interpolation token, so\n * resolve `${env:VAR}` references to literals at install time.\n */\n private renderEnv(\n env: Record<string, string> | undefined,\n ): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n return resolveEnvRefsDeep({ ...env });\n }\n\n // ── Hooks (unavailable — Trae is mcp-only) ───────────────────────────────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Trae is mcp-only)\",\n },\n ];\n }\n\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Trae is mcp-only)\",\n },\n ];\n }\n\n /**\n * True when a hook command references our home binary AND this connector id\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand).\n * Trae installs no hooks, but this guard keeps any future shared-file edit\n * from removing another connector's entries.\n */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const connectorId = ctx.connector.id;\n return [\n {\n name: `${this.name}: mcp.json present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: server entry registered`,\n check: () => {\n // Only assert what the connector declares: a server-less connector —\n // e.g. a catalog-only bundle of agents/skills/commands — never writes\n // an mcpServers entry, so its absence is healthy.\n if (!ctx.connector.server) {\n return { status: \"OK\", detail: \"no MCP server declared\" };\n }\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\n }\n return connectorId in bucket\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\n : {\n status: \"FAIL\",\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\n };\n },\n },\n ];\n }\n}\n\nexport const adapter = new TraeAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}