@ken-jo/agent-connector 0.4.1 → 0.4.7

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 (167) hide show
  1. package/README.md +2 -2
  2. package/dist/{action-WT7GVRCC.js → action-YCU53FNE.js} +8 -8
  3. package/dist/{amazon-q-COAL3764.js → amazon-q-W574ZX35.js} +2 -2
  4. package/dist/amp-JPBQJJVM.js +666 -0
  5. package/dist/amp-JPBQJJVM.js.map +1 -0
  6. package/dist/{antigravity-AMKKKHS4.js → antigravity-VK2Y3FGV.js} +3 -3
  7. package/dist/{antigravity-cli-XERXEH5W.js → antigravity-cli-D4PCCUG2.js} +3 -3
  8. package/dist/{chunk-DCKFYWGM.js → chunk-2F5QH3D4.js} +36 -36
  9. package/dist/{chunk-RIMVWCZY.js → chunk-6RYPUR6O.js} +5 -5
  10. package/dist/{chunk-QREL7LZJ.js → chunk-7ECYDK5T.js} +2 -2
  11. package/dist/{chunk-O5TWCIJN.js → chunk-CYOAH23F.js} +18 -18
  12. package/dist/{chunk-URHQMFB3.js → chunk-DT6Y7XBI.js} +62 -16
  13. package/dist/chunk-DT6Y7XBI.js.map +1 -0
  14. package/dist/{chunk-2AVLX7GH.js → chunk-HAIMYUEY.js} +3 -3
  15. package/dist/{chunk-4ENJK5S2.js → chunk-MDNX7HTN.js} +2 -2
  16. package/dist/{chunk-EXLS7BSI.js → chunk-NLFPH4S2.js} +10 -2
  17. package/dist/chunk-NLFPH4S2.js.map +1 -0
  18. package/dist/{chunk-CPLK7GTE.js → chunk-PFDUGDOA.js} +351 -34
  19. package/dist/chunk-PFDUGDOA.js.map +1 -0
  20. package/dist/{chunk-EGCBZ2DC.js → chunk-SDPIT4HW.js} +2 -2
  21. package/dist/{chunk-5OWS5CMA.js → chunk-SPWFUHHK.js} +5 -5
  22. package/dist/{chunk-LQRAPXS4.js → chunk-TZQBASI7.js} +4 -2
  23. package/dist/chunk-TZQBASI7.js.map +1 -0
  24. package/dist/{chunk-XJ4S47CT.js → chunk-WFXWJITA.js} +2 -2
  25. package/dist/{chunk-24IDL5RW.js → chunk-YQLQJZ7S.js} +2 -2
  26. package/dist/{claude-code-W4PUFZL5.js → claude-code-ROSIILTM.js} +36 -100
  27. package/dist/claude-code-ROSIILTM.js.map +1 -0
  28. package/dist/cli/sdk.js +4 -4
  29. package/dist/cli.js +1 -1
  30. package/dist/{cline-WRYMNS7Z.js → cline-JUTO4V27.js} +2 -2
  31. package/dist/{codebuff-DH5Y7GAT.js → codebuff-2QUHL6HO.js} +127 -6
  32. package/dist/codebuff-2QUHL6HO.js.map +1 -0
  33. package/dist/{codex-DDHIV767.js → codex-YBBTIDD4.js} +109 -114
  34. package/dist/codex-YBBTIDD4.js.map +1 -0
  35. package/dist/{continue-K43SUHLQ.js → continue-W4TU4JSB.js} +5 -3
  36. package/dist/continue-W4TU4JSB.js.map +1 -0
  37. package/dist/{copilot-cli-Q3SSPT4V.js → copilot-cli-Y74SOP5G.js} +4 -2
  38. package/dist/copilot-cli-Y74SOP5G.js.map +1 -0
  39. package/dist/{crush-MBEH2R3I.js → crush-GMEWLXK5.js} +4 -2
  40. package/dist/{crush-MBEH2R3I.js.map → crush-GMEWLXK5.js.map} +1 -1
  41. package/dist/{cursor-TMBXDYR4.js → cursor-JBS4B3Q4.js} +50 -134
  42. package/dist/cursor-JBS4B3Q4.js.map +1 -0
  43. package/dist/{detect-KG5FG3EV.js → detect-2NIXILMZ.js} +4 -4
  44. package/dist/{doctor-FLZF34Y3.js → doctor-QWJBWALA.js} +8 -8
  45. package/dist/{droid-JC2NT6S4.js → droid-TJMTNCQE.js} +48 -106
  46. package/dist/droid-TJMTNCQE.js.map +1 -0
  47. package/dist/{gemini-cli-ILR7M5X3.js → gemini-cli-RAONGZRG.js} +7 -2
  48. package/dist/gemini-cli-RAONGZRG.js.map +1 -0
  49. package/dist/{goose-SFO5BBGW.js → goose-G4KKM6YU.js} +91 -131
  50. package/dist/goose-G4KKM6YU.js.map +1 -0
  51. package/dist/{hermes-3N7WN4WS.js → hermes-PJDTJE6F.js} +29 -33
  52. package/dist/hermes-PJDTJE6F.js.map +1 -0
  53. package/dist/{hook-XR3Z45FB.js → hook-FDGIQPRC.js} +8 -8
  54. package/dist/index.d.ts +2 -2
  55. package/dist/index.js +2 -2
  56. package/dist/{install-BSR62UHJ.js → install-TLG3QVP3.js} +8 -8
  57. package/dist/{introspect-Nw8hTReX.d.ts → introspect-Cn3MSA4_.d.ts} +1 -1
  58. package/dist/{jetbrains-copilot-NRZHI5PC.js → jetbrains-copilot-DNXSLQE5.js} +4 -2
  59. package/dist/jetbrains-copilot-DNXSLQE5.js.map +1 -0
  60. package/dist/{kilo-5NWOXVSD.js → kilo-FERJ3X46.js} +101 -5
  61. package/dist/kilo-FERJ3X46.js.map +1 -0
  62. package/dist/{kilo-cli-UZ7R5UOP.js → kilo-cli-TDCONH5G.js} +108 -12
  63. package/dist/kilo-cli-TDCONH5G.js.map +1 -0
  64. package/dist/{kimi-2YFK2GBA.js → kimi-RIRD4J5J.js} +12 -2
  65. package/dist/kimi-RIRD4J5J.js.map +1 -0
  66. package/dist/{kiro-YL6AWUYG.js → kiro-X7JVLAN7.js} +4 -2
  67. package/dist/kiro-X7JVLAN7.js.map +1 -0
  68. package/dist/{leaderboard-MJG24O35.js → leaderboard-MXGENYXN.js} +2 -2
  69. package/dist/{mimo-code-FTMGSKMQ.js → mimo-code-RFLQ727H.js} +2 -2
  70. package/dist/{mux-5XZFB44C.js → mux-D77HBSBU.js} +3 -17
  71. package/dist/mux-D77HBSBU.js.map +1 -0
  72. package/dist/{nemoclaw-W5KEJ3WX.js → nemoclaw-LXUTMR56.js} +3 -3
  73. package/dist/{omp-2QMEY6HD.js → omp-CO7IXURG.js} +2 -2
  74. package/dist/{openclaw-EXJEFNZI.js → openclaw-XWJLEW35.js} +3 -3
  75. package/dist/{opencode-WNXYJR4X.js → opencode-QKZ5EIYU.js} +5 -2
  76. package/dist/opencode-QKZ5EIYU.js.map +1 -0
  77. package/dist/{package-ACZXJHWB.js → package-IA56LSC3.js} +6 -6
  78. package/dist/{pi-PVVPVWKG.js → pi-YGBXYWY5.js} +2 -2
  79. package/dist/{qwen-code-G4CXKUHR.js → qwen-code-E2MSEZK6.js} +55 -123
  80. package/dist/qwen-code-E2MSEZK6.js.map +1 -0
  81. package/dist/{roo-code-67TYJIQR.js → roo-code-AGGJ473T.js} +2 -2
  82. package/dist/runtime/index.d.ts +1 -1
  83. package/dist/runtime/index.js +6 -6
  84. package/dist/sdk/index.d.ts +3 -3
  85. package/dist/sdk/index.js +3 -3
  86. package/dist/sdk/test.d.ts +2 -2
  87. package/dist/sdk/test.js +5 -5
  88. package/dist/{serve-GER7URPR.js → serve-RNUCK5F7.js} +8 -8
  89. package/dist/{status-LAJE3BM5.js → status-JOX6RLJU.js} +6 -6
  90. package/dist/{statusline-L376ZPZU.js → statusline-ZVFI5DRT.js} +7 -7
  91. package/dist/{telemetry-B3DX3PWU.js → telemetry-3FN6HDVU.js} +5 -5
  92. package/dist/{trae-7CZZGOGI.js → trae-6L226ZDU.js} +2 -2
  93. package/dist/{types-CRVrFWeU.d.ts → types-_6arHbX9.d.ts} +5 -4
  94. package/dist/{uninstall-ZYTW7YMZ.js → uninstall-SCKZYB4J.js} +8 -8
  95. package/dist/{upgrade-4LUEEOZW.js → upgrade-WU3KZWR4.js} +8 -8
  96. package/dist/{usage-ZFBVQF3H.js → usage-G72SF7JG.js} +2 -2
  97. package/dist/{usage-event-GZ32AGEB.js → usage-event-DHSEBO5T.js} +7 -7
  98. package/dist/{vscode-copilot-MF2CDNMT.js → vscode-copilot-6EOZDLXC.js} +4 -2
  99. package/dist/vscode-copilot-6EOZDLXC.js.map +1 -0
  100. package/dist/{warp-VKG55TAT.js → warp-N5YYN5BF.js} +2 -2
  101. package/dist/{windsurf-FU5G4SHF.js → windsurf-4TGSJIVV.js} +2 -2
  102. package/dist/{zed-SFUHL3GS.js → zed-6P2UFWXU.js} +2 -2
  103. package/package.json +1 -1
  104. package/dist/amp-4U33CU7E.js +0 -300
  105. package/dist/amp-4U33CU7E.js.map +0 -1
  106. package/dist/chunk-CPLK7GTE.js.map +0 -1
  107. package/dist/chunk-EXLS7BSI.js.map +0 -1
  108. package/dist/chunk-LQRAPXS4.js.map +0 -1
  109. package/dist/chunk-URHQMFB3.js.map +0 -1
  110. package/dist/claude-code-W4PUFZL5.js.map +0 -1
  111. package/dist/codebuff-DH5Y7GAT.js.map +0 -1
  112. package/dist/codex-DDHIV767.js.map +0 -1
  113. package/dist/continue-K43SUHLQ.js.map +0 -1
  114. package/dist/copilot-cli-Q3SSPT4V.js.map +0 -1
  115. package/dist/cursor-TMBXDYR4.js.map +0 -1
  116. package/dist/droid-JC2NT6S4.js.map +0 -1
  117. package/dist/gemini-cli-ILR7M5X3.js.map +0 -1
  118. package/dist/goose-SFO5BBGW.js.map +0 -1
  119. package/dist/hermes-3N7WN4WS.js.map +0 -1
  120. package/dist/jetbrains-copilot-NRZHI5PC.js.map +0 -1
  121. package/dist/kilo-5NWOXVSD.js.map +0 -1
  122. package/dist/kilo-cli-UZ7R5UOP.js.map +0 -1
  123. package/dist/kimi-2YFK2GBA.js.map +0 -1
  124. package/dist/kiro-YL6AWUYG.js.map +0 -1
  125. package/dist/mux-5XZFB44C.js.map +0 -1
  126. package/dist/opencode-WNXYJR4X.js.map +0 -1
  127. package/dist/qwen-code-G4CXKUHR.js.map +0 -1
  128. package/dist/vscode-copilot-MF2CDNMT.js.map +0 -1
  129. /package/dist/{action-WT7GVRCC.js.map → action-YCU53FNE.js.map} +0 -0
  130. /package/dist/{amazon-q-COAL3764.js.map → amazon-q-W574ZX35.js.map} +0 -0
  131. /package/dist/{antigravity-AMKKKHS4.js.map → antigravity-VK2Y3FGV.js.map} +0 -0
  132. /package/dist/{antigravity-cli-XERXEH5W.js.map → antigravity-cli-D4PCCUG2.js.map} +0 -0
  133. /package/dist/{chunk-DCKFYWGM.js.map → chunk-2F5QH3D4.js.map} +0 -0
  134. /package/dist/{chunk-RIMVWCZY.js.map → chunk-6RYPUR6O.js.map} +0 -0
  135. /package/dist/{chunk-QREL7LZJ.js.map → chunk-7ECYDK5T.js.map} +0 -0
  136. /package/dist/{chunk-O5TWCIJN.js.map → chunk-CYOAH23F.js.map} +0 -0
  137. /package/dist/{chunk-2AVLX7GH.js.map → chunk-HAIMYUEY.js.map} +0 -0
  138. /package/dist/{chunk-4ENJK5S2.js.map → chunk-MDNX7HTN.js.map} +0 -0
  139. /package/dist/{chunk-EGCBZ2DC.js.map → chunk-SDPIT4HW.js.map} +0 -0
  140. /package/dist/{chunk-5OWS5CMA.js.map → chunk-SPWFUHHK.js.map} +0 -0
  141. /package/dist/{chunk-XJ4S47CT.js.map → chunk-WFXWJITA.js.map} +0 -0
  142. /package/dist/{chunk-24IDL5RW.js.map → chunk-YQLQJZ7S.js.map} +0 -0
  143. /package/dist/{cline-WRYMNS7Z.js.map → cline-JUTO4V27.js.map} +0 -0
  144. /package/dist/{detect-KG5FG3EV.js.map → detect-2NIXILMZ.js.map} +0 -0
  145. /package/dist/{doctor-FLZF34Y3.js.map → doctor-QWJBWALA.js.map} +0 -0
  146. /package/dist/{hook-XR3Z45FB.js.map → hook-FDGIQPRC.js.map} +0 -0
  147. /package/dist/{install-BSR62UHJ.js.map → install-TLG3QVP3.js.map} +0 -0
  148. /package/dist/{leaderboard-MJG24O35.js.map → leaderboard-MXGENYXN.js.map} +0 -0
  149. /package/dist/{mimo-code-FTMGSKMQ.js.map → mimo-code-RFLQ727H.js.map} +0 -0
  150. /package/dist/{nemoclaw-W5KEJ3WX.js.map → nemoclaw-LXUTMR56.js.map} +0 -0
  151. /package/dist/{omp-2QMEY6HD.js.map → omp-CO7IXURG.js.map} +0 -0
  152. /package/dist/{openclaw-EXJEFNZI.js.map → openclaw-XWJLEW35.js.map} +0 -0
  153. /package/dist/{package-ACZXJHWB.js.map → package-IA56LSC3.js.map} +0 -0
  154. /package/dist/{pi-PVVPVWKG.js.map → pi-YGBXYWY5.js.map} +0 -0
  155. /package/dist/{roo-code-67TYJIQR.js.map → roo-code-AGGJ473T.js.map} +0 -0
  156. /package/dist/{serve-GER7URPR.js.map → serve-RNUCK5F7.js.map} +0 -0
  157. /package/dist/{status-LAJE3BM5.js.map → status-JOX6RLJU.js.map} +0 -0
  158. /package/dist/{statusline-L376ZPZU.js.map → statusline-ZVFI5DRT.js.map} +0 -0
  159. /package/dist/{telemetry-B3DX3PWU.js.map → telemetry-3FN6HDVU.js.map} +0 -0
  160. /package/dist/{trae-7CZZGOGI.js.map → trae-6L226ZDU.js.map} +0 -0
  161. /package/dist/{uninstall-ZYTW7YMZ.js.map → uninstall-SCKZYB4J.js.map} +0 -0
  162. /package/dist/{upgrade-4LUEEOZW.js.map → upgrade-WU3KZWR4.js.map} +0 -0
  163. /package/dist/{usage-ZFBVQF3H.js.map → usage-G72SF7JG.js.map} +0 -0
  164. /package/dist/{usage-event-GZ32AGEB.js.map → usage-event-DHSEBO5T.js.map} +0 -0
  165. /package/dist/{warp-VKG55TAT.js.map → warp-N5YYN5BF.js.map} +0 -0
  166. /package/dist/{windsurf-FU5G4SHF.js.map → windsurf-4TGSJIVV.js.map} +0 -0
  167. /package/dist/{zed-SFUHL3GS.js.map → zed-6P2UFWXU.js.map} +0 -0
