@ken-jo/agent-connector 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +6 -0
  3. package/README.md +348 -0
  4. package/dist/amp-QSFH2V7Y.js +217 -0
  5. package/dist/amp-QSFH2V7Y.js.map +1 -0
  6. package/dist/amp-TULUPXXL.js +237 -0
  7. package/dist/amp-TULUPXXL.js.map +1 -0
  8. package/dist/antigravity-CX2YLSY7.js +17 -0
  9. package/dist/antigravity-CX2YLSY7.js.map +1 -0
  10. package/dist/antigravity-STHZWMP3.js +171 -0
  11. package/dist/antigravity-STHZWMP3.js.map +1 -0
  12. package/dist/antigravity-cli-P6HADOAO.js +121 -0
  13. package/dist/antigravity-cli-P6HADOAO.js.map +1 -0
  14. package/dist/antigravity-cli-YQDFVV4U.js +86 -0
  15. package/dist/antigravity-cli-YQDFVV4U.js.map +1 -0
  16. package/dist/chunk-54EMKTTX.js +191 -0
  17. package/dist/chunk-54EMKTTX.js.map +1 -0
  18. package/dist/chunk-7L6ITC4T.js +54 -0
  19. package/dist/chunk-7L6ITC4T.js.map +1 -0
  20. package/dist/chunk-7MSDGHJW.js +316 -0
  21. package/dist/chunk-7MSDGHJW.js.map +1 -0
  22. package/dist/chunk-BCHWFTV4.js +196 -0
  23. package/dist/chunk-BCHWFTV4.js.map +1 -0
  24. package/dist/chunk-DBQMX75U.js +36 -0
  25. package/dist/chunk-DBQMX75U.js.map +1 -0
  26. package/dist/chunk-EXLS7BSI.js +29 -0
  27. package/dist/chunk-EXLS7BSI.js.map +1 -0
  28. package/dist/chunk-JNM3TPLX.js +593 -0
  29. package/dist/chunk-JNM3TPLX.js.map +1 -0
  30. package/dist/chunk-JWNT5KW7.js +197 -0
  31. package/dist/chunk-JWNT5KW7.js.map +1 -0
  32. package/dist/chunk-KHO5WNTP.js +30 -0
  33. package/dist/chunk-KHO5WNTP.js.map +1 -0
  34. package/dist/chunk-LTT56GI3.js +155 -0
  35. package/dist/chunk-LTT56GI3.js.map +1 -0
  36. package/dist/chunk-MEH7GC7R.js +111 -0
  37. package/dist/chunk-MEH7GC7R.js.map +1 -0
  38. package/dist/chunk-MQPNU2CY.js +64 -0
  39. package/dist/chunk-MQPNU2CY.js.map +1 -0
  40. package/dist/chunk-OPXAP3AC.js +12 -0
  41. package/dist/chunk-OPXAP3AC.js.map +1 -0
  42. package/dist/chunk-RK6VBLXP.js +50 -0
  43. package/dist/chunk-RK6VBLXP.js.map +1 -0
  44. package/dist/chunk-TIIP3RG2.js +420 -0
  45. package/dist/chunk-TIIP3RG2.js.map +1 -0
  46. package/dist/chunk-TRKWUNO4.js +702 -0
  47. package/dist/chunk-TRKWUNO4.js.map +1 -0
  48. package/dist/chunk-TRQKHP7D.js +93 -0
  49. package/dist/chunk-TRQKHP7D.js.map +1 -0
  50. package/dist/chunk-WCETQWWK.js +59 -0
  51. package/dist/chunk-WCETQWWK.js.map +1 -0
  52. package/dist/chunk-WV63X7IK.js +357 -0
  53. package/dist/chunk-WV63X7IK.js.map +1 -0
  54. package/dist/chunk-XD7MY6HB.js +343 -0
  55. package/dist/chunk-XD7MY6HB.js.map +1 -0
  56. package/dist/chunk-XNAM7F35.js +276 -0
  57. package/dist/chunk-XNAM7F35.js.map +1 -0
  58. package/dist/chunk-XUCWLJY5.js +238 -0
  59. package/dist/chunk-XUCWLJY5.js.map +1 -0
  60. package/dist/chunk-YNZU6PAV.js +800 -0
  61. package/dist/chunk-YNZU6PAV.js.map +1 -0
  62. package/dist/chunk-YT43MUSJ.js +146 -0
  63. package/dist/chunk-YT43MUSJ.js.map +1 -0
  64. package/dist/claude-code-HKDV7T32.js +637 -0
  65. package/dist/claude-code-HKDV7T32.js.map +1 -0
  66. package/dist/claude-code-W74MNTAC.js +652 -0
  67. package/dist/claude-code-W74MNTAC.js.map +1 -0
  68. package/dist/cli/sdk.d.ts +54 -0
  69. package/dist/cli/sdk.js +82 -0
  70. package/dist/cli/sdk.js.map +1 -0
  71. package/dist/cli.d.ts +2 -0
  72. package/dist/cli.js +15 -0
  73. package/dist/cli.js.map +1 -0
  74. package/dist/codebuff-3PMZJJHP.js +307 -0
  75. package/dist/codebuff-3PMZJJHP.js.map +1 -0
  76. package/dist/codebuff-QX57FJDN.js +220 -0
  77. package/dist/codebuff-QX57FJDN.js.map +1 -0
  78. package/dist/codex-JFQTS6LU.js +593 -0
  79. package/dist/codex-JFQTS6LU.js.map +1 -0
  80. package/dist/codex-Q3ATRRX3.js +364 -0
  81. package/dist/codex-Q3ATRRX3.js.map +1 -0
  82. package/dist/copilot-cli-MTCGHZ2T.js +622 -0
  83. package/dist/copilot-cli-MTCGHZ2T.js.map +1 -0
  84. package/dist/copilot-cli-SJGIXVSD.js +369 -0
  85. package/dist/copilot-cli-SJGIXVSD.js.map +1 -0
  86. package/dist/crush-I7PK3FGI.js +360 -0
  87. package/dist/crush-I7PK3FGI.js.map +1 -0
  88. package/dist/crush-LN5QFFR2.js +183 -0
  89. package/dist/crush-LN5QFFR2.js.map +1 -0
  90. package/dist/cursor-4TMXKJOZ.js +603 -0
  91. package/dist/cursor-4TMXKJOZ.js.map +1 -0
  92. package/dist/cursor-QZ6MTO74.js +194 -0
  93. package/dist/cursor-QZ6MTO74.js.map +1 -0
  94. package/dist/detect-WIAGVYS4.js +68 -0
  95. package/dist/detect-WIAGVYS4.js.map +1 -0
  96. package/dist/doctor-EZW2K4NI.js +372 -0
  97. package/dist/doctor-EZW2K4NI.js.map +1 -0
  98. package/dist/droid-KN6VRMMT.js +424 -0
  99. package/dist/droid-KN6VRMMT.js.map +1 -0
  100. package/dist/droid-W5WF5XEX.js +224 -0
  101. package/dist/droid-W5WF5XEX.js.map +1 -0
  102. package/dist/gemini-cli-CIRW37TU.js +369 -0
  103. package/dist/gemini-cli-CIRW37TU.js.map +1 -0
  104. package/dist/gemini-cli-Y35FFK4M.js +705 -0
  105. package/dist/gemini-cli-Y35FFK4M.js.map +1 -0
  106. package/dist/goose-A3M5GODH.js +212 -0
  107. package/dist/goose-A3M5GODH.js.map +1 -0
  108. package/dist/goose-ZTGTSUFJ.js +480 -0
  109. package/dist/goose-ZTGTSUFJ.js.map +1 -0
  110. package/dist/hermes-H2KV44GK.js +470 -0
  111. package/dist/hermes-H2KV44GK.js.map +1 -0
  112. package/dist/hermes-ZYLMOFLZ.js +196 -0
  113. package/dist/hermes-ZYLMOFLZ.js.map +1 -0
  114. package/dist/hook-YVDILAMZ.js +75 -0
  115. package/dist/hook-YVDILAMZ.js.map +1 -0
  116. package/dist/index.d.ts +22 -0
  117. package/dist/index.js +10 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/install-HQRYZOQ2.js +60 -0
  120. package/dist/install-HQRYZOQ2.js.map +1 -0
  121. package/dist/jetbrains-copilot-HWA3DMH7.js +633 -0
  122. package/dist/jetbrains-copilot-HWA3DMH7.js.map +1 -0
  123. package/dist/kilo-NSWAVP6P.js +235 -0
  124. package/dist/kilo-NSWAVP6P.js.map +1 -0
  125. package/dist/kilo-QXJRCSLT.js +384 -0
  126. package/dist/kilo-QXJRCSLT.js.map +1 -0
  127. package/dist/kilo-cli-EAQTHXUW.js +587 -0
  128. package/dist/kilo-cli-EAQTHXUW.js.map +1 -0
  129. package/dist/kilo-cli-EVBKUODA.js +160 -0
  130. package/dist/kilo-cli-EVBKUODA.js.map +1 -0
  131. package/dist/kimi-EI3UM3ZV.js +155 -0
  132. package/dist/kimi-EI3UM3ZV.js.map +1 -0
  133. package/dist/kimi-GQ7VXNYT.js +423 -0
  134. package/dist/kimi-GQ7VXNYT.js.map +1 -0
  135. package/dist/kiro-UCLSLBW2.js +217 -0
  136. package/dist/kiro-UCLSLBW2.js.map +1 -0
  137. package/dist/kiro-VQTT6LO2.js +451 -0
  138. package/dist/kiro-VQTT6LO2.js.map +1 -0
  139. package/dist/leaderboard-K6ON3SWW.js +137 -0
  140. package/dist/leaderboard-K6ON3SWW.js.map +1 -0
  141. package/dist/mux-T2TV4CIQ.js +211 -0
  142. package/dist/mux-T2TV4CIQ.js.map +1 -0
  143. package/dist/mux-ZMLVAXOO.js +96 -0
  144. package/dist/mux-ZMLVAXOO.js.map +1 -0
  145. package/dist/omp-PB4VDKS6.js +586 -0
  146. package/dist/omp-PB4VDKS6.js.map +1 -0
  147. package/dist/openclaw-ETN2M63O.js +751 -0
  148. package/dist/openclaw-ETN2M63O.js.map +1 -0
  149. package/dist/openclaw-IYA7ASL6.js +150 -0
  150. package/dist/openclaw-IYA7ASL6.js.map +1 -0
  151. package/dist/opencode-FZ33JKUZ.js +734 -0
  152. package/dist/opencode-FZ33JKUZ.js.map +1 -0
  153. package/dist/opencode-HWT3RSMN.js +216 -0
  154. package/dist/opencode-HWT3RSMN.js.map +1 -0
  155. package/dist/package-DLOVE2E4.js +1132 -0
  156. package/dist/package-DLOVE2E4.js.map +1 -0
  157. package/dist/pi-CIU2QHT4.js +208 -0
  158. package/dist/pi-CIU2QHT4.js.map +1 -0
  159. package/dist/pi-UFX2OYFV.js +139 -0
  160. package/dist/pi-UFX2OYFV.js.map +1 -0
  161. package/dist/qwen-code-5POCNU6P.js +573 -0
  162. package/dist/qwen-code-5POCNU6P.js.map +1 -0
  163. package/dist/qwen-code-W7NUCDEN.js +134 -0
  164. package/dist/qwen-code-W7NUCDEN.js.map +1 -0
  165. package/dist/roo-code-IOIUXRDE.js +242 -0
  166. package/dist/roo-code-IOIUXRDE.js.map +1 -0
  167. package/dist/roo-code-ZLKH4A7N.js +229 -0
  168. package/dist/roo-code-ZLKH4A7N.js.map +1 -0
  169. package/dist/runtime/index.d.ts +157 -0
  170. package/dist/runtime/index.js +20 -0
  171. package/dist/runtime/index.js.map +1 -0
  172. package/dist/serve-HVWWY4B6.js +65 -0
  173. package/dist/serve-HVWWY4B6.js.map +1 -0
  174. package/dist/status-FE7TECZD.js +128 -0
  175. package/dist/status-FE7TECZD.js.map +1 -0
  176. package/dist/synthetic-UKR6SMGS.js +178 -0
  177. package/dist/synthetic-UKR6SMGS.js.map +1 -0
  178. package/dist/telemetry-36GESKQQ.js +349 -0
  179. package/dist/telemetry-36GESKQQ.js.map +1 -0
  180. package/dist/trae-JSNDZFKL.js +204 -0
  181. package/dist/trae-JSNDZFKL.js.map +1 -0
  182. package/dist/trae-PA26DPBW.js +157 -0
  183. package/dist/trae-PA26DPBW.js.map +1 -0
  184. package/dist/types-CYUB1OTr.d.ts +427 -0
  185. package/dist/uninstall-IGCKNOSF.js +72 -0
  186. package/dist/uninstall-IGCKNOSF.js.map +1 -0
  187. package/dist/upgrade-JV2VK242.js +104 -0
  188. package/dist/upgrade-JV2VK242.js.map +1 -0
  189. package/dist/usage-6ER6EMEY.js +324 -0
  190. package/dist/usage-6ER6EMEY.js.map +1 -0
  191. package/dist/usage-event-JKBI6XCF.js +48 -0
  192. package/dist/usage-event-JKBI6XCF.js.map +1 -0
  193. package/dist/vscode-copilot-CK3NO54M.js +715 -0
  194. package/dist/vscode-copilot-CK3NO54M.js.map +1 -0
  195. package/dist/warp-JNQA7PBU.js +126 -0
  196. package/dist/warp-JNQA7PBU.js.map +1 -0
  197. package/dist/warp-QNVDXOG4.js +199 -0
  198. package/dist/warp-QNVDXOG4.js.map +1 -0
  199. package/dist/zed-NNNX5MNT.js +272 -0
  200. package/dist/zed-NNNX5MNT.js.map +1 -0
  201. package/dist/zed-VRJKWYUR.js +209 -0
  202. package/dist/zed-VRJKWYUR.js.map +1 -0
  203. package/package.json +79 -0
