@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,272 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ openSqlite
4
+ } from "./chunk-YT43MUSJ.js";
5
+ import {
6
+ firstExistingRoot
7
+ } from "./chunk-JWNT5KW7.js";
8
+ import {
9
+ emptyTokens,
10
+ normalizeWorkspaceKey,
11
+ workspaceLabelFromKey
12
+ } from "./chunk-XD7MY6HB.js";
13
+
14
+ // src/usage/readers/zed.ts
15
+ import { decompress } from "fzstd";
16
+ var PLATFORM_ID = "zed";
17
+ var ZED_HOSTED_PROVIDER = "zed.dev";
18
+ var MAX_ZED_THREAD_JSON_BYTES = 32 * 1024 * 1024;
19
+ function threadColumns(db) {
20
+ const cols = /* @__PURE__ */ new Set();
21
+ for (const row of db.all("PRAGMA table_info(threads)")) {
22
+ const name = row.name;
23
+ if (typeof name === "string") cols.add(name);
24
+ }
25
+ return cols;
26
+ }
27
+ function optionalColumn(columns, column) {
28
+ return columns.has(column) ? column : "NULL";
29
+ }
30
+ function buildThreadsQuery(columns) {
31
+ const createdAt = optionalColumn(columns, "created_at");
32
+ const folderPaths = optionalColumn(columns, "folder_paths");
33
+ const folderPathsOrder = optionalColumn(columns, "folder_paths_order");
34
+ return `SELECT id, updated_at, ${createdAt}, ${folderPaths}, ${folderPathsOrder}, data_type, data FROM threads`;
35
+ }
36
+ function toBytes(v) {
37
+ if (v instanceof Uint8Array) return v;
38
+ if (Array.isArray(v)) return Uint8Array.from(v);
39
+ if (v instanceof ArrayBuffer) return new Uint8Array(v);
40
+ return null;
41
+ }
42
+ function decodeThreadJson(dataType, data) {
43
+ switch (dataType.trim().toLowerCase()) {
44
+ case "json": {
45
+ if (data.length > MAX_ZED_THREAD_JSON_BYTES) return null;
46
+ return data;
47
+ }
48
+ case "zstd": {
49
+ let decoded;
50
+ try {
51
+ decoded = decompress(data);
52
+ } catch {
53
+ return null;
54
+ }
55
+ if (decoded.length > MAX_ZED_THREAD_JSON_BYTES) return null;
56
+ return decoded;
57
+ }
58
+ default:
59
+ return null;
60
+ }
61
+ }
62
+ function parseJsonBytes(bytes) {
63
+ let text;
64
+ try {
65
+ text = new TextDecoder("utf-8", { fatal: false }).decode(bytes);
66
+ } catch {
67
+ return null;
68
+ }
69
+ try {
70
+ return JSON.parse(text);
71
+ } catch {
72
+ return null;
73
+ }
74
+ }
75
+ function totalTokens(t) {
76
+ return t.input + t.output + t.cacheRead + t.cacheWrite + t.reasoning;
77
+ }
78
+ function usageField(obj, field) {
79
+ const v = obj[field];
80
+ let n;
81
+ if (typeof v === "number") n = v;
82
+ else if (typeof v === "string") n = Number(v);
83
+ else return 0;
84
+ if (!Number.isFinite(n)) return 0;
85
+ return Math.max(0, Math.trunc(n));
86
+ }
87
+ function tokenUsageFromValue(value) {
88
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
89
+ const obj = value;
90
+ const tokens = emptyTokens();
91
+ tokens.input = usageField(obj, "input_tokens");
92
+ tokens.output = usageField(obj, "output_tokens");
93
+ tokens.cacheRead = usageField(obj, "cache_read_input_tokens");
94
+ tokens.cacheWrite = usageField(obj, "cache_creation_input_tokens");
95
+ return tokens;
96
+ }
97
+ function sumRequestTokenUsage(value) {
98
+ const total = emptyTokens();
99
+ let count = 0;
100
+ let usages;
101
+ if (Array.isArray(value)) {
102
+ usages = value;
103
+ } else if (typeof value === "object" && value !== null) {
104
+ usages = Object.values(value);
105
+ } else {
106
+ return { tokens: total, count };
107
+ }
108
+ for (const usageValue of usages) {
109
+ const usage = tokenUsageFromValue(usageValue);
110
+ if (usage === null) continue;
111
+ if (totalTokens(usage) <= 0) continue;
112
+ total.input += usage.input;
113
+ total.output += usage.output;
114
+ total.cacheRead += usage.cacheRead;
115
+ total.cacheWrite += usage.cacheWrite;
116
+ total.reasoning += usage.reasoning;
117
+ count += 1;
118
+ }
119
+ return { tokens: total, count };
120
+ }
121
+ function threadUsage(thread) {
122
+ const { tokens: requestTokens, count } = sumRequestTokenUsage(thread.request_token_usage);
123
+ if (totalTokens(requestTokens) > 0) {
124
+ return { tokens: requestTokens, messageCount: Math.max(1, count) };
125
+ }
126
+ const cumulative = tokenUsageFromValue(thread.cumulative_token_usage);
127
+ if (cumulative !== null && totalTokens(cumulative) > 0) {
128
+ return { tokens: cumulative, messageCount: 1 };
129
+ }
130
+ return null;
131
+ }
132
+ function parseTimestampStr(value) {
133
+ const iso = Date.parse(value);
134
+ if (!Number.isNaN(iso)) return iso;
135
+ if (/^[+-]?\d+$/.test(value.trim())) {
136
+ const numeric = Number(value.trim());
137
+ if (!Number.isFinite(numeric) || numeric <= 0) return null;
138
+ return numeric >= 1e12 ? Math.trunc(numeric) : Math.trunc(numeric * 1e3);
139
+ }
140
+ return null;
141
+ }
142
+ function asString(v) {
143
+ return typeof v === "string" ? v : void 0;
144
+ }
145
+ function timestampMs(row, thread) {
146
+ const createdAt = asString(row.created_at);
147
+ if (createdAt !== void 0) {
148
+ const ms = parseTimestampStr(createdAt);
149
+ if (ms !== null) return ms;
150
+ }
151
+ const updatedAt = asString(row.updated_at);
152
+ if (updatedAt !== void 0) {
153
+ const ms = parseTimestampStr(updatedAt);
154
+ if (ms !== null) return ms;
155
+ }
156
+ const payloadUpdatedAt = asString(thread.updated_at);
157
+ if (payloadUpdatedAt !== void 0) {
158
+ const ms = parseTimestampStr(payloadUpdatedAt);
159
+ if (ms !== null) return ms;
160
+ }
161
+ return null;
162
+ }
163
+ function firstOrderedPathIndex(order, pathCount) {
164
+ let bestIndex;
165
+ let bestOrder = Number.POSITIVE_INFINITY;
166
+ const parts = order.split(",");
167
+ for (let index = 0; index < parts.length; index++) {
168
+ if (index >= pathCount) continue;
169
+ const raw = parts[index].trim();
170
+ if (!/^\d+$/.test(raw)) continue;
171
+ const value = Number(raw);
172
+ if (!Number.isFinite(value)) continue;
173
+ if (value < bestOrder) {
174
+ bestOrder = value;
175
+ bestIndex = index;
176
+ }
177
+ }
178
+ return bestIndex;
179
+ }
180
+ function workspaceKeyFromFolders(paths, order) {
181
+ if (typeof paths !== "string") return void 0;
182
+ const list = paths.split(/\r?\n/).map((p) => p.trim()).filter((p) => p !== "");
183
+ if (list.length === 0) return void 0;
184
+ let selected;
185
+ if (typeof order === "string") {
186
+ const idx = firstOrderedPathIndex(order, list.length);
187
+ if (idx !== void 0) selected = list[idx];
188
+ }
189
+ if (selected === void 0) selected = list[0];
190
+ return normalizeWorkspaceKey(selected);
191
+ }
192
+ function parseThreadRow(row) {
193
+ const id = asString(row.id);
194
+ if (id === void 0 || id === "") return null;
195
+ const dataType = asString(row.data_type);
196
+ if (dataType === void 0) return null;
197
+ const dataBytes = toBytes(row.data);
198
+ if (dataBytes === null) return null;
199
+ const jsonBytes = decodeThreadJson(dataType, dataBytes);
200
+ if (jsonBytes === null) return null;
201
+ const parsed = parseJsonBytes(jsonBytes);
202
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return null;
203
+ const thread = parsed;
204
+ if (thread.imported === true) return null;
205
+ const model = thread.model;
206
+ if (typeof model !== "object" || model === null || Array.isArray(model)) return null;
207
+ const modelObj = model;
208
+ const provider = asString(modelObj.provider);
209
+ if (provider === void 0) return null;
210
+ if (provider.trim().toLowerCase() !== ZED_HOSTED_PROVIDER) return null;
211
+ const modelRaw = asString(modelObj.model);
212
+ if (modelRaw === void 0) return null;
213
+ const modelId = modelRaw.trim();
214
+ if (modelId === "") return null;
215
+ const usage = threadUsage(thread);
216
+ if (usage === null) return null;
217
+ const ts = timestampMs(row, thread);
218
+ if (ts === null) return null;
219
+ const record = {
220
+ platformId: PLATFORM_ID,
221
+ modelId,
222
+ providerId: ZED_HOSTED_PROVIDER,
223
+ sessionId: id,
224
+ tokens: usage.tokens,
225
+ ts,
226
+ messageCount: usage.messageCount,
227
+ dedupKey: `zed:${id}`,
228
+ confidence: "host-reported"
229
+ };
230
+ const projectKey = workspaceKeyFromFolders(row.folder_paths, row.folder_paths_order);
231
+ if (projectKey !== void 0) {
232
+ record.projectKey = projectKey;
233
+ const label = workspaceLabelFromKey(projectKey);
234
+ if (label !== void 0) record.projectLabel = label;
235
+ }
236
+ return record;
237
+ }
238
+ var zedReader = {
239
+ platformId: PLATFORM_ID,
240
+ kind: "local",
241
+ async read({ sinceMs }) {
242
+ const dbPath = firstExistingRoot(PLATFORM_ID);
243
+ if (dbPath === void 0) return [];
244
+ const db = await openSqlite(dbPath);
245
+ if (db === null) return [];
246
+ try {
247
+ const columns = threadColumns(db);
248
+ const query = buildThreadsQuery(columns);
249
+ const rows = db.all(query);
250
+ const records = [];
251
+ for (const raw of rows) {
252
+ let record;
253
+ try {
254
+ record = parseThreadRow(raw);
255
+ } catch {
256
+ continue;
257
+ }
258
+ if (record === null) continue;
259
+ if (sinceMs !== void 0 && record.ts < sinceMs) continue;
260
+ records.push(record);
261
+ }
262
+ return records;
263
+ } finally {
264
+ db.close();
265
+ }
266
+ }
267
+ };
268
+ var zed_default = zedReader;
269
+ export {
270
+ zed_default as default
271
+ };
272
+ //# sourceMappingURL=zed-NNNX5MNT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/usage/readers/zed.ts"],"sourcesContent":["/**\n * usage/readers/zed — Zed Agent hosted-thread usage reader (SQLite + zstd JSON).\n *\n * Faithful port of tokscale sessions/zed.rs. Zed persists one row per agent\n * thread in a `threads` table inside a single SQLite database:\n * • Linux/FreeBSD: $XDG_DATA_HOME/zed/threads/threads.db (~/.local/share/zed/…)\n * • macOS: ~/Library/Application Support/Zed/threads/threads.db\n * • Windows: %LOCALAPPDATA%\\Zed\\threads\\threads.db\n * (host roots, incl. the AGENT_CONNECTOR_ZED_DIR override, are resolved by\n * paths.ts hostRoots(\"zed\").)\n *\n * Only Zed-HOSTED model rows (provider == \"zed.dev\", case-insensitive) are\n * counted. External ACP agents are billed/logged by their own providers/CLIs, so\n * counting their Zed UI rows would double-count those sources.\n *\n * The thread payload is stored in a `data` BLOB whose `data_type` is either:\n * • \"json\" — the raw UTF-8 JSON bytes; or\n * • \"zstd\" — ZSTD-compressed JSON, decompressed here via fzstd's decompress().\n * Any other data_type, a failed zstd decode, or invalid JSON → the row is skipped\n * (fail-open). A decoded payload exceeding 32 MiB is rejected.\n *\n * One SELECT pulls every thread; the schema is backward-compatible — created_at,\n * folder_paths, folder_paths_order are OPTIONAL columns (older Zed builds omit\n * them). We probe `PRAGMA table_info(threads)` and substitute NULL for any column\n * that is absent so the SELECT never errors on an old schema:\n * SELECT id, updated_at, {created_at|NULL}, {folder_paths|NULL},\n * {folder_paths_order|NULL}, data_type, data FROM threads\n *\n * Token extraction (nested JSON in the decoded payload; reasoning always 0 — Zed's\n * TokenUsage has no reasoning field). Each TokenUsage object maps:\n * input = input_tokens\n * output = output_tokens\n * cacheRead = cache_read_input_tokens\n * cacheWrite = cache_creation_input_tokens\n * Primary source is `request_token_usage` (an object map keyed by request id, OR\n * an array): each entry with a positive total is summed and counted. When the\n * request usage total is > 0 we use it (messageCount = count, min 1). Otherwise we\n * fall back to a single `cumulative_token_usage` object (messageCount = 1). A\n * thread with no positive token total is dropped.\n *\n * Model: model.model (trimmed, required non-empty). Provider hard-coded \"zed.dev\"\n * (per zed.rs — the row is only kept when model.provider == \"zed.dev\"). Threads\n * with imported == true are skipped. Timestamp (port of timestamp_ms): the\n * created_at column, else the updated_at column, else the payload's updated_at —\n * each parsed via parse_timestamp_str (RFC3339 or numeric s/ms). Session id = the\n * `id` column (thread id), which also seeds the dedup key \"zed:<thread_id>\".\n * Project: folder_paths (newline-separated) selected by folder_paths_order\n * (comma-separated indices; lowest order wins) or the first path, normalized via\n * normalizeWorkspaceKey. Confidence is \"host-reported\".\n *\n * Fail-open: db missing/locked/unreadable/non-sqlite → openSqlite returns null →\n * []; a bad/zstd-undecodable/non-hosted row is skipped, never thrown.\n */\n\nimport { decompress } from \"fzstd\";\n\nimport type { TokenBreakdown, UsageReader, UsageRecord } from \"../types.js\";\nimport { emptyTokens } from \"../aggregate.js\";\nimport { normalizeWorkspaceKey, workspaceLabelFromKey } from \"../normalize.js\";\nimport { firstExistingRoot } from \"../paths.js\";\nimport { openSqlite } from \"../sqlite.js\";\n\nconst PLATFORM_ID = \"zed\" as const;\n/** Only Zed-hosted threads (provider == this) are counted (per zed.rs). */\nconst ZED_HOSTED_PROVIDER = \"zed.dev\";\n/** Reject a decoded thread payload larger than this (mirrors the Rust guard). */\nconst MAX_ZED_THREAD_JSON_BYTES = 32 * 1024 * 1024;\n\n/** The thread columns we read off each SQLite row (everything unknown). */\ninterface ZedThreadRow {\n id?: unknown;\n updated_at?: unknown;\n created_at?: unknown;\n folder_paths?: unknown;\n folder_paths_order?: unknown;\n data_type?: unknown;\n data?: unknown;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Schema probe + query build (backward-compat optional columns)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The set of column names on the `threads` table (empty on any probe error). */\nfunction threadColumns(db: { all(sql: string): Array<Record<string, unknown>> }): Set<string> {\n const cols = new Set<string>();\n for (const row of db.all(\"PRAGMA table_info(threads)\")) {\n // table_info's column-name field is `name`.\n const name = row.name;\n if (typeof name === \"string\") cols.add(name);\n }\n return cols;\n}\n\n/** `column` when present on the table, else the literal `NULL` (port of optional_column). */\nfunction optionalColumn(columns: Set<string>, column: string): string {\n return columns.has(column) ? column : \"NULL\";\n}\n\n/** Build the threads SELECT, substituting NULL for any absent optional column. */\nfunction buildThreadsQuery(columns: Set<string>): string {\n const createdAt = optionalColumn(columns, \"created_at\");\n const folderPaths = optionalColumn(columns, \"folder_paths\");\n const folderPathsOrder = optionalColumn(columns, \"folder_paths_order\");\n return (\n `SELECT id, updated_at, ${createdAt}, ${folderPaths}, ${folderPathsOrder}, ` +\n `data_type, data FROM threads`\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// BLOB decode (json / zstd → JSON value)\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Coerce a sql.js BLOB cell to a Uint8Array (sql.js returns BLOBs as Uint8Array;\n * be tolerant of Buffer / number[] just in case), or null when it is not bytes.\n */\nfunction toBytes(v: unknown): Uint8Array | null {\n if (v instanceof Uint8Array) return v;\n if (Array.isArray(v)) return Uint8Array.from(v as number[]);\n if (v instanceof ArrayBuffer) return new Uint8Array(v);\n return null;\n}\n\n/**\n * Decode the `data` BLOB to JSON bytes (port of decode_thread_json): \"json\"\n * passes the bytes through; \"zstd\" decompresses via fzstd. Returns null on an\n * unsupported data_type, a failed zstd decode, or an over-size payload (the row\n * is then skipped — fail-open).\n */\nfunction decodeThreadJson(dataType: string, data: Uint8Array): Uint8Array | null {\n switch (dataType.trim().toLowerCase()) {\n case \"json\": {\n if (data.length > MAX_ZED_THREAD_JSON_BYTES) return null;\n return data;\n }\n case \"zstd\": {\n let decoded: Uint8Array;\n try {\n decoded = decompress(data);\n } catch {\n return null; // undecodable zstd → skip the row (fail-open)\n }\n if (decoded.length > MAX_ZED_THREAD_JSON_BYTES) return null;\n return decoded;\n }\n default:\n return null; // unsupported data_type → skip\n }\n}\n\n/** Decode a UTF-8 byte payload to a parsed JSON value, or null on failure. */\nfunction parseJsonBytes(bytes: Uint8Array): unknown {\n let text: string;\n try {\n text = new TextDecoder(\"utf-8\", { fatal: false }).decode(bytes);\n } catch {\n return null;\n }\n try {\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Token usage extraction (port of thread_usage / token_usage_from_value)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Sum the five token dimensions of a breakdown. */\nfunction totalTokens(t: TokenBreakdown): number {\n return t.input + t.output + t.cacheRead + t.cacheWrite + t.reasoning;\n}\n\n/**\n * Coerce a TokenUsage field to a non-negative integer (port of usage_field):\n * accept a number or a numeric string; clamp ≥ 0; 0 on absence/garbage.\n */\nfunction usageField(obj: Record<string, unknown>, field: string): number {\n const v = obj[field];\n let n: number;\n if (typeof v === \"number\") n = v;\n else if (typeof v === \"string\") n = Number(v);\n else return 0;\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.trunc(n));\n}\n\n/**\n * Build a TokenBreakdown from a single TokenUsage value (port of\n * token_usage_from_value); reasoning stays 0 (not present in Zed's schema).\n * Returns null when the value is not an object.\n */\nfunction tokenUsageFromValue(value: unknown): TokenBreakdown | null {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return null;\n const obj = value as Record<string, unknown>;\n const tokens = emptyTokens();\n tokens.input = usageField(obj, \"input_tokens\");\n tokens.output = usageField(obj, \"output_tokens\");\n tokens.cacheRead = usageField(obj, \"cache_read_input_tokens\");\n tokens.cacheWrite = usageField(obj, \"cache_creation_input_tokens\");\n // reasoning stays 0.\n return tokens;\n}\n\n/**\n * Sum every positive TokenUsage in `request_token_usage` (port of\n * sum_request_token_usage). The value may be an object map (keyed by request id)\n * or an array; non-object members and zero-total entries are skipped. Returns the\n * summed breakdown and the count of positive entries.\n */\nfunction sumRequestTokenUsage(value: unknown): { tokens: TokenBreakdown; count: number } {\n const total = emptyTokens();\n let count = 0;\n\n let usages: unknown[];\n if (Array.isArray(value)) {\n usages = value;\n } else if (typeof value === \"object\" && value !== null) {\n usages = Object.values(value as Record<string, unknown>);\n } else {\n return { tokens: total, count };\n }\n\n for (const usageValue of usages) {\n const usage = tokenUsageFromValue(usageValue);\n if (usage === null) continue;\n if (totalTokens(usage) <= 0) continue;\n total.input += usage.input;\n total.output += usage.output;\n total.cacheRead += usage.cacheRead;\n total.cacheWrite += usage.cacheWrite;\n total.reasoning += usage.reasoning;\n count += 1;\n }\n\n return { tokens: total, count };\n}\n\n/**\n * Resolve a thread's usage (port of thread_usage): prefer the summed\n * request_token_usage when its total is > 0 (messageCount = count, min 1),\n * otherwise fall back to a single cumulative_token_usage (messageCount = 1).\n * Returns null when neither source yields a positive total.\n */\nfunction threadUsage(thread: Record<string, unknown>): { tokens: TokenBreakdown; messageCount: number } | null {\n const { tokens: requestTokens, count } = sumRequestTokenUsage(thread.request_token_usage);\n if (totalTokens(requestTokens) > 0) {\n return { tokens: requestTokens, messageCount: Math.max(1, count) };\n }\n\n const cumulative = tokenUsageFromValue(thread.cumulative_token_usage);\n if (cumulative !== null && totalTokens(cumulative) > 0) {\n return { tokens: cumulative, messageCount: 1 };\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Timestamp (port of timestamp_ms + parse_timestamp_str)\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Parse a timestamp string to epoch ms (port of parse_timestamp_str): RFC3339\n * first, else a positive integer disambiguated s↔ms (≥ 1e12 → ms, else × 1000).\n * Returns null on a non-positive / unparseable value.\n */\nfunction parseTimestampStr(value: string): number | null {\n const iso = Date.parse(value);\n if (!Number.isNaN(iso)) return iso;\n\n // Strict integer parse (the Rust path uses i64::from_str_radix-style parsing).\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 ? Math.trunc(numeric) : Math.trunc(numeric * 1000);\n }\n return null;\n}\n\n/** A cell that should be a string, else undefined. */\nfunction asString(v: unknown): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n/**\n * Resolve the thread timestamp (port of timestamp_ms): created_at column, else\n * updated_at column, else the payload's updated_at — first that parses. Returns\n * null when none yields a valid timestamp.\n */\nfunction timestampMs(row: ZedThreadRow, thread: Record<string, unknown>): number | null {\n const createdAt = asString(row.created_at);\n if (createdAt !== undefined) {\n const ms = parseTimestampStr(createdAt);\n if (ms !== null) return ms;\n }\n const updatedAt = asString(row.updated_at);\n if (updatedAt !== undefined) {\n const ms = parseTimestampStr(updatedAt);\n if (ms !== null) return ms;\n }\n const payloadUpdatedAt = asString(thread.updated_at);\n if (payloadUpdatedAt !== undefined) {\n const ms = parseTimestampStr(payloadUpdatedAt);\n if (ms !== null) return ms;\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Project / workspace (port of workspace_key_from_folders)\n// ─────────────────────────────────────────────────────────────────────────\n\n/**\n * Pick the index of the lowest-order path (port of first_ordered_path_index):\n * `order` is a comma-separated list of indices aligned positionally with the\n * paths; we take the position whose parsed order value is smallest, ignoring\n * positions beyond the path count. Returns undefined when nothing parses.\n */\nfunction firstOrderedPathIndex(order: string, pathCount: number): number | undefined {\n let bestIndex: number | undefined;\n let bestOrder = Number.POSITIVE_INFINITY;\n const parts = order.split(\",\");\n for (let index = 0; index < parts.length; index++) {\n if (index >= pathCount) continue;\n const raw = (parts[index] as string).trim();\n if (!/^\\d+$/.test(raw)) continue;\n const value = Number(raw);\n if (!Number.isFinite(value)) continue;\n if (value < bestOrder) {\n bestOrder = value;\n bestIndex = index;\n }\n }\n return bestIndex;\n}\n\n/**\n * Derive a normalized workspace key from the folder columns (port of\n * workspace_key_from_folders): split `paths` on newlines (trimmed, non-empty),\n * select by `order` (lowest-order index) or the first path, then normalize.\n */\nfunction workspaceKeyFromFolders(paths: unknown, order: unknown): string | undefined {\n if (typeof paths !== \"string\") return undefined;\n const list = paths\n .split(/\\r?\\n/)\n .map((p) => p.trim())\n .filter((p) => p !== \"\");\n if (list.length === 0) return undefined;\n\n let selected: string | undefined;\n if (typeof order === \"string\") {\n const idx = firstOrderedPathIndex(order, list.length);\n if (idx !== undefined) selected = list[idx];\n }\n if (selected === undefined) selected = list[0];\n\n return normalizeWorkspaceKey(selected as string);\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Row → record (port of parse_thread_row)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Parse one threads row into a UsageRecord, or null when it should be skipped. */\nfunction parseThreadRow(row: ZedThreadRow): UsageRecord | null {\n const id = asString(row.id);\n if (id === undefined || id === \"\") return null;\n\n const dataType = asString(row.data_type);\n if (dataType === undefined) return null;\n const dataBytes = toBytes(row.data);\n if (dataBytes === null) return null;\n\n const jsonBytes = decodeThreadJson(dataType, dataBytes);\n if (jsonBytes === null) return null; // unsupported / undecodable / oversize → skip\n\n const parsed = parseJsonBytes(jsonBytes);\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return null;\n const thread = parsed as Record<string, unknown>;\n\n // Skip imported threads.\n if (thread.imported === true) return null;\n\n // Require a hosted (zed.dev) model with a non-empty model id.\n const model = thread.model;\n if (typeof model !== \"object\" || model === null || Array.isArray(model)) return null;\n const modelObj = model as Record<string, unknown>;\n const provider = asString(modelObj.provider);\n if (provider === undefined) return null;\n if (provider.trim().toLowerCase() !== ZED_HOSTED_PROVIDER) return null;\n\n const modelRaw = asString(modelObj.model);\n if (modelRaw === undefined) return null;\n const modelId = modelRaw.trim();\n if (modelId === \"\") return null;\n\n const usage = threadUsage(thread);\n if (usage === null) return null; // no positive token total → drop\n\n const ts = timestampMs(row, thread);\n if (ts === null) return null;\n\n const record: UsageRecord = {\n platformId: PLATFORM_ID,\n modelId,\n providerId: ZED_HOSTED_PROVIDER,\n sessionId: id,\n tokens: usage.tokens,\n ts,\n messageCount: usage.messageCount,\n dedupKey: `zed:${id}`,\n confidence: \"host-reported\",\n };\n\n const projectKey = workspaceKeyFromFolders(row.folder_paths, row.folder_paths_order);\n if (projectKey !== undefined) {\n record.projectKey = projectKey;\n const label = workspaceLabelFromKey(projectKey);\n if (label !== undefined) record.projectLabel = label;\n }\n\n return record;\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Reader\n// ─────────────────────────────────────────────────────────────────────────\n\n/** The Zed Agent hosted-thread usage reader singleton. */\nconst zedReader: UsageReader = {\n platformId: PLATFORM_ID,\n kind: \"local\",\n async read({ sinceMs }: { sinceMs?: number }): Promise<UsageRecord[]> {\n const dbPath = firstExistingRoot(PLATFORM_ID);\n if (dbPath === undefined) return []; // no threads.db → fail-open\n\n const db = await openSqlite(dbPath);\n if (db === null) return []; // missing / locked / unreadable / non-sqlite → fail-open\n\n try {\n const columns = threadColumns(db);\n const query = buildThreadsQuery(columns);\n const rows = db.all(query); // bad SQL / schema mismatch → [] (fail-open)\n const records: UsageRecord[] = [];\n\n for (const raw of rows) {\n let record: UsageRecord | null;\n try {\n record = parseThreadRow(raw as ZedThreadRow);\n } catch {\n continue; // any per-row decode failure → skip (fail-open)\n }\n if (record === null) continue;\n if (sinceMs !== undefined && record.ts < sinceMs) continue;\n records.push(record);\n }\n\n return records;\n } finally {\n db.close();\n }\n },\n};\n\nexport default zedReader;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveEnvRefsDeep
4
+ } from "./chunk-DBQMX75U.js";
5
+ import {
6
+ BaseAdapter
7
+ } from "./chunk-TIIP3RG2.js";
8
+ import "./chunk-7L6ITC4T.js";
9
+ import {
10
+ buildServeWrapperCommand,
11
+ shouldWrapForTelemetry
12
+ } from "./chunk-MEH7GC7R.js";
13
+ import "./chunk-TRQKHP7D.js";
14
+
15
+ // src/adapters/zed/index.ts
16
+ import { existsSync } from "fs";
17
+ import { homedir } from "os";
18
+ import { join, resolve } from "path";
19
+ var HOST = "zed";
20
+ var MCP_ROOT_KEY = "context_servers";
21
+ var ZedAdapter = class extends BaseAdapter {
22
+ id = HOST;
23
+ name = "Zed";
24
+ paradigm = "mcp-only";
25
+ capabilities = {
26
+ // Zed has no lifecycle hook system — every hook capability is false.
27
+ preToolUse: false,
28
+ postToolUse: false,
29
+ preCompact: false,
30
+ sessionStart: false,
31
+ sessionEnd: false,
32
+ userPromptSubmit: false,
33
+ stop: false,
34
+ notification: false,
35
+ canModifyArgs: false,
36
+ canModifyOutput: false,
37
+ canInjectSessionContext: false,
38
+ // Zed registers stdio context servers; remote URLs are also accepted.
39
+ transports: ["stdio", "sse", "http"]
40
+ };
41
+ // ── Detection ────────────────────────────────────────────────────────────
42
+ detectInstalled(projectDir) {
43
+ const userDir = this.userConfigDir();
44
+ const userSettings = this.userSettingsPath();
45
+ const projDir = join(projectDir, ".zed");
46
+ const projSettings = join(projDir, "settings.json");
47
+ const userInstalled = existsSync(userDir) || existsSync(userSettings);
48
+ const projInstalled = existsSync(projDir) || existsSync(projSettings);
49
+ const installed = userInstalled || projInstalled;
50
+ const scope = projInstalled && !userInstalled ? "project" : "user";
51
+ const configPath = scope === "project" ? projSettings : userSettings;
52
+ return {
53
+ id: this.id,
54
+ name: this.name,
55
+ installed,
56
+ paradigm: this.paradigm,
57
+ capabilities: this.capabilities,
58
+ configPath,
59
+ scope,
60
+ reason: installed ? `found Zed config (${scope}) at ${configPath}` : `no Zed config at ${userSettings} or ${projSettings}`,
61
+ confidence: installed ? "high" : "low"
62
+ };
63
+ }
64
+ // ── Native paths ─────────────────────────────────────────────────────────
65
+ getConfigDir(ctx) {
66
+ return ctx.scope === "project" ? join(ctx.projectDir, ".zed") : this.userConfigDir();
67
+ }
68
+ getServerConfigPath(ctx) {
69
+ return join(this.getConfigDir(ctx), "settings.json");
70
+ }
71
+ /**
72
+ * Zed has no hook file — hooks are not a thing here. The hook "config path"
73
+ * is the same settings.json so the generic doctor/backup behave sensibly.
74
+ */
75
+ getHookConfigPath(ctx) {
76
+ return this.getServerConfigPath(ctx);
77
+ }
78
+ /**
79
+ * Zed's user config dir is OS-native (Rust `dirs::config_dir()`), NOT a
80
+ * uniform ~/.config:
81
+ * - Windows: %APPDATA%\Zed (Roaming, NOT Local/%LOCALAPPDATA%)
82
+ * - macOS / Linux: ~/.config/zed
83
+ */
84
+ userConfigDir() {
85
+ if (process.platform === "win32") {
86
+ const appData = process.env.APPDATA && process.env.APPDATA.trim() !== "" ? process.env.APPDATA : resolve(homedir(), "AppData", "Roaming");
87
+ return join(appData, "Zed");
88
+ }
89
+ return join(homedir(), ".config", "zed");
90
+ }
91
+ userSettingsPath() {
92
+ return join(this.userConfigDir(), "settings.json");
93
+ }
94
+ // ── MCP server install / uninstall ───────────────────────────────────────
95
+ installServer(ctx) {
96
+ const { connector } = ctx;
97
+ const override = connector.platforms[HOST]?.server;
98
+ if (!connector.server || override === false) {
99
+ return [
100
+ {
101
+ platform: this.id,
102
+ action: "skip",
103
+ detail: connector.server ? "server registration disabled for zed" : "connector declares no MCP server"
104
+ }
105
+ ];
106
+ }
107
+ const server = override && typeof override === "object" ? { ...connector.server, ...override } : connector.server;
108
+ const serverPath = this.getServerConfigPath(ctx);
109
+ const entry = this.renderServerEntry(ctx, server);
110
+ return [
111
+ this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun)
112
+ ];
113
+ }
114
+ uninstallServer(ctx) {
115
+ const serverPath = this.getServerConfigPath(ctx);
116
+ return [
117
+ this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun)
118
+ ];
119
+ }
120
+ /** Render a normalized ServerDef into Zed's native context_servers entry. */
121
+ renderServerEntry(ctx, server) {
122
+ const transport = server.transport;
123
+ if (transport === "stdio") {
124
+ let command = server.command ?? "";
125
+ let args = [...server.args ?? []];
126
+ if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
127
+ const wrapped = buildServeWrapperCommand(
128
+ ctx.homeBinPath,
129
+ ctx.connector.id,
130
+ command,
131
+ args,
132
+ ctx.scope,
133
+ this.id
134
+ );
135
+ command = wrapped.command;
136
+ args = wrapped.args;
137
+ }
138
+ const entry2 = { command: resolveEnvRefsDeep(command) };
139
+ if (args.length > 0) entry2.args = resolveEnvRefsDeep(args);
140
+ const env = this.renderEnv(server.env);
141
+ if (env) entry2.env = env;
142
+ return entry2;
143
+ }
144
+ const entry = { url: resolveEnvRefsDeep(server.url ?? "") };
145
+ const headers = this.renderEnv(server.headers);
146
+ if (headers) entry.headers = headers;
147
+ return entry;
148
+ }
149
+ /**
150
+ * Render env/header values. Zed documents no native interpolation token, so
151
+ * resolve `${env:VAR}` references to literals at install time.
152
+ */
153
+ renderEnv(env) {
154
+ if (!env || Object.keys(env).length === 0) return void 0;
155
+ return resolveEnvRefsDeep({ ...env });
156
+ }
157
+ // ── Hooks (unavailable — Zed is mcp-only) ────────────────────────────────
158
+ installHooks(_ctx) {
159
+ return [
160
+ {
161
+ platform: this.id,
162
+ action: "skip",
163
+ detail: "hooks unavailable (Zed is mcp-only)"
164
+ }
165
+ ];
166
+ }
167
+ uninstallHooks(_ctx) {
168
+ return [
169
+ {
170
+ platform: this.id,
171
+ action: "skip",
172
+ detail: "hooks unavailable (Zed is mcp-only)"
173
+ }
174
+ ];
175
+ }
176
+ // ── Diagnostics ──────────────────────────────────────────────────────────
177
+ getHealthChecks(ctx) {
178
+ const settingsPath = this.getServerConfigPath(ctx);
179
+ const connectorId = ctx.connector.id;
180
+ return [
181
+ {
182
+ name: `${this.name}: settings.json present`,
183
+ check: () => existsSync(settingsPath) ? { status: "OK", detail: settingsPath } : { status: "FAIL", detail: `not found: ${settingsPath}` }
184
+ },
185
+ {
186
+ name: `${this.name}: context server entry registered`,
187
+ check: () => {
188
+ const cfg = this.readJson(settingsPath);
189
+ const bucket = cfg?.[MCP_ROOT_KEY];
190
+ if (!cfg || !bucket) {
191
+ return { status: "FAIL", detail: `no ${MCP_ROOT_KEY} in ${settingsPath}` };
192
+ }
193
+ return connectorId in bucket ? { status: "OK", detail: `${MCP_ROOT_KEY}.${connectorId} present` } : {
194
+ status: "FAIL",
195
+ detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${settingsPath}`
196
+ };
197
+ }
198
+ }
199
+ ];
200
+ }
201
+ };
202
+ var adapter = new ZedAdapter();
203
+ var zed_default = adapter;
204
+ export {
205
+ ZedAdapter,
206
+ adapter,
207
+ zed_default as default
208
+ };
209
+ //# sourceMappingURL=zed-VRJKWYUR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/zed/index.ts"],"sourcesContent":["/**\n * adapters/zed — Zed editor platform adapter for agent-connector.\n *\n * Zed is an **mcp-only** host: it is an IDE, not a CLI with a hook pipeline, so\n * there is NO lifecycle hook system. MCP (\"context servers\") is the only\n * integration path, so this adapter installs only the MCP server and reports\n * hooks as unavailable — like Warp, it exercises the `mcp-only` paradigm.\n *\n * MCP config (one JSON-with-comments settings file, NOT a dedicated MCP file):\n * - user scope → settings.json under Zed's OS-native config dir (Rust\n * `dirs::config_dir()`):\n * • Windows: %APPDATA%\\Zed\\settings.json (Roaming, NOT %LOCALAPPDATA%)\n * • macOS / Linux: ~/.config/zed/settings.json\n * - project scope → <projectDir>/.zed/settings.json\n * Root key is \"context_servers\" (NOT \"mcpServers\"). The same file holds the\n * (non-existent) hook config — there is no separate hook file here.\n *\n * MERGE CONTRACT: Zed's settings.json is a large user-owned IDE config. We read\n * the whole file, set ONLY context_servers[<id>], and write it back — every\n * other top-level key and sibling context server is preserved. (Zed accepts\n * JSONC; we WRITE plain JSON, mirroring the other JSON-config adapters.)\n *\n * ENTRY SHAPE QUIRK (verified against context-mode's proven Zed adapter +\n * zed-industries/zed crates/settings_content/src/project.rs): Zed's\n * context_servers Stdio variant flattens ContextServerCommand and renames its\n * `path` field to the JSON key `command`. The accepted shape is therefore a\n * FLAT entry: { \"command\": \"<exe>\", \"args\": [...], \"env\": {...} }. The nested\n * { command: { path, args } } form fails to deserialize under Zed's\n * #[serde(untagged)] enum and is silently dropped (the server never loads).\n *\n * Zed documents no native ${env:VAR} interpolation token for context_servers,\n * so env refs are resolved to literals at install time (the no-native-token\n * path, same as Warp).\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, InstallContext } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n ServerDef,\n Transport,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildServeWrapperCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"zed\";\nconst MCP_ROOT_KEY = \"context_servers\";\n\n/**\n * Zed's context_servers Stdio entry. FLAT shape — `command` is a string, NOT a\n * nested { path, args } object (see file header). Remote transports are\n * represented as a URL-bearing entry.\n */\ninterface ZedStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n}\ninterface ZedHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\nexport class ZedAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Zed\";\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Zed 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 // Zed registers stdio context servers; remote URLs are also accepted.\n transports: [\"stdio\", \"sse\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = this.userConfigDir();\n const userSettings = this.userSettingsPath();\n const projDir = join(projectDir, \".zed\");\n const projSettings = join(projDir, \"settings.json\");\n\n const userInstalled = existsSync(userDir) || existsSync(userSettings);\n const projInstalled = existsSync(projDir) || existsSync(projSettings);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projSettings : 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 Zed config (${scope}) at ${configPath}`\n : `no Zed config at ${userSettings} or ${projSettings}`,\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, \".zed\")\n : this.userConfigDir();\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"settings.json\");\n }\n\n /**\n * Zed has no hook file — hooks are not a thing here. The hook \"config path\"\n * is 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 /**\n * Zed's user config dir is OS-native (Rust `dirs::config_dir()`), NOT a\n * uniform ~/.config:\n * - Windows: %APPDATA%\\Zed (Roaming, NOT Local/%LOCALAPPDATA%)\n * - macOS / Linux: ~/.config/zed\n */\n private userConfigDir(): string {\n if (process.platform === \"win32\") {\n const appData =\n process.env.APPDATA && process.env.APPDATA.trim() !== \"\"\n ? process.env.APPDATA\n : resolve(homedir(), \"AppData\", \"Roaming\");\n return join(appData, \"Zed\");\n }\n return join(homedir(), \".config\", \"zed\");\n }\n\n private userSettingsPath(): string {\n return join(this.userConfigDir(), \"settings.json\");\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 zed\"\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 // upsertServerInJson reads the WHOLE settings file, sets only\n // context_servers[<id>], and writes it back — preserving every other\n // top-level key and sibling context server (the merge contract).\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 Zed's native context_servers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): ZedStdioServer | ZedHttpServer {\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 // Zed has no documented native interpolation token, so resolve every\n // ${env:VAR} to a literal at install time.\n // FLAT shape: `command` is a string, never a nested { path, args }.\n const entry: ZedStdioServer = { command: resolveEnvRefsDeep(command) };\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // sse / http (and any other remote transport) — Zed registers a URL.\n const entry: ZedHttpServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Zed documents no native interpolation token, so\n * resolve `${env:VAR}` references to literals at install time.\n */\n private renderEnv(\n env: Record<string, string> | undefined,\n ): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n return resolveEnvRefsDeep({ ...env });\n }\n\n // ── Hooks (unavailable — Zed is mcp-only) ────────────────────────────────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Zed 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 (Zed is mcp-only)\",\n },\n ];\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}: context 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\nexport const adapter = new ZedAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@ken-jo/agent-connector",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Write your MCP server + hooks once; agent-connector installs and adapts them across every AI-agent platform (Claude Code, Codex, Cursor, OpenCode, Copilot, Gemini, Warp, …) and gives you default, platform-independent per-tool token telemetry.",
6
+ "keywords": [
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "hooks",
10
+ "claude-code",
11
+ "codex",
12
+ "cursor",
13
+ "opencode",
14
+ "copilot",
15
+ "gemini-cli",
16
+ "telemetry",
17
+ "tokens",
18
+ "multi-platform"
19
+ ],
20
+ "license": "Apache-2.0",
21
+ "author": "KenJo",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/ken-jo/agent-connector.git"
25
+ },
26
+ "homepage": "https://github.com/ken-jo/agent-connector#readme",
27
+ "bugs": {
28
+ "url": "https://github.com/ken-jo/agent-connector/issues"
29
+ },
30
+ "bin": {
31
+ "agent-connector": "./dist/cli.js"
32
+ },
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ },
38
+ "./runtime": {
39
+ "types": "./dist/runtime/index.d.ts",
40
+ "import": "./dist/runtime/index.js"
41
+ },
42
+ "./cli": {
43
+ "types": "./dist/cli/sdk.d.ts",
44
+ "import": "./dist/cli/sdk.js"
45
+ }
46
+ },
47
+ "files": [
48
+ "dist",
49
+ "NOTICE"
50
+ ],
51
+ "engines": {
52
+ "node": ">=18.17"
53
+ },
54
+ "workspaces": [
55
+ "examples/*"
56
+ ],
57
+ "scripts": {
58
+ "build": "tsup",
59
+ "dev": "tsx src/cli/index.ts",
60
+ "typecheck": "tsc --noEmit",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest",
63
+ "prepublishOnly": "npm run typecheck && npm run build"
64
+ },
65
+ "dependencies": {
66
+ "@iarna/toml": "^2.2.5",
67
+ "fzstd": "^0.1.1",
68
+ "gpt-tokenizer": "^2.9.0",
69
+ "sql.js": "^1.14.1",
70
+ "yaml": "^2.9.0"
71
+ },
72
+ "devDependencies": {
73
+ "@types/node": "^22.10.0",
74
+ "tsup": "^8.3.5",
75
+ "tsx": "^4.19.2",
76
+ "typescript": "^5.7.2",
77
+ "vitest": "^2.1.8"
78
+ }
79
+ }