@@ -4,10 +4,9 @@ import {
4
4
  } from "./chunk-DBQMX75U.js";
5
5
  import {
6
6
  BaseAdapter
7
- } from "./chunk-CPLK7GTE.js";
7
+ } from "./chunk-PFDUGDOA.js";
8
8
  import "./chunk-7L6ITC4T.js";
9
9
  import {
10
- buildHomeBinHookCommand,
11
10
  buildServeWrapperCommand,
12
11
  isHomeBinHookCommand,
13
12
  shouldWrapForTelemetry
@@ -219,140 +218,57 @@ var CursorAdapter = class extends BaseAdapter {
219
218
  }
220
219
  ];
221
220
  }
222
- const hooksPath = this.getHookConfigPath(ctx);
223
- const file = this.readJson(hooksPath) ?? {};
224
- const hooks = file.hooks ??= {};
225
- const changes = [];
226
- let mutated = false;
227
- for (const event of normalizedEvents) {
228
- const cursorEvent = EVENT_MAP[event];
229
- if (!cursorEvent) {
230
- changes.push({
231
- platform: this.id,
232
- action: "warn",
233
- path: hooksPath,
234
- detail: `${event} has no Cursor hook equivalent \u2014 skipped`
235
- });
236
- continue;
237
- }
238
- const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
239
- const matcher = connector.hooks[event]?.matcher;
240
- const entry = matcher ? { command, matcher } : { command };
241
- const bucket = hooks[cursorEvent] ??= [];
242
- const existingIdx = bucket.findIndex((e) => this.isOurCommand(e.command, ctx));
243
- if (existingIdx >= 0) {
244
- if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
245
- changes.push({
246
- platform: this.id,
247
- action: "skip",
248
- path: hooksPath,
249
- detail: `hooks.${cursorEvent} already registered`
250
- });
251
- continue;
252
- }
253
- bucket[existingIdx] = entry;
254
- changes.push({
255
- platform: this.id,
256
- action: "update",
257
- path: hooksPath,
258
- detail: `hooks.${cursorEvent}`
259
- });
260
- } else {
261
- bucket.push(entry);
262
- changes.push({
263
- platform: this.id,
264
- action: "create",
265
- path: hooksPath,
266
- detail: `hooks.${cursorEvent}`
267
- });
268
- }
269
- mutated = true;
270
- }
271
- for (const event of nativeEvents) {
272
- if (this.upsertNativeHook(ctx, hooks, event, nativeHooks[event]?.matcher, hooksPath, changes)) {
273
- mutated = true;
274
- }
275
- }
276
- if (mutated) {
277
- file.version = CURSOR_HOOKS_VERSION;
278
- this.writeJson(hooksPath, file, ctx.dryRun);
279
- }
280
- return changes;
221
+ const pending = normalizedEvents.map((event) => ({
222
+ event,
223
+ matcher: connector.hooks[event]?.matcher ?? ""
224
+ }));
225
+ const native = nativeEvents.map((event) => ({
226
+ event,
227
+ matcher: nativeHooks[event]?.matcher ?? ""
228
+ }));
229
+ return this.upsertHookEntries(
230
+ ctx,
231
+ this.getHookConfigPath(ctx),
232
+ pending,
233
+ this.hookDescriptor(ctx),
234
+ native
235
+ );
236
+ }
237
+ uninstallHooks(ctx) {
238
+ return this.removeHookEntries(ctx, this.getHookConfigPath(ctx), this.hookDescriptor(ctx));
281
239
  }