@@ -0,0 +1,603 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ rewriteEnvRefs
4
+ } from "./chunk-DBQMX75U.js";
5
+ import {
6
+ BaseAdapter
7
+ } from "./chunk-TIIP3RG2.js";
8
+ import "./chunk-7L6ITC4T.js";
9
+ import {
10
+ buildHomeBinHookCommand,
11
+ buildServeWrapperCommand,
12
+ isHomeBinHookCommand,
13
+ shouldWrapForTelemetry
14
+ } from "./chunk-MEH7GC7R.js";
15
+ import "./chunk-TRQKHP7D.js";
16
+
17
+ // src/adapters/cursor/index.ts
18
+ import { existsSync } from "fs";
19
+ import { homedir } from "os";
20
+ import { join } from "path";
21
+ var HOST = "cursor";
22
+ var MCP_ROOT_KEY = "mcpServers";
23
+ var CURSOR_HOOKS_VERSION = 1;
24
+ var CURSOR_EVENT = {
25
+ PreToolUse: "preToolUse",
26
+ PostToolUse: "postToolUse",
27
+ SessionStart: "sessionStart",
28
+ Stop: "stop"
29
+ };
30
+ var EVENT_MAP = {
31
+ PreToolUse: CURSOR_EVENT.PreToolUse,
32
+ PostToolUse: CURSOR_EVENT.PostToolUse,
33
+ SessionStart: CURSOR_EVENT.SessionStart,
34
+ Stop: CURSOR_EVENT.Stop
35
+ };
36
+ var CursorAdapter = class extends BaseAdapter {
37
+ id = HOST;
38
+ name = "Cursor";
39
+ paradigm = "json-stdio";
40
+ capabilities = {
41
+ // Cursor natively supports pre/post tool-use, session start, and stop.
42
+ preToolUse: true,
43
+ postToolUse: true,
44
+ preCompact: false,
45
+ sessionStart: true,
46
+ sessionEnd: false,
47
+ userPromptSubmit: false,
48
+ stop: true,
49
+ notification: false,
50
+ // Cursor's preToolUse can rewrite tool input (updated_input) but cannot
51
+ // rewrite already-emitted tool output.
52
+ canModifyArgs: true,
53
+ canModifyOutput: false,
54
+ canInjectSessionContext: true,
55
+ transports: ["stdio", "http"],
56
+ // Content surfaces: Cursor supports all three (commands, skills, subagents).
57
+ supportsCommands: true,
58
+ supportsSkills: true,
59
+ supportsSubagents: true
60
+ };
61
+ // ── Detection ────────────────────────────────────────────────────────────
62
+ detectInstalled(projectDir) {
63
+ const userDir = join(homedir(), ".cursor");
64
+ const userMcp = join(userDir, "mcp.json");
65
+ const userHooks = join(userDir, "hooks.json");
66
+ const projectDirCursor = join(projectDir, ".cursor");
67
+ const installed = existsSync(userDir) || existsSync(userMcp) || existsSync(userHooks) || existsSync(projectDirCursor);
68
+ return {
69
+ id: this.id,
70
+ name: this.name,
71
+ installed,
72
+ paradigm: this.paradigm,
73
+ capabilities: this.capabilities,
74
+ configPath: userMcp,
75
+ scope: "user",
76
+ reason: installed ? `found Cursor config under ${userDir}` : `no Cursor config at ${userDir}`,
77
+ confidence: installed ? "high" : "low"
78
+ };
79
+ }
80
+ // ── Native paths ─────────────────────────────────────────────────────────
81
+ getConfigDir(ctx) {
82
+ return ctx.scope === "project" ? join(ctx.projectDir, ".cursor") : join(homedir(), ".cursor");
83
+ }
84
+ getServerConfigPath(ctx) {
85
+ return join(this.getConfigDir(ctx), "mcp.json");
86
+ }
87
+ getHookConfigPath(ctx) {
88
+ return join(this.getConfigDir(ctx), "hooks.json");
89
+ }
90
+ // ── MCP server install / uninstall ───────────────────────────────────────
91
+ installServer(ctx) {
92
+ const { connector } = ctx;
93
+ const override = connector.platforms[HOST]?.server;
94
+ if (!connector.server || override === false) {
95
+ return [
96
+ {
97
+ platform: this.id,
98
+ action: "skip",
99
+ detail: connector.server ? "server registration disabled for cursor" : "connector declares no MCP server"
100
+ }
101
+ ];
102
+ }
103
+ const server = override && typeof override === "object" ? { ...connector.server, ...override } : connector.server;
104
+ const serverPath = this.getServerConfigPath(ctx);
105
+ const entry = this.renderServerEntry(ctx, server);
106
+ return [
107
+ this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun)
108
+ ];
109
+ }
110
+ uninstallServer(ctx) {
111
+ const serverPath = this.getServerConfigPath(ctx);
112
+ return [
113
+ this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun)
114
+ ];
115
+ }
116
+ /** Render a normalized ServerDef into Cursor's native mcpServers entry. */
117
+ renderServerEntry(ctx, server) {
118
+ const transport = server.transport;
119
+ if (transport === "stdio") {
120
+ let command = server.command ?? "";
121
+ let args = [...server.args ?? []];
122
+ if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {
123
+ const wrapped = buildServeWrapperCommand(
124
+ ctx.homeBinPath,
125
+ ctx.connector.id,
126
+ command,
127
+ args,
128
+ ctx.scope,
129
+ this.id
130
+ );
131
+ command = wrapped.command;
132
+ args = wrapped.args;
133
+ }
134
+ const entry2 = { command: this.rewrite(command) };
135
+ if (args.length > 0) entry2.args = args.map((a) => this.rewrite(a));
136
+ const env = this.renderEnv(server.env);
137
+ if (env) entry2.env = env;
138
+ if (server.cwd) entry2.cwd = this.rewrite(server.cwd);
139
+ return entry2;
140
+ }
141
+ const entry = { url: this.rewrite(server.url ?? "") };
142
+ const headers = this.renderEnv(server.headers);
143
+ if (headers) entry.headers = headers;
144
+ return entry;
145
+ }
146
+ /**
147
+ * Render env/header values. Cursor supports its own `${env:VAR}` native
148
+ * interpolation, so translate `${env:VAR}` refs to that native token rather
149
+ * than baking secrets into the file. Literals pass through unchanged.
150
+ */
151
+ renderEnv(env) {
152
+ if (!env || Object.keys(env).length === 0) return void 0;
153
+ const out = {};
154
+ for (const [k, v] of Object.entries(env)) out[k] = this.rewrite(v);
155
+ return out;
156
+ }
157
+ /** Translate `${env:VAR(:-default)}` to Cursor's native `${env:VAR}` token. */
158
+ rewrite(value) {
159
+ return rewriteEnvRefs(value, cursorEnvToken);
160
+ }
161
+ // ── Hook install / uninstall ─────────────────────────────────────────────
162
+ installHooks(ctx) {
163
+ const { connector } = ctx;
164
+ if (connector.platforms[HOST]?.hooks === false) {
165
+ return [{ platform: this.id, action: "skip", detail: "hooks disabled for cursor" }];
166
+ }
167
+ if (connector.hookEvents.length === 0) {
168
+ return [{ platform: this.id, action: "skip", detail: "connector declares no hooks" }];
169
+ }
170
+ const hooksPath = this.getHookConfigPath(ctx);
171
+ const file = this.readJson(hooksPath) ?? {};
172
+ const hooks = file.hooks ??= {};
173
+ const changes = [];
174
+ let mutated = false;
175
+ for (const event of connector.hookEvents) {
176
+ const cursorEvent = EVENT_MAP[event];
177
+ if (!cursorEvent) {
178
+ changes.push({
179
+ platform: this.id,
180
+ action: "warn",
181
+ path: hooksPath,
182
+ detail: `${event} has no Cursor hook equivalent \u2014 skipped`
183
+ });
184
+ continue;
185
+ }
186
+ const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
187
+ const matcher = connector.hooks[event]?.matcher;
188
+ const entry = matcher ? { command, matcher } : { command };
189
+ const bucket = hooks[cursorEvent] ??= [];
190
+ const existingIdx = bucket.findIndex((e) => this.isOurCommand(e.command, ctx));
191
+ if (existingIdx >= 0) {
192
+ if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
193
+ changes.push({
194
+ platform: this.id,
195
+ action: "skip",
196
+ path: hooksPath,
197
+ detail: `hooks.${cursorEvent} already registered`
198
+ });
199
+ continue;
200
+ }
201
+ bucket[existingIdx] = entry;
202
+ changes.push({
203
+ platform: this.id,
204
+ action: "update",
205
+ path: hooksPath,
206
+ detail: `hooks.${cursorEvent}`
207
+ });
208
+ } else {
209
+ bucket.push(entry);
210
+ changes.push({
211
+ platform: this.id,
212
+ action: "create",
213
+ path: hooksPath,
214
+ detail: `hooks.${cursorEvent}`
215
+ });
216
+ }
217
+ mutated = true;
218
+ }
219
+ if (mutated) {
220
+ file.version = CURSOR_HOOKS_VERSION;
221
+ this.writeJson(hooksPath, file, ctx.dryRun);
222
+ }
223
+ return changes;
224
+ }
225
+ uninstallHooks(ctx) {
226
+ const hooksPath = this.getHookConfigPath(ctx);
227
+ const file = this.readJson(hooksPath);
228
+ const hooks = file?.hooks;
229
+ if (!file || !hooks) {
230
+ return [
231
+ {
232
+ platform: this.id,
233
+ action: "skip",
234
+ path: hooksPath,
235
+ detail: "no hooks section present"
236
+ }
237
+ ];
238
+ }
239
+ const changes = [];
240
+ let mutated = false;
241
+ for (const cursorEvent of Object.keys(hooks)) {
242
+ const bucket = hooks[cursorEvent];
243
+ if (!Array.isArray(bucket)) continue;
244
+ const before = bucket.length;
245
+ const next = bucket.filter((e) => !this.isOurCommand(e.command, ctx));
246
+ const removed = before - next.length;
247
+ if (removed > 0) {
248
+ if (next.length > 0) hooks[cursorEvent] = next;
249
+ else delete hooks[cursorEvent];
250
+ changes.push({
251
+ platform: this.id,
252
+ action: "remove",
253
+ path: hooksPath,
254
+ detail: `hooks.${cursorEvent} (${removed})`
255
+ });
256
+ mutated = true;
257
+ }
258
+ }
259
+ if (mutated) this.writeJson(hooksPath, file, ctx.dryRun);
260
+ if (changes.length === 0) {
261
+ changes.push({
262
+ platform: this.id,
263
+ action: "skip",
264
+ path: hooksPath,
265
+ detail: "no matching hook entries"
266
+ });
267
+ }
268
+ return changes;
269
+ }
270
+ /** True when a hook command references our home binary AND this connector id
271
+ * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */
272
+ isOurCommand(command, ctx) {
273
+ return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
274
+ }
275
+ // ── Content surfaces: commands / skills / subagents ──────────────────────
276
+ // CONTENT-ONLY: pure native-file writers under <configDir>/{commands,skills,
277
+ // agents}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each
278
+ // method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile
279
+ // and reversible via removeContentFile. Honors platforms["cursor"] per-surface
280
+ // false to skip. Cursor commands are BODY-ONLY markdown (no frontmatter);
281
+ // skills are the uniform <name>/SKILL.md + resources; subagents are md+fm.
282
+ commandsDir(ctx) {
283
+ return join(this.getConfigDir(ctx), "commands");
284
+ }
285
+ skillsDir(ctx) {
286
+ return join(this.getConfigDir(ctx), "skills");
287
+ }
288
+ agentsDir(ctx) {
289
+ return join(this.getConfigDir(ctx), "agents");
290
+ }
291
+ /** Native command file path: <configDir>/commands/<name>.md. */
292
+ commandPath(ctx, name) {
293
+ return join(this.commandsDir(ctx), `${name}.md`);
294
+ }
295
+ /** Native skill dir: <configDir>/skills/<name>. */
296
+ skillDir(ctx, name) {
297
+ return join(this.skillsDir(ctx), name);
298
+ }
299
+ /** Native subagent file path: <configDir>/agents/<name>.md. */
300
+ subagentPath(ctx, name) {
301
+ return join(this.agentsDir(ctx), `${name}.md`);
302
+ }
303
+ // ── Commands ──────────────────────────────────────────────────────────────
304
+ installCommands(ctx) {
305
+ const { connector } = ctx;
306
+ if (connector.platforms[HOST]?.commands === false) {
307
+ return [{ platform: this.id, action: "skip", detail: "commands disabled for cursor" }];
308
+ }
309
+ if (connector.commands.length === 0) {
310
+ return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
311
+ }
312
+ return connector.commands.map(
313
+ (cmd) => this.writeContentFile(
314
+ this.commandPath(ctx, cmd.name),
315
+ this.renderCommand(cmd),
316
+ ctx.dryRun
317
+ )
318
+ );
319
+ }
320
+ uninstallCommands(ctx) {
321
+ const { connector } = ctx;
322
+ if (connector.commands.length === 0) {
323
+ return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
324
+ }
325
+ return connector.commands.map(
326
+ (cmd) => this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun)
327
+ );
328
+ }
329
+ /**
330
+ * Render a Cursor command: BODY-ONLY markdown (no frontmatter). Cursor reads
331
+ * the file as the command prompt verbatim. We prepend the one-line description
332
+ * as an HTML comment header when present so authoring intent survives the
333
+ * round-trip without leaking into the rendered prompt. A description containing
334
+ * "-->" would prematurely CLOSE the HTML comment and leak the remainder into
335
+ * the prompt, so we neutralize that sequence before embedding it.
336
+ */
337
+ renderCommand(cmd) {
338
+ if (!cmd.description) return `${cmd.prompt}
339
+ `;
340
+ const safe = cmd.description.replace(/--+>/g, (m) => m.replace(/>/g, "&gt;"));
341
+ return `<!-- ${safe} -->
342
+
343
+ ${cmd.prompt}
344
+ `;
345
+ }
346
+ // ── Skills ────────────────────────────────────────────────────────────────
347
+ installSkills(ctx) {
348
+ const { connector } = ctx;
349
+ if (connector.platforms[HOST]?.skills === false) {
350
+ return [{ platform: this.id, action: "skip", detail: "skills disabled for cursor" }];
351
+ }
352
+ if (connector.skills.length === 0) {
353
+ return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
354
+ }
355
+ const changes = [];
356
+ for (const skill of connector.skills) {
357
+ const dir = this.skillDir(ctx, skill.name);
358
+ changes.push(
359
+ this.writeContentFile(join(dir, "SKILL.md"), this.renderSkill(skill), ctx.dryRun)
360
+ );
361
+ for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
362
+ const target = this.resolveWithin(dir, rel);
363
+ if (target === null) {
364
+ changes.push({
365
+ platform: this.id,
366
+ action: "warn",
367
+ detail: `skill resource "${rel}" escapes the skill dir; skipped`
368
+ });
369
+ continue;
370
+ }
371
+ changes.push(this.writeContentFile(target, contents, ctx.dryRun));
372
+ }
373
+ }
374
+ return changes;
375
+ }
376
+ uninstallSkills(ctx) {
377
+ const { connector } = ctx;
378
+ if (connector.skills.length === 0) {
379
+ return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
380
+ }
381
+ const changes = [];
382
+ for (const skill of connector.skills) {
383
+ const dir = this.skillDir(ctx, skill.name);
384
+ changes.push(this.removeContentFile(join(dir, "SKILL.md"), ctx.dryRun));
385
+ for (const rel of Object.keys(skill.resources ?? {})) {
386
+ const target = this.resolveWithin(dir, rel);
387
+ if (target === null) continue;
388
+ changes.push(this.removeContentFile(target, ctx.dryRun));
389
+ }
390
+ changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));
391
+ }
392
+ return changes;
393
+ }
394
+ /**
395
+ * Render a skill's SKILL.md: frontmatter (name, description + optional model,
396
+ * allowed-tools, disable-model-invocation) + body. Uniform across platforms;
397
+ * only the parent dir differs.
398
+ */
399
+ renderSkill(skill) {
400
+ const frontmatter = {
401
+ name: skill.name,
402
+ description: skill.description
403
+ };
404
+ if (skill.model !== void 0) frontmatter.model = skill.model;
405
+ const allow = skill.tools?.allow;
406
+ if (allow && allow.length > 0) frontmatter["allowed-tools"] = allow.join(", ");
407
+ if (skill.disableModelInvocation !== void 0) {
408
+ frontmatter["disable-model-invocation"] = skill.disableModelInvocation;
409
+ }
410
+ if (skill.extra) Object.assign(frontmatter, skill.extra);
411
+ return this.renderFrontmatterMd(frontmatter, skill.body);
412
+ }
413
+ // ── Subagents ───────────────────────────────────────────────────────────────
414
+ installSubagents(ctx) {
415
+ const { connector } = ctx;
416
+ if (connector.platforms[HOST]?.subagents === false) {
417
+ return [{ platform: this.id, action: "skip", detail: "subagents disabled for cursor" }];
418
+ }
419
+ if (connector.subagents.length === 0) {
420
+ return [{ platform: this.id, action: "skip", detail: "connector declares no subagents" }];
421
+ }
422
+ return connector.subagents.map(
423
+ (agent) => this.writeContentFile(
424
+ this.subagentPath(ctx, agent.name),
425
+ this.renderSubagent(agent),
426
+ ctx.dryRun
427
+ )
428
+ );
429
+ }
430
+ uninstallSubagents(ctx) {
431
+ const { connector } = ctx;
432
+ if (connector.subagents.length === 0) {
433
+ return [{ platform: this.id, action: "skip", detail: "connector declares no subagents" }];
434
+ }
435
+ return connector.subagents.map(
436
+ (agent) => this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun)
437
+ );
438
+ }
439
+ /** Render a Cursor subagent to md+frontmatter (name, description, model, readonly) + prompt body. */
440
+ renderSubagent(agent) {
441
+ const frontmatter = {
442
+ name: agent.name,
443
+ description: agent.description
444
+ };
445
+ if (agent.model !== void 0) frontmatter.model = agent.model;
446
+ if (agent.readonly !== void 0) frontmatter.readonly = agent.readonly;
447
+ if (agent.extra) Object.assign(frontmatter, agent.extra);
448
+ return this.renderFrontmatterMd(frontmatter, agent.prompt);
449
+ }
450
+ // ── Diagnostics ──────────────────────────────────────────────────────────
451
+ getHealthChecks(ctx) {
452
+ const mcpPath = this.getServerConfigPath(ctx);
453
+ const hooksPath = this.getHookConfigPath(ctx);
454
+ const checks = [
455
+ {
456
+ name: `${this.name}: mcp.json present`,
457
+ check: () => existsSync(mcpPath) ? { status: "OK", detail: mcpPath } : { status: "FAIL", detail: `not found: ${mcpPath}` }
458
+ },
459
+ {
460
+ name: `${this.name}: hooks.json present`,
461
+ check: () => existsSync(hooksPath) ? { status: "OK", detail: hooksPath } : { status: "FAIL", detail: `not found: ${hooksPath}` }
462
+ }
463
+ ];
464
+ for (const cmd of ctx.connector.commands) {
465
+ const p = this.commandPath(ctx, cmd.name);
466
+ checks.push({
467
+ name: `${this.name}: command ${cmd.name} present`,
468
+ check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
469
+ });
470
+ }
471
+ for (const skill of ctx.connector.skills) {
472
+ const p = join(this.skillDir(ctx, skill.name), "SKILL.md");
473
+ checks.push({
474
+ name: `${this.name}: skill ${skill.name} present`,
475
+ check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
476
+ });
477
+ }
478
+ for (const agent of ctx.connector.subagents) {
479
+ const p = this.subagentPath(ctx, agent.name);
480
+ checks.push({
481
+ name: `${this.name}: subagent ${agent.name} present`,
482
+ check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
483
+ });
484
+ }
485
+ return checks;
486
+ }
487
+ // ── Runtime: parse Cursor stdin JSON → normalized event ──────────────────
488
+ parseEvent(event, raw) {
489
+ const input = raw ?? {};
490
+ const connectorId = typeof input.connector === "string" ? input.connector : "";
491
+ const sessionId = extractSessionId(input);
492
+ const projectDir = this.getProjectDir(input);
493
+ const base = {
494
+ hostPlatform: HOST,
495
+ connectorId,
496
+ sessionId,
497
+ raw,
498
+ ...projectDir !== void 0 ? { projectDir } : {}
499
+ };
500
+ switch (event) {
501
+ case "PreToolUse": {
502
+ const ev = {
503
+ ...base,
504
+ toolName: input.tool_name ?? "",
505
+ toolInput: input.tool_input ?? {}
506
+ };
507
+ return ev;
508
+ }
509
+ case "PostToolUse": {
510
+ const toolOutput = input.tool_output ?? input.error_message;
511
+ const ev = {
512
+ ...base,
513
+ toolName: input.tool_name ?? "",
514
+ toolInput: input.tool_input ?? {},
515
+ ...toolOutput !== void 0 ? { toolOutput } : {},
516
+ ...input.error_message ? { isError: true } : {}
517
+ };
518
+ return ev;
519
+ }
520
+ case "SessionStart": {
521
+ const ev = {
522
+ ...base,
523
+ source: normalizeSessionSource(input.source ?? input.trigger)
524
+ };
525
+ return ev;
526
+ }
527
+ case "Stop": {
528
+ const ev = {
529
+ ...base,
530
+ ...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
531
+ };
532
+ return ev;
533
+ }
534
+ default: {
535
+ throw new Error(`unsupported cursor hook event: ${String(event)}`);
536
+ }
537
+ }
538
+ }
539
+ getProjectDir(input) {
540
+ return input.cwd ?? input.workspace_roots?.[0] ?? void 0;
541
+ }
542
+ // ── Runtime: normalized response → Cursor native hook reply ──────────────
543
+ formatReply(event, response) {
544
+ const decision = response.decision ?? "allow";
545
+ if (decision === "deny") {
546
+ return this.stdout({
547
+ permission: "deny",
548
+ user_message: response.reason ?? "Blocked by hook"
549
+ });
550
+ }
551
+ if (decision === "ask") {
552
+ return this.stdout({
553
+ permission: "ask",
554
+ user_message: response.reason ?? "Confirmation required by hook"
555
+ });
556
+ }
557
+ if (decision === "modify") {
558
+ if (event === "PreToolUse" && response.updatedInput) {
559
+ return this.stdout({ updated_input: response.updatedInput });
560
+ }
561
+ }
562
+ if (decision === "context" && response.additionalContext) {
563
+ return event === "PreToolUse" ? this.stdout({ agent_message: response.additionalContext }) : this.stdout({ additional_context: response.additionalContext });
564
+ }
565
+ if (event === "SessionStart") {
566
+ return this.stdout({ additional_context: response.additionalContext ?? "" });
567
+ }
568
+ if (event === "PreToolUse") return this.stdout({ agent_message: "" });
569
+ if (event === "PostToolUse") return this.stdout({ additional_context: "" });
570
+ return { exitCode: 0 };
571
+ }
572
+ stdout(payload) {
573
+ return { exitCode: 0, stdout: JSON.stringify(payload) };
574
+ }
575
+ };
576
+ function cursorEnvToken(name) {
577
+ return `\${env:${name}}`;
578
+ }
579
+ function extractSessionId(input) {
580
+ if (typeof input.conversation_id === "string") return input.conversation_id;
581
+ if (typeof input.session_id === "string") return input.session_id;
582
+ return "";
583
+ }
584
+ function normalizeSessionSource(source) {
585
+ switch (source) {
586
+ case "compact":
587
+ return "compact";
588
+ case "resume":
589
+ return "resume";
590
+ case "clear":
591
+ return "clear";
592
+ default:
593
+ return "startup";
594
+ }
595
+ }
596
+ var adapter = new CursorAdapter();
597
+ var cursor_default = adapter;
598
+ export {
599
+ CursorAdapter,
600
+ adapter,
601
+ cursor_default as default
602
+ };
603
+ //# sourceMappingURL=cursor-4TMXKJOZ.js.map