@ken-jo/agent-connector 0.1.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 (203) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +6 -0
  3. package/README.md +348 -0
  4. package/dist/amp-QSFH2V7Y.js +217 -0
  5. package/dist/amp-QSFH2V7Y.js.map +1 -0
  6. package/dist/amp-TULUPXXL.js +237 -0
  7. package/dist/amp-TULUPXXL.js.map +1 -0
  8. package/dist/antigravity-CX2YLSY7.js +17 -0
  9. package/dist/antigravity-CX2YLSY7.js.map +1 -0
  10. package/dist/antigravity-STHZWMP3.js +171 -0
  11. package/dist/antigravity-STHZWMP3.js.map +1 -0
  12. package/dist/antigravity-cli-P6HADOAO.js +121 -0
  13. package/dist/antigravity-cli-P6HADOAO.js.map +1 -0
  14. package/dist/antigravity-cli-YQDFVV4U.js +86 -0
  15. package/dist/antigravity-cli-YQDFVV4U.js.map +1 -0
  16. package/dist/chunk-54EMKTTX.js +191 -0
  17. package/dist/chunk-54EMKTTX.js.map +1 -0
  18. package/dist/chunk-7L6ITC4T.js +54 -0
  19. package/dist/chunk-7L6ITC4T.js.map +1 -0
  20. package/dist/chunk-7MSDGHJW.js +316 -0
  21. package/dist/chunk-7MSDGHJW.js.map +1 -0
  22. package/dist/chunk-BCHWFTV4.js +196 -0
  23. package/dist/chunk-BCHWFTV4.js.map +1 -0
  24. package/dist/chunk-DBQMX75U.js +36 -0
  25. package/dist/chunk-DBQMX75U.js.map +1 -0
  26. package/dist/chunk-EXLS7BSI.js +29 -0
  27. package/dist/chunk-EXLS7BSI.js.map +1 -0
  28. package/dist/chunk-JNM3TPLX.js +593 -0
  29. package/dist/chunk-JNM3TPLX.js.map +1 -0
  30. package/dist/chunk-JWNT5KW7.js +197 -0
  31. package/dist/chunk-JWNT5KW7.js.map +1 -0
  32. package/dist/chunk-KHO5WNTP.js +30 -0
  33. package/dist/chunk-KHO5WNTP.js.map +1 -0
  34. package/dist/chunk-LTT56GI3.js +155 -0
  35. package/dist/chunk-LTT56GI3.js.map +1 -0
  36. package/dist/chunk-MEH7GC7R.js +111 -0
  37. package/dist/chunk-MEH7GC7R.js.map +1 -0
  38. package/dist/chunk-MQPNU2CY.js +64 -0
  39. package/dist/chunk-MQPNU2CY.js.map +1 -0
  40. package/dist/chunk-OPXAP3AC.js +12 -0
  41. package/dist/chunk-OPXAP3AC.js.map +1 -0
  42. package/dist/chunk-RK6VBLXP.js +50 -0
  43. package/dist/chunk-RK6VBLXP.js.map +1 -0
  44. package/dist/chunk-TIIP3RG2.js +420 -0
  45. package/dist/chunk-TIIP3RG2.js.map +1 -0
  46. package/dist/chunk-TRKWUNO4.js +702 -0
  47. package/dist/chunk-TRKWUNO4.js.map +1 -0
  48. package/dist/chunk-TRQKHP7D.js +93 -0
  49. package/dist/chunk-TRQKHP7D.js.map +1 -0
  50. package/dist/chunk-WCETQWWK.js +59 -0
  51. package/dist/chunk-WCETQWWK.js.map +1 -0
  52. package/dist/chunk-WV63X7IK.js +357 -0
  53. package/dist/chunk-WV63X7IK.js.map +1 -0
  54. package/dist/chunk-XD7MY6HB.js +343 -0
  55. package/dist/chunk-XD7MY6HB.js.map +1 -0
  56. package/dist/chunk-XNAM7F35.js +276 -0
  57. package/dist/chunk-XNAM7F35.js.map +1 -0
  58. package/dist/chunk-XUCWLJY5.js +238 -0
  59. package/dist/chunk-XUCWLJY5.js.map +1 -0
  60. package/dist/chunk-YNZU6PAV.js +800 -0
  61. package/dist/chunk-YNZU6PAV.js.map +1 -0
  62. package/dist/chunk-YT43MUSJ.js +146 -0
  63. package/dist/chunk-YT43MUSJ.js.map +1 -0
  64. package/dist/claude-code-HKDV7T32.js +637 -0
  65. package/dist/claude-code-HKDV7T32.js.map +1 -0
  66. package/dist/claude-code-W74MNTAC.js +652 -0
  67. package/dist/claude-code-W74MNTAC.js.map +1 -0
  68. package/dist/cli/sdk.d.ts +54 -0
  69. package/dist/cli/sdk.js +82 -0
  70. package/dist/cli/sdk.js.map +1 -0
  71. package/dist/cli.d.ts +2 -0
  72. package/dist/cli.js +15 -0
  73. package/dist/cli.js.map +1 -0
  74. package/dist/codebuff-3PMZJJHP.js +307 -0
  75. package/dist/codebuff-3PMZJJHP.js.map +1 -0
  76. package/dist/codebuff-QX57FJDN.js +220 -0
  77. package/dist/codebuff-QX57FJDN.js.map +1 -0
  78. package/dist/codex-JFQTS6LU.js +593 -0
  79. package/dist/codex-JFQTS6LU.js.map +1 -0
  80. package/dist/codex-Q3ATRRX3.js +364 -0
  81. package/dist/codex-Q3ATRRX3.js.map +1 -0
  82. package/dist/copilot-cli-MTCGHZ2T.js +622 -0
  83. package/dist/copilot-cli-MTCGHZ2T.js.map +1 -0
  84. package/dist/copilot-cli-SJGIXVSD.js +369 -0
  85. package/dist/copilot-cli-SJGIXVSD.js.map +1 -0
  86. package/dist/crush-I7PK3FGI.js +360 -0
  87. package/dist/crush-I7PK3FGI.js.map +1 -0
  88. package/dist/crush-LN5QFFR2.js +183 -0
  89. package/dist/crush-LN5QFFR2.js.map +1 -0
  90. package/dist/cursor-4TMXKJOZ.js +603 -0
  91. package/dist/cursor-4TMXKJOZ.js.map +1 -0
  92. package/dist/cursor-QZ6MTO74.js +194 -0
  93. package/dist/cursor-QZ6MTO74.js.map +1 -0
  94. package/dist/detect-WIAGVYS4.js +68 -0
  95. package/dist/detect-WIAGVYS4.js.map +1 -0
  96. package/dist/doctor-EZW2K4NI.js +372 -0
  97. package/dist/doctor-EZW2K4NI.js.map +1 -0
  98. package/dist/droid-KN6VRMMT.js +424 -0
  99. package/dist/droid-KN6VRMMT.js.map +1 -0
  100. package/dist/droid-W5WF5XEX.js +224 -0
  101. package/dist/droid-W5WF5XEX.js.map +1 -0
  102. package/dist/gemini-cli-CIRW37TU.js +369 -0
  103. package/dist/gemini-cli-CIRW37TU.js.map +1 -0
  104. package/dist/gemini-cli-Y35FFK4M.js +705 -0
  105. package/dist/gemini-cli-Y35FFK4M.js.map +1 -0
  106. package/dist/goose-A3M5GODH.js +212 -0
  107. package/dist/goose-A3M5GODH.js.map +1 -0
  108. package/dist/goose-ZTGTSUFJ.js +480 -0
  109. package/dist/goose-ZTGTSUFJ.js.map +1 -0
  110. package/dist/hermes-H2KV44GK.js +470 -0
  111. package/dist/hermes-H2KV44GK.js.map +1 -0
  112. package/dist/hermes-ZYLMOFLZ.js +196 -0
  113. package/dist/hermes-ZYLMOFLZ.js.map +1 -0
  114. package/dist/hook-YVDILAMZ.js +75 -0
  115. package/dist/hook-YVDILAMZ.js.map +1 -0
  116. package/dist/index.d.ts +22 -0
  117. package/dist/index.js +10 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/install-HQRYZOQ2.js +60 -0
  120. package/dist/install-HQRYZOQ2.js.map +1 -0
  121. package/dist/jetbrains-copilot-HWA3DMH7.js +633 -0
  122. package/dist/jetbrains-copilot-HWA3DMH7.js.map +1 -0
  123. package/dist/kilo-NSWAVP6P.js +235 -0
  124. package/dist/kilo-NSWAVP6P.js.map +1 -0
  125. package/dist/kilo-QXJRCSLT.js +384 -0
  126. package/dist/kilo-QXJRCSLT.js.map +1 -0
  127. package/dist/kilo-cli-EAQTHXUW.js +587 -0
  128. package/dist/kilo-cli-EAQTHXUW.js.map +1 -0
  129. package/dist/kilo-cli-EVBKUODA.js +160 -0
  130. package/dist/kilo-cli-EVBKUODA.js.map +1 -0
  131. package/dist/kimi-EI3UM3ZV.js +155 -0
  132. package/dist/kimi-EI3UM3ZV.js.map +1 -0
  133. package/dist/kimi-GQ7VXNYT.js +423 -0
  134. package/dist/kimi-GQ7VXNYT.js.map +1 -0
  135. package/dist/kiro-UCLSLBW2.js +217 -0
  136. package/dist/kiro-UCLSLBW2.js.map +1 -0
  137. package/dist/kiro-VQTT6LO2.js +451 -0
  138. package/dist/kiro-VQTT6LO2.js.map +1 -0
  139. package/dist/leaderboard-K6ON3SWW.js +137 -0
  140. package/dist/leaderboard-K6ON3SWW.js.map +1 -0
  141. package/dist/mux-T2TV4CIQ.js +211 -0
  142. package/dist/mux-T2TV4CIQ.js.map +1 -0
  143. package/dist/mux-ZMLVAXOO.js +96 -0
  144. package/dist/mux-ZMLVAXOO.js.map +1 -0
  145. package/dist/omp-PB4VDKS6.js +586 -0
  146. package/dist/omp-PB4VDKS6.js.map +1 -0
  147. package/dist/openclaw-ETN2M63O.js +751 -0
  148. package/dist/openclaw-ETN2M63O.js.map +1 -0
  149. package/dist/openclaw-IYA7ASL6.js +150 -0
  150. package/dist/openclaw-IYA7ASL6.js.map +1 -0
  151. package/dist/opencode-FZ33JKUZ.js +734 -0
  152. package/dist/opencode-FZ33JKUZ.js.map +1 -0
  153. package/dist/opencode-HWT3RSMN.js +216 -0
  154. package/dist/opencode-HWT3RSMN.js.map +1 -0
  155. package/dist/package-DLOVE2E4.js +1132 -0
  156. package/dist/package-DLOVE2E4.js.map +1 -0
  157. package/dist/pi-CIU2QHT4.js +208 -0
  158. package/dist/pi-CIU2QHT4.js.map +1 -0
  159. package/dist/pi-UFX2OYFV.js +139 -0
  160. package/dist/pi-UFX2OYFV.js.map +1 -0
  161. package/dist/qwen-code-5POCNU6P.js +573 -0
  162. package/dist/qwen-code-5POCNU6P.js.map +1 -0
  163. package/dist/qwen-code-W7NUCDEN.js +134 -0
  164. package/dist/qwen-code-W7NUCDEN.js.map +1 -0
  165. package/dist/roo-code-IOIUXRDE.js +242 -0
  166. package/dist/roo-code-IOIUXRDE.js.map +1 -0
  167. package/dist/roo-code-ZLKH4A7N.js +229 -0
  168. package/dist/roo-code-ZLKH4A7N.js.map +1 -0
  169. package/dist/runtime/index.d.ts +157 -0
  170. package/dist/runtime/index.js +20 -0
  171. package/dist/runtime/index.js.map +1 -0
  172. package/dist/serve-HVWWY4B6.js +65 -0
  173. package/dist/serve-HVWWY4B6.js.map +1 -0
  174. package/dist/status-FE7TECZD.js +128 -0
  175. package/dist/status-FE7TECZD.js.map +1 -0
  176. package/dist/synthetic-UKR6SMGS.js +178 -0
  177. package/dist/synthetic-UKR6SMGS.js.map +1 -0
  178. package/dist/telemetry-36GESKQQ.js +349 -0
  179. package/dist/telemetry-36GESKQQ.js.map +1 -0
  180. package/dist/trae-JSNDZFKL.js +204 -0
  181. package/dist/trae-JSNDZFKL.js.map +1 -0
  182. package/dist/trae-PA26DPBW.js +157 -0
  183. package/dist/trae-PA26DPBW.js.map +1 -0
  184. package/dist/types-CYUB1OTr.d.ts +427 -0
  185. package/dist/uninstall-IGCKNOSF.js +72 -0
  186. package/dist/uninstall-IGCKNOSF.js.map +1 -0
  187. package/dist/upgrade-JV2VK242.js +104 -0
  188. package/dist/upgrade-JV2VK242.js.map +1 -0
  189. package/dist/usage-6ER6EMEY.js +324 -0
  190. package/dist/usage-6ER6EMEY.js.map +1 -0
  191. package/dist/usage-event-JKBI6XCF.js +48 -0
  192. package/dist/usage-event-JKBI6XCF.js.map +1 -0
  193. package/dist/vscode-copilot-CK3NO54M.js +715 -0
  194. package/dist/vscode-copilot-CK3NO54M.js.map +1 -0
  195. package/dist/warp-JNQA7PBU.js +126 -0
  196. package/dist/warp-JNQA7PBU.js.map +1 -0
  197. package/dist/warp-QNVDXOG4.js +199 -0
  198. package/dist/warp-QNVDXOG4.js.map +1 -0
  199. package/dist/zed-NNNX5MNT.js +272 -0
  200. package/dist/zed-NNNX5MNT.js.map +1 -0
  201. package/dist/zed-VRJKWYUR.js +209 -0
  202. package/dist/zed-VRJKWYUR.js.map +1 -0
  203. package/package.json +79 -0
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readJsonFile
4
+ } from "./chunk-RK6VBLXP.js";
5
+ import {
6
+ expandHome,
7
+ walkFiles
8
+ } from "./chunk-JWNT5KW7.js";
9
+ import {
10
+ emptyTokens
11
+ } from "./chunk-XD7MY6HB.js";
12
+
13
+ // src/usage/readers/roo-code.ts
14
+ import { existsSync, readFileSync } from "fs";
15
+ import { homedir, platform as osPlatform } from "os";
16
+ import { basename, dirname, isAbsolute, join, resolve } from "path";
17
+ var PLATFORM_ID = "roo-code";
18
+ var DEFAULT_MODEL = "unknown";
19
+ var DEFAULT_PROVIDER = "unknown";
20
+ var DEFAULT_SESSION = "unknown";
21
+ var ROO_EXTENSION_ID = "rooveterinaryinc.roo-cline";
22
+ function vscodeUserDir() {
23
+ const home = homedir();
24
+ switch (osPlatform()) {
25
+ case "darwin":
26
+ return join(home, "Library", "Application Support", "Code", "User");
27
+ case "win32": {
28
+ const appData = process.env.APPDATA ?? join(home, "AppData", "Roaming");
29
+ return join(appData, "Code", "User");
30
+ }
31
+ default:
32
+ return join(home, ".config", "Code", "User");
33
+ }
34
+ }
35
+ function tasksRoot() {
36
+ const raw = process.env.AGENT_CONNECTOR_ROO_CODE_DIR;
37
+ if (raw != null && raw.trim() !== "") {
38
+ const expanded = expandHome(raw.trim());
39
+ return isAbsolute(expanded) ? expanded : resolve(expanded);
40
+ }
41
+ return join(vscodeUserDir(), "globalStorage", ROO_EXTENSION_ID, "tasks");
42
+ }
43
+ function extractI64(v) {
44
+ if (typeof v === "number") {
45
+ if (!Number.isFinite(v)) return void 0;
46
+ return Math.trunc(v);
47
+ }
48
+ if (typeof v === "string") {
49
+ const trimmed = v.trim();
50
+ if (!/^[+-]?\d+$/.test(trimmed)) return void 0;
51
+ const n = Number(trimmed);
52
+ return Number.isFinite(n) ? Math.trunc(n) : void 0;
53
+ }
54
+ return void 0;
55
+ }
56
+ function tokenField(v) {
57
+ const n = extractI64(v);
58
+ return n === void 0 ? 0 : Math.max(0, n);
59
+ }
60
+ function extractF64(v) {
61
+ if (typeof v === "number") return Number.isFinite(v) ? v : void 0;
62
+ if (typeof v === "string") {
63
+ const n = Number(v.trim());
64
+ return Number.isFinite(n) ? n : void 0;
65
+ }
66
+ return void 0;
67
+ }
68
+ function parseEntryTimestamp(v) {
69
+ let s;
70
+ if (typeof v === "string") s = v;
71
+ else if (typeof v === "number" && Number.isFinite(v)) s = String(Math.trunc(v));
72
+ else return null;
73
+ return parseTimestampStr(s);
74
+ }
75
+ function parseTimestampStr(value) {
76
+ const ms = Date.parse(value);
77
+ if (!Number.isNaN(ms)) return ms;
78
+ if (/^[+-]?\d+$/.test(value.trim())) {
79
+ const numeric = Number(value.trim());
80
+ if (!Number.isFinite(numeric) || numeric <= 0) return null;
81
+ return numeric >= 1e12 ? numeric : numeric * 1e3;
82
+ }
83
+ return null;
84
+ }
85
+ function extractSessionId(path) {
86
+ const parent = basename(dirname(path));
87
+ return parent !== "" ? parent : DEFAULT_SESSION;
88
+ }
89
+ function readTaskMetadata(uiMessagesPath) {
90
+ const historyPath = join(dirname(uiMessagesPath), "api_conversation_history.json");
91
+ let content;
92
+ try {
93
+ content = readFileSync(historyPath, "utf8");
94
+ } catch {
95
+ return { model: DEFAULT_MODEL };
96
+ }
97
+ return extractModelAndAgent(content);
98
+ }
99
+ function extractModelAndAgent(content) {
100
+ const ENV_START = "<environment_details>";
101
+ const ENV_END = "</environment_details>";
102
+ let offset = 0;
103
+ let lastModel;
104
+ let lastSlug;
105
+ let lastName;
106
+ for (; ; ) {
107
+ const startRel = content.indexOf(ENV_START, offset);
108
+ if (startRel < 0) break;
109
+ const startIdx = startRel + ENV_START.length;
110
+ const endRel = content.indexOf(ENV_END, startIdx);
111
+ if (endRel < 0) break;
112
+ const block = content.slice(startIdx, endRel);
113
+ const model = extractTagValue(block, "model");
114
+ if (model !== void 0) lastModel = model;
115
+ const slug = extractTagValue(block, "slug");
116
+ if (slug !== void 0) lastSlug = slug;
117
+ const name = extractTagValue(block, "name");
118
+ if (name !== void 0) lastName = name;
119
+ offset = endRel + ENV_END.length;
120
+ }
121
+ const agent = lastSlug ?? lastName;
122
+ const result = { model: lastModel ?? DEFAULT_MODEL };
123
+ if (agent !== void 0) result.agent = agent;
124
+ return result;
125
+ }
126
+ function extractTagValue(block, tag) {
127
+ const open = `<${tag}>`;
128
+ const close = `</${tag}>`;
129
+ const openIdx = block.indexOf(open);
130
+ if (openIdx < 0) return void 0;
131
+ const start = openIdx + open.length;
132
+ const endRel = block.indexOf(close, start);
133
+ if (endRel < 0) return void 0;
134
+ const value = block.slice(start, endRel).trim();
135
+ return value === "" ? void 0 : value;
136
+ }
137
+ function parseApiReqStartedPayload(text) {
138
+ let value;
139
+ try {
140
+ value = JSON.parse(text);
141
+ } catch {
142
+ return void 0;
143
+ }
144
+ if (typeof value !== "object" || value === null) return void 0;
145
+ const obj = value;
146
+ const cost = Math.max(0, extractF64(obj["cost"]) ?? 0);
147
+ const apiProtocolRaw = typeof obj["apiProtocol"] === "string" ? obj["apiProtocol"] : void 0;
148
+ const payload = {
149
+ cost,
150
+ tokensIn: tokenField(obj["tokensIn"]),
151
+ tokensOut: tokenField(obj["tokensOut"]),
152
+ cacheReads: tokenField(obj["cacheReads"]),
153
+ cacheWrites: tokenField(obj["cacheWrites"])
154
+ };
155
+ if (apiProtocolRaw !== void 0) payload.apiProtocol = apiProtocolRaw;
156
+ return payload;
157
+ }
158
+ function providerFromApiProtocol(apiProtocol) {
159
+ if (apiProtocol === void 0) return DEFAULT_PROVIDER;
160
+ const trimmed = apiProtocol.trim();
161
+ return trimmed === "" ? DEFAULT_PROVIDER : trimmed;
162
+ }
163
+ function parseRooCodeFile(path) {
164
+ const data = readJsonFile(path);
165
+ if (!Array.isArray(data)) return [];
166
+ const sessionId = extractSessionId(path);
167
+ const { model, agent } = readTaskMetadata(path);
168
+ const out = [];
169
+ for (const raw of data) {
170
+ if (typeof raw !== "object" || raw === null) continue;
171
+ const entry = raw;
172
+ if (entry.type !== "say" || entry.say !== "api_req_started") continue;
173
+ if (typeof entry.text !== "string") continue;
174
+ const ts = parseEntryTimestamp(entry.ts);
175
+ if (ts === null) continue;
176
+ const payload = parseApiReqStartedPayload(entry.text);
177
+ if (payload === void 0) continue;
178
+ const providerId = providerFromApiProtocol(payload.apiProtocol);
179
+ const tokens = emptyTokens();
180
+ tokens.input = payload.tokensIn;
181
+ tokens.output = payload.tokensOut;
182
+ tokens.cacheRead = payload.cacheReads;
183
+ tokens.cacheWrite = payload.cacheWrites;
184
+ const record = {
185
+ platformId: PLATFORM_ID,
186
+ modelId: model,
187
+ providerId,
188
+ sessionId,
189
+ tokens,
190
+ ts,
191
+ messageCount: 1,
192
+ confidence: "host-reported"
193
+ };
194
+ if (payload.cost > 0) record.cost = payload.cost;
195
+ if (agent !== void 0) record.agent = agent;
196
+ out.push(record);
197
+ }
198
+ return out;
199
+ }
200
+ var rooCodeReader = {
201
+ platformId: PLATFORM_ID,
202
+ kind: "local",
203
+ async read({ sinceMs }) {
204
+ const root = tasksRoot();
205
+ if (!existsSync(root)) return [];
206
+ const files = walkFiles(root, (name, abs) => {
207
+ return name === "ui_messages.json" && /[\\/]ui_messages\.json$/.test(abs);
208
+ });
209
+ const records = [];
210
+ for (const file of files) {
211
+ let rows;
212
+ try {
213
+ rows = parseRooCodeFile(file);
214
+ } catch {
215
+ continue;
216
+ }
217
+ for (const row of rows) {
218
+ if (sinceMs !== void 0 && row.ts < sinceMs) continue;
219
+ records.push(row);
220
+ }
221
+ }
222
+ return records;
223
+ }
224
+ };
225
+ var roo_code_default = rooCodeReader;
226
+ export {
227
+ roo_code_default as default
228
+ };
229
+ //# sourceMappingURL=roo-code-ZLKH4A7N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/usage/readers/roo-code.ts"],"sourcesContent":["/**\n * usage/readers/roo-code — Roo Code (VS Code extension) task-log reader.\n *\n * Faithful port of tokscale sessions/roocode.rs (parse_roo_kilo_file, source\n * \"roocode\"). Roo Code (rooveterinaryinc.roo-cline) is a Cline-fork VS Code\n * extension that persists per-task logs under its VS Code globalStorage:\n * <vscodeUserDir>/globalStorage/rooveterinaryinc.roo-cline/tasks/<taskId>/\n * ui_messages.json (the UI message stream — token source)\n * api_conversation_history.json (sibling — model/agent source)\n *\n * roo-code is NOT in paths.ts hostRoots (the framework's per-platform table\n * targets CLIs with ~/.<tool> roots, not VS Code extension globalStorage), so\n * this reader resolves the cross-OS VS Code \"User\" dir itself, mirroring the\n * roo-code platform adapter (adapters/roo-code/index.ts vscodeUserDir):\n * - macOS → ~/Library/Application Support/Code/User\n * - Windows → %APPDATA%/Code/User (else ~/AppData/Roaming/Code/User)\n * - Linux → ~/.config/Code/User\n * An AGENT_CONNECTOR_ROO_CODE_DIR override (verbatim, non-empty, ~-expanded)\n * points directly at a `tasks` parent when set, matching the env convention in\n * paths.ts hostRoots.\n *\n * Tokens (ui_messages.json): the file is a JSON ARRAY of entries; only entries\n * with type==\"say\" AND say==\"api_req_started\" carry usage. Each such entry's\n * `text` field is a JSON-in-string payload:\n * tokensIn → input\n * tokensOut → output\n * cacheReads → cacheRead\n * cacheWrites → cacheWrite\n * cost (f64) → cost\n * apiProtocol → providerId (preserved verbatim, e.g. \"bedrock/anthropic\")\n * reasoning is ALWAYS 0 (Roo Code does not report it). A malformed text payload,\n * a missing text, or an unparseable `ts` skips just that entry.\n *\n * model / agent (api_conversation_history.json): scan every\n * <environment_details>…</environment_details> block for <model>, <slug>, <name>\n * tags; the LAST <model> wins (default \"unknown\"); agent prefers <slug> then\n * <name> (optional). When the sibling file is absent/unreadable: model \"unknown\",\n * no agent — exactly the Rust read_task_metadata fallback.\n *\n * session id is the taskId — the parent directory name of ui_messages.json\n * (port of extract_session_id), defaulting to \"unknown\". provider from\n * apiProtocol (trimmed, default \"unknown\"). No project attribution (Roo Code's\n * logs carry no cwd). No dedup — one row per api_req_started event. Confidence is\n * \"host-reported\".\n *\n * Fail-open: no root → []; unreadable/malformed file, entry, or payload → skipped\n * (never throws). Read-only.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir, platform as osPlatform } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve } from \"node:path\";\n\nimport type { UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { readJsonFile } from \"../jsonl.js\";\nimport { expandHome, walkFiles } from \"../paths.js\";\n\nconst PLATFORM_ID = \"roo-code\" as const;\nconst DEFAULT_MODEL = \"unknown\";\nconst DEFAULT_PROVIDER = \"unknown\";\nconst DEFAULT_SESSION = \"unknown\";\n\n/** Roo Code extension id → its VS Code globalStorage folder. */\nconst ROO_EXTENSION_ID = \"rooveterinaryinc.roo-cline\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Storage-root resolution (mirrors adapters/roo-code vscodeUserDir + the\n// AGENT_CONNECTOR_<PLATFORM>_DIR env convention in paths.ts hostRoots)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Resolve the cross-OS VS Code per-user \"User\" dir (the globalStorage parent). */\nfunction vscodeUserDir(): string {\n const home = homedir();\n switch (osPlatform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Code\", \"User\");\n case \"win32\": {\n const appData = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n return join(appData, \"Code\", \"User\");\n }\n default:\n return join(home, \".config\", \"Code\", \"User\");\n }\n}\n\n/**\n * The `tasks` root holding per-task subdirectories. Honors an\n * AGENT_CONNECTOR_ROO_CODE_DIR override (verbatim, non-empty, ~-expanded,\n * resolved against CWD when relative), else the extension's globalStorage tasks\n * dir under the resolved VS Code user dir.\n */\nfunction tasksRoot(): string {\n const raw = process.env.AGENT_CONNECTOR_ROO_CODE_DIR;\n if (raw != null && raw.trim() !== \"\") {\n const expanded = expandHome(raw.trim());\n return isAbsolute(expanded) ? expanded : resolve(expanded);\n }\n return join(vscodeUserDir(), \"globalStorage\", ROO_EXTENSION_ID, \"tasks\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Value coercion (ports of utils.rs extract_i64 / extract_f64 / parse_timestamp_str)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Port of extract_i64: number / numeric-string → integer, else undefined. */\nfunction extractI64(v: unknown): number | undefined {\n if (typeof v === \"number\") {\n if (!Number.isFinite(v)) return undefined;\n return Math.trunc(v);\n }\n if (typeof v === \"string\") {\n const trimmed = v.trim();\n if (!/^[+-]?\\d+$/.test(trimmed)) return undefined; // Rust parses as i64 (integer-only)\n const n = Number(trimmed);\n return Number.isFinite(n) ? Math.trunc(n) : undefined;\n }\n return undefined;\n}\n\n/** A non-negative integer from a payload field (0 on absence/garbage, clamped ≥ 0). */\nfunction tokenField(v: unknown): number {\n const n = extractI64(v);\n return n === undefined ? 0 : Math.max(0, n);\n}\n\n/** Port of extract_f64: number / numeric-string → f64, else undefined. */\nfunction extractF64(v: unknown): number | undefined {\n if (typeof v === \"number\") return Number.isFinite(v) ? v : undefined;\n if (typeof v === \"string\") {\n const n = Number(v.trim());\n return Number.isFinite(n) ? n : undefined;\n }\n return undefined;\n}\n\n/**\n * Port of utils.rs parse_timestamp_str / parse_entry_timestamp: an RFC3339 string\n * → epoch ms; an integer (string or number) → ms (×1000 when below the 1e12 ms\n * threshold); rejects ≤ 0. Returns null when unusable so the entry is skipped.\n */\nfunction parseEntryTimestamp(v: unknown): number | null {\n let s: string;\n if (typeof v === \"string\") s = v;\n else if (typeof v === \"number\" && Number.isFinite(v)) s = String(Math.trunc(v));\n else return null;\n\n return parseTimestampStr(s);\n}\n\nfunction parseTimestampStr(value: string): number | null {\n const ms = Date.parse(value);\n if (!Number.isNaN(ms)) return ms; // RFC3339 / any Date-parseable form\n\n if (/^[+-]?\\d+$/.test(value.trim())) {\n const numeric = Number(value.trim());\n if (!Number.isFinite(numeric) || numeric <= 0) return null;\n return numeric >= 1_000_000_000_000 ? numeric : numeric * 1000;\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// session id (port of extract_session_id)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Session id = the parent directory (taskId) of ui_messages.json, else \"unknown\". */\nfunction extractSessionId(path: string): string {\n const parent = basename(dirname(path));\n return parent !== \"\" ? parent : DEFAULT_SESSION;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// model / agent (ports of read_task_metadata / extract_model_and_agent / extract_tag_value)\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface TaskMetadata {\n model: string;\n agent?: string;\n}\n\n/** Read the sibling api_conversation_history.json for model/agent (fail-open). */\nfunction readTaskMetadata(uiMessagesPath: string): TaskMetadata {\n const historyPath = join(dirname(uiMessagesPath), \"api_conversation_history.json\");\n let content: string;\n try {\n content = readFileSync(historyPath, \"utf8\");\n } catch {\n return { model: DEFAULT_MODEL }; // missing/unreadable → (\"unknown\", None)\n }\n return extractModelAndAgent(content);\n}\n\n/**\n * Scan every <environment_details>…</environment_details> block, extracting\n * <model>, <slug>, <name>. The LAST non-empty value of each tag wins (port of the\n * Rust last_* accumulation). model defaults to \"unknown\"; agent prefers slug then\n * name (and is omitted when neither is present).\n */\nfunction extractModelAndAgent(content: string): TaskMetadata {\n const ENV_START = \"<environment_details>\";\n const ENV_END = \"</environment_details>\";\n\n let offset = 0;\n let lastModel: string | undefined;\n let lastSlug: string | undefined;\n let lastName: string | undefined;\n\n for (;;) {\n const startRel = content.indexOf(ENV_START, offset);\n if (startRel < 0) break;\n const startIdx = startRel + ENV_START.length;\n\n const endRel = content.indexOf(ENV_END, startIdx);\n if (endRel < 0) break;\n\n const block = content.slice(startIdx, endRel);\n\n const model = extractTagValue(block, \"model\");\n if (model !== undefined) lastModel = model;\n const slug = extractTagValue(block, \"slug\");\n if (slug !== undefined) lastSlug = slug;\n const name = extractTagValue(block, \"name\");\n if (name !== undefined) lastName = name;\n\n offset = endRel + ENV_END.length;\n }\n\n const agent = lastSlug ?? lastName;\n const result: TaskMetadata = { model: lastModel ?? DEFAULT_MODEL };\n if (agent !== undefined) result.agent = agent;\n return result;\n}\n\n/** First <tag>…</tag> value in `block`, trimmed; undefined when absent or empty. */\nfunction extractTagValue(block: string, tag: string): string | undefined {\n const open = `<${tag}>`;\n const close = `</${tag}>`;\n\n const openIdx = block.indexOf(open);\n if (openIdx < 0) return undefined;\n const start = openIdx + open.length;\n const endRel = block.indexOf(close, start);\n if (endRel < 0) return undefined;\n\n const value = block.slice(start, endRel).trim();\n return value === \"\" ? undefined : value;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// api_req_started payload (port of parse_api_req_started_payload + provider_from_api_protocol)\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface ApiReqStartedPayload {\n cost: number;\n tokensIn: number;\n tokensOut: number;\n cacheReads: number;\n cacheWrites: number;\n apiProtocol?: string;\n}\n\n/** Parse the JSON-in-string `text` payload of an api_req_started entry. */\nfunction parseApiReqStartedPayload(text: string): ApiReqStartedPayload | undefined {\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch {\n return undefined;\n }\n if (typeof value !== \"object\" || value === null) return undefined;\n const obj = value as Record<string, unknown>;\n\n // cost: extract_f64(.cost).unwrap_or(0.0).max(0.0)\n const cost = Math.max(0, extractF64(obj[\"cost\"]) ?? 0);\n const apiProtocolRaw = typeof obj[\"apiProtocol\"] === \"string\" ? (obj[\"apiProtocol\"] as string) : undefined;\n\n const payload: ApiReqStartedPayload = {\n cost,\n tokensIn: tokenField(obj[\"tokensIn\"]),\n tokensOut: tokenField(obj[\"tokensOut\"]),\n cacheReads: tokenField(obj[\"cacheReads\"]),\n cacheWrites: tokenField(obj[\"cacheWrites\"]),\n };\n if (apiProtocolRaw !== undefined) payload.apiProtocol = apiProtocolRaw;\n return payload;\n}\n\n/** Provider from apiProtocol: trimmed, non-empty, else \"unknown\" (verbatim — no inference). */\nfunction providerFromApiProtocol(apiProtocol: string | undefined): string {\n if (apiProtocol === undefined) return DEFAULT_PROVIDER;\n const trimmed = apiProtocol.trim();\n return trimmed === \"\" ? DEFAULT_PROVIDER : trimmed;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// File parse (port of parse_roo_kilo_file with source \"roocode\")\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The fields we read off a ui_messages.json entry (all optional / unknown). */\ninterface UiMessageEntry {\n type?: unknown;\n say?: unknown;\n text?: unknown;\n ts?: unknown;\n}\n\n/** Parse one task's ui_messages.json into usage records. */\nfunction parseRooCodeFile(path: string): UsageRecord[] {\n const data = readJsonFile(path);\n if (!Array.isArray(data)) return []; // malformed / non-array → no rows\n\n const sessionId = extractSessionId(path);\n const { model, agent } = readTaskMetadata(path);\n\n const out: UsageRecord[] = [];\n for (const raw of data) {\n if (typeof raw !== \"object\" || raw === null) continue;\n const entry = raw as UiMessageEntry;\n\n if (entry.type !== \"say\" || entry.say !== \"api_req_started\") continue;\n\n if (typeof entry.text !== \"string\") continue; // None => skip\n const ts = parseEntryTimestamp(entry.ts);\n if (ts === null) continue; // unparseable ts => skip\n\n const payload = parseApiReqStartedPayload(entry.text);\n if (payload === undefined) continue; // malformed payload => skip\n\n const providerId = providerFromApiProtocol(payload.apiProtocol);\n\n const tokens = emptyTokens();\n tokens.input = payload.tokensIn;\n tokens.output = payload.tokensOut;\n tokens.cacheRead = payload.cacheReads;\n tokens.cacheWrite = payload.cacheWrites;\n // reasoning stays 0 (Roo Code does not report it).\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId: model,\n providerId,\n sessionId,\n tokens,\n ts,\n messageCount: 1,\n confidence: \"host-reported\",\n };\n if (payload.cost > 0) record.cost = payload.cost;\n if (agent !== undefined) record.agent = agent;\n out.push(record);\n }\n\n return out;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Reader singleton\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The Roo Code (VS Code extension) usage reader singleton. */\nconst rooCodeReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"local\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n const root = tasksRoot();\n if (!existsSync(root)) return []; // no tasks dir → fail-open\n\n // <root>/<taskId>/ui_messages.json\n const files = walkFiles(root, (name, abs) => {\n return name === \"ui_messages.json\" && /[\\\\/]ui_messages\\.json$/.test(abs);\n });\n\n const records: UsageRecord[] = [];\n for (const file of files) {\n let rows: UsageRecord[];\n try {\n rows = parseRooCodeFile(file);\n } catch {\n continue; // fail-open per file\n }\n for (const row of rows) {\n if (sinceMs !== undefined && row.ts < sinceMs) continue;\n records.push(row);\n }\n }\n return records;\n },\n};\n\nexport default rooCodeReader;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,157 @@
1
+ import { c as HookEventName, h as PlatformId } from '../types-CYUB1OTr.js';
2
+
3
+ /**
4
+ * runtime/hook-entrypoint — the universal json-stdio hook dispatcher.
5
+ *
6
+ * Every json-stdio host points its hook config at the single stable home binary
7
+ * (`<homeBin> hook <platformId> <event> --connector <id>`, built by
8
+ * core/spawn.buildHomeBinHookCommand). The CLI reads stdin and calls
9
+ * {@link runHook} with the parsed flags + the raw stdin string. This module:
10
+ *
11
+ * 1. Loads the registered connector (live handlers) and the host adapter.
12
+ * 2. Parses the host's stdin payload into a normalized event via the adapter.
13
+ * 3. Finds the connector's handler for the event, honoring the tool matcher.
14
+ * 4. Runs the handler, normalizes its return, and formats the adapter's native
15
+ * reply.
16
+ *
17
+ * Fail-open is the safety contract: ANY error degrades to exit 0 ("allow") so a
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.
21
+ */
22
+
23
+ /** Flags + stdin the CLI hands to {@link runHook}. */
24
+ interface RunHookOptions {
25
+ /** Host platform id from the hook command (`hook <platformId> ...`). */
26
+ platformId: string;
27
+ /** Canonical lifecycle event name from the hook command. */
28
+ event: HookEventName;
29
+ /** Connector id from `--connector <id>`. */
30
+ connectorId: string;
31
+ /** Raw stdin payload (host-native JSON). Empty string is tolerated → `{}`. */
32
+ stdin: string;
33
+ }
34
+ /** Process-level result the CLI translates into exit code + stdout/stderr. */
35
+ interface RunHookResult {
36
+ exitCode: number;
37
+ stdout?: string;
38
+ stderr?: string;
39
+ }
40
+ /**
41
+ * Dispatch one host hook invocation. Always resolves (never rejects): every
42
+ * failure path returns a concrete {@link RunHookResult} so the CLI can exit
43
+ * cleanly. See the module header for the fail-open contract.
44
+ */
45
+ declare function runHook(opts: RunHookOptions): Promise<RunHookResult>;
46
+
47
+ /**
48
+ * telemetry/types — runtime telemetry contracts.
49
+ *
50
+ * The framework measures the MCP server's OWN bytes (tool args in, tool result
51
+ * out, tool-definition schemas) and tokenizes them locally — the only signal
52
+ * identical across every host (no host reports per-tool usage to a server).
53
+ * Records are aggregate counts only; raw arguments/results are NEVER stored.
54
+ */
55
+
56
+ /**
57
+ * The install scope a wrapped server was deployed under, narrowed to the two
58
+ * dimensions that matter for slicing telemetry: a `user`-global install vs a
59
+ * `project`-local one. The framework's broader {@link InstallScope}
60
+ * (`system|user|project|profile|managed`) is mapped down to this at wrap time —
61
+ * everything that is not project-local reads as `user`. Optional on the record
62
+ * so rows written before this field existed are treated as "unknown".
63
+ */
64
+ type TelemetryInstallScope = "user" | "project";
65
+
66
+ /**
67
+ * runtime/serve — the `agent-connector serve` telemetry-wrapping entrypoint.
68
+ *
69
+ * When a stdio MCP server opts into transparent telemetry, its host config is
70
+ * rewritten (by the adapter, via core/spawn.buildServeWrapperCommand) to launch
71
+ * <homeBin> serve --connector <id> -- <realCommand> <realArgs...>
72
+ * instead of the server directly. The CLI parses those flags and calls
73
+ * {@link runServe}, which stands up the per-session telemetry context (store,
74
+ * tokenizer, project identity, host detection) and hands off to the proxy.
75
+ *
76
+ * The proxy (telemetry/proxy.runServeProxy) forwards bytes VERBATIM in both
77
+ * directions and measures aggregate per-tool token counts out of band, so this
78
+ * wrapper is transparent to both the host and the real server. It resolves with
79
+ * the child server's exit code, which the CLI uses as its own.
80
+ */
81
+
82
+ /** Flags the CLI hands to {@link runServe}. */
83
+ interface RunServeOptions {
84
+ /** Connector id from `--connector <id>`; selects telemetry config + stamps records. */
85
+ connectorId: string;
86
+ /** The real MCP server executable to spawn (everything after `--`). */
87
+ serverCommand: string;
88
+ /** Arguments passed to that executable. */
89
+ serverArgs: string[];
90
+ /**
91
+ * Install scope from `--scope <user|project>`. OPTIONAL: absent for configs
92
+ * written before scope plumbing existed — left unstamped so older rows read
93
+ * as "unknown". Stamped verbatim onto every telemetry record when present.
94
+ */
95
+ installScope?: TelemetryInstallScope;
96
+ /**
97
+ * Install TARGET platform id from `--host <platformId>` (baked into the
98
+ * wrapper at install time). OPTIONAL: when a recognized platform id, it
99
+ * OVERRIDES runtime env detection so headless spawns stamp hostPlatform
100
+ * correctly (detectRuntimeHost only knows env markers for a few hosts and
101
+ * otherwise mis-attributes). Absent/unrecognized → fall back to detection.
102
+ */
103
+ hostPlatformOverride?: PlatformId;
104
+ }
105
+ declare function runServe(opts: RunServeOptions): Promise<number>;
106
+
107
+ /**
108
+ * runtime/usage-event — the OPT-IN host-native turn-usage enricher (enricher 4a).
109
+ *
110
+ * Gemini CLI / Antigravity fire an `AfterModel` (Antigravity CLI: `PostInvocation`)
111
+ * hook AFTER each model turn, whose stdin payload carries a `usageMetadata` block
112
+ * with the host's OWN exact token accounting for that whole conversation turn:
113
+ * { promptTokenCount, candidatesTokenCount, cachedContentTokenCount,
114
+ * thoughtsTokenCount, totalTokenCount }
115
+ * This is the single point in the whole matrix where a host reports REAL per-turn
116
+ * usage to a command we control — so we record it as `confidenceSource:"host-native"`
117
+ * (the top of CONFIDENCE_RANK), upgrading those rows from the serve-proxy estimate.
118
+ *
119
+ * DISTINCT, NEVER-SUMMED ORIGIN. Host-native turn usage is WHOLE-CONVERSATION, not
120
+ * per-MCP. To avoid double-counting against (a) the per-MCP serve-proxy `call`
121
+ * rows and (b) the usage-reader host-scan numbers, every record written here uses
122
+ * the DISTINCT scope `"model_turn"`. The MCP leaderboard excludes that scope (just
123
+ * as it special-cases `tool_defs`); the unified leaderboard surfaces it as its own
124
+ * clearly-labeled section that is explicitly never added to the other two origins.
125
+ *
126
+ * PRIVACY + FAIL-OPEN. This enricher is OPT-IN at install time (see the adapters);
127
+ * it stores AGGREGATE COUNTS ONLY (no raw content — the payload's prompt/response
128
+ * text is never read). ANY parse / store / IO error degrades to exit 0 and records
129
+ * NOTHING: a host-native usage hook must never break a model turn. This function
130
+ * never throws.
131
+ */
132
+ /** Flags + stdin the CLI hands to {@link runUsageEvent}. */
133
+ interface RunUsageEventOptions {
134
+ /** Host platform id from the command (`usage-event <platformId> …`). */
135
+ platformId: string;
136
+ /** Connector id from `--connector <id>` (stamped on the record). */
137
+ connectorId: string;
138
+ /** Raw stdin payload (host-native JSON). Empty string is tolerated → no record. */
139
+ stdin: string;
140
+ }
141
+ /** Process-level result the CLI translates into an exit code. */
142
+ interface RunUsageEventResult {
143
+ /** Always 0 — a host-native usage hook must never block a model turn. */
144
+ exitCode: number;
145
+ /** True when a `model_turn` record was appended (false on any fail-open path). */
146
+ recorded: boolean;
147
+ }
148
+ /**
149
+ * Record one host-native model turn. Parses the host's `usageMetadata`, maps it to
150
+ * a DISTINCT `model_turn` `ToolEventRecord` (confidence `host-native`, toolName
151
+ * `"*"`), and appends it to the shared telemetry store. NEVER throws and never
152
+ * blocks the turn: every failure path resolves to {@link NOOP} (exit 0, nothing
153
+ * recorded).
154
+ */
155
+ declare function runUsageEvent(opts: RunUsageEventOptions): Promise<RunUsageEventResult>;
156
+
157
+ export { type RunHookOptions, type RunHookResult, type RunServeOptions, type RunUsageEventOptions, type RunUsageEventResult, runHook, runServe, runUsageEvent };
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runHook,
4
+ runServe,
5
+ runUsageEvent
6
+ } from "../chunk-YNZU6PAV.js";
7
+ 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";
13
+ import "../chunk-MEH7GC7R.js";
14
+ import "../chunk-TRQKHP7D.js";
15
+ export {
16
+ runHook,
17
+ runServe,
18
+ runUsageEvent
19
+ };
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ fail
4
+ } from "./chunk-54EMKTTX.js";
5
+ import {
6
+ runServe
7
+ } from "./chunk-YNZU6PAV.js";
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";
14
+ import "./chunk-MEH7GC7R.js";
15
+ import "./chunk-TRQKHP7D.js";
16
+
17
+ // src/cli/commands/serve.ts
18
+ import { parseArgs } from "util";
19
+ async function run(argv) {
20
+ const sepIndex = argv.indexOf("--");
21
+ if (sepIndex === -1) {
22
+ return fail(
23
+ "usage: agent-connector serve --connector <id> [--scope <user|project>] [--host <platformId>] -- <command> [args...]"
24
+ );
25
+ }
26
+ const flagArgs = argv.slice(0, sepIndex);
27
+ const serverInvocation = argv.slice(sepIndex + 1);
28
+ const { values } = parseArgs({
29
+ args: flagArgs,
30
+ options: {
31
+ connector: { type: "string" },
32
+ scope: { type: "string" },
33
+ // `--host <platformId>` bakes the install TARGET platform into the wrapper
34
+ // so the proxy stamps hostPlatform correctly under a headless spawn (where
35
+ // runtime env markers are absent). Optional + tolerated (strict:false).
36
+ host: { type: "string" }
37
+ },
38
+ allowPositionals: true,
39
+ strict: false
40
+ });
41
+ const connectorId = typeof values.connector === "string" ? values.connector : void 0;
42
+ if (!connectorId || connectorId.trim() === "") {
43
+ return fail("serve requires --connector <id>");
44
+ }
45
+ const rawScope = values.scope;
46
+ const installScope = rawScope === "user" || rawScope === "project" ? rawScope : void 0;
47
+ const hostPlatformOverride = typeof values.host === "string" ? values.host : void 0;
48
+ const serverCommand = serverInvocation[0];
49
+ if (!serverCommand) {
50
+ return fail("serve requires a command after `--`");
51
+ }
52
+ const serverArgs = serverInvocation.slice(1);
53
+ const code = await runServe({
54
+ connectorId,
55
+ serverCommand,
56
+ serverArgs,
57
+ installScope,
58
+ hostPlatformOverride
59
+ });
60
+ process.exit(code);
61
+ }
62
+ export {
63
+ run
64
+ };
65
+ //# sourceMappingURL=serve-HVWWY4B6.js.map
@@ -0,0 +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":[]}
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ fail,
4
+ parseScope,
5
+ print
6
+ } from "./chunk-54EMKTTX.js";
7
+ import {
8
+ detectInstalledPlatforms,
9
+ loadAdapter
10
+ } from "./chunk-XUCWLJY5.js";
11
+ import {
12
+ findConnectorConfig,
13
+ listRegisteredConnectors,
14
+ loadConnectorFromPath
15
+ } from "./chunk-LTT56GI3.js";
16
+ import "./chunk-XNAM7F35.js";
17
+ import {
18
+ dataRoot,
19
+ homeBinPath
20
+ } from "./chunk-TRQKHP7D.js";
21
+
22
+ // src/cli/commands/status.ts
23
+ import { parseArgs } from "util";
24
+ import { readFileSync } from "fs";
25
+ async function resolveConnectors(connectorPath, projectDir) {
26
+ const configPath = connectorPath ?? findConnectorConfig(projectDir);
27
+ if (configPath) {
28
+ try {
29
+ const { connector } = await loadConnectorFromPath(configPath);
30
+ return [connector];
31
+ } catch {
32
+ }
33
+ }
34
+ return listRegisteredConnectors();
35
+ }
36
+ function buildContext(connector, id, scope, projectDir) {
37
+ return {
38
+ connector,
39
+ scope: connector.platforms[id]?.scope ?? scope,
40
+ projectDir,
41
+ homeBinPath: homeBinPath(),
42
+ dataRoot: dataRoot(),
43
+ dryRun: true
44
+ };
45
+ }
46
+ function fileMentions(path, needle) {
47
+ try {
48
+ return readFileSync(path, "utf8").includes(needle);
49
+ } catch {
50
+ return false;
51
+ }
52
+ }
53
+ async function run(argv) {
54
+ const { values } = parseArgs({
55
+ args: argv,
56
+ options: {
57
+ scope: { type: "string", default: "user" },
58
+ connector: { type: "string" },
59
+ project: { type: "string" },
60
+ json: { type: "boolean", default: false }
61
+ },
62
+ allowPositionals: false
63
+ });
64
+ const projectDir = values.project ?? process.cwd();
65
+ const scope = parseScope(values.scope);
66
+ if (scope == null) return fail(`invalid --scope "${values.scope}" (use user|project)`);
67
+ const connectors = await resolveConnectors(values.connector, projectDir);
68
+ const detected = await detectInstalledPlatforms(projectDir);
69
+ const rows = [];
70
+ for (const p of detected) {
71
+ const adapter = await loadAdapter(p.id);
72
+ if (!adapter) continue;
73
+ const connStatuses = connectors.map((connector) => {
74
+ const ctx = buildContext(connector, p.id, scope, projectDir);
75
+ let serverPath = "";
76
+ let hookPath = "";
77
+ try {
78
+ serverPath = adapter.getServerConfigPath(ctx);
79
+ } catch {
80
+ }
81
+ try {
82
+ hookPath = adapter.getHookConfigPath(ctx);
83
+ } catch {
84
+ }
85
+ return {
86
+ id: connector.id,
87
+ serverPresent: serverPath ? fileMentions(serverPath, connector.id) : false,
88
+ hooksPresent: hookPath ? fileMentions(hookPath, connector.id) : false
89
+ };
90
+ });
91
+ rows.push({
92
+ platform: p.id,
93
+ scope: p.scope,
94
+ configPath: p.configPath,
95
+ connectors: connStatuses
96
+ });
97
+ }
98
+ if (values.json) {
99
+ print(JSON.stringify(rows, null, 2));
100
+ return 0;
101
+ }
102
+ if (rows.length === 0) {
103
+ print("status: no agent platforms detected.");
104
+ return 0;
105
+ }
106
+ if (connectors.length === 0) {
107
+ print("status: no connectors found (pass --connector <path> or install one).\n");
108
+ }
109
+ for (const r of rows) {
110
+ print(`${r.platform} [${r.scope}] ${r.configPath}`);
111
+ if (r.connectors.length === 0) {
112
+ print(" (no connectors to check)");
113
+ } else {
114
+ for (const c of r.connectors) {
115
+ const mark = c.serverPresent || c.hooksPresent ? "[installed]" : "[absent ]";
116
+ const server = c.serverPresent ? "server \u2713" : "server \xB7";
117
+ const hooks = c.hooksPresent ? "hooks \u2713" : "hooks \xB7";
118
+ print(` ${mark} ${c.id} ${server} ${hooks}`);
119
+ }
120
+ }
121
+ print("");
122
+ }
123
+ return 0;
124
+ }
125
+ export {
126
+ run
127
+ };
128
+ //# sourceMappingURL=status-FE7TECZD.js.map