282
240
  /**
283
- * Upsert one NATIVE (cursor-native event-name) hook into `hooks[event]`. The
284
- * key is written verbatim. Matched by EXACT command — not just "one of ours" —
285
- * so a native key that coincides with a normalized event's mapped key never
286
- * clobbers the normalized entry; it adds a second, distinct command instead.
287
- * Idempotent: byte-identical skip, drifted → update.
241
+ * Cursor's hook-merge descriptor (FLAT shape `{ command, matcher? }`):
242
+ * - mapEvent renames canonical Cursor's lower-camel native key (EVENT_MAP);
243
+ * an unmapped event warn-skips (no Cursor equivalent).
244
+ * - renderEntry omits the `matcher` key when the matcher is falsy this
245
+ * `{command}` vs `{command,matcher}` distinction is load-bearing on-disk
246
+ * bytes (Cursor's flat entry shape), reproduced exactly here.
247
+ * - install find is connector-generic (ANY of our commands at the flat
248
+ * `entry.command`); uninstall drops whole owned entries (flat — NO
249
+ * stripInner). The version stamp is install-only via onMutate.
250
+ * - the native pass uses EXACT-command ownership so a native key coinciding
251
+ * with a normalized event's mapped key adds a SECOND distinct command
252
+ * rather than clobbering the normalized entry.
288
253
  */
