@ken-jo/agent-connector 0.3.0 → 0.4.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 (166) hide show
  1. package/README.md +188 -20
  2. package/dist/action-PLZW5BGX.js +54 -0
  3. package/dist/action-PLZW5BGX.js.map +1 -0
  4. package/dist/{amp-YGV66GJT.js → amp-B524U6LO.js} +81 -5
  5. package/dist/amp-B524U6LO.js.map +1 -0
  6. package/dist/{antigravity-7IBYFO6P.js → antigravity-ANDKF3K7.js} +4 -4
  7. package/dist/{antigravity-cli-JEOUP2VN.js → antigravity-cli-LLRPDDOT.js} +4 -4
  8. package/dist/chunk-22Y24V7O.js +21 -0
  9. package/dist/chunk-22Y24V7O.js.map +1 -0
  10. package/dist/chunk-3PFFTFCU.js +190 -0
  11. package/dist/chunk-3PFFTFCU.js.map +1 -0
  12. package/dist/{chunk-SCVBYSF7.js → chunk-6XHB6BE3.js} +1 -1
  13. package/dist/chunk-76FUSVIA.js +43 -0
  14. package/dist/chunk-76FUSVIA.js.map +1 -0
  15. package/dist/{chunk-GSGDG2BV.js → chunk-ADTHT2FN.js} +109 -16
  16. package/dist/chunk-ADTHT2FN.js.map +1 -0
  17. package/dist/{chunk-ZAM4M7LI.js → chunk-BHUCB6LY.js} +135 -296
  18. package/dist/chunk-BHUCB6LY.js.map +1 -0
  19. package/dist/{chunk-MEH7GC7R.js → chunk-BXGFUENQ.js} +20 -3
  20. package/dist/chunk-BXGFUENQ.js.map +1 -0
  21. package/dist/chunk-CIRDOY2V.js +351 -0
  22. package/dist/chunk-CIRDOY2V.js.map +1 -0
  23. package/dist/{chunk-QADSG2JY.js → chunk-G3ER4SY5.js} +1152 -106
  24. package/dist/chunk-G3ER4SY5.js.map +1 -0
  25. package/dist/{chunk-44HUXXC6.js → chunk-G5CQHVQG.js} +232 -5
  26. package/dist/chunk-G5CQHVQG.js.map +1 -0
  27. package/dist/{chunk-PD4VFEBY.js → chunk-IW77FFNX.js} +39 -1
  28. package/dist/chunk-IW77FFNX.js.map +1 -0
  29. package/dist/chunk-J3D5W5T2.js +83 -0
  30. package/dist/chunk-J3D5W5T2.js.map +1 -0
  31. package/dist/{openclaw-UZ5BMCGQ.js → chunk-KGGBNKI4.js} +125 -33
  32. package/dist/chunk-KGGBNKI4.js.map +1 -0
  33. package/dist/{chunk-3JCRUROU.js → chunk-KGJWE6A2.js} +13 -4
  34. package/dist/chunk-KGJWE6A2.js.map +1 -0
  35. package/dist/{chunk-DS3LUFVN.js → chunk-KGXDYGNJ.js} +26 -16
  36. package/dist/chunk-KGXDYGNJ.js.map +1 -0
  37. package/dist/{chunk-KVAAFYRR.js → chunk-KHO5WNTP.js} +2 -18
  38. package/dist/chunk-KHO5WNTP.js.map +1 -0
  39. package/dist/{chunk-KQSNDFBN.js → chunk-LL4OBGRU.js} +3 -3
  40. package/dist/{chunk-WNREHWKL.js → chunk-MAH6QQTO.js} +3 -3
  41. package/dist/{claude-code-4275HQU4.js → claude-code-MLWS7CW6.js} +180 -28
  42. package/dist/claude-code-MLWS7CW6.js.map +1 -0
  43. package/dist/cli/sdk.js +4 -3
  44. package/dist/cli/sdk.js.map +1 -1
  45. package/dist/cli.js +1 -1
  46. package/dist/{codebuff-LE3KBZGM.js → codebuff-SH2S3QAN.js} +102 -5
  47. package/dist/codebuff-SH2S3QAN.js.map +1 -0
  48. package/dist/{codex-4BY2ZJIW.js → codex-BXA4FIF4.js} +3 -3
  49. package/dist/{copilot-cli-IPISKO3V.js → copilot-cli-ROIBTTDT.js} +3 -3
  50. package/dist/{crush-X3E25EQG.js → crush-QLEFLHUC.js} +3 -3
  51. package/dist/{cursor-UH3W622V.js → cursor-ASJPWZ4R.js} +6 -3
  52. package/dist/cursor-ASJPWZ4R.js.map +1 -0
  53. package/dist/{detect-MNDHGLSV.js → detect-ZIIS55LD.js} +4 -3
  54. package/dist/{detect-MNDHGLSV.js.map → detect-ZIIS55LD.js.map} +1 -1
  55. package/dist/{doctor-N5KZDD55.js → doctor-TJUGSQ5C.js} +17 -13
  56. package/dist/doctor-TJUGSQ5C.js.map +1 -0
  57. package/dist/{droid-T5VBRXZF.js → droid-NCSS3B5Y.js} +170 -4
  58. package/dist/droid-NCSS3B5Y.js.map +1 -0
  59. package/dist/{gemini-cli-ZSUK55UA.js → gemini-cli-SLVWLXJW.js} +3 -3
  60. package/dist/{goose-M3RR3CZG.js → goose-PBA7KTE5.js} +100 -5
  61. package/dist/goose-PBA7KTE5.js.map +1 -0
  62. package/dist/{hermes-CUNKIAR5.js → hermes-ONDCECP2.js} +3 -3
  63. package/dist/{hook-7LUOKIXH.js → hook-OU522ABV.js} +12 -9
  64. package/dist/{hook-7LUOKIXH.js.map → hook-OU522ABV.js.map} +1 -1
  65. package/dist/index.d.ts +71 -3
  66. package/dist/index.js +22 -3
  67. package/dist/{install-TQTT4F3I.js → install-UDCBL7HP.js} +12 -10
  68. package/dist/{install-TQTT4F3I.js.map → install-UDCBL7HP.js.map} +1 -1
  69. package/dist/introspect-DuZSPSHB.d.ts +53 -0
  70. package/dist/{jetbrains-copilot-C3HDGGML.js → jetbrains-copilot-YABZ3HFA.js} +3 -3
  71. package/dist/{kilo-PKAJCWPX.js → kilo-F3ZDZKCT.js} +3 -3
  72. package/dist/{kilo-cli-QWUVXG2O.js → kilo-cli-3HWPWBY4.js} +3 -3
  73. package/dist/{kimi-EVD7YKXS.js → kimi-NV72FVAO.js} +3 -3
  74. package/dist/{kiro-UQRY6EIO.js → kiro-C5W6AGDR.js} +3 -3
  75. package/dist/{leaderboard-MUJ7DURM.js → leaderboard-TIBVONVT.js} +3 -3
  76. package/dist/mimo-code-IMM5YM3M.js +754 -0
  77. package/dist/mimo-code-IMM5YM3M.js.map +1 -0
  78. package/dist/{mux-5CI5FP2W.js → mux-DSSH4AFS.js} +3 -3
  79. package/dist/nemoclaw-3EVNKD3I.js +58 -0
  80. package/dist/nemoclaw-3EVNKD3I.js.map +1 -0
  81. package/dist/{omp-AXA7XY22.js → omp-Z6FRNDPN.js} +3 -3
  82. package/dist/openclaw-7G437NT7.js +18 -0
  83. package/dist/openclaw-7G437NT7.js.map +1 -0
  84. package/dist/{opencode-NZBRLJN3.js → opencode-Q6KBSAKW.js} +3 -3
  85. package/dist/{package-SYPA5POO.js → package-RMPN57YZ.js} +7 -6
  86. package/dist/{package-SYPA5POO.js.map → package-RMPN57YZ.js.map} +1 -1
  87. package/dist/{pi-WMTUX6ES.js → pi-LZT6WWAZ.js} +2 -2
  88. package/dist/{qwen-code-MRRIUQ3P.js → qwen-code-WQBKRPWJ.js} +3 -3
  89. package/dist/{roo-code-NI5UU6JB.js → roo-code-GWSNU3OW.js} +137 -4
  90. package/dist/roo-code-GWSNU3OW.js.map +1 -0
  91. package/dist/runtime/index.d.ts +96 -2
  92. package/dist/runtime/index.js +18 -10
  93. package/dist/sdk/index.d.ts +52 -0
  94. package/dist/sdk/index.js +81 -0
  95. package/dist/sdk/index.js.map +1 -0
  96. package/dist/sdk/test.d.ts +74 -0
  97. package/dist/sdk/test.js +291 -0
  98. package/dist/sdk/test.js.map +1 -0
  99. package/dist/{serve-XJOSA7BY.js → serve-D3GO36UT.js} +12 -9
  100. package/dist/{serve-XJOSA7BY.js.map → serve-D3GO36UT.js.map} +1 -1
  101. package/dist/{status-DYSS6BOR.js → status-KOSKCETC.js} +10 -8
  102. package/dist/{status-DYSS6BOR.js.map → status-KOSKCETC.js.map} +1 -1
  103. package/dist/statusline-ZNTCL5YC.js +59 -0
  104. package/dist/statusline-ZNTCL5YC.js.map +1 -0
  105. package/dist/{telemetry-IJ4GP2Q3.js → telemetry-XIKUUGTQ.js} +5 -4
  106. package/dist/{telemetry-IJ4GP2Q3.js.map → telemetry-XIKUUGTQ.js.map} +1 -1
  107. package/dist/{trae-CQC72RHH.js → trae-NWT3TMSZ.js} +99 -5
  108. package/dist/trae-NWT3TMSZ.js.map +1 -0
  109. package/dist/{types-CNigfEuR.d.ts → types-BEKsAium.d.ts} +268 -6
  110. package/dist/{uninstall-3DXIBRCV.js → uninstall-2LBLQVFA.js} +12 -10
  111. package/dist/{uninstall-3DXIBRCV.js.map → uninstall-2LBLQVFA.js.map} +1 -1
  112. package/dist/{upgrade-GJEB3ITY.js → upgrade-ZC2S7VRN.js} +12 -10
  113. package/dist/{upgrade-GJEB3ITY.js.map → upgrade-ZC2S7VRN.js.map} +1 -1
  114. package/dist/{usage-2BJLM3GJ.js → usage-E2A4O2CY.js} +3 -3
  115. package/dist/{usage-event-472X3DOY.js → usage-event-JKMC4QC4.js} +11 -8
  116. package/dist/{usage-event-472X3DOY.js.map → usage-event-JKMC4QC4.js.map} +1 -1
  117. package/dist/{vscode-copilot-4RVRTCKV.js → vscode-copilot-ALV45XF6.js} +3 -3
  118. package/dist/{warp-X6MB67NT.js → warp-H6IX4U3J.js} +3 -3
  119. package/dist/{zed-NTCYW4V2.js → zed-RH34TNSW.js} +3 -3
  120. package/package.json +9 -1
  121. package/dist/amp-YGV66GJT.js.map +0 -1
  122. package/dist/chunk-3JCRUROU.js.map +0 -1
  123. package/dist/chunk-44HUXXC6.js.map +0 -1
  124. package/dist/chunk-DS3LUFVN.js.map +0 -1
  125. package/dist/chunk-GSGDG2BV.js.map +0 -1
  126. package/dist/chunk-KVAAFYRR.js.map +0 -1
  127. package/dist/chunk-MEH7GC7R.js.map +0 -1
  128. package/dist/chunk-NJU275US.js +0 -238
  129. package/dist/chunk-NJU275US.js.map +0 -1
  130. package/dist/chunk-PD4VFEBY.js.map +0 -1
  131. package/dist/chunk-QADSG2JY.js.map +0 -1
  132. package/dist/chunk-ZAM4M7LI.js.map +0 -1
  133. package/dist/claude-code-4275HQU4.js.map +0 -1
  134. package/dist/codebuff-LE3KBZGM.js.map +0 -1
  135. package/dist/cursor-UH3W622V.js.map +0 -1
  136. package/dist/doctor-N5KZDD55.js.map +0 -1
  137. package/dist/droid-T5VBRXZF.js.map +0 -1
  138. package/dist/goose-M3RR3CZG.js.map +0 -1
  139. package/dist/openclaw-UZ5BMCGQ.js.map +0 -1
  140. package/dist/roo-code-NI5UU6JB.js.map +0 -1
  141. package/dist/trae-CQC72RHH.js.map +0 -1
  142. /package/dist/{antigravity-7IBYFO6P.js.map → antigravity-ANDKF3K7.js.map} +0 -0
  143. /package/dist/{antigravity-cli-JEOUP2VN.js.map → antigravity-cli-LLRPDDOT.js.map} +0 -0
  144. /package/dist/{chunk-SCVBYSF7.js.map → chunk-6XHB6BE3.js.map} +0 -0
  145. /package/dist/{chunk-KQSNDFBN.js.map → chunk-LL4OBGRU.js.map} +0 -0
  146. /package/dist/{chunk-WNREHWKL.js.map → chunk-MAH6QQTO.js.map} +0 -0
  147. /package/dist/{codex-4BY2ZJIW.js.map → codex-BXA4FIF4.js.map} +0 -0
  148. /package/dist/{copilot-cli-IPISKO3V.js.map → copilot-cli-ROIBTTDT.js.map} +0 -0
  149. /package/dist/{crush-X3E25EQG.js.map → crush-QLEFLHUC.js.map} +0 -0
  150. /package/dist/{gemini-cli-ZSUK55UA.js.map → gemini-cli-SLVWLXJW.js.map} +0 -0
  151. /package/dist/{hermes-CUNKIAR5.js.map → hermes-ONDCECP2.js.map} +0 -0
  152. /package/dist/{jetbrains-copilot-C3HDGGML.js.map → jetbrains-copilot-YABZ3HFA.js.map} +0 -0
  153. /package/dist/{kilo-PKAJCWPX.js.map → kilo-F3ZDZKCT.js.map} +0 -0
  154. /package/dist/{kilo-cli-QWUVXG2O.js.map → kilo-cli-3HWPWBY4.js.map} +0 -0
  155. /package/dist/{kimi-EVD7YKXS.js.map → kimi-NV72FVAO.js.map} +0 -0
  156. /package/dist/{kiro-UQRY6EIO.js.map → kiro-C5W6AGDR.js.map} +0 -0
  157. /package/dist/{leaderboard-MUJ7DURM.js.map → leaderboard-TIBVONVT.js.map} +0 -0
  158. /package/dist/{mux-5CI5FP2W.js.map → mux-DSSH4AFS.js.map} +0 -0
  159. /package/dist/{omp-AXA7XY22.js.map → omp-Z6FRNDPN.js.map} +0 -0
  160. /package/dist/{opencode-NZBRLJN3.js.map → opencode-Q6KBSAKW.js.map} +0 -0
  161. /package/dist/{pi-WMTUX6ES.js.map → pi-LZT6WWAZ.js.map} +0 -0
  162. /package/dist/{qwen-code-MRRIUQ3P.js.map → qwen-code-WQBKRPWJ.js.map} +0 -0
  163. /package/dist/{usage-2BJLM3GJ.js.map → usage-E2A4O2CY.js.map} +0 -0
  164. /package/dist/{vscode-copilot-4RVRTCKV.js.map → vscode-copilot-ALV45XF6.js.map} +0 -0
  165. /package/dist/{warp-X6MB67NT.js.map → warp-H6IX4U3J.js.map} +0 -0
  166. /package/dist/{zed-NTCYW4V2.js.map → zed-RH34TNSW.js.map} +0 -0
