@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,217 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ rewriteEnvRefs
4
+ } from "./chunk-DBQMX75U.js";
5
+ import {
6
+ BaseAdapter
7
+ } from "./chunk-TIIP3RG2.js";
8
+ import "./chunk-7L6ITC4T.js";
9
+ import {
10
+ buildServeWrapperCommand,
11
+ isHomeBinHookCommand,
12
+ shouldWrapForTelemetry
13
+ } from "./chunk-MEH7GC7R.js";
14
+ import "./chunk-TRQKHP7D.js";
15
+
16
+ // src/adapters/amp/index.ts
17
+ import { existsSync } from "fs";
18
+ import { homedir } from "os";
19
+ import { join } from "path";
20
+ var HOST = "amp";
21
+ var MCP_ROOT_KEY = "amp.mcpServers";
22
+ var AmpAdapter = class extends BaseAdapter {
23
+ id = HOST;
24
+ name = "Amp";
25
+ paradigm = "mcp-only";
26
+ capabilities = {
27
+ // Amp has no lifecycle hook system — every hook capability is false.
28
+ preToolUse: false,
29
+ postToolUse: false,
30
+ preCompact: false,
31
+ sessionStart: false,
32
+ sessionEnd: false,
33
+ userPromptSubmit: false,
34
+ stop: false,
35
+ notification: false,
36
+ canModifyArgs: false,
37
+ canModifyOutput: false,
38
+ canInjectSessionContext: false,
39
+ // Amp registers stdio and Streamable HTTP MCP servers.
40
+ transports: ["stdio", "http"]
41
+ };
42
+ // ── Detection ────────────────────────────────────────────────────────────
43
+ detectInstalled(projectDir) {
44
+ const userDir = join(homedir(), ".config", "amp");
45
+ const userSettings = join(userDir, "settings.json");
46
+ const projectDirAmp = join(projectDir, ".amp");
47
+ const projectSettings = join(projectDirAmp, "settings.json");
48
+ const userInstalled = existsSync(userDir) || existsSync(userSettings);
49
+ const projectInstalled = existsSync(projectDirAmp) || existsSync(projectSettings);
50
+ const installed = userInstalled || projectInstalled;
51
+ const scope = projectInstalled && !userInstalled ? "project" : "user";
52
+ const configPath = scope === "project" ? projectSettings : userSettings;
53
+ return {
54
+ id: this.id,
55
+ name: this.name,
56
+ installed,
57
+ paradigm: this.paradigm,
58
+ capabilities: this.capabilities,
59
+ configPath,
60
+ scope,
61
+ reason: installed ? `found Amp config (${scope}) at ${configPath}` : `no Amp config at ${userSettings} or ${projectSettings}`,
62
+ confidence: installed ? "high" : "low"
63
+ };
64
+ }
65
+ // ── Native paths ─────────────────────────────────────────────────────────
66
+ getConfigDir(ctx) {
67
+ return ctx.scope === "project" ? join(ctx.projectDir, ".amp") : join(homedir(), ".config", "amp");
68
+ }
69
+ getServerConfigPath(ctx) {
70
+ return join(this.getConfigDir(ctx), "settings.json");
71
+ }
72
+ /**
73
+ * Amp has no hook file — hooks are not a thing here. The hook "config path" is
74
+ * the same settings.json so the generic doctor/backup behave sensibly.
75
+ */
76
+ getHookConfigPath(ctx) {
77
+ return this.getServerConfigPath(ctx);
78
+ }
79
+ // ── MCP server install / uninstall ───────────────────────────────────────
80
+ installServer(ctx) {
81
+ const { connector } = ctx;
82
+ const override = connector.platforms[HOST]?.server;
83
+ if (!connector.server || override === false) {
84
+ return [
85
+ {
86
+ platform: this.id,
87
+ action: "skip",
88
+ detail: connector.server ? "server registration disabled for amp" : "connector declares no MCP server"
89
+ }
90
+ ];
91
+ }
92
+ const server = override && typeof override === "object" ? { ...connector.server, ...override } : connector.server;
93
+ const serverPath = this.getServerConfigPath(ctx);
94
+ const entry = this.renderServerEntry(ctx, server);
95
+ return [
96
+ this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun)
97
+ ];
98
+ }
99
+ uninstallServer(ctx) {
100
+ const serverPath = this.getServerConfigPath(ctx);
101
+ return [
102
+ this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun)
103
+ ];
104
+ }
105
+ /** Render a normalized ServerDef into Amp's native `amp.mcpServers` entry. */
106
+ renderServerEntry(ctx, server) {
107
+ const transport = server.transport;
108
+ if (transport === "stdio") {
109
+ let command = server.command ?? "";
110
+ let args = [...server.args ?? []];
111
+ if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
112
+ const wrapped = buildServeWrapperCommand(
113
+ ctx.homeBinPath,
114
+ ctx.connector.id,
115
+ command,
116
+ args,
117
+ ctx.scope,
118
+ this.id
119
+ );
120
+ command = wrapped.command;
121
+ args = wrapped.args;
122
+ }
123
+ const entry2 = { command: this.rewrite(command) };
124
+ if (args.length > 0) entry2.args = args.map((a) => this.rewrite(a));
125
+ const env = this.renderEnv(server.env);
126
+ if (env) entry2.env = env;
127
+ return entry2;
128
+ }
129
+ const entry = { url: this.rewrite(server.url ?? "") };
130
+ const headers = this.renderEnv(server.headers);
131
+ if (headers) entry.headers = headers;
132
+ return entry;
133
+ }
134
+ /**
135
+ * Render env/header values. Amp supports native `${VAR_NAME}` interpolation,
136
+ * so translate `${env:VAR}` refs to that native token rather than baking
137
+ * secrets into the file. Literals pass through unchanged.
138
+ */
139
+ renderEnv(env) {
140
+ if (!env || Object.keys(env).length === 0) return void 0;
141
+ const out = {};
142
+ for (const [k, v] of Object.entries(env)) out[k] = this.rewrite(v);
143
+ return out;
144
+ }
145
+ /** Translate `${env:VAR(:-default)}` to Amp's native `${VAR}` token. */
146
+ rewrite(value) {
147
+ return rewriteEnvRefs(value, ampEnvToken);
148
+ }
149
+ // ── Hooks (unavailable — Amp is mcp-only) ────────────────────────────────
150
+ installHooks(_ctx) {
151
+ return [
152
+ {
153
+ platform: this.id,
154
+ action: "skip",
155
+ detail: "hooks unavailable (Amp is mcp-only)"
156
+ }
157
+ ];
158
+ }
159
+ uninstallHooks(_ctx) {
160
+ return [
161
+ {
162
+ platform: this.id,
163
+ action: "skip",
164
+ detail: "hooks unavailable (Amp is mcp-only)"
165
+ }
166
+ ];
167
+ }
168
+ /**
169
+ * True when a hook command references our home binary AND this connector id
170
+ * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand).
171
+ * Amp installs no hooks, but this guard keeps any future shared-file edit from
172
+ * removing another connector's entries.
173
+ */
174
+ isOurCommand(command, ctx) {
175
+ return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
176
+ }
177
+ // ── Diagnostics ──────────────────────────────────────────────────────────
178
+ getHealthChecks(ctx) {
179
+ const settingsPath = this.getServerConfigPath(ctx);
180
+ const connectorId = ctx.connector.id;
181
+ return [
182
+ {
183
+ name: `${this.name}: settings.json present`,
184
+ check: () => existsSync(settingsPath) ? { status: "OK", detail: settingsPath } : { status: "FAIL", detail: `not found: ${settingsPath}` }
185
+ },
186
+ {
187
+ name: `${this.name}: server entry registered`,
188
+ check: () => {
189
+ const cfg = this.readJson(settingsPath);
190
+ const bucket = cfg?.[MCP_ROOT_KEY];
191
+ if (!cfg || !bucket) {
192
+ return { status: "FAIL", detail: `no "${MCP_ROOT_KEY}" in ${settingsPath}` };
193
+ }
194
+ return connectorId in bucket ? { status: "OK", detail: `"${MCP_ROOT_KEY}".${connectorId} present` } : {
195
+ status: "FAIL",
196
+ detail: `no "${MCP_ROOT_KEY}".${connectorId} in ${settingsPath}`
197
+ };
198
+ }
199
+ }
200
+ ];
201
+ }
202
+ };
203
+ function ampEnvToken(name, def) {
204
+ if (def !== void 0) {
205
+ const v = process.env[name];
206
+ return v != null && v !== "" ? v : def;
207
+ }
208
+ return `\${${name}}`;
209
+ }
210
+ var adapter = new AmpAdapter();
211
+ var amp_default = adapter;
212
+ export {
213
+ AmpAdapter,
214
+ adapter,
215
+ amp_default as default
216
+ };
217
+ //# sourceMappingURL=amp-QSFH2V7Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/amp/index.ts"],"sourcesContent":["/**\n * adapters/amp — Amp (Sourcegraph / AmpCode) platform adapter for agent-connector.\n *\n * Amp is an **mcp-only** host: it exposes no lifecycle hook system, so MCP is the\n * only extensibility surface. This adapter installs the MCP server entry and\n * reports hooks as unavailable — the same shape validated by the Warp adapter.\n *\n * MCP config (report §2 / §5.3):\n * - user scope → ~/.config/amp/settings.json\n * - project scope → <projectDir>/.amp/settings.json\n * Both are JSONC (we write plain JSON, which is valid JSONC). The settings file\n * is SHARED with the rest of Amp's configuration, so we MERGE our entry into\n * the existing object and never clobber unrelated keys.\n *\n * QUIRK 1 — dotted top-level key: Amp does NOT use a nested `mcpServers` object.\n * The MCP registry is a single FLAT settings key literally named\n * `\"amp.mcpServers\"`, whose value is an object of `{ id: { command, args, env } }`.\n * We therefore set `settings[\"amp.mcpServers\"][connectorId] = entry`. Because the\n * base JSON helpers index `config[rootKey][serverId]`, passing the dotted string\n * as the root key writes exactly that flat key while preserving every sibling\n * setting (true merge).\n *\n * QUIRK 2 — native interpolation: Amp expands `${VAR_NAME}` in stdio entries at\n * runtime, so we KEEP env/header/url refs native by rewriting the portable\n * `${env:VAR}` syntax to Amp's `${VAR}` token rather than resolving to literals\n * (secrets stay out of the settings file).\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 { rewriteEnvRefs } from \"../../core/interpolate.js\";\nimport {\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"amp\";\n/**\n * QUIRK: a single FLAT, dotted settings key — NOT a nested object. The base\n * JSON helpers treat this as `config[\"amp.mcpServers\"][serverId]`.\n */\nconst MCP_ROOT_KEY = \"amp.mcpServers\";\n\n/** Native MCP server entry shapes Amp accepts under `amp.mcpServers`. */\ninterface AmpStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\ninterface AmpHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\nexport class AmpAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Amp\";\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Amp has no lifecycle hook system — every hook capability 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 // Amp registers stdio and Streamable HTTP MCP servers.\n transports: [\"stdio\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".config\", \"amp\");\n const userSettings = join(userDir, \"settings.json\");\n const projectDirAmp = join(projectDir, \".amp\");\n const projectSettings = join(projectDirAmp, \"settings.json\");\n\n const userInstalled = existsSync(userDir) || existsSync(userSettings);\n const projectInstalled = existsSync(projectDirAmp) || existsSync(projectSettings);\n const installed = userInstalled || projectInstalled;\n const scope = projectInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projectSettings : userSettings;\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 Amp config (${scope}) at ${configPath}`\n : `no Amp config at ${userSettings} or ${projectSettings}`,\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, \".amp\")\n : join(homedir(), \".config\", \"amp\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"settings.json\");\n }\n\n /**\n * Amp has no hook file — hooks are not a thing here. The hook \"config path\" is\n * the same settings.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 amp\"\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 // Upsert into the flat \"amp.mcpServers\" key, merging into existing settings.\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 Amp's native `amp.mcpServers` entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): AmpStdioServer | AmpHttpServer {\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 // Amp expands ${VAR_NAME} natively, so keep refs native (no literals).\n const entry: AmpStdioServer = { command: this.rewrite(command) };\n if (args.length > 0) entry.args = args.map((a) => this.rewrite(a));\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // http (and any other remote transport we surface) — Amp registers a URL.\n const entry: AmpHttpServer = { url: this.rewrite(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. Amp supports native `${VAR_NAME}` interpolation,\n * so translate `${env:VAR}` refs to that native token rather than baking\n * secrets into the file. Literals pass through unchanged.\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 const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(env)) out[k] = this.rewrite(v);\n return out;\n }\n\n /** Translate `${env:VAR(:-default)}` to Amp's native `${VAR}` token. */\n private rewrite(value: string): string {\n return rewriteEnvRefs(value, ampEnvToken);\n }\n\n // ── Hooks (unavailable — Amp is mcp-only) ────────────────────────────────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Amp 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 (Amp 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 * Amp installs no hooks, but this guard keeps any future shared-file edit from\n * 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 settingsPath = this.getServerConfigPath(ctx);\n const connectorId = ctx.connector.id;\n return [\n {\n name: `${this.name}: settings.json present`,\n check: () =>\n existsSync(settingsPath)\n ? { status: \"OK\", detail: settingsPath }\n : { status: \"FAIL\", detail: `not found: ${settingsPath}` },\n },\n {\n name: `${this.name}: server entry registered`,\n check: () => {\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(settingsPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no \"${MCP_ROOT_KEY}\" in ${settingsPath}` };\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 ${settingsPath}`,\n };\n },\n },\n ];\n }\n}\n\n/**\n * Amp native interpolation token: `${env:VAR}` → `${VAR}`.\n *\n * When the portable ref carried a default (`${env:VAR:-fallback}`), Amp's native\n * `${VAR}` token has no way to express it — so a bare native token would silently\n * DROP the default. Instead, resolve the default at install time: emit the live\n * value when VAR is set and non-empty, else the literal fallback. The native\n * token is only emitted when there is no default to preserve.\n */\nfunction ampEnvToken(name: string, def?: string): string {\n if (def !== undefined) {\n const v = process.env[name];\n return v != null && v !== \"\" ? v : def;\n }\n return `\\${${name}}`;\n}\n\nexport const adapter = new AmpAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ fileMtimeMs,
4
+ readJsonFile
5
+ } from "./chunk-RK6VBLXP.js";
6
+ import {
7
+ firstExistingRoot,
8
+ walkFiles
9
+ } from "./chunk-JWNT5KW7.js";
10
+ import {
11
+ emptyTokens,
12
+ inferProvider
13
+ } from "./chunk-XD7MY6HB.js";
14
+
15
+ // src/usage/readers/amp.ts
16
+ import { basename } from "path";
17
+ var PLATFORM_ID = "amp";
18
+ var DEFAULT_PROVIDER = "anthropic";
19
+ function toNonNegInt(v) {
20
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
21
+ if (!Number.isFinite(n)) return 0;
22
+ return Math.max(0, Math.trunc(n));
23
+ }
24
+ function toNonNegFloat(v) {
25
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
26
+ if (!Number.isFinite(n)) return 0;
27
+ return Math.max(0, n);
28
+ }
29
+ function toIntOrNull(v) {
30
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
31
+ if (!Number.isFinite(n)) return null;
32
+ return Math.trunc(n);
33
+ }
34
+ function parseAmpTimestamp(v) {
35
+ if (typeof v !== "string" || v === "") return null;
36
+ const ms = Date.parse(v);
37
+ if (Number.isNaN(ms) || ms === 0) return null;
38
+ return ms;
39
+ }
40
+ function fallbackAmpTimestamp(explicit, threadCreatedMs, fileMtime) {
41
+ if (explicit !== null && explicit !== 0) return explicit;
42
+ if (threadCreatedMs !== 0) return threadCreatedMs;
43
+ return fileMtime;
44
+ }
45
+ function tokensEqual(a, b) {
46
+ return a.input === b.input && a.output === b.output && a.cacheRead === b.cacheRead && a.cacheWrite === b.cacheWrite && a.reasoning === b.reasoning;
47
+ }
48
+ function matchesMessageUsage(a, b) {
49
+ return a.model === b.model && tokensEqual(a.tokens, b.tokens);
50
+ }
51
+ function parseLedgerRecords(eventsRaw, threadCreatedMs, fileMtime) {
52
+ if (!Array.isArray(eventsRaw)) return [];
53
+ const out = [];
54
+ for (const raw of eventsRaw) {
55
+ if (typeof raw !== "object" || raw === null) continue;
56
+ const event = raw;
57
+ if (typeof event.model !== "string" || event.model === "") continue;
58
+ const model = event.model;
59
+ const explicit = parseAmpTimestamp(event.timestamp);
60
+ const timestamp = fallbackAmpTimestamp(explicit, threadCreatedMs, fileMtime);
61
+ const tokensRaw = event.tokens ?? {};
62
+ const tokens = emptyTokens();
63
+ tokens.input = toNonNegInt(tokensRaw.input);
64
+ tokens.output = toNonNegInt(tokensRaw.output);
65
+ tokens.cacheRead = toNonNegInt(tokensRaw.cacheReadInputTokens);
66
+ tokens.cacheWrite = toNonNegInt(tokensRaw.cacheCreationInputTokens);
67
+ const toMsgId = toIntOrNull(event.toMessageId);
68
+ out.push({
69
+ model,
70
+ timestamp,
71
+ hasExplicitTimestamp: explicit !== null,
72
+ messageId: null,
73
+ ledgerToMessageId: toMsgId !== null && toMsgId > 0 ? toMsgId : null,
74
+ tokens,
75
+ cost: toNonNegFloat(event.credits)
76
+ });
77
+ }
78
+ return out;
79
+ }
80
+ function parseMessageRecords(messagesRaw, threadCreatedMs, fileMtime) {
81
+ if (!Array.isArray(messagesRaw)) return [];
82
+ const baseTimestamp = threadCreatedMs !== 0 ? threadCreatedMs : fileMtime;
83
+ const out = [];
84
+ for (const raw of messagesRaw) {
85
+ if (typeof raw !== "object" || raw === null) continue;
86
+ const msg = raw;
87
+ if (msg.role !== "assistant") continue;
88
+ const usage = msg.usage;
89
+ if (usage === void 0 || usage === null) continue;
90
+ if (typeof usage.model !== "string" || usage.model === "") continue;
91
+ const model = usage.model;
92
+ const messageId = Math.max(0, toIntOrNull(msg.messageId) ?? 0);
93
+ const timestamp = baseTimestamp + messageId * 1e3;
94
+ const tokens = emptyTokens();
95
+ tokens.input = toNonNegInt(usage.inputTokens);
96
+ tokens.output = toNonNegInt(usage.outputTokens);
97
+ tokens.cacheRead = toNonNegInt(usage.cacheReadInputTokens);
98
+ tokens.cacheWrite = toNonNegInt(usage.cacheCreationInputTokens);
99
+ out.push({
100
+ model,
101
+ timestamp,
102
+ hasExplicitTimestamp: false,
103
+ messageId: messageId > 0 ? messageId : null,
104
+ ledgerToMessageId: null,
105
+ tokens,
106
+ cost: toNonNegFloat(usage.credits)
107
+ });
108
+ }
109
+ return out;
110
+ }
111
+ function findMatchingLedgerRecord(ledger, consumed, searchStart, messageRecord) {
112
+ const findMatch = (predicate) => {
113
+ for (let i = searchStart; i < ledger.length; i++) {
114
+ if (predicate(i)) return i;
115
+ }
116
+ for (let i = 0; i < searchStart; i++) {
117
+ if (predicate(i)) return i;
118
+ }
119
+ return null;
120
+ };
121
+ if (messageRecord.messageId !== null) {
122
+ const byId = findMatch(
123
+ (i) => !consumed[i] && ledger[i].ledgerToMessageId === messageRecord.messageId
124
+ );
125
+ if (byId !== null) return byId;
126
+ }
127
+ return findMatch((i) => !consumed[i] && matchesMessageUsage(ledger[i], messageRecord));
128
+ }
129
+ function mergeAmpRecords(ledger, message) {
130
+ if (ledger.hasExplicitTimestamp) {
131
+ if (ledger.cost > 0 || message.cost <= 0) {
132
+ return ledger;
133
+ }
134
+ return { ...ledger, cost: message.cost, messageId: message.messageId };
135
+ }
136
+ return {
137
+ model: ledger.model,
138
+ timestamp: message.timestamp,
139
+ hasExplicitTimestamp: false,
140
+ messageId: message.messageId,
141
+ ledgerToMessageId: ledger.ledgerToMessageId,
142
+ tokens: ledger.tokens,
143
+ cost: ledger.cost > 0 ? ledger.cost : message.cost
144
+ };
145
+ }
146
+ function stripExt(name) {
147
+ const dot = name.lastIndexOf(".");
148
+ return dot > 0 ? name.slice(0, dot) : name;
149
+ }
150
+ function dedupKey(threadId, rec) {
151
+ const t = rec.tokens;
152
+ return `amp:${threadId}:${rec.timestamp}:${rec.model}:${t.input}-${t.output}-${t.cacheRead}-${t.cacheWrite}-${t.reasoning}`;
153
+ }
154
+ function parseAmpFile(path) {
155
+ const parsed = readJsonFile(path);
156
+ if (typeof parsed !== "object" || parsed === null) return [];
157
+ const thread = parsed;
158
+ const fileMtime = fileMtimeMs(path);
159
+ const threadId = typeof thread.id === "string" && thread.id !== "" ? thread.id : stripExt(basename(path)) || "unknown";
160
+ const threadCreatedMs = toIntOrNull(thread.created) ?? 0;
161
+ const ledgerRecords = parseLedgerRecords(
162
+ thread.usageLedger?.events,
163
+ threadCreatedMs,
164
+ fileMtime
165
+ );
166
+ const messageRecords = parseMessageRecords(thread.messages, threadCreatedMs, fileMtime);
167
+ let reconciled;
168
+ if (ledgerRecords.length === 0) {
169
+ reconciled = messageRecords.slice().sort((a, b) => a.timestamp - b.timestamp);
170
+ } else {
171
+ const consumed = new Array(ledgerRecords.length).fill(false);
172
+ let searchStart = 0;
173
+ const unmatched = [];
174
+ for (const messageRecord of messageRecords) {
175
+ const index = findMatchingLedgerRecord(
176
+ ledgerRecords,
177
+ consumed,
178
+ searchStart,
179
+ messageRecord
180
+ );
181
+ if (index !== null) {
182
+ consumed[index] = true;
183
+ searchStart = index + 1;
184
+ ledgerRecords[index] = mergeAmpRecords(ledgerRecords[index], messageRecord);
185
+ } else {
186
+ unmatched.push(messageRecord);
187
+ }
188
+ }
189
+ reconciled = ledgerRecords.concat(unmatched).sort((a, b) => a.timestamp - b.timestamp);
190
+ }
191
+ return reconciled.map((rec) => {
192
+ const modelId = rec.model;
193
+ const providerId = inferProvider(modelId) ?? DEFAULT_PROVIDER;
194
+ const tokens = emptyTokens();
195
+ tokens.input = rec.tokens.input;
196
+ tokens.output = rec.tokens.output;
197
+ tokens.cacheRead = rec.tokens.cacheRead;
198
+ tokens.cacheWrite = rec.tokens.cacheWrite;
199
+ tokens.reasoning = rec.tokens.reasoning;
200
+ const record = {
201
+ platformId: PLATFORM_ID,
202
+ modelId,
203
+ providerId,
204
+ sessionId: threadId,
205
+ tokens,
206
+ ts: rec.timestamp,
207
+ messageCount: 1,
208
+ confidence: "host-reported",
209
+ dedupKey: dedupKey(threadId, rec)
210
+ };
211
+ if (rec.cost > 0) record.cost = rec.cost;
212
+ return record;
213
+ });
214
+ }
215
+ var ampReader = {
216
+ platformId: PLATFORM_ID,
217
+ kind: "local",
218
+ async read({ sinceMs }) {
219
+ const root = firstExistingRoot(PLATFORM_ID);
220
+ if (root === void 0) return [];
221
+ const files = walkFiles(root, (name) => name.endsWith(".json"));
222
+ const records = [];
223
+ for (const file of files) {
224
+ const rows = parseAmpFile(file);
225
+ for (const row of rows) {
226
+ if (sinceMs !== void 0 && row.ts < sinceMs) continue;
227
+ records.push(row);
228
+ }
229
+ }
230
+ return records;
231
+ }
232
+ };
233
+ var amp_default = ampReader;
234
+ export {
235
+ amp_default as default
236
+ };
237
+ //# sourceMappingURL=amp-TULUPXXL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/usage/readers/amp.ts"],"sourcesContent":["/**\n * usage/readers/amp — Amp (Sourcegraph) native session-log reader.\n *\n * Faithful port of tokscale sessions/amp.rs. Reads one JSON file per thread from\n * ~/.local/share/amp/threads/*.json. Each thread carries token usage in TWO\n * overlapping places that describe the SAME calls and must be MERGED, not summed:\n *\n * 1. `usageLedger.events[]` — billing ledger rows:\n * tokens.input → input\n * tokens.output → output\n * tokens.cacheReadInputTokens → cacheRead\n * tokens.cacheCreationInputTokens → cacheWrite\n * model, credits (cost), timestamp (RFC3339), toMessageId.\n * 2. `messages[].usage` (assistant role only) — per-message usage:\n * inputTokens / outputTokens / cacheReadInputTokens /\n * cacheCreationInputTokens, model, credits.\n *\n * Reconciliation (port of parse_amp_file + merge_amp_records): when a ledger\n * exists, each assistant message-record is matched to at most one ledger record —\n * first by `toMessageId == messageId`, else by an exact (model, tokens) heuristic\n * — using a rotating search cursor so earlier matches are not re-consumed. A match\n * MERGES into the ledger record (the ledger keeps its explicit timestamp/cost,\n * but borrows the message timestamp/cost where it lacks them); an unmatched\n * message-record is appended as its own row. Ledger rows that match nothing stay.\n * When there is NO ledger, message-records pass through directly. This in-file\n * merge is the dedup: a call logged in both places yields ONE row, never two.\n *\n * Timestamps (port of parse_amp_timestamp / fallback_amp_timestamp): a ledger\n * event prefers its RFC3339 string, else thread.created, else file mtime. A\n * message-record derives `thread.created (or mtime) + messageId*1000` so messages\n * order by id. reasoning is always 0 (Amp does not report it).\n *\n * Attribution: session = thread.id (or the filename stem). Project is not captured\n * by Amp, so projectKey/projectLabel are omitted. model/provider come from the\n * row's model (provider inferred, default \"anthropic\"). Confidence is\n * \"host-reported\" (real host token counts). A stable cross-source `dedupKey`\n * (`amp:<thread>:<ts>:<model>:<tokens>`) guards against the same file being read\n * twice; the in-file merge already prevents ledger/message double counting.\n *\n * Fail-open: no root → []; unreadable/malformed file → skipped (no throw).\n * Read-only.\n */\n\nimport { basename } from \"node:path\";\n\nimport type { UsageReader, UsageRecord, TokenBreakdown } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { fileMtimeMs, readJsonFile } from \"../jsonl.js\";\nimport { inferProvider } from \"../normalize.js\";\nimport { firstExistingRoot, walkFiles } from \"../paths.js\";\n\nconst PLATFORM_ID = \"amp\" as const;\nconst DEFAULT_PROVIDER = \"anthropic\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Raw shapes (everything optional / unknown — narrowed at read time)\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface AmpTokensRaw {\n input?: unknown;\n output?: unknown;\n cacheReadInputTokens?: unknown;\n cacheCreationInputTokens?: unknown;\n}\n\ninterface AmpUsageEventRaw {\n timestamp?: unknown;\n model?: unknown;\n credits?: unknown;\n tokens?: AmpTokensRaw;\n toMessageId?: unknown;\n}\n\ninterface AmpMessageUsageRaw {\n model?: unknown;\n inputTokens?: unknown;\n outputTokens?: unknown;\n cacheReadInputTokens?: unknown;\n cacheCreationInputTokens?: unknown;\n credits?: unknown;\n}\n\ninterface AmpMessageRaw {\n role?: unknown;\n messageId?: unknown;\n usage?: AmpMessageUsageRaw;\n}\n\ninterface AmpThreadRaw {\n id?: unknown;\n created?: unknown;\n messages?: unknown;\n usageLedger?: { events?: unknown };\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Coercion helpers\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Coerce an unknown to a non-negative integer (0 on absence/garbage). Mirrors `.unwrap_or(0).max(0)`. */\nfunction toNonNegInt(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.trunc(n));\n}\n\n/** Coerce an unknown to a non-negative float (0 on absence/garbage). Mirrors credits `.unwrap_or(0.0).max(0.0)`. */\nfunction toNonNegFloat(v: unknown): number {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, n);\n}\n\n/** Coerce an unknown to an integer, or null when absent/garbage (for ids). */\nfunction toIntOrNull(v: unknown): number | null {\n const n = typeof v === \"number\" ? v : typeof v === \"string\" ? Number(v) : NaN;\n if (!Number.isFinite(n)) return null;\n return Math.trunc(n);\n}\n\n/**\n * Parse an RFC3339 timestamp string to epoch ms, filtering 0 out. Port of\n * parse_amp_timestamp: returns null when absent, unparseable, or exactly 0.\n */\nfunction parseAmpTimestamp(v: unknown): number | null {\n if (typeof v !== \"string\" || v === \"\") return null;\n const ms = Date.parse(v);\n if (Number.isNaN(ms) || ms === 0) return null;\n return ms;\n}\n\n/**\n * Pick a ledger timestamp with fallback (port of fallback_amp_timestamp):\n * explicit (when non-zero) → thread.created (when non-zero) → file mtime.\n */\nfunction fallbackAmpTimestamp(\n explicit: number | null,\n threadCreatedMs: number,\n fileMtime: number,\n): number {\n if (explicit !== null && explicit !== 0) return explicit;\n if (threadCreatedMs !== 0) return threadCreatedMs;\n return fileMtime;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Intermediate record (port of AmpUsageRecord)\n// ─────────────────────────────────────────────────────────────────────────\n\ninterface AmpUsageRecord {\n model: string;\n timestamp: number;\n hasExplicitTimestamp: boolean;\n /** assistant messageId (>0) when this row came from / merged a message. */\n messageId: number | null;\n /** ledger event's toMessageId (>0) used for id-based matching. */\n ledgerToMessageId: number | null;\n tokens: TokenBreakdown;\n cost: number;\n}\n\n/** Element-wise token equality (port of `self.tokens == other.tokens`). */\nfunction tokensEqual(a: TokenBreakdown, b: TokenBreakdown): boolean {\n return (\n a.input === b.input &&\n a.output === b.output &&\n a.cacheRead === b.cacheRead &&\n a.cacheWrite === b.cacheWrite &&\n a.reasoning === b.reasoning\n );\n}\n\n/** Heuristic match: same model AND identical tokens (port of matches_message_usage). */\nfunction matchesMessageUsage(a: AmpUsageRecord, b: AmpUsageRecord): boolean {\n return a.model === b.model && tokensEqual(a.tokens, b.tokens);\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Ledger / message parsing\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Port of parse_amp_ledger_records. */\nfunction parseLedgerRecords(\n eventsRaw: unknown,\n threadCreatedMs: number,\n fileMtime: number,\n): AmpUsageRecord[] {\n if (!Array.isArray(eventsRaw)) return [];\n\n const out: AmpUsageRecord[] = [];\n for (const raw of eventsRaw) {\n if (typeof raw !== \"object\" || raw === null) continue;\n const event = raw as AmpUsageEventRaw;\n\n if (typeof event.model !== \"string\" || event.model === \"\") continue; // model? early-return\n const model = event.model;\n\n const explicit = parseAmpTimestamp(event.timestamp);\n const timestamp = fallbackAmpTimestamp(explicit, threadCreatedMs, fileMtime);\n\n const tokensRaw = event.tokens ?? {};\n const tokens = emptyTokens();\n tokens.input = toNonNegInt(tokensRaw.input);\n tokens.output = toNonNegInt(tokensRaw.output);\n tokens.cacheRead = toNonNegInt(tokensRaw.cacheReadInputTokens);\n tokens.cacheWrite = toNonNegInt(tokensRaw.cacheCreationInputTokens);\n // reasoning stays 0.\n\n const toMsgId = toIntOrNull(event.toMessageId);\n\n out.push({\n model,\n timestamp,\n hasExplicitTimestamp: explicit !== null,\n messageId: null,\n ledgerToMessageId: toMsgId !== null && toMsgId > 0 ? toMsgId : null,\n tokens,\n cost: toNonNegFloat(event.credits),\n });\n }\n return out;\n}\n\n/** Port of parse_amp_message_records (assistant rows only). */\nfunction parseMessageRecords(\n messagesRaw: unknown,\n threadCreatedMs: number,\n fileMtime: number,\n): AmpUsageRecord[] {\n if (!Array.isArray(messagesRaw)) return [];\n\n const baseTimestamp = threadCreatedMs !== 0 ? threadCreatedMs : fileMtime;\n\n const out: AmpUsageRecord[] = [];\n for (const raw of messagesRaw) {\n if (typeof raw !== \"object\" || raw === null) continue;\n const msg = raw as AmpMessageRaw;\n\n if (msg.role !== \"assistant\") continue;\n const usage = msg.usage;\n if (usage === undefined || usage === null) continue; // usage? early-return\n if (typeof usage.model !== \"string\" || usage.model === \"\") continue; // model? early-return\n const model = usage.model;\n\n const messageId = Math.max(0, toIntOrNull(msg.messageId) ?? 0);\n // base + messageId*1000 (saturating in Rust; JS numbers don't overflow here).\n const timestamp = baseTimestamp + messageId * 1000;\n\n const tokens = emptyTokens();\n tokens.input = toNonNegInt(usage.inputTokens);\n tokens.output = toNonNegInt(usage.outputTokens);\n tokens.cacheRead = toNonNegInt(usage.cacheReadInputTokens);\n tokens.cacheWrite = toNonNegInt(usage.cacheCreationInputTokens);\n // reasoning stays 0.\n\n out.push({\n model,\n timestamp,\n hasExplicitTimestamp: false,\n messageId: messageId > 0 ? messageId : null,\n ledgerToMessageId: null,\n tokens,\n cost: toNonNegFloat(usage.credits),\n });\n }\n return out;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Reconciliation (port of find_matching_ledger_record + merge_amp_records)\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Find an unconsumed ledger record matching `messageRecord`, scanning from\n * `searchStart` forward then wrapping to the front (port of the rotating\n * find_match). Prefers a `toMessageId == messageId` match, then the\n * (model, tokens) heuristic. Returns the index, or null when none matches.\n */\nfunction findMatchingLedgerRecord(\n ledger: AmpUsageRecord[],\n consumed: boolean[],\n searchStart: number,\n messageRecord: AmpUsageRecord,\n): number | null {\n const findMatch = (predicate: (i: number) => boolean): number | null => {\n for (let i = searchStart; i < ledger.length; i++) {\n if (predicate(i)) return i;\n }\n for (let i = 0; i < searchStart; i++) {\n if (predicate(i)) return i;\n }\n return null;\n };\n\n if (messageRecord.messageId !== null) {\n const byId = findMatch(\n (i) => !consumed[i] && ledger[i]!.ledgerToMessageId === messageRecord.messageId,\n );\n if (byId !== null) return byId;\n }\n\n return findMatch((i) => !consumed[i] && matchesMessageUsage(ledger[i]!, messageRecord));\n}\n\n/**\n * Merge a matched message-record into its ledger record (port of merge_amp_records).\n * If the ledger row has an explicit timestamp, it wins (only borrowing the\n * message cost/messageId when the ledger had no cost); otherwise the merged row\n * adopts the message timestamp, keeping ledger tokens and the better cost.\n */\nfunction mergeAmpRecords(ledger: AmpUsageRecord, message: AmpUsageRecord): AmpUsageRecord {\n if (ledger.hasExplicitTimestamp) {\n if (ledger.cost > 0 || message.cost <= 0) {\n return ledger;\n }\n return { ...ledger, cost: message.cost, messageId: message.messageId };\n }\n return {\n model: ledger.model,\n timestamp: message.timestamp,\n hasExplicitTimestamp: false,\n messageId: message.messageId,\n ledgerToMessageId: ledger.ledgerToMessageId,\n tokens: ledger.tokens,\n cost: ledger.cost > 0 ? ledger.cost : message.cost,\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// File parse (port of parse_amp_file)\n// ─────────────────────────────────────────────────────────────────────────\n\nfunction stripExt(name: string): string {\n const dot = name.lastIndexOf(\".\");\n return dot > 0 ? name.slice(0, dot) : name;\n}\n\n/** Stable cross-source dedup key for one reconciled row. */\nfunction dedupKey(threadId: string, rec: AmpUsageRecord): string {\n const t = rec.tokens;\n return `amp:${threadId}:${rec.timestamp}:${rec.model}:${t.input}-${t.output}-${t.cacheRead}-${t.cacheWrite}-${t.reasoning}`;\n}\n\nfunction parseAmpFile(path: string): UsageRecord[] {\n const parsed = readJsonFile(path);\n if (typeof parsed !== \"object\" || parsed === null) return []; // missing/malformed → []\n const thread = parsed as AmpThreadRaw;\n\n const fileMtime = fileMtimeMs(path);\n\n const threadId =\n typeof thread.id === \"string\" && thread.id !== \"\"\n ? thread.id\n : stripExt(basename(path)) || \"unknown\";\n\n const threadCreatedMs = toIntOrNull(thread.created) ?? 0;\n\n const ledgerRecords = parseLedgerRecords(\n thread.usageLedger?.events,\n threadCreatedMs,\n fileMtime,\n );\n const messageRecords = parseMessageRecords(thread.messages, threadCreatedMs, fileMtime);\n\n let reconciled: AmpUsageRecord[];\n\n if (ledgerRecords.length === 0) {\n // No ledger → message-records pass through, sorted by timestamp.\n reconciled = messageRecords.slice().sort((a, b) => a.timestamp - b.timestamp);\n } else {\n const consumed = new Array<boolean>(ledgerRecords.length).fill(false);\n let searchStart = 0;\n const unmatched: AmpUsageRecord[] = [];\n\n for (const messageRecord of messageRecords) {\n const index = findMatchingLedgerRecord(\n ledgerRecords,\n consumed,\n searchStart,\n messageRecord,\n );\n if (index !== null) {\n consumed[index] = true;\n searchStart = index + 1;\n ledgerRecords[index] = mergeAmpRecords(ledgerRecords[index]!, messageRecord);\n } else {\n unmatched.push(messageRecord);\n }\n }\n\n reconciled = ledgerRecords.concat(unmatched).sort((a, b) => a.timestamp - b.timestamp);\n }\n\n return reconciled.map((rec) => {\n const modelId = rec.model;\n const providerId = inferProvider(modelId) ?? DEFAULT_PROVIDER;\n\n const tokens = emptyTokens();\n tokens.input = rec.tokens.input;\n tokens.output = rec.tokens.output;\n tokens.cacheRead = rec.tokens.cacheRead;\n tokens.cacheWrite = rec.tokens.cacheWrite;\n tokens.reasoning = rec.tokens.reasoning;\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId,\n providerId,\n sessionId: threadId,\n tokens,\n ts: rec.timestamp,\n messageCount: 1,\n confidence: \"host-reported\",\n dedupKey: dedupKey(threadId, rec),\n };\n if (rec.cost > 0) record.cost = rec.cost;\n // Amp does not capture a project → projectKey/projectLabel omitted.\n return record;\n });\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Reader\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The Amp (Sourcegraph) usage reader singleton. */\nconst ampReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"local\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n const root = firstExistingRoot(PLATFORM_ID);\n if (root === undefined) return []; // no ~/.local/share/amp/threads → fail-open\n\n // ~/.local/share/amp/threads/*.json\n const files = walkFiles(root, (name) => name.endsWith(\".json\"));\n\n const records: UsageRecord[] = [];\n for (const file of files) {\n const rows = parseAmpFile(file);\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 ampReader;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ AntigravityAdapter,
4
+ adapter,
5
+ antigravity_default
6
+ } from "./chunk-TRKWUNO4.js";
7
+ import "./chunk-DBQMX75U.js";
8
+ import "./chunk-TIIP3RG2.js";
9
+ import "./chunk-7L6ITC4T.js";
10
+ import "./chunk-MEH7GC7R.js";
11
+ import "./chunk-TRQKHP7D.js";
12
+ export {
13
+ AntigravityAdapter,
14
+ adapter,
15
+ antigravity_default as default
16
+ };
17
+ //# sourceMappingURL=antigravity-CX2YLSY7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}