289
- upsertNativeHook(ctx, hooks, event, matcher, hooksPath, changes) {
290
- const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, ctx.connector.id);
291
- const entry = matcher ? { command, matcher } : { command };
292
- const bucket = hooks[event] ??= [];
293
- const existingIdx = bucket.findIndex((e) => e.command === command);
294
- if (existingIdx >= 0) {
295
- if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
296
- changes.push({
297
- platform: this.id,
298
- action: "skip",
299
- path: hooksPath,
300
- detail: `hooks.${event} (native) already registered`
301
- });
302
- return false;
303
- }
304
- bucket[existingIdx] = entry;
305
- changes.push({ platform: this.id, action: "update", path: hooksPath, detail: `hooks.${event} (native)` });
306
- } else {
307
- bucket.push(entry);
308
- changes.push({ platform: this.id, action: "create", path: hooksPath, detail: `hooks.${event} (native)` });
309
- }
310
- return true;
311
- }
312
- uninstallHooks(ctx) {
313
- const hooksPath = this.getHookConfigPath(ctx);
314
- const file = this.readJson(hooksPath);
315
- const hooks = file?.hooks;
316
- if (!file || !hooks) {
317
- return [
318
- {
319
- platform: this.id,
320
- action: "skip",
321
- path: hooksPath,
322
- detail: "no hooks section present"
323
- }
324
- ];
325
- }
326
- const changes = [];
327
- let mutated = false;
328
- for (const cursorEvent of Object.keys(hooks)) {
329
- const bucket = hooks[cursorEvent];
330
- if (!Array.isArray(bucket)) continue;
331
- const before = bucket.length;
332
- const next = bucket.filter((e) => !this.isOurCommand(e.command, ctx));
333
- const removed = before - next.length;
334
- if (removed > 0) {
335
- if (next.length > 0) hooks[cursorEvent] = next;
336
- else delete hooks[cursorEvent];
337
- changes.push({
338
- platform: this.id,
339
- action: "remove",
340
- path: hooksPath,
341
- detail: `hooks.${cursorEvent} (${removed})`
342
- });
343
- mutated = true;
344
- }
345
- }
346
- if (mutated) this.writeJson(hooksPath, file, ctx.dryRun);
347
- if (changes.length === 0) {
348
- changes.push({
349
- platform: this.id,
350
- action: "skip",
351
- path: hooksPath,
352
- detail: "no matching hook entries"
353
- });
354
- }
355
- return changes;
254
+ hookDescriptor(ctx) {
255
+ return {
256
+ mapEvent: (e) => EVENT_MAP[e],
257
+ unmappedWarnDetail: (e) => `${e} has no Cursor hook equivalent \u2014 skipped`,
258
+ renderEntry: (_event, matcher, command) => matcher ? { command, matcher } : { command },
259
+ entryOwnsCommand: (entry, _command) => this.isOurCommand(entry.command, ctx),
260
+ ownsEntryForRemove: (c) => (entry) => this.isOurCommand(entry.command, c),
261
+ skipDetail: (e) => `hooks.${e} already registered`,
262
+ removeDetail: (e, n) => `hooks.${e} (${n})`,
263
+ absentDetail: "no hooks section present",
264
+ noMatchDetail: "no matching hook entries",
265
+ onMutate: (file) => {
266
+ file.version = CURSOR_HOOKS_VERSION;
267
+ },
268
+ nativeOwnsCommand: (entry, command) => entry.command === command,
269
+ nativeSkipDetail: (e) => `hooks.${e} (native) already registered`,
270
+ nativeMutateDetail: (e) => `hooks.${e} (native)`
271
+ };
356
272
  }
357
273
  /** True when a hook command references our home binary AND this connector id
358
274
  * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */
@@ -764,4 +680,4 @@ export {
764
680
  adapter,
765
681
  cursor_default as default
766
682
  };
767
- //# sourceMappingURL=cursor-TMBXDYR4.js.map
683
+ //# sourceMappingURL=cursor-JBS4B3Q4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/cursor/index.ts"],"sourcesContent":["/**\n * adapters/cursor — Cursor platform adapter for agent-connector.\n *\n * Generalized from context-mode's proven Cursor adapter: the served identity is\n * now `ctx.connector` (not a hardcoded \"context-mode\"), and every hook command\n * points at the single stable home binary (the shared hook-merge engine builds\n * the command) so one framework update propagates everywhere.\n *\n * Cursor is a json-stdio host:\n * - MCP servers: user scope → ~/.cursor/mcp.json (\"mcpServers\"); project scope\n * → <projectDir>/.cursor/mcp.json (\"mcpServers\").\n * - Hooks: <configDir>/hooks.json with shape `{ version, hooks: { <cursorEvent>:\n * [ { command, matcher? } ] } }`. Unlike Claude, each entry is a FLAT command\n * object (no `{ matcher, hooks:[...] }` wrapper).\n * - Reply: a JSON object on stdout (exit 0). deny/ask carry `permission` +\n * `user_message`; modify carries `updated_input`; context injects via\n * `agent_message` (PreToolUse) or `additional_context` (Post/SessionStart).\n *\n * Cursor supports its own `${env:VAR}` native interpolation, so env/header/url\n * values are rewritten to that native token rather than baked into the file.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter, type HookMergeDescriptor } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PostToolUseFailureEvent,\n PreCompactEvent,\n PreToolUseEvent,\n ServerDef,\n SessionEndEvent,\n SessionStartEvent,\n SkillDef,\n StopEvent,\n SubagentDef,\n SubagentStartEvent,\n SubagentStopEvent,\n Transport,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { rewriteEnvRefs } from \"../../core/interpolate.js\";\nimport {\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"cursor\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/** Native hooks.json version Cursor expects. */\nconst CURSOR_HOOKS_VERSION = 1;\n\n/**\n * Cursor-native hook event names, in the lower-camel form Cursor reads from\n * hooks.json. The first four are the events the proven context-mode adapter\n * registers; postToolUseFailure / subagentStart / subagentStop are Cursor's\n * documented \"Subagent (Task tool) lifecycle\" + tool-failure hooks.\n */\nconst CURSOR_EVENT = {\n PreToolUse: \"preToolUse\",\n PostToolUse: \"postToolUse\",\n SessionStart: \"sessionStart\",\n Stop: \"stop\",\n PostToolUseFailure: \"postToolUseFailure\",\n SubagentStart: \"subagentStart\",\n SubagentStop: \"subagentStop\",\n // Lifecycle/prompt events Cursor 1.7+ documents (cursor.com/docs/hooks):\n // sessionEnd is fire-and-forget; preCompact is observational (cannot block);\n // beforeSubmitPrompt fires before a prompt is sent and CAN prevent submission\n // (Cursor itself matches beforeSubmitPrompt against the value \"UserPromptSubmit\").\n SessionEnd: \"sessionEnd\",\n PreCompact: \"preCompact\",\n UserPromptSubmit: \"beforeSubmitPrompt\",\n} as const;\n\n/**\n * Map our normalized event names to Cursor's native hook event names. Only the\n * events Cursor actually supports are present; everything else has no Cursor\n * equivalent and is reported as a skip/warn at install time.\n *\n * PermissionRequest is deliberately ABSENT: Cursor has no permission-dialog\n * event — its permission gate is the OUTPUT field `permission: \"allow\"|\"deny\"|\n * \"ask\"` of the before* hooks (beforeShellExecution / beforeMCPExecution /\n * beforeReadFile / preToolUse), not an observable event. Install reports the\n * standard skip-warn for it.\n */\nconst EVENT_MAP: Partial<Record<HookEventName, string>> = {\n PreToolUse: CURSOR_EVENT.PreToolUse,\n PostToolUse: CURSOR_EVENT.PostToolUse,\n SessionStart: CURSOR_EVENT.SessionStart,\n Stop: CURSOR_EVENT.Stop,\n PostToolUseFailure: CURSOR_EVENT.PostToolUseFailure,\n SubagentStart: CURSOR_EVENT.SubagentStart,\n SubagentStop: CURSOR_EVENT.SubagentStop,\n SessionEnd: CURSOR_EVENT.SessionEnd,\n PreCompact: CURSOR_EVENT.PreCompact,\n UserPromptSubmit: CURSOR_EVENT.UserPromptSubmit,\n};\n\n/** A single Cursor native hook entry — a flat command object. */\ninterface CursorHookEntry {\n command: string;\n matcher?: string;\n}\n\n/** Native MCP server entry shapes Cursor accepts under `mcpServers`. */\ninterface CursorStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\ninterface CursorHttpServer {\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Raw Cursor hook stdin payload (snake_case wire fields). */\ninterface CursorWireInput {\n connector?: unknown;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_output?: string;\n error_message?: string;\n cwd?: string;\n workspace_roots?: string[];\n conversation_id?: string;\n session_id?: string;\n generation_id?: string;\n source?: string;\n trigger?: string;\n status?: string;\n loop_count?: number;\n stop_hook_active?: boolean;\n\n // beforeSubmitPrompt (UserPromptSubmit) — the submitted prompt text.\n // sessionEnd — the documented end reason. Both field names are taken\n // verbatim from cursor.com/docs/hooks (snake_case wire).\n prompt?: string;\n reason?: string;\n\n // postToolUseFailure — Cursor's existing error vocabulary is error_message;\n // the Claude-compatible names are accepted defensively (unverified wire).\n error?: string;\n tool_use_id?: string;\n is_interrupt?: boolean;\n duration_ms?: number;\n\n // subagentStart / subagentStop (Task-tool lifecycle). Both name families are\n // parsed defensively: agent_* (Claude-compatible) and subagent_* (Cursor-ish).\n agent_id?: string;\n agent_type?: string;\n subagent_id?: string;\n subagent_type?: string;\n last_assistant_message?: string;\n}\n\nexport class CursorAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Cursor\";\n readonly paradigm: HookParadigm = \"json-stdio\";\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 // Cursor natively supports pre/post tool-use, session start/end, prompt\n // submission, context compaction, and stop (cursor.com/docs/hooks, v1.7+).\n preToolUse: true,\n postToolUse: true,\n preCompact: true,\n sessionStart: true,\n sessionEnd: true,\n userPromptSubmit: true,\n stop: true,\n notification: false,\n // Newer events: Cursor has dedicated postToolUseFailure + subagentStart/\n // subagentStop hooks. permissionRequest stays unset — Cursor's permission\n // gate is an OUTPUT field of its before* hooks, not an observable event\n // (see the EVENT_MAP note).\n postToolUseFailure: true,\n subagentStart: true,\n subagentStop: true,\n // Cursor's preToolUse can rewrite tool input (updated_input) but cannot\n // rewrite already-emitted tool output.\n canModifyArgs: true,\n canModifyOutput: false,\n canInjectSessionContext: true,\n transports: [\"stdio\", \"http\"],\n // Content surfaces: Cursor supports all three (commands, skills, subagents).\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n // Native passthrough hooks: Cursor documents many granular hooks with NO\n // canonical analog — beforeShellExecution / afterShellExecution /\n // beforeMCPExecution / afterMCPExecution / beforeReadFile / afterFileEdit /\n // beforeTabFileRead / afterTabFileEdit / workspaceOpen / afterAgentResponse /\n // afterAgentThought (cursor.com/docs/hooks). They are\n // host-specific (below the >=3-host core bar; see\n // docs/research/host-specific-hook-events-design.md). A connector reaches them\n // by declaring platforms[\"cursor\"].nativeHooks; installHooks writes those\n // event-name keys verbatim into hooks.json, and the generic uninstall reverses\n // them.\n supportsNativeHooks: true,\n // Cursor has a command-driven status line (`/statusline` → `statusLine` in\n // ~/.cursor/cli-config.json, GLOBAL scope only) per the Cursor changelog, but\n // the config-key shape + the Claude-parity stdin payload are sourced from a\n // community tool (agent-status-pills), not first-party Cursor docs — payload\n // field names unverified. Deferred pending a live cursor-agent capture; not a\n // permanent gap; user-scope only when wired.\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".cursor\");\n const userMcp = join(userDir, \"mcp.json\");\n const userHooks = join(userDir, \"hooks.json\");\n const projectDirCursor = join(projectDir, \".cursor\");\n const installed =\n existsSync(userDir) ||\n existsSync(userMcp) ||\n existsSync(userHooks) ||\n existsSync(projectDirCursor);\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath: userMcp,\n scope: \"user\",\n reason: installed\n ? `found Cursor config under ${userDir}`\n : `no Cursor config at ${userDir}`,\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, \".cursor\")\n : join(homedir(), \".cursor\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"hooks.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 cursor\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Cursor's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): CursorStdioServer | CursorHttpServer {\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 const entry: CursorStdioServer = { 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 if (server.cwd) entry.cwd = this.rewrite(server.cwd);\n return entry;\n }\n\n // http (and any other remote transport we surface) — Cursor registers a URL.\n const entry: CursorHttpServer = { 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. Cursor supports its own `${env:VAR}` native\n * interpolation, so translate `${env:VAR}` refs to that native token rather\n * than baking 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 Cursor's native `${env:VAR}` token. */\n private rewrite(value: string): string {\n return rewriteEnvRefs(value, cursorEnvToken);\n }\n\n // ── Hook install / uninstall ─────────────────────────────────────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST];\n\n // `hooks: false` disables only the NORMALIZED events. nativeHooks is a\n // sibling, cursor-scoped declaration on the same override and installs\n // regardless.\n const normalizedEvents = override?.hooks === false ? [] : connector.hookEvents;\n const nativeHooks = override?.nativeHooks ?? {};\n const nativeEvents = Object.keys(nativeHooks);\n\n if (normalizedEvents.length === 0 && nativeEvents.length === 0) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: override?.hooks === false ? \"hooks disabled for cursor\" : \"connector declares no hooks\",\n },\n ];\n }\n\n // Normalized events go through the engine's mapEvent/warn path; native\n // event-name keys ride the separate `native` pass (verbatim keys, EXACT\n // command, the `(native)` detail) — see the descriptor + base.upsertHookEntries.\n const pending = normalizedEvents.map((event) => ({\n event,\n matcher: connector.hooks[event]?.matcher ?? \"\",\n }));\n const native = nativeEvents.map((event) => ({\n event,\n matcher: nativeHooks[event]?.matcher ?? \"\",\n }));\n return this.upsertHookEntries(\n ctx,\n this.getHookConfigPath(ctx),\n pending,\n this.hookDescriptor(ctx),\n native,\n );\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n return this.removeHookEntries(ctx, this.getHookConfigPath(ctx), this.hookDescriptor(ctx));\n }\n\n /**\n * Cursor's hook-merge descriptor (FLAT shape `{ command, matcher? }`):\n * - mapEvent renames canonical → Cursor's lower-camel native key (EVENT_MAP);\n * an unmapped event warn-skips (no Cursor equivalent).\n * - renderEntry omits the `matcher` key when the matcher is falsy — this\n * `{command}` vs `{command,matcher}` distinction is load-bearing on-disk\n * bytes (Cursor's flat entry shape), reproduced exactly here.\n * - install find is connector-generic (ANY of our commands at the flat\n * `entry.command`); uninstall drops whole owned entries (flat — NO\n * stripInner). The version stamp is install-only via onMutate.\n * - the native pass uses EXACT-command ownership so a native key coinciding\n * with a normalized event's mapped key adds a SECOND distinct command\n * rather than clobbering the normalized entry.\n */\n private hookDescriptor(ctx: InstallContext): HookMergeDescriptor<CursorHookEntry> {\n return {\n mapEvent: (e) => EVENT_MAP[e as HookEventName],\n unmappedWarnDetail: (e) => `${e} has no Cursor hook equivalent — skipped`,\n renderEntry: (_event, matcher, command) =>\n matcher ? { command, matcher } : { command },\n entryOwnsCommand: (entry, _command) => this.isOurCommand(entry.command, ctx),\n ownsEntryForRemove: (c) => (entry) => this.isOurCommand(entry.command, c),\n skipDetail: (e) => `hooks.${e} already registered`,\n removeDetail: (e, n) => `hooks.${e} (${n})`,\n absentDetail: \"no hooks section present\",\n noMatchDetail: \"no matching hook entries\",\n onMutate: (file) => {\n (file as { version?: number }).version = CURSOR_HOOKS_VERSION;\n },\n nativeOwnsCommand: (entry, command) => entry.command === command,\n nativeSkipDetail: (e) => `hooks.${e} (native) already registered`,\n nativeMutateDetail: (e) => `hooks.${e} (native)`,\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 private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Content surfaces: commands / skills / subagents ──────────────────────\n // CONTENT-ONLY: pure native-file writers under <configDir>/{commands,skills,\n // agents}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\n // method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile\n // and reversible via removeContentFile. Honors platforms[\"cursor\"] per-surface\n // false to skip. Cursor commands are BODY-ONLY markdown (no frontmatter);\n // skills are the uniform <name>/SKILL.md + resources; subagents are md+fm.\n\n private commandsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"commands\");\n }\n private skillsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"skills\");\n }\n private agentsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"agents\");\n }\n\n /** Native command file path: <configDir>/commands/<name>.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.commandsDir(ctx), `${name}.md`);\n }\n /** Native skill dir: <configDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n /** Native subagent file path: <configDir>/agents/<name>.md. */\n private subagentPath(ctx: InstallContext, name: string): string {\n return join(this.agentsDir(ctx), `${name}.md`);\n }\n\n // ── Commands ──────────────────────────────────────────────────────────────\n\n override installCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.commands === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for cursor\" }];\n }\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.writeContentFile(\n this.commandPath(ctx, cmd.name),\n this.renderCommand(cmd),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\n );\n }\n\n /**\n * Render a Cursor command: BODY-ONLY markdown (no frontmatter). Cursor reads\n * the file as the command prompt verbatim. We prepend the one-line description\n * as an HTML comment header when present so authoring intent survives the\n * round-trip without leaking into the rendered prompt. A description containing\n * \"-->\" would prematurely CLOSE the HTML comment and leak the remainder into\n * the prompt, so we neutralize that sequence before embedding it.\n */\n private renderCommand(cmd: CommandDef): string {\n if (!cmd.description) return `${cmd.prompt}\\n`;\n // Break any literal comment-close so it cannot terminate our header early.\n const safe = cmd.description.replace(/--+>/g, (m) => m.replace(/>/g, \"&gt;\"));\n return `<!-- ${safe} -->\\n\\n${cmd.prompt}\\n`;\n }\n\n // ── Skills ────────────────────────────────────────────────────────────────\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 cursor\" }];\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 /**\n * Render a skill's SKILL.md: frontmatter (name, description + optional model,\n * allowed-tools, disable-model-invocation) + body. Uniform across platforms;\n * only the parent dir differs.\n */\n private renderSkill(skill: SkillDef): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n };\n if (skill.model !== undefined) frontmatter.model = skill.model;\n const allow = skill.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (skill.disableModelInvocation !== undefined) {\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\n }\n if (skill.extra) Object.assign(frontmatter, skill.extra);\n return this.renderFrontmatterMd(frontmatter, skill.body);\n }\n\n // ── Subagents ───────────────────────────────────────────────────────────────\n\n override installSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.subagents === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"subagents disabled for cursor\" }];\n }\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.writeContentFile(\n this.subagentPath(ctx, agent.name),\n this.renderSubagent(agent),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun),\n );\n }\n\n /** Render a Cursor subagent to md+frontmatter (name, description, model, readonly) + prompt body. */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n name: agent.name,\n description: agent.description,\n };\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.readonly !== undefined) frontmatter.readonly = agent.readonly;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const hooksPath = this.getHookConfigPath(ctx);\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: mcp.json present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: hooks.json present`,\n check: () => {\n // Same \"only assert what the connector declares\" rule as the\n // content-surface checks below: a hookless connector never writes\n // hooks.json, so its absence is healthy, not a failure.\n if (ctx.connector.hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n return existsSync(hooksPath)\n ? { status: \"OK\", detail: hooksPath }\n : { status: \"FAIL\", detail: `not found: ${hooksPath}` };\n },\n },\n ];\n\n // Content-surface checks: only assert presence of the files this connector\n // declares (skip silently for surfaces it never asked for).\n for (const cmd of ctx.connector.commands) {\n const p = this.commandPath(ctx, cmd.name);\n checks.push({\n name: `${this.name}: command ${cmd.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const skill of ctx.connector.skills) {\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\n checks.push({\n name: `${this.name}: skill ${skill.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const agent of ctx.connector.subagents) {\n const p = this.subagentPath(ctx, agent.name);\n checks.push({\n name: `${this.name}: subagent ${agent.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n return checks;\n }\n\n // ── Runtime: parse Cursor stdin JSON → normalized event ──────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as CursorWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = extractSessionId(input);\n const projectDir = this.getProjectDir(input);\n\n const base = {\n hostPlatform: HOST,\n connectorId,\n sessionId,\n raw,\n ...(projectDir !== undefined ? { projectDir } : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const toolOutput = input.tool_output ?? input.error_message;\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolOutput !== undefined ? { toolOutput } : {}),\n ...(input.error_message ? { isError: true } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = {\n ...base,\n source: normalizeSessionSource(input.source ?? input.trigger),\n };\n return ev;\n }\n case \"Stop\": {\n const ev: StopEvent = {\n ...base,\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n case \"SessionEnd\": {\n // Cursor sessionEnd: { session_id, reason, duration_ms, ... }. session_id\n // is already folded into base.sessionId via extractSessionId; only the\n // documented `reason` enum maps onto the normalized SessionEnd shape.\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n // Cursor beforeSubmitPrompt: { prompt, attachments }. attachments has no\n // normalized field and is preserved via base.raw; only `prompt` maps.\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\n // Cursor preCompact: { trigger: \"auto\"|\"manual\", context_*… }. Only the\n // documented `trigger` enum maps onto the normalized PreCompact shape.\n const ev: PreCompactEvent = {\n ...base,\n ...(input.trigger === \"auto\" || input.trigger === \"manual\"\n ? { trigger: input.trigger }\n : {}),\n };\n return ev;\n }\n case \"PostToolUseFailure\": {\n // Cursor's established error field is error_message; fall back to the\n // Claude-compatible `error` defensively.\n const error = input.error_message ?? input.error ?? \"\";\n const ev: PostToolUseFailureEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n error,\n ...(typeof input.tool_use_id === \"string\"\n ? { toolUseId: input.tool_use_id }\n : {}),\n ...(typeof input.is_interrupt === \"boolean\"\n ? { isInterrupt: input.is_interrupt }\n : {}),\n ...(typeof input.duration_ms === \"number\"\n ? { durationMs: input.duration_ms }\n : {}),\n };\n return ev;\n }\n case \"SubagentStart\": {\n const agentId = input.agent_id ?? input.subagent_id;\n const agentType = input.agent_type ?? input.subagent_type;\n const ev: SubagentStartEvent = {\n ...base,\n ...(typeof agentId === \"string\" ? { agentId } : {}),\n ...(typeof agentType === \"string\" ? { agentType } : {}),\n };\n return ev;\n }\n case \"SubagentStop\": {\n const agentId = input.agent_id ?? input.subagent_id;\n const agentType = input.agent_type ?? input.subagent_type;\n const ev: SubagentStopEvent = {\n ...base,\n ...(typeof agentId === \"string\" ? { agentId } : {}),\n ...(typeof agentType === \"string\" ? { agentType } : {}),\n ...(typeof input.last_assistant_message === \"string\"\n ? { lastAssistantMessage: input.last_assistant_message }\n : {}),\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n default: {\n // Cursor never delivers Notification / PermissionRequest (no native\n // equivalent — permission is an OUTPUT field of its before* hooks, not\n // an event). If the runtime dispatches one anyway, fail loudly.\n throw new Error(`unsupported cursor hook event: ${String(event)}`);\n }\n }\n }\n\n private getProjectDir(input: CursorWireInput): string | undefined {\n return input.cwd ?? input.workspace_roots?.[0] ?? undefined;\n }\n\n // ── Runtime: normalized response → Cursor native hook reply ──────────────\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const decision = response.decision ?? \"allow\";\n\n // postToolUseFailure (feedback beside the error) and subagentStart (context\n // injected into the SUBAGENT's conversation) are observe/context-only on\n // Cursor: \"context\" emits additional_context, and a \"deny\" DEGRADES to the\n // same shape carrying the reason (the tool already failed / the spawn is\n // not blockable). Everything else is a minimal no-op payload (Cursor\n // rejects empty stdout as \"no valid response\").\n if (event === \"PostToolUseFailure\" || event === \"SubagentStart\") {\n const context =\n decision === \"context\"\n ? response.additionalContext\n : decision === \"deny\"\n ? response.reason ?? response.additionalContext\n : undefined;\n return this.stdout({ additional_context: context ?? \"\" });\n }\n\n // beforeSubmitPrompt (UserPromptSubmit) is a BLOCK gate, not a permission/\n // context surface: its only documented output is { continue, user_message }\n // (cursor.com/docs/hooks). A \"deny\" prevents submission (continue:false +\n // reason); it cannot inject context (no additional_context/agent_message\n // field), so every non-deny decision is a no-op continue:true.\n if (event === \"UserPromptSubmit\") {\n if (decision === \"deny\") {\n return this.stdout({\n continue: false,\n user_message: response.reason ?? \"Blocked by hook\",\n });\n }\n return this.stdout({ continue: true });\n }\n\n // sessionEnd is fire-and-forget (the response is logged but not used) and\n // preCompact is observational (cannot block or modify compaction) per\n // cursor.com/docs/hooks — neither carries a decision Cursor honors, so both\n // are an unconditional no-op passthrough (mirrors Stop).\n if (event === \"SessionEnd\" || event === \"PreCompact\") {\n return { exitCode: 0 };\n }\n\n // deny → block the action with a user-facing message. (On SubagentStop\n // this follows the adapter's Stop idiom — the deny carries Stop semantics.)\n if (decision === \"deny\") {\n return this.stdout({\n permission: \"deny\",\n user_message: response.reason ?? \"Blocked by hook\",\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n permission: \"ask\",\n user_message: response.reason ?? \"Confirmation required by hook\",\n });\n }\n\n // modify → rewrite PreToolUse input (only where Cursor supports it).\n if (decision === \"modify\") {\n if (event === \"PreToolUse\" && response.updatedInput) {\n return this.stdout({ updated_input: response.updatedInput });\n }\n // Output rewrite is unsupported on Cursor; fall through to allow.\n }\n\n // context → inject soft guidance. PreToolUse uses `agent_message`; Post and\n // SessionStart use `additional_context`.\n if (decision === \"context\" && response.additionalContext) {\n return event === \"PreToolUse\"\n ? this.stdout({ agent_message: response.additionalContext })\n : this.stdout({ additional_context: response.additionalContext });\n }\n\n // SessionStart always emits valid JSON even on a no-op (Cursor rejects empty\n // stdout as \"no valid response\").\n if (event === \"SessionStart\") {\n return this.stdout({ additional_context: response.additionalContext ?? \"\" });\n }\n\n // allow / void → minimal no-op payload (Cursor rejects empty stdout).\n if (event === \"PreToolUse\") return this.stdout({ agent_message: \"\" });\n if (event === \"PostToolUse\") return this.stdout({ additional_context: \"\" });\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/** Cursor native interpolation token: `${env:VAR}` → `${env:VAR}` (passthrough). */\nfunction cursorEnvToken(name: string): string {\n return `\\${env:${name}}`;\n}\n\nfunction extractSessionId(input: CursorWireInput): string {\n if (typeof input.conversation_id === \"string\") return input.conversation_id;\n if (typeof input.session_id === \"string\") return input.session_id;\n return \"\";\n}\n\nfunction normalizeSessionSource(source: string | undefined): SessionStartEvent[\"source\"] {\n switch (source) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\nexport const adapter = new CursorAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  print
4
- } from "./chunk-O5TWCIJN.js";
4
+ } from "./chunk-CYOAH23F.js";
5
5
  import {
6
6
  detectInstalledPlatforms
7
- } from "./chunk-EGCBZ2DC.js";
8
- import "./chunk-DCKFYWGM.js";
7
+ } from "./chunk-SDPIT4HW.js";
8
+ import "./chunk-2F5QH3D4.js";
9
9
 