package/README.md CHANGED
@@ -8,13 +8,13 @@
8
8
 
9
9
  [![npm](https://img.shields.io/npm/v/@ken-jo/agent-connector?color=cb3837&logo=npm)](https://www.npmjs.com/package/@ken-jo/agent-connector)
10
10
  [![license](https://img.shields.io/npm/l/@ken-jo/agent-connector?color=22c55e)](LICENSE)
11
- ![platforms](https://img.shields.io/badge/platforms-29-2563eb)
12
- ![surfaces](https://img.shields.io/badge/surfaces-MCP%20%7C%20hooks%20%7C%20commands%20%7C%20tools%20%7C%20memory-2563eb)
11
+ ![platforms](https://img.shields.io/badge/platforms-31-2563eb)
12
+ ![surfaces](https://img.shields.io/badge/surfaces-MCP%20%7C%20hooks%20%7C%20commands%20%7C%20tools%20%7C%20memory%20%7C%20status%20line-2563eb)
13
13
  ![hook paradigms](https://img.shields.io/badge/hook%20paradigms-3-2563eb)
14
14
  ![install verified](https://img.shields.io/badge/install%20verified-29%2F29-22c55e)
15
15
  ![headless runtime](https://img.shields.io/badge/headless%20runtime-10%20CLIs%20activated-22c55e)
16
16
  ![marketplace](https://img.shields.io/badge/package-9%20marketplace%20formats-2563eb)
17
- ![tests](https://img.shields.io/badge/tests-1438%20passing-22c55e)
17
+ ![tests](https://img.shields.io/badge/tests-1727%20passing-22c55e)
18
18
 
19
19
  ## Who this is for
20
20
 
@@ -57,14 +57,14 @@ agent-connector is the middleware that does it for you:
57
57
  registered but **not wrapped** (the proxy cannot intercept remote transports),
58
58
  so they yield no per-tool telemetry.
59
59
 
60
- > Status: **29 platforms, all 3 hook paradigms** (exceeds the
60
+ > Status: **31 platforms, all 3 hook paradigms** (exceeds the
61
61
  > [tokscale](https://github.com/junhoyeo/tokscale) token-leaderboard coverage).
62
62
  >
63
63
  > | Paradigm | Platforms |
64
64
  > |---|---|
65
65
  > | `json-stdio` (full hook dispatch) | Claude Code · Codex CLI · Cursor · VS Code Copilot · JetBrains Copilot · GitHub Copilot CLI · Gemini CLI · Qwen CLI · Kiro · Kimi CLI · Crush · Goose · Hermes · Droid (Factory) · Antigravity · Antigravity CLI |
66
66
  > | `mcp-only` (MCP registration only) | Warp · Kilo · Roo Code · Trae · Zed · Amp · Codebuff · Mux · Pi |
67
- > | `ts-plugin` (generated bridge module) | OpenCode · Kilo CLI · OMP · OpenClaw |
67
+ > | `ts-plugin` (generated bridge module) | OpenCode · MiMoCode · Kilo CLI · Kilo · OMP · NemoClaw · OpenClaw |
68
68
  >
69
69
  > …plus the telemetry core. Adding a platform = **one registry entry + one
70
70
  > adapter**. (Google Antigravity is now fully supported, including the `agy` CLI,
@@ -72,10 +72,13 @@ agent-connector is the middleware that does it for you:
72
72
 
73
73
  ## Verification
74
74
 
75
- The full single-API contract is **install-verified across all 29 platforms**. A
75
+ The full single-API contract is **install-verified across the platform set**. A
76
76
  sample connector declaring **all four launch surfaces** — MCP server **+**
77
77
  lifecycle hooks **+** slash commands **+** tools (skills + subagents) — was
78
- installed into an isolated environment for every adapter and inspected on disk:
78
+ installed into an isolated environment for every adapter and inspected on disk
79
+ (the 29-platform full sweep below; the two newest adapters — MiMoCode and
80
+ NemoClaw — were added with a focused isolated-HOME install check landing the MCP
81
+ server in the right file + root key):
79
82
 
80
83
  - **29 / 29 platforms — zero missing, zero failed surfaces.** Each surface is
81
84
  written where the host supports it and gracefully *skip-warned* (never silently
@@ -102,7 +105,7 @@ installed into an isolated environment for every adapter and inspected on disk:
102
105
  - **Clean uninstall + `--purge`.** Every installed surface reverses; `--purge`
103
106
  deregisters the connector record and tears down the home binary when no
104
107
  connectors remain (29 / 29).
105
- - **1438 tests passing** · `tsc` clean · build green.
108
+ - **1727 tests passing** · `tsc` clean · build green.
106
109
 
107
110
  The 0.2.0 additions — the `memory` surface, the `nativeHooks` passthrough, and
108
111
  `configPatch` — went through the same bar: dogfooded against real connector
@@ -192,7 +195,7 @@ npx @ken-jo/agent-connector install
192
195
 
193
196
  > `install` targets only the hosts actually **detected** on this machine (or an
194
197
  > explicit `--targets` / `connector.targets` list), intersected with the
195
- > 29-adapter registry — there is no "install to all 29 unconditionally" path.
198
+ > 31-adapter registry — there is no "install to all 31 unconditionally" path.
196
199
 
197
200
  > **Optional convenience.** A global `npm i -g @ken-jo/agent-connector` is **not**
198
201
  > required for the flow above — `npx @ken-jo/agent-connector …` runs it straight from
@@ -254,6 +257,72 @@ acme-db`, `acme-db install` ≈ `agent-connector install --connector
254
257
  tools share that infrastructure. An explicit `--connector` / `--connector-id`
255
258
  always overrides the injected default.
256
259
 
260
+ ### Author + test offline — the Connector SDK (`/sdk`, `/sdk/test`)
261
+
262
+ ```ts
263
+ import { defineConnector, defineHook, hostsSupporting } from "@ken-jo/agent-connector/sdk";
264
+ import { simulate, explain } from "@ken-jo/agent-connector/sdk/test";
265
+ ```
266
+
267
+ `@ken-jo/agent-connector/sdk` is the consolidated **authoring** surface — it
268
+ re-exports `defineConnector`, the full `define*` family, the introspection
269
+ helpers, and public types from one import site (the root export is unchanged;
270
+ `/sdk` is additive).
271
+
272
+ **`define*` typed helpers** — each is a typed identity function (`(def) => def`)
273
+ that gives you per-surface type inference and a single import site:
274
+ `defineCommand`, `defineSkill`, `defineSubagent`, `defineMemory`,
275
+ `defineConfigPatch`, `defineNativeHook`. `defineHook` is event-parameterized
276
+ so the handler payload narrows to the concrete event type:
277
+
278
+ ```ts
279
+ const guard = defineHook("PreToolUse", {
280
+ handler(evt) {
281
+ // evt.toolName is typed as PreToolUseEvent — not the union
282
+ return evt.toolName === "acme_write"
283
+ ? { decision: "ask", reason: "Confirm write" }
284
+ : { decision: "allow" };
285
+ },
286
+ });
287
+ ```
288
+
289
+ **Introspection** (async — adapters load lazily):
290
+
291
+ - `hostsSupporting(surface)` → `Promise<PlatformId[]>` — which registered hosts
292
+ honor a surface (`"hooks"` | `"statusline"` | `"memory"` | …).
293
+ - `capabilitiesOf(host)` → `Promise<PlatformCapabilities | undefined>`.
294
+ - `surfaceSupport(host, surface)` → `Promise<boolean>` — convenience single-pair check.
295
+
296
+ **Offline harness** (`@ken-jo/agent-connector/sdk/test`) answers *"does my
297
+ handler / HUD actually work on host X?"* before you touch a real host:
298
+
299
+ - `explain(connector)` → `Promise<ExplainRow[]>` — the per-host × per-declared-surface
300
+ matrix. Each row is `{ host, surface, support: "native"|"skip-warn"|"disabled", reason }`.
301
+ Only surfaces the connector actually declares are included.
302
+ - `simulate(connector, { surface, host, event?, input })` → `Promise<{ honored, hostReply?, reason }>`
303
+ — runs the **real** adapter parse→handler→format chain offline and judges the
304
+ actual `(event, decision)` contract. It encodes each host's real honor / drop /
305
+ degrade quirks — not substring guessing:
306
+
307
+ ```ts
308
+ // Does codex honor a context injection on UserPromptSubmit?
309
+ const result = await simulate(connector, {
310
+ surface: "hooks",
311
+ host: "codex",
312
+ event: "UserPromptSubmit",
313
+ input: { hookEventName: "UserPromptSubmit", prompt: "explain this" },
314
+ });
315
+ // → { honored: false, reason: "drops context on UserPromptSubmit (no stdout path)" }
316
+ ```
317
+
318
+ > Other verdicts the harness encodes: a `deny` on `Stop`/`SubagentStop` is
319
+ > continuation/persistence → `honored:true` (reason explains); `deny` on
320
+ > `SubagentStart`/`PostToolUseFailure` degrades to a context note →
321
+ > `honored:false`; a PermissionRequest `ask` is honored by the host's native
322
+ > dialog → `honored:true`. Matcher-scoped handlers that don't match the input
323
+ > are not run. The harness mirrors the runtime exactly — tolerant stdin,
324
+ > matcher filtering, real verdict.
325
+
257
326
  ### Two ways to ship: direct install **or** a marketplace package
258
327
 
259
328
  Same one definition, your choice of distribution:
@@ -261,12 +330,16 @@ Same one definition, your choice of distribution:
261
330
  - **Direct install** (above) — `install` writes each host's native MCP + plugin/
262
331
  extension config in place; no per-platform marketplace submission or review.
263
332
  - **Marketplace install** — `install --method marketplace` drives the host's own
264
- plugin flow end-to-end for **Claude Code, codex, and agy/Antigravity** (stages
265
- the bundle, registers a local marketplace where the host has one, then runs the
266
- host's plugin-install verb; headless, idempotent verified live on Linux and
267
- native Windows). `uninstall --method auto` reverses whichever method is actually
268
- installed, a guard refuses installing the same connector by BOTH methods
269
- (duplicated hooks/servers), and `doctor` checks registration drift.
333
+ plugin flow end-to-end for **10 hosts**: Claude Code, Codex, OpenCode, Kilo
334
+ (CLI + ext), Antigravity (CLI + IDE) live-verified on Linux, Windows, and
335
+ macOS plus Droid and Qwen Code (driver shipped, pending a live host) and
336
+ Gemini CLI (legacy sunsetting toward Antigravity; driver kept for existing
337
+ installs). It stages the bundle, registers a local marketplace where the host
338
+ has one, then runs the host's plugin-install verb (or, for npm-plugin hosts,
339
+ writes a local `file://` entry); headless and idempotent. `uninstall --method
340
+ auto` reverses whichever method is installed, a guard refuses installing the
341
+ same connector by BOTH methods, and `doctor` checks registration drift. Other
342
+ marketplace-format hosts print the exact manual commands.
270
343
  - **Marketplace package** — `agent-connector package` turns the connector into a
271
344
  marketplace/extension bundle (manifest + bundled commands, agents, skills,
272
345
  hooks, MCP) for **9 host formats** (plus 2 official MCP standard artifacts —
@@ -328,14 +401,16 @@ export default defineConnector({
328
401
  > Code only for now; other hosts skip-warn, never silently.
329
402
 
330
403
  > **Host-config key patches.** For host-exclusive *settings keys* no other
331
- > surface reaches (Claude Code's `statusLine`, an experimental `env.*` flag),
332
- > declare `platforms: { "claude-code": { configPatch: [{ key, value, reason }] } }`.
404
+ > surface reaches (e.g. an experimental `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`
405
+ > flag), declare `platforms: { "claude-code": { configPatch: [{ key, value, reason }] } }`.
333
406
  > Semantics are fixed: **set-if-absent + skip-warn on any conflict** — never
334
407
  > overwrite, never deep-merge. Ownership is refcounted in a persisted ledger, so
335
408
  > uninstall removes a key only when the last owning connector releases it and the
336
409
  > value is untouched; security-relevant keys (`permissions*`, `apiKey*`,
337
- > `env.ANTHROPIC_*`, token/secret env vars, …) are hard-refused. Claude Code only
338
- > for now; other hosts skip-warn with the exact manual edit.
410
+ > `env.ANTHROPIC_*`, token/secret env vars, …) are hard-refused, as are keys
411
+ > agent-connector models as first-class surfaces (`hooks*`, `mcpServers*`,
412
+ > `statusLine` → use the `statusline` surface instead). Claude Code only for now;
413
+ > other hosts skip-warn with the exact manual edit.
339
414
 
340
415
  `agent-connector install` turns that into, e.g.:
341
416
 
@@ -362,7 +437,7 @@ memory: [
362
437
  ```
363
438
 
364
439
  **Write the guidance once — it lands in the standard
365
- [AGENTS.md](https://agents.md) on 27 of the 29 hosts** (the open, Linux
440
+ [AGENTS.md](https://agents.md) on 29 of the 31 hosts** (the open, Linux
366
441
  Foundation-stewarded "README for agents" format): project scope targets
367
442
  `<projectDir>/AGENTS.md` — and where a host resolves its rules file
368
443
  exclusively, the target is *probed* so the block lands in the file the host
@@ -391,6 +466,99 @@ Uninstall excises exactly your blocks and `doctor` verifies them (present /
391
466
  hash-intact / user-edited / file missing). Hosts with no writable memory file at
392
467
  a scope skip-warn, never silently.
393
468
 
469
+ ### Status line (`statusline`) — live HUD per connector
470
+
471
+ Ship a render function that the host calls on every status refresh:
472
+
473
+ ```ts
474
+ import { defineConnector, defineStatusline } from "@ken-jo/agent-connector";
475
+
476
+ export default defineConnector({
477
+ id: "acme-db",
478
+ // ...
479
+ statusline: defineStatusline({
480
+ render(ctx) {
481
+ const model = ctx.model?.displayName ?? ctx.model?.id ?? "unknown";
482
+ return `acme-db · ${model} · $${(ctx.cost?.totalUsd ?? 0).toFixed(4)}`;
483
+ },
484
+ }),
485
+ });
486
+ ```
487
+
488
+ `StatuslineContext` provides (where the host supplies them) `host`,
489
+ `connectorId`, `sessionId`, `cwd`, `model` (`id` / `displayName`),
490
+ `cost` (`totalUsd`), `context` (`usedTokens` / `maxTokens` / `percent`),
491
+ `transcriptPath`, and `raw` (the host's verbatim payload). Fields the host
492
+ does not provide are `undefined`.
493
+
494
+ > **`ctx.context` is reserved** — `context.usedTokens` / `maxTokens` / `percent`
495
+ > are declared in `StatuslineContext` for a future AC-usage integration but are
496
+ > **not populated by any v1 code path**. Rendering `ctx.context?.percent ?? 0`
497
+ > always produces `0%`. Use `ctx.cost?.totalUsd` and `ctx.model?.displayName`
498
+ > (both populated by claude-code) instead.
499
+
500
+ **v1: claude-code only.** Install registers `settings.json.statusLine` via the
501
+ same configPatch ownership ledger — **set-if-absent, never clobbers a
502
+ `statusLine` agent-connector doesn't own** (skip-warns and prints the manual
503
+ edit instead), refcounted, reversible. Every other host adapter skip-warns at
504
+ install time, never silently. The runtime is **fail-safe**: any error — a
505
+ throwing `render`, unknown connector, malformed stdin — exits 0 with empty
506
+ stdout so a HUD never wedges the host. `doctor` includes a dedicated
507
+ `statusline wired` check.
508
+
509
+ > `defineStatusline` is a typed identity helper and is optional — you can
510
+ > pass the `{ render }` object directly to `statusline:`. Both
511
+ > `StatuslineDef` and `StatuslineContext` are exported from
512
+ > `@ken-jo/agent-connector`.
513
+
514
+ ### Actions (`defineAction`) — user-triggered dispatch
515
+
516
+ Declare named, user-invocable operations on your connector:
517
+
518
+ ```ts
519
+ import { defineConnector, defineAction } from "@ken-jo/agent-connector";
520
+
521
+ export default defineConnector({
522
+ id: "acme-db",
523
+ // ...
524
+ actions: [
525
+ defineAction({
526
+ id: "flush-cache",
527
+ description: "Flush the acme-db query cache",
528
+ async run(ctx) {
529
+ // ctx is HostCtx — same context object as hooks
530
+ await flushCache();
531
+ return { message: "Cache flushed." };
532
+ },
533
+ }),
534
+ ],
535
+ });
536
+ ```
537
+
538
+ The **universal verb** runs any declared action from the shell (or from a
539
+ script / IDE task):
540
+
541
+ ```bash
542
+ agent-connector action <platform> flush-cache --connector acme-db
543
+ ```
544
+
545
+ `run(ctx)` executes and its optional `{ message }` return is printed to
546
+ stdout. **Error semantics are user-triggered**: an unknown action id or a
547
+ throw exits 1 and writes to stderr (unlike hooks and statusline, which are
548
+ fail-safe/silent on error).
549
+
550
+ `defineAction` is a typed identity helper and is exported from both
551
+ `@ken-jo/agent-connector` and `@ken-jo/agent-connector/sdk`.
552
+ `ActionDef = { id, description?, run, hosts? }` and `ActionResult = { message? }`.
553
+
554
+ **v1: dispatch backbone only.** `install` skip-warns on every host — there
555
+ is no host affordance emitter yet (binding a slash-command or keybinding to
556
+ the verb requires generated IDE extensions, a later phase). The `action`
557
+ verb is fully functional today; host-side registration is deferred.
558
+ `explain()` emits action rows (skip-warn everywhere in v1); `simulate()`
559
+ does not cover actions (actions take no host payload and have no host-honor
560
+ verdict — intentional).
561
+
394
562
  ## How it works (operating model)
395
563
 
396
564
  - **Home-dir, single binary.** The runtime installs once under
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ fail
4
+ } from "./chunk-KGXDYGNJ.js";
5
+ import {
6
+ runAction
7
+ } from "./chunk-BHUCB6LY.js";
8
+ import "./chunk-OP4KBXUO.js";
9
+ import "./chunk-22Y24V7O.js";
10
+ import "./chunk-J3D5W5T2.js";
11
+ import "./chunk-CIRDOY2V.js";
12
+ import "./chunk-BCHWFTV4.js";
13
+ import "./chunk-KHO5WNTP.js";
14
+ import "./chunk-KGJWE6A2.js";
15
+ import "./chunk-ADTHT2FN.js";
16
+ import "./chunk-3PFFTFCU.js";
17
+ import "./chunk-BXGFUENQ.js";
18
+ import "./chunk-N6HH7K6P.js";
19
+ import "./chunk-TRQKHP7D.js";
20
+
21
+ // src/cli/commands/action.ts
22
+ import { parseArgs } from "util";
23
+ async function run(argv) {
24
+ const { values, positionals } = parseArgs({
25
+ args: argv,
26
+ options: {
27
+ connector: { type: "string" }
28
+ },
29
+ allowPositionals: true
30
+ });
31
+ const platformId = positionals[0];
32
+ const actionId = positionals[1];
33
+ if (!platformId || !actionId) {
34
+ return fail("usage: agent-connector action <platform> <actionId> --connector <id>");
35
+ }
36
+ const connectorId = values.connector;
37
+ if (!connectorId || connectorId.trim() === "") {
38
+ return fail("action requires --connector <id>");
39
+ }
40
+ const reply = await runAction({ platformId, actionId, connectorId });
41
+ if (reply.stdout !== void 0 && reply.stdout !== "") {
42
+ process.stdout.write(reply.stdout.endsWith("\n") ? reply.stdout : `${reply.stdout}
43
+ `);
44
+ }
45
+ if (reply.stderr !== void 0 && reply.stderr !== "") {
46
+ process.stderr.write(reply.stderr.endsWith("\n") ? reply.stderr : `${reply.stderr}
47
+ `);
48
+ }
49
+ process.exit(reply.exitCode);
50
+ }
51
+ export {
52
+ run
53
+ };
54
+ //# sourceMappingURL=action-PLZW5BGX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/action.ts"],"sourcesContent":["/**\n * cli/commands/action — the universal user-invokable action entrypoint.\n *\n * agent-connector action <platform> <actionId> --connector <id>\n *\n * A future host affordance (slash command / keybinding) points at the single\n * stable home binary (via core/spawn.buildHomeBinActionCommand). This command\n * parses the positionals + --connector, dispatches through runAction, writes any\n * stdout/stderr the action produced, and exits with its code. It reads NO stdin\n * (an action takes no host payload, unlike a hook or status line).\n *\n * USER-TRIGGERED is the runtime's contract: unlike the fail-open hook command,\n * an unknown action id or a throwing run surfaces as exit 1 + a stderr message —\n * the user invoked it deliberately, so the failure is shown, never swallowed.\n */\n\nimport { parseArgs } from \"node:util\";\n\nimport { runAction } from \"../../runtime/index.js\";\nimport { fail } from \"../app.js\";\n\nexport async function run(argv: string[]): Promise<number> {\n const { values, positionals } = parseArgs({\n args: argv,\n options: {\n connector: { type: \"string\" },\n },\n allowPositionals: true,\n });\n\n const platformId = positionals[0];\n const actionId = positionals[1];\n if (!platformId || !actionId) {\n return fail(\"usage: agent-connector action <platform> <actionId> --connector <id>\");\n }\n const connectorId = values.connector;\n if (!connectorId || connectorId.trim() === \"\") {\n return fail(\"action requires --connector <id>\");\n }\n\n const reply = await runAction({ platformId, actionId, connectorId });\n if (reply.stdout !== undefined && reply.stdout !== \"\") {\n process.stdout.write(reply.stdout.endsWith(\"\\n\") ? reply.stdout : `${reply.stdout}\\n`);\n }\n if (reply.stderr !== undefined && reply.stderr !== \"\") {\n process.stderr.write(reply.stderr.endsWith(\"\\n\") ? reply.stderr : `${reply.stderr}\\n`);\n }\n process.exit(reply.exitCode);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgBA,SAAS,iBAAiB;AAK1B,eAAsB,IAAI,MAAiC;AACzD,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,MAAM;AAAA,IACN,SAAS;AAAA,MACP,WAAW,EAAE,MAAM,SAAS;AAAA,IAC9B;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,YAAY,CAAC;AAChC,QAAM,WAAW,YAAY,CAAC;AAC9B,MAAI,CAAC,cAAc,CAAC,UAAU;AAC5B,WAAO,KAAK,sEAAsE;AAAA,EACpF;AACA,QAAM,cAAc,OAAO;AAC3B,MAAI,CAAC,eAAe,YAAY,KAAK,MAAM,IAAI;AAC7C,WAAO,KAAK,kCAAkC;AAAA,EAChD;AAEA,QAAM,QAAQ,MAAM,UAAU,EAAE,YAAY,UAAU,YAAY,CAAC;AACnE,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AACA,MAAI,MAAM,WAAW,UAAa,MAAM,WAAW,IAAI;AACrD,YAAQ,OAAO,MAAM,MAAM,OAAO,SAAS,IAAI,IAAI,MAAM,SAAS,GAAG,MAAM,MAAM;AAAA,CAAI;AAAA,EACvF;AACA,UAAQ,KAAK,MAAM,QAAQ;AAC7B;","names":[]}
@@ -4,13 +4,15 @@ import {
4
4
  } from "./chunk-DBQMX75U.js";
5
5
  import {
6
6
  BaseAdapter
7
- } from "./chunk-PD4VFEBY.js";
8
- import "./chunk-7L6ITC4T.js";
7
+ } from "./chunk-IW77FFNX.js";
8
+ import {
9
+ renderSkillMd
10
+ } from "./chunk-7L6ITC4T.js";
9
11
  import {
10
12
  buildServeWrapperCommand,
11
13
  isHomeBinHookCommand,
12
14
  shouldWrapForTelemetry
13
- } from "./chunk-MEH7GC7R.js";
15
+ } from "./chunk-BXGFUENQ.js";
14
16
  import "./chunk-N6HH7K6P.js";
15
17
  import "./chunk-TRQKHP7D.js";
16
18
 
@@ -41,7 +43,11 @@ var AmpAdapter = class extends BaseAdapter {
41
43
  canModifyOutput: false,
42
44
  canInjectSessionContext: false,
43
45
  // Amp registers stdio and Streamable HTTP MCP servers.
44
- transports: ["stdio", "http"]
46
+ transports: ["stdio", "http"],
47
+ // Skills: Amp reads SKILL.md from ~/.config/agents/skills/<name>/SKILL.md
48
+ // (user) and <projectDir>/.agents/skills/<name>/SKILL.md (project) — a root
49
+ // OUTSIDE the config dir, so the skillDir() helper resolves it explicitly.
50
+ supportsSkills: true
45
51
  };
46
52
  // ── Detection ────────────────────────────────────────────────────────────
47
53
  detectInstalled(projectDir) {
@@ -150,6 +156,76 @@ var AmpAdapter = class extends BaseAdapter {
150
156
  rewrite(value) {
151
157
  return rewriteEnvRefs(value, ampEnvToken);
152
158
  }
159
+ // ── Skills surface ───────────────────────────────────────────────────────
160
+ // CONTENT-ONLY: pure native-file writers under the skill root. No runtime
161
+ // dispatch, no home-bin pointer, no telemetry wrap. Idempotent (byte-identical
162
+ // → skip) via writeContentFile and reversible via removeContentFile. Honors
163
+ // platforms["amp"].skills === false to skip.
164
+ //
165
+ // QUIRK: the skill root is NOT under getConfigDir (~/.config/amp). Amp reads
166
+ // SKILL.md from the sibling cross-agent `agents` tree:
167
+ // user scope → ~/.config/agents/skills/<name>/SKILL.md
168
+ // project scope → <projectDir>/.agents/skills/<name>/SKILL.md
169
+ // so skillDir() resolves it explicitly rather than reusing getConfigDir.
170
+ /** Skill root: user `~/.config/agents/skills`, project `<projectDir>/.agents/skills`. */
171
+ skillsDir(ctx) {
172
+ return ctx.scope === "project" ? join(ctx.projectDir, ".agents", "skills") : join(homedir(), ".config", "agents", "skills");
173
+ }
174
+ /** Native skill dir: <skillRoot>/<name>. */
175
+ skillDir(ctx, name) {
176
+ return join(this.skillsDir(ctx), name);
177
+ }
178
+ installSkills(ctx) {
179
+ const { connector } = ctx;
180
+ if (connector.platforms[HOST]?.skills === false) {
181
+ return [{ platform: this.id, action: "skip", detail: "skills disabled for amp" }];
182
+ }
183
+ if (connector.skills.length === 0) {
184
+ return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
185
+ }
186
+ const changes = [];
187
+ for (const skill of connector.skills) {
188
+ const dir = this.skillDir(ctx, skill.name);
189
+ changes.push(
190
+ this.writeContentFile(join(dir, "SKILL.md"), this.renderSkill(skill), ctx.dryRun)
191
+ );
192
+ for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
193
+ const target = this.resolveWithin(dir, rel);
194
+ if (target === null) {
195
+ changes.push({
196
+ platform: this.id,
197
+ action: "warn",
198
+ detail: `skill resource "${rel}" escapes the skill dir; skipped`
199
+ });
200
+ continue;
201
+ }
202
+ changes.push(this.writeContentFile(target, contents, ctx.dryRun));
203
+ }
204
+ }
205
+ return changes;
206
+ }
207
+ uninstallSkills(ctx) {
208
+ const { connector } = ctx;
209
+ if (connector.skills.length === 0) {
210
+ return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
211
+ }
212
+ const changes = [];
213
+ for (const skill of connector.skills) {
214
+ const dir = this.skillDir(ctx, skill.name);
215
+ changes.push(this.removeContentFile(join(dir, "SKILL.md"), ctx.dryRun));
216
+ for (const rel of Object.keys(skill.resources ?? {})) {
217
+ const target = this.resolveWithin(dir, rel);
218
+ if (target === null) continue;
219
+ changes.push(this.removeContentFile(target, ctx.dryRun));
220
+ }
221
+ changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));
222
+ }
223
+ return changes;
224
+ }
225
+ /** Render a skill's SKILL.md (delegates to the shared renderer). */
226
+ renderSkill(skill) {
227
+ return renderSkillMd(skill);
228
+ }
153
229
  // ── Hooks (unavailable — Amp is mcp-only) ────────────────────────────────
154
230
  installHooks(_ctx) {
155
231
  return [
@@ -221,4 +297,4 @@ export {
221
297
  adapter,
222
298
  amp_default as default
223
299
  };
224
- //# sourceMappingURL=amp-YGV66GJT.js.map
300
+ //# sourceMappingURL=amp-B524U6LO.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 * Skills surface: Amp reads SKILL.md files (dir-per-skill, same shape as\n * claude-code) from a skill root that is NOT under the config dir\n * (`~/.config/amp`):\n * - user scope → ~/.config/agents/skills/<name>/SKILL.md (the sibling\n * cross-agent `agents` dir — `~/.config/amp/skills/` is also documented-native,\n * but the `agents` root is the cross-agent standard we standardize on)\n * - project scope → <projectDir>/.agents/skills/<name>/SKILL.md\n * Because that root differs from getConfigDir, skills use a dedicated skillDir()\n * helper rather than reusing getConfigDir.\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 SkillDef,\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\";\nimport { renderSkillMd } from \"../claude-code/render.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 // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\n supportsMemory: true,\n // 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 // Skills: Amp reads SKILL.md from ~/.config/agents/skills/<name>/SKILL.md\n // (user) and <projectDir>/.agents/skills/<name>/SKILL.md (project) — a root\n // OUTSIDE the config dir, so the skillDir() helper resolves it explicitly.\n supportsSkills: true,\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 // ── Skills surface ───────────────────────────────────────────────────────\n // CONTENT-ONLY: pure native-file writers under the skill root. No runtime\n // dispatch, no home-bin pointer, no telemetry wrap. Idempotent (byte-identical\n // → skip) via writeContentFile and reversible via removeContentFile. Honors\n // platforms[\"amp\"].skills === false to skip.\n //\n // QUIRK: the skill root is NOT under getConfigDir (~/.config/amp). Amp reads\n // SKILL.md from the sibling cross-agent `agents` tree:\n // user scope → ~/.config/agents/skills/<name>/SKILL.md\n // project scope → <projectDir>/.agents/skills/<name>/SKILL.md\n // so skillDir() resolves it explicitly rather than reusing getConfigDir.\n\n /** Skill root: user `~/.config/agents/skills`, project `<projectDir>/.agents/skills`. */\n private skillsDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".agents\", \"skills\")\n : join(homedir(), \".config\", \"agents\", \"skills\");\n }\n\n /** Native skill dir: <skillRoot>/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for amp\" }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), this.renderSkill(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n /** Render a skill's SKILL.md (delegates to the shared renderer). */\n private renderSkill(skill: SkillDef): string {\n return renderSkillMd(skill);\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 // Only assert what the connector declares: a server-less connector\n // never writes a server entry, so its absence is healthy.\n if (!ctx.connector.server) {\n return { status: \"OK\", detail: \"no MCP server declared\" };\n }\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(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"]}
@@ -3,11 +3,11 @@ import {
3
3
  AntigravityAdapter,
4
4
  adapter,
5
5
  antigravity_default
6
- } from "./chunk-KQSNDFBN.js";
6
+ } from "./chunk-LL4OBGRU.js";
7
7
  import "./chunk-DBQMX75U.js";
8
- import "./chunk-PD4VFEBY.js";
8
+ import "./chunk-IW77FFNX.js";
9
9
  import "./chunk-7L6ITC4T.js";
10
- import "./chunk-MEH7GC7R.js";
10
+ import "./chunk-BXGFUENQ.js";
11
11
  import "./chunk-N6HH7K6P.js";
12
12
  import "./chunk-TRQKHP7D.js";
13
13
  export {
@@ -15,4 +15,4 @@ export {
15
15
  adapter,
16
16
  antigravity_default as default
17
17
  };
18
- //# sourceMappingURL=antigravity-7IBYFO6P.js.map
18
+ //# sourceMappingURL=antigravity-ANDKF3K7.js.map
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  AntigravityAdapter
4
- } from "./chunk-KQSNDFBN.js";
4
+ } from "./chunk-LL4OBGRU.js";
5
5
  import "./chunk-DBQMX75U.js";
6
- import "./chunk-PD4VFEBY.js";
6
+ import "./chunk-IW77FFNX.js";
7
7
  import "./chunk-7L6ITC4T.js";
8
- import "./chunk-MEH7GC7R.js";
8
+ import "./chunk-BXGFUENQ.js";
9
9
  import "./chunk-N6HH7K6P.js";
10
10
  import "./chunk-TRQKHP7D.js";
11
11
 
@@ -84,4 +84,4 @@ export {
84
84
  adapter,
85
85
  antigravity_cli_default as default
86
86
  };
87
- //# sourceMappingURL=antigravity-cli-JEOUP2VN.js.map
87
+ //# sourceMappingURL=antigravity-cli-LLRPDDOT.js.map
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveSpawnCommand
4
+ } from "./chunk-BXGFUENQ.js";
5
+
6
+ // src/core/spawn-child.ts
7
+ import { spawn } from "child_process";
8
+ function winQuoteArg(s) {
9
+ return `"${s.replace(/"/g, '""')}"`;
10
+ }
11
+ function spawnChild(command, args, options) {
12
+ const resolved = resolveSpawnCommand(command);
13
+ if (!resolved.needsShell) return spawn(resolved.file, args, options);
14
+ const line = [resolved.file, ...args].map(winQuoteArg).join(" ");
15
+ return spawn(line, { ...options, shell: true });
16
+ }
17
+
18
+ export {
19
+ spawnChild
20
+ };
21
+ //# sourceMappingURL=chunk-22Y24V7O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/spawn-child.ts"],"sourcesContent":["/**\n * core/spawn-child — the cross-platform child_process.spawn wrapper.\n *\n * Kept SEPARATE from core/spawn.ts (pure string/path helpers, imported widely\n * and early) so that pulling in `node:child_process` here does not perturb the\n * module-eval order of test suites that vi.mock(\"node:child_process\").\n */\n\nimport { type ChildProcess, type SpawnOptions, spawn } from \"node:child_process\";\n\nimport { resolveSpawnCommand } from \"./spawn.js\";\n\n/**\n * Quote one token for a cmd.exe command line: wrap in double quotes, doubling any\n * embedded double quote. Sufficient for the paths / package names / flags we\n * spawn (connector config, not untrusted end-user input) — we intentionally do\n * not escape cmd metacharacters (& | ^ %), which never appear in those tokens.\n */\nfunction winQuoteArg(s: string): string {\n return `\"${s.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Cross-platform child spawn that fixes native-Windows package-runner launches.\n * Direct spawn on macOS/Linux. On win32 it routes through\n * {@link resolveSpawnCommand}; an `.exe` runs directly, while a `.cmd`/`.bat`\n * (npx.cmd, the agent-connector.cmd launcher) is launched via a SINGLE quoted\n * command line with `shell: true` — a string rather than an args array, which\n * Node requires for a batch file AND which avoids the DEP0190 deprecation that\n * `shell: true` + an args array triggers on Node ≥ 24.\n */\nexport function spawnChild(\n command: string,\n args: string[],\n options: SpawnOptions,\n): ChildProcess {\n const resolved = resolveSpawnCommand(command);\n if (!resolved.needsShell) return spawn(resolved.file, args, options);\n const line = [resolved.file, ...args].map(winQuoteArg).join(\" \");\n return spawn(line, { ...options, shell: true });\n}\n"],"mappings":";;;;;;AAQA,SAA+C,aAAa;AAU5D,SAAS,YAAY,GAAmB;AACtC,SAAO,IAAI,EAAE,QAAQ,MAAM,IAAI,CAAC;AAClC;AAWO,SAAS,WACd,SACA,MACA,SACc;AACd,QAAM,WAAW,oBAAoB,OAAO;AAC5C,MAAI,CAAC,SAAS,WAAY,QAAO,MAAM,SAAS,MAAM,MAAM,OAAO;AACnE,QAAM,OAAO,CAAC,SAAS,MAAM,GAAG,IAAI,EAAE,IAAI,WAAW,EAAE,KAAK,GAAG;AAC/D,SAAO,MAAM,MAAM,EAAE,GAAG,SAAS,OAAO,KAAK,CAAC;AAChD;","names":[]}