10
10
  // src/cli/commands/detect.ts
11
11
  import { parseArgs } from "util";
@@ -71,4 +71,4 @@ async function run(argv) {
71
71
  export {
72
72
  run
73
73
  };
74
- //# sourceMappingURL=detect-KG5FG3EV.js.map
74
+ //# sourceMappingURL=detect-2NIXILMZ.js.map
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  marketplaceDoctorChecks,
4
4
  syncConnector
5
- } from "./chunk-RIMVWCZY.js";
6
- import "./chunk-QREL7LZJ.js";
5
+ } from "./chunk-6RYPUR6O.js";
6
+ import "./chunk-7ECYDK5T.js";
7
7
  import {
8
8
  readMarketplaceInstalls
9
9
  } from "./chunk-G5CQHVQG.js";
@@ -12,7 +12,7 @@ import {
12
12
  parseScope,
13
13
  parseTargets,
14
14
  print
15
- } from "./chunk-O5TWCIJN.js";
15
+ } from "./chunk-CYOAH23F.js";
16
16
  import {
17
17
  LineBuffer,
18
18
  idKey,
@@ -23,21 +23,21 @@ import {
23
23
  } from "./chunk-F5RX62T7.js";
24
24
  import {
25
25
  detectInstalledPlatforms
26
- } from "./chunk-EGCBZ2DC.js";
26
+ } from "./chunk-SDPIT4HW.js";
27
27
  import "./chunk-KHO5WNTP.js";
28
28
  import {
29
29
  findConnectorConfig,
30
30
  listRegisteredConnectors,
31
31
  loadConnectorFromPath,
32
32
  readRegisteredMeta
33
- } from "./chunk-24IDL5RW.js";
33
+ } from "./chunk-YQLQJZ7S.js";
34
34
  import {
35
35
  MCP_PROTOCOL_VERSION
36
- } from "./chunk-4ENJK5S2.js";
36
+ } from "./chunk-MDNX7HTN.js";
37
37
  import {
38
38
  REGISTERED_PLATFORM_IDS,
39
39
  loadAdapter
40
- } from "./chunk-DCKFYWGM.js";
40
+ } from "./chunk-2F5QH3D4.js";
41
41
  import "./chunk-FAHIMJRU.js";
42
42
  import "./chunk-OPXAP3AC.js";
43
43
  import "./chunk-7L6ITC4T.js";
@@ -537,4 +537,4 @@ async function run(argv) {
537
537
  export {
538
538
  run
539
539
  };
540
- //# sourceMappingURL=doctor-FLZF34Y3.js.map
540
+ //# sourceMappingURL=doctor-QWJBWALA.js.map
@@ -4,10 +4,9 @@ import {
4
4
  } from "./chunk-DBQMX75U.js";
5
5
  import {
6
6
  BaseAdapter
7
- } from "./chunk-CPLK7GTE.js";
7
+ } from "./chunk-PFDUGDOA.js";
8
8
  import "./chunk-7L6ITC4T.js";
9
9
  import {
10
- buildHomeBinHookCommand,
11
10
  buildServeWrapperCommand,
12
11
  isHomeBinHookCommand,
13
12
  shouldWrapForTelemetry
@@ -204,112 +203,55 @@ var DroidAdapter = class extends BaseAdapter {
204
203
  if (connector.hookEvents.length === 0) {
205
204
  return [{ platform: this.id, action: "skip", detail: "connector declares no hooks" }];
206
205
  }
207
- const hookPath = this.getHookConfigPath(ctx);
208
- const file = this.readJson(hookPath) ?? {};
209
- const hooks = file.hooks ??= {};
210
- const changes = [];
211
- let mutated = false;
212
- for (const event of connector.hookEvents) {
213
- if (!SUPPORTED_EVENTS.has(event)) {
214
- changes.push({
215
- platform: this.id,
216
- action: "warn",
217
- path: hookPath,
218
- detail: `${event} has no Droid hook equivalent \u2014 skipped`
219
- });
220
- continue;
221
- }
222
- const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
223
- const matcher = connector.hooks[event]?.matcher ?? "";
224
- const entry = {
225
- matcher,
226
- hooks: [{ type: "command", command }]
227
- };
228
- const bucket = hooks[event] ??= [];
229
- const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));
230
- if (existingIdx >= 0) {
231
- if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
232
- changes.push({
233
- platform: this.id,
234
- action: "skip",
235
- path: hookPath,
236
- detail: `hooks.${event} already registered`
237
- });
238
- continue;
239
- }
240
- bucket[existingIdx] = entry;
241
- changes.push({
242
- platform: this.id,
243
- action: "update",
244
- path: hookPath,
245
- detail: `hooks.${event}`
246
- });
247
- } else {
248
- bucket.push(entry);
249
- changes.push({
250
- platform: this.id,
251
- action: "create",
252
- path: hookPath,
253
- detail: `hooks.${event}`
254
- });
255
- }
256
- mutated = true;
257
- }
258
- if (mutated) this.writeJson(hookPath, file, ctx.dryRun);
259
- return changes;
206
+ const pending = connector.hookEvents.map((event) => ({
207
+ event,
208
+ matcher: connector.hooks[event]?.matcher ?? ""
209
+ }));
210
+ return this.upsertHookEntries(
211
+ ctx,
212
+ this.getHookConfigPath(ctx),
213
+ pending,
214
+ this.hookDescriptor(ctx)
215
+ );
260
216
  }
261
217
  uninstallHooks(ctx) {
262
- const hookPath = this.getHookConfigPath(ctx);
263
- const file = this.readJson(hookPath);
264
- const hooks = file?.hooks;
265
- if (!file || !hooks) {
266
- return [
267
- {
268
- platform: this.id,
269
- action: "skip",
270
- path: hookPath,
271
- detail: "no hooks section present"
272
- }
273
- ];
274
- }
275
- const changes = [];
276
- let mutated = false;
277
- for (const event of Object.keys(hooks)) {
278
- const bucket = hooks[event];
279
- if (!Array.isArray(bucket)) continue;
280
- const next = [];
281
- let removed = 0;
282
- for (const e of bucket) {
283
- const innerBefore = e.hooks?.length ?? 0;
284
- const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));
285
- removed += innerBefore - inner.length;
286
- if (inner.length > 0) next.push({ matcher: e.matcher ?? "", hooks: inner });
287
- }
288
- if (removed > 0) {
289
- if (next.length > 0) hooks[event] = next;
290
- else delete hooks[event];
291
- changes.push({
292
- platform: this.id,
293
- action: "remove",
294
- path: hookPath,
295
- detail: `hooks.${event} (${removed})`
296
- });
297
- mutated = true;
298
- }
299
- }
300
- if (mutated) this.writeJson(hookPath, file, ctx.dryRun);
301
- if (changes.length === 0) {
302
- changes.push({
303
- platform: this.id,
304
- action: "skip",
305
- path: hookPath,
306
- detail: "no matching hook entries"
307
- });
308
- }
309
- return changes;
218
+ return this.removeHookEntries(ctx, this.getHookConfigPath(ctx), this.hookDescriptor(ctx));
310
219
  }
311
- entryHasOurCommand(entry, ctx) {
312
- return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));
220
+ /**
221
+ * Droid's hook-merge descriptor (NESTED shape `{ matcher, hooks: [...] }`).
222
+ * Bound to `ctx` because droid's ownership is CONNECTOR-GENERIC (ANY of our
223
+ * commands in the entry's inner `hooks`, not a specific-command match):
224
+ * - mapEvent = drop events outside SUPPORTED_EVENTS (Droid has no equivalent
225
+ * for PermissionRequest / PostToolUseFailure / SubagentStart / PostCompact);
226
+ * droid's event names are Claude-identical, so supported events map 1:1.
227
+ * - entryOwnsCommand ignores the specific command — it reuses isOurCommand
228
+ * over the inner commands (the old entryHasOurCommand, folded in here).
229
+ * - uninstall = inner-strip ONLY (ownsEntryForRemove never-true); every detail
230
+ * string is the literal droid wording.
231
+ */
232
+ hookDescriptor(ctx) {
233
+ return {
234
+ mapEvent: (e) => SUPPORTED_EVENTS.has(e) ? e : void 0,
235
+ unmappedWarnDetail: (e) => `${e} has no Droid hook equivalent \u2014 skipped`,
236
+ renderEntry: (_event, matcher, command) => ({
237
+ matcher,
238
+ hooks: [{ type: "command", command }]
239
+ }),
240
+ entryOwnsCommand: (entry, _command) => (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx)),
241
+ ownsEntryForRemove: () => () => false,
242
+ stripInner: (c) => (entry) => {
243
+ const innerBefore = entry.hooks?.length ?? 0;
244
+ const inner = (entry.hooks ?? []).filter((h) => !this.isOurCommand(h.command, c));
245
+ return {
246
+ next: inner.length > 0 ? { matcher: entry.matcher ?? "", hooks: inner } : null,
247
+ removed: innerBefore - inner.length
248
+ };
249
+ },
250
+ skipDetail: (event) => `hooks.${event} already registered`,
251
+ removeDetail: (event, removed) => `hooks.${event} (${removed})`,
252
+ absentDetail: "no hooks section present",
253
+ noMatchDetail: "no matching hook entries"
254
+ };
313
255
  }
314
256
  /** True when a hook command references our home binary AND this connector id
315
257
  * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */
@@ -738,4 +680,4 @@ export {
738
680
  adapter,
739
681
  droid_default as default
740
682
  };
741
- //# sourceMappingURL=droid-JC2NT6S4.js.map
683
+ //# sourceMappingURL=droid-TJMTNCQE.js.map