@cursor/july 0.1.100 → 0.1.102

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 (484) hide show
  1. package/README.md +27 -0
  2. package/dist/bin/agent-serve.js +3 -2
  3. package/dist/channels/deployments/deployments-channel.d.ts +41 -5
  4. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
  5. package/dist/channels/deployments/deployments-channel.js +88 -8
  6. package/dist/channels/deployments/types.d.ts +4 -3
  7. package/dist/channels/deployments/types.d.ts.map +1 -1
  8. package/dist/channels/origin/defaults.d.ts +43 -0
  9. package/dist/channels/origin/defaults.d.ts.map +1 -0
  10. package/dist/channels/origin/defaults.js +111 -0
  11. package/dist/channels/origin/index.d.ts +2 -0
  12. package/dist/channels/origin/index.d.ts.map +1 -1
  13. package/dist/channels/origin/index.js +2 -0
  14. package/dist/channels/origin/origin-channel.d.ts +2 -1
  15. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  16. package/dist/channels/origin/origin-channel.js +24 -3
  17. package/dist/channels/origin/state.d.ts +32 -0
  18. package/dist/channels/origin/state.d.ts.map +1 -0
  19. package/dist/channels/origin/state.js +23 -0
  20. package/dist/channels/origin/types.d.ts +23 -1
  21. package/dist/channels/origin/types.d.ts.map +1 -1
  22. package/dist/channels/slack/api.d.ts +1 -1
  23. package/dist/channels/slack/api.d.ts.map +1 -1
  24. package/dist/channels/slack/api.js +5 -2
  25. package/dist/channels/slack/assistant.d.ts +1 -1
  26. package/dist/channels/slack/assistant.d.ts.map +1 -1
  27. package/dist/channels/slack/code-fences.d.ts +17 -0
  28. package/dist/channels/slack/code-fences.d.ts.map +1 -0
  29. package/dist/channels/slack/code-fences.js +168 -0
  30. package/dist/channels/slack/dispatch.d.ts +3 -2
  31. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  32. package/dist/channels/slack/dispatch.js +28 -8
  33. package/dist/channels/slack/inbound.d.ts +8 -0
  34. package/dist/channels/slack/inbound.d.ts.map +1 -1
  35. package/dist/channels/slack/inbound.js +28 -0
  36. package/dist/channels/slack/index.d.ts +1 -0
  37. package/dist/channels/slack/index.d.ts.map +1 -1
  38. package/dist/channels/slack/index.js +1 -0
  39. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  40. package/dist/channels/slack/live-delivery.js +11 -4
  41. package/dist/channels/slack/manifest.d.ts.map +1 -1
  42. package/dist/channels/slack/manifest.js +2 -1
  43. package/dist/connections.d.ts +18 -2
  44. package/dist/connections.d.ts.map +1 -1
  45. package/dist/connections.js +18 -2
  46. package/dist/docs/404.html +2 -2
  47. package/dist/docs/ab.html +4 -4
  48. package/dist/docs/assets/{app.DZ1e0Ycq.js → app.CLA03RCz.js} +1 -1
  49. package/dist/docs/assets/chunks/@localSearchIndexroot.FAqdWIXo.js +1 -0
  50. package/dist/docs/assets/chunks/{VPLocalSearchBox.l8omwc6D.js → VPLocalSearchBox.ifxv-cJV.js} +1 -1
  51. package/dist/docs/assets/chunks/{theme.JVcD6gel.js → theme.DWCwM6p-.js} +2 -2
  52. package/dist/docs/assets/concepts.md.rPzW2HZN.js +1 -0
  53. package/dist/docs/assets/guides_cloud-agents.md.DumwWXba.js +9 -0
  54. package/dist/docs/assets/guides_cloud-agents.md.DumwWXba.lean.js +1 -0
  55. package/dist/docs/assets/{guides_cloud-runtime.md.CkYbjnAX.js → guides_cloud-runtime.md.BRirbRAN.js} +1 -1
  56. package/dist/docs/assets/index.md.Kiht7ell.js +5 -0
  57. package/dist/docs/assets/{index.md.Bb4k8kUm.lean.js → index.md.Kiht7ell.lean.js} +1 -1
  58. package/dist/docs/assets/{reference_connections.md.BiGoBAk2.js → reference_connections.md.Di6jJAXF.js} +12 -2
  59. package/dist/docs/assets/{reference_connections.md.BiGoBAk2.lean.js → reference_connections.md.Di6jJAXF.lean.js} +1 -1
  60. package/dist/docs/assets/reference_extensions.md.9WQMZe1l.js +56 -0
  61. package/dist/docs/assets/reference_extensions.md.9WQMZe1l.lean.js +1 -0
  62. package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.js → reference_http-api.md.oySXBO8o.js} +1 -1
  63. package/dist/docs/assets/{reference_project-layout.md.Bv4KOtlB.js → reference_project-layout.md.CA6QP6Lw.js} +2 -2
  64. package/dist/docs/assets/{reference_project-layout.md.Bv4KOtlB.lean.js → reference_project-layout.md.CA6QP6Lw.lean.js} +1 -1
  65. package/dist/docs/assets/{reference_skills.md.BFW9retM.js → reference_skills.md.l2ezAcaN.js} +1 -1
  66. package/dist/docs/assets/{reference_tools.md.CvAHsdSp.js → reference_tools.md.B1up2r9W.js} +1 -1
  67. package/dist/docs/assets/skills_framework-map.md.DDa4MeEW.js +1 -0
  68. package/dist/docs/assets/{skills_framework-map.md.BTi817yv.lean.js → skills_framework-map.md.DDa4MeEW.lean.js} +1 -1
  69. package/dist/docs/building-with-agents.html +4 -4
  70. package/dist/docs/concepts.html +5 -5
  71. package/dist/docs/concepts.md +3 -3
  72. package/dist/docs/deployment.html +4 -4
  73. package/dist/docs/evals.html +4 -4
  74. package/dist/docs/guides/agent-to-agent.html +4 -4
  75. package/dist/docs/guides/cloud-agents.html +35 -0
  76. package/dist/docs/guides/cloud-agents.md +93 -0
  77. package/dist/docs/guides/cloud-runtime.html +6 -6
  78. package/dist/docs/guides/cloud-runtime.md +2 -0
  79. package/dist/docs/guides/convert-automation.html +4 -4
  80. package/dist/docs/guides/github.html +4 -4
  81. package/dist/docs/guides/human-in-the-loop.html +4 -4
  82. package/dist/docs/guides/mcp-oauth.html +4 -4
  83. package/dist/docs/guides/opentelemetry.html +5 -5
  84. package/dist/docs/guides/slack.html +4 -4
  85. package/dist/docs/guides/webhooks.html +4 -4
  86. package/dist/docs/hashmap.json +1 -1
  87. package/dist/docs/hillclimbing.html +4 -4
  88. package/dist/docs/index.html +6 -6
  89. package/dist/docs/index.md +5 -1
  90. package/dist/docs/llms-full.txt +353 -5
  91. package/dist/docs/llms.txt +2 -0
  92. package/dist/docs/quickstart.html +4 -4
  93. package/dist/docs/reference/agent-config.html +4 -4
  94. package/dist/docs/reference/artifacts.html +4 -4
  95. package/dist/docs/reference/channels.html +5 -5
  96. package/dist/docs/reference/cli.html +4 -4
  97. package/dist/docs/reference/connections.html +16 -6
  98. package/dist/docs/reference/connections.md +31 -0
  99. package/dist/docs/reference/extensions.html +82 -0
  100. package/dist/docs/reference/extensions.md +200 -0
  101. package/dist/docs/reference/hooks.html +4 -4
  102. package/dist/docs/reference/http-api.html +6 -6
  103. package/dist/docs/reference/http-api.md +1 -1
  104. package/dist/docs/reference/instructions.html +4 -4
  105. package/dist/docs/reference/playground.html +4 -4
  106. package/dist/docs/reference/project-layout.html +6 -6
  107. package/dist/docs/reference/project-layout.md +3 -0
  108. package/dist/docs/reference/prompt.html +4 -4
  109. package/dist/docs/reference/schedules.html +4 -4
  110. package/dist/docs/reference/sessions.html +4 -4
  111. package/dist/docs/reference/skills.html +6 -6
  112. package/dist/docs/reference/skills.md +2 -0
  113. package/dist/docs/reference/subagents.html +5 -5
  114. package/dist/docs/reference/tools.html +6 -6
  115. package/dist/docs/reference/tools.md +2 -0
  116. package/dist/docs/scaffolding-agents.html +4 -4
  117. package/dist/docs/skills/ab.html +4 -4
  118. package/dist/docs/skills/create-agent.html +4 -4
  119. package/dist/docs/skills/debug.html +4 -4
  120. package/dist/docs/skills/evals.html +4 -4
  121. package/dist/docs/skills/framework-map.html +5 -5
  122. package/dist/docs/skills/framework-map.md +1 -0
  123. package/dist/docs/skills/github.html +4 -4
  124. package/dist/docs/skills/hillclimb.html +4 -4
  125. package/dist/docs/skills/index.html +4 -4
  126. package/dist/docs/skills/mcp-auth.html +4 -4
  127. package/dist/docs/skills/otel.html +4 -4
  128. package/dist/docs/skills/setup-slack.html +4 -4
  129. package/dist/docs/storage.html +4 -4
  130. package/dist/docs/templates/agentic-owners.html +4 -4
  131. package/dist/docs/templates/agents-md.html +4 -4
  132. package/dist/docs/templates/code-wiki.html +4 -4
  133. package/dist/docs/templates/demo.html +4 -4
  134. package/dist/docs/templates/pr-autofixer.html +4 -4
  135. package/dist/docs/templates/security-help.html +4 -4
  136. package/dist/docs/templates/security-reviewer.html +4 -4
  137. package/dist/docs/templates/triage.html +4 -4
  138. package/dist/docs/troubleshooting.html +4 -4
  139. package/dist/extensions/cursor-cloud-agents/extension.d.ts +57 -0
  140. package/dist/extensions/cursor-cloud-agents/extension.d.ts.map +1 -0
  141. package/dist/extensions/cursor-cloud-agents/extension.js +66 -0
  142. package/dist/extensions/cursor-cloud-agents/lib/backend.d.ts +78 -0
  143. package/dist/extensions/cursor-cloud-agents/lib/backend.d.ts.map +1 -0
  144. package/dist/extensions/cursor-cloud-agents/lib/backend.js +286 -0
  145. package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts +25 -0
  146. package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts.map +1 -0
  147. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +85 -0
  148. package/dist/extensions/cursor-cloud-agents/lib/inputs.d.ts +5 -0
  149. package/dist/extensions/cursor-cloud-agents/lib/inputs.d.ts.map +1 -0
  150. package/dist/extensions/cursor-cloud-agents/lib/inputs.js +4 -0
  151. package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts +15 -0
  152. package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts.map +1 -0
  153. package/dist/extensions/cursor-cloud-agents/lib/repos.js +55 -0
  154. package/dist/extensions/cursor-cloud-agents/lib/transcript.d.ts +8 -0
  155. package/dist/extensions/cursor-cloud-agents/lib/transcript.d.ts.map +1 -0
  156. package/dist/extensions/cursor-cloud-agents/lib/transcript.js +15 -0
  157. package/dist/extensions/cursor-cloud-agents/skills/handoff.md +41 -0
  158. package/dist/extensions/cursor-cloud-agents/tools/cancel.d.ts +4 -0
  159. package/dist/extensions/cursor-cloud-agents/tools/cancel.d.ts.map +1 -0
  160. package/dist/extensions/cursor-cloud-agents/tools/cancel.js +26 -0
  161. package/dist/extensions/cursor-cloud-agents/tools/dump.d.ts +4 -0
  162. package/dist/extensions/cursor-cloud-agents/tools/dump.d.ts.map +1 -0
  163. package/dist/extensions/cursor-cloud-agents/tools/dump.js +54 -0
  164. package/dist/extensions/cursor-cloud-agents/tools/get.d.ts +4 -0
  165. package/dist/extensions/cursor-cloud-agents/tools/get.d.ts.map +1 -0
  166. package/dist/extensions/cursor-cloud-agents/tools/get.js +25 -0
  167. package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts +4 -0
  168. package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts.map +1 -0
  169. package/dist/extensions/cursor-cloud-agents/tools/launch.js +59 -0
  170. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts +4 -0
  171. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts.map +1 -0
  172. package/dist/extensions/cursor-cloud-agents/tools/list.js +36 -0
  173. package/dist/extensions/cursor-cloud-agents/tools/reply.d.ts +4 -0
  174. package/dist/extensions/cursor-cloud-agents/tools/reply.d.ts.map +1 -0
  175. package/dist/extensions/cursor-cloud-agents/tools/reply.js +35 -0
  176. package/dist/extensions.d.ts +73 -0
  177. package/dist/extensions.d.ts.map +1 -0
  178. package/dist/extensions.js +112 -0
  179. package/dist/files-backends/cursor-hosted.d.ts +0 -8
  180. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  181. package/dist/files-backends/cursor-hosted.js +1 -11
  182. package/dist/files.d.ts +5 -1
  183. package/dist/files.d.ts.map +1 -1
  184. package/dist/files.js +22 -18
  185. package/dist/index.d.ts +4 -3
  186. package/dist/index.d.ts.map +1 -1
  187. package/dist/index.js +3 -2
  188. package/dist/internal/advertise-tools.d.ts +4 -1
  189. package/dist/internal/advertise-tools.d.ts.map +1 -1
  190. package/dist/internal/advertise-tools.js +20 -1
  191. package/dist/internal/as-of.d.ts +18 -0
  192. package/dist/internal/as-of.d.ts.map +1 -1
  193. package/dist/internal/as-of.js +131 -0
  194. package/dist/internal/cli-deploy.d.ts.map +1 -1
  195. package/dist/internal/cli-deploy.js +64 -19
  196. package/dist/internal/continuation-identity.d.ts.map +1 -1
  197. package/dist/internal/continuation-identity.js +3 -1
  198. package/dist/internal/conversation-mirror.d.ts.map +1 -1
  199. package/dist/internal/conversation-mirror.js +13 -15
  200. package/dist/internal/cursor/backend-client.d.ts +8 -1
  201. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  202. package/dist/internal/cursor/backend-client.js +25 -9
  203. package/dist/internal/cursor/hosted-deployment-secrets.d.ts +16 -0
  204. package/dist/internal/cursor/hosted-deployment-secrets.d.ts.map +1 -0
  205. package/dist/internal/cursor/hosted-deployment-secrets.js +61 -0
  206. package/dist/internal/cursor/hosted-store-secrets.d.ts +11 -0
  207. package/dist/internal/cursor/hosted-store-secrets.d.ts.map +1 -1
  208. package/dist/internal/cursor/hosted-store-secrets.js +15 -0
  209. package/dist/internal/cursor-deployment-relay.d.ts +15 -1
  210. package/dist/internal/cursor-deployment-relay.d.ts.map +1 -1
  211. package/dist/internal/cursor-deployment-relay.js +46 -7
  212. package/dist/internal/deploy-client.d.ts +23 -0
  213. package/dist/internal/deploy-client.d.ts.map +1 -1
  214. package/dist/internal/deploy-client.js +54 -12
  215. package/dist/internal/discovery/ab.d.ts +9 -0
  216. package/dist/internal/discovery/ab.d.ts.map +1 -0
  217. package/dist/internal/discovery/ab.js +101 -0
  218. package/dist/internal/discovery/agent-config.d.ts +35 -0
  219. package/dist/internal/discovery/agent-config.d.ts.map +1 -0
  220. package/dist/internal/discovery/agent-config.js +173 -0
  221. package/dist/internal/discovery/agent.d.ts +11 -0
  222. package/dist/internal/discovery/agent.d.ts.map +1 -0
  223. package/dist/internal/discovery/agent.js +306 -0
  224. package/dist/internal/discovery/channels.d.ts +10 -0
  225. package/dist/internal/discovery/channels.d.ts.map +1 -0
  226. package/dist/internal/discovery/channels.js +97 -0
  227. package/dist/internal/discovery/connections.d.ts +17 -0
  228. package/dist/internal/discovery/connections.d.ts.map +1 -0
  229. package/dist/internal/discovery/connections.js +436 -0
  230. package/dist/internal/discovery/context.d.ts +20 -0
  231. package/dist/internal/discovery/context.d.ts.map +1 -0
  232. package/dist/internal/discovery/context.js +30 -0
  233. package/dist/internal/discovery/cursor-plugin.d.ts +25 -0
  234. package/dist/internal/discovery/cursor-plugin.d.ts.map +1 -0
  235. package/dist/internal/discovery/cursor-plugin.js +570 -0
  236. package/dist/internal/discovery/extensions.d.ts +19 -0
  237. package/dist/internal/discovery/extensions.d.ts.map +1 -0
  238. package/dist/internal/discovery/extensions.js +238 -0
  239. package/dist/internal/discovery/fs.d.ts +15 -0
  240. package/dist/internal/discovery/fs.d.ts.map +1 -0
  241. package/dist/internal/discovery/fs.js +115 -0
  242. package/dist/internal/discovery/hooks.d.ts +7 -0
  243. package/dist/internal/discovery/hooks.d.ts.map +1 -0
  244. package/dist/internal/discovery/hooks.js +48 -0
  245. package/dist/internal/discovery/info.d.ts +6 -0
  246. package/dist/internal/discovery/info.d.ts.map +1 -0
  247. package/dist/internal/discovery/info.js +141 -0
  248. package/dist/internal/discovery/instructions.d.ts +7 -0
  249. package/dist/internal/discovery/instructions.d.ts.map +1 -0
  250. package/dist/internal/discovery/instructions.js +95 -0
  251. package/dist/internal/discovery/modules.d.ts +20 -0
  252. package/dist/internal/discovery/modules.d.ts.map +1 -0
  253. package/dist/internal/discovery/modules.js +101 -0
  254. package/dist/internal/discovery/names.d.ts +12 -0
  255. package/dist/internal/discovery/names.d.ts.map +1 -0
  256. package/dist/internal/discovery/names.js +36 -0
  257. package/dist/internal/discovery/project.d.ts +53 -0
  258. package/dist/internal/discovery/project.d.ts.map +1 -0
  259. package/dist/internal/discovery/project.js +239 -0
  260. package/dist/internal/discovery/runtime.d.ts +34 -0
  261. package/dist/internal/discovery/runtime.d.ts.map +1 -0
  262. package/dist/internal/discovery/runtime.js +98 -0
  263. package/dist/internal/discovery/schedules.d.ts +7 -0
  264. package/dist/internal/discovery/schedules.d.ts.map +1 -0
  265. package/dist/internal/discovery/schedules.js +97 -0
  266. package/dist/internal/discovery/seed-files.d.ts +7 -0
  267. package/dist/internal/discovery/seed-files.d.ts.map +1 -0
  268. package/dist/internal/discovery/seed-files.js +41 -0
  269. package/dist/internal/discovery/services.d.ts +17 -0
  270. package/dist/internal/discovery/services.d.ts.map +1 -0
  271. package/dist/internal/discovery/services.js +104 -0
  272. package/dist/internal/discovery/skills.d.ts +16 -0
  273. package/dist/internal/discovery/skills.d.ts.map +1 -0
  274. package/dist/internal/discovery/skills.js +151 -0
  275. package/dist/internal/discovery/subagent.d.ts +13 -0
  276. package/dist/internal/discovery/subagent.d.ts.map +1 -0
  277. package/dist/internal/discovery/subagent.js +19 -0
  278. package/dist/internal/discovery/tools.d.ts +18 -0
  279. package/dist/internal/discovery/tools.d.ts.map +1 -0
  280. package/dist/internal/discovery/tools.js +159 -0
  281. package/dist/internal/discovery.d.ts +8 -62
  282. package/dist/internal/discovery.d.ts.map +1 -1
  283. package/dist/internal/discovery.js +8 -2210
  284. package/dist/internal/distribution.d.ts.map +1 -1
  285. package/dist/internal/distribution.js +5 -0
  286. package/dist/internal/framework-file-storage.d.ts +3 -3
  287. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  288. package/dist/internal/framework-file-storage.js +38 -9
  289. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  290. package/dist/internal/framework-storage-selection.js +8 -7
  291. package/dist/internal/frontmatter.d.ts +11 -3
  292. package/dist/internal/frontmatter.d.ts.map +1 -1
  293. package/dist/internal/frontmatter.js +29 -3
  294. package/dist/internal/hosted-delivery.d.ts +3 -1
  295. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  296. package/dist/internal/hosted-delivery.js +19 -32
  297. package/dist/internal/hosted-execution-diag.d.ts +5 -0
  298. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  299. package/dist/internal/hosted-execution-diag.js +5 -0
  300. package/dist/internal/hosted-execution-flush.d.ts +46 -0
  301. package/dist/internal/hosted-execution-flush.d.ts.map +1 -0
  302. package/dist/internal/hosted-execution-flush.js +81 -0
  303. package/dist/internal/mcp-endpoint.js +1 -0
  304. package/dist/internal/mcp-host.d.ts +2 -1
  305. package/dist/internal/mcp-host.d.ts.map +1 -1
  306. package/dist/internal/mcp-host.js +66 -29
  307. package/dist/internal/otel/collector.d.ts +13 -0
  308. package/dist/internal/otel/collector.d.ts.map +1 -1
  309. package/dist/internal/otel/collector.js +84 -17
  310. package/dist/internal/otel/http.d.ts.map +1 -1
  311. package/dist/internal/otel/http.js +2 -10
  312. package/dist/internal/otel/mcp.d.ts +16 -0
  313. package/dist/internal/otel/mcp.d.ts.map +1 -0
  314. package/dist/internal/otel/mcp.js +68 -0
  315. package/dist/internal/otel/propagation.d.ts +6 -0
  316. package/dist/internal/otel/propagation.d.ts.map +1 -0
  317. package/dist/internal/otel/propagation.js +14 -0
  318. package/dist/internal/otel/runtime.d.ts.map +1 -1
  319. package/dist/internal/otel/runtime.js +2 -0
  320. package/dist/internal/review-comments.d.ts +1 -1
  321. package/dist/internal/review-comments.d.ts.map +1 -1
  322. package/dist/internal/review-comments.js +4 -4
  323. package/dist/internal/server.d.ts +3 -0
  324. package/dist/internal/server.d.ts.map +1 -1
  325. package/dist/internal/server.js +79 -104
  326. package/dist/internal/session-engine.d.ts +14 -7
  327. package/dist/internal/session-engine.d.ts.map +1 -1
  328. package/dist/internal/session-engine.js +113 -66
  329. package/dist/internal/session-run-log.d.ts +3 -1
  330. package/dist/internal/session-run-log.d.ts.map +1 -1
  331. package/dist/internal/session-run-log.js +14 -14
  332. package/dist/internal/start-log-store.d.ts +60 -0
  333. package/dist/internal/start-log-store.d.ts.map +1 -0
  334. package/dist/internal/start-log-store.js +149 -0
  335. package/dist/internal/storage-coordinator.d.ts +4 -1
  336. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  337. package/dist/internal/storage-coordinator.js +15 -13
  338. package/dist/internal/tool-catalog.d.ts.map +1 -1
  339. package/dist/internal/tool-catalog.js +9 -6
  340. package/dist/internal/tool-policy.d.ts +8 -0
  341. package/dist/internal/tool-policy.d.ts.map +1 -1
  342. package/dist/internal/tool-policy.js +19 -7
  343. package/dist/internal/turn-cost.d.ts +14 -0
  344. package/dist/internal/turn-cost.d.ts.map +1 -1
  345. package/dist/internal/turn-cost.js +41 -9
  346. package/dist/internal/v2-hosting.d.ts +22 -0
  347. package/dist/internal/v2-hosting.d.ts.map +1 -0
  348. package/dist/internal/v2-hosting.js +23 -0
  349. package/dist/otel.d.ts +16 -0
  350. package/dist/otel.d.ts.map +1 -1
  351. package/dist/otel.js +26 -0
  352. package/dist/playground/assets/index-B6C9S9nG.css +1 -0
  353. package/dist/playground/assets/{index-DVs98vPL.js → index-ZqNoT8Ie.js} +45 -45
  354. package/dist/playground/index.html +2 -2
  355. package/dist/storage-protocol.d.ts +47 -22
  356. package/dist/storage-protocol.d.ts.map +1 -1
  357. package/dist/storage-protocol.js +90 -54
  358. package/dist/storage.d.ts +2 -2
  359. package/dist/storage.d.ts.map +1 -1
  360. package/dist/storage.js +1 -1
  361. package/dist/tools.d.ts +9 -0
  362. package/dist/tools.d.ts.map +1 -1
  363. package/dist/tools.js +9 -0
  364. package/dist/types.d.ts +154 -6
  365. package/dist/types.d.ts.map +1 -1
  366. package/dist/types.js +29 -1
  367. package/docs/README.md +5 -1
  368. package/docs/concepts.md +3 -3
  369. package/docs/guides/cloud-agents.md +98 -0
  370. package/docs/guides/cloud-runtime.md +2 -0
  371. package/docs/reference/connections.md +31 -0
  372. package/docs/reference/extensions.md +205 -0
  373. package/docs/reference/http-api.md +1 -1
  374. package/docs/reference/project-layout.md +3 -0
  375. package/docs/reference/skills.md +2 -0
  376. package/docs/reference/tools.md +2 -0
  377. package/package.json +18 -4
  378. package/skills/framework-map/SKILL.md +1 -0
  379. package/src/bin/agent-serve.ts +11 -2
  380. package/src/channels/deployments/deployments-channel.ts +117 -8
  381. package/src/channels/deployments/types.ts +4 -3
  382. package/src/channels/origin/defaults.ts +143 -0
  383. package/src/channels/origin/index.ts +2 -0
  384. package/src/channels/origin/origin-channel.ts +37 -1
  385. package/src/channels/origin/state.ts +54 -0
  386. package/src/channels/origin/types.ts +24 -0
  387. package/src/channels/slack/api.ts +6 -3
  388. package/src/channels/slack/assistant.ts +1 -1
  389. package/src/channels/slack/code-fences.ts +183 -0
  390. package/src/channels/slack/dispatch.ts +27 -2
  391. package/src/channels/slack/inbound.ts +37 -0
  392. package/src/channels/slack/index.ts +1 -0
  393. package/src/channels/slack/live-delivery.ts +16 -13
  394. package/src/channels/slack/manifest.ts +2 -1
  395. package/src/connections.ts +18 -1
  396. package/src/extensions/cursor-cloud-agents/extension.ts +120 -0
  397. package/src/extensions/cursor-cloud-agents/lib/backend.ts +395 -0
  398. package/src/extensions/cursor-cloud-agents/lib/fleet.ts +109 -0
  399. package/src/extensions/cursor-cloud-agents/lib/inputs.ts +5 -0
  400. package/src/extensions/cursor-cloud-agents/lib/repos.ts +81 -0
  401. package/src/extensions/cursor-cloud-agents/lib/transcript.ts +23 -0
  402. package/src/extensions/cursor-cloud-agents/skills/handoff.md +41 -0
  403. package/src/extensions/cursor-cloud-agents/tools/cancel.ts +19 -0
  404. package/src/extensions/cursor-cloud-agents/tools/dump.ts +51 -0
  405. package/src/extensions/cursor-cloud-agents/tools/get.ts +18 -0
  406. package/src/extensions/cursor-cloud-agents/tools/launch.ts +64 -0
  407. package/src/extensions/cursor-cloud-agents/tools/list.ts +31 -0
  408. package/src/extensions/cursor-cloud-agents/tools/reply.ts +34 -0
  409. package/src/extensions.ts +141 -0
  410. package/src/files-backends/cursor-hosted.ts +1 -17
  411. package/src/files.ts +43 -34
  412. package/src/index.ts +11 -0
  413. package/src/internal/advertise-tools.ts +37 -12
  414. package/src/internal/as-of.ts +163 -0
  415. package/src/internal/cli-deploy.ts +86 -23
  416. package/src/internal/continuation-identity.ts +3 -1
  417. package/src/internal/conversation-mirror.ts +23 -18
  418. package/src/internal/cursor/backend-client.ts +32 -10
  419. package/src/internal/cursor/hosted-deployment-secrets.ts +72 -0
  420. package/src/internal/cursor/hosted-store-secrets.ts +27 -0
  421. package/src/internal/cursor-deployment-relay.ts +65 -8
  422. package/src/internal/deploy-client.ts +73 -18
  423. package/src/internal/discovery/ab.ts +111 -0
  424. package/src/internal/discovery/agent-config.ts +222 -0
  425. package/src/internal/discovery/agent.ts +360 -0
  426. package/src/internal/discovery/channels.ts +103 -0
  427. package/src/internal/discovery/connections.ts +540 -0
  428. package/src/internal/discovery/context.ts +46 -0
  429. package/src/internal/discovery/cursor-plugin.ts +708 -0
  430. package/src/internal/discovery/extensions.ts +348 -0
  431. package/src/internal/discovery/fs.ts +108 -0
  432. package/src/internal/discovery/hooks.ts +45 -0
  433. package/src/internal/discovery/info.ts +179 -0
  434. package/src/internal/discovery/instructions.ts +113 -0
  435. package/src/internal/discovery/modules.ts +107 -0
  436. package/src/internal/discovery/names.ts +44 -0
  437. package/src/internal/discovery/project.ts +270 -0
  438. package/src/internal/discovery/runtime.ts +159 -0
  439. package/src/internal/discovery/schedules.ts +94 -0
  440. package/src/internal/discovery/seed-files.ts +37 -0
  441. package/src/internal/discovery/services.ts +124 -0
  442. package/src/internal/discovery/skills.ts +176 -0
  443. package/src/internal/discovery/subagent.ts +29 -0
  444. package/src/internal/discovery/tools.ts +182 -0
  445. package/src/internal/discovery.ts +20 -2724
  446. package/src/internal/distribution.ts +5 -0
  447. package/src/internal/framework-file-storage.ts +43 -9
  448. package/src/internal/framework-storage-selection.ts +9 -9
  449. package/src/internal/frontmatter.ts +36 -3
  450. package/src/internal/hosted-delivery.ts +38 -63
  451. package/src/internal/hosted-execution-diag.ts +6 -0
  452. package/src/internal/hosted-execution-flush.ts +142 -0
  453. package/src/internal/mcp-endpoint.ts +1 -0
  454. package/src/internal/mcp-host.ts +116 -37
  455. package/src/internal/otel/collector.ts +125 -25
  456. package/src/internal/otel/http.ts +2 -12
  457. package/src/internal/otel/mcp.ts +69 -0
  458. package/src/internal/otel/propagation.ts +17 -0
  459. package/src/internal/otel/runtime.ts +2 -0
  460. package/src/internal/review-comments.ts +5 -2
  461. package/src/internal/server.ts +81 -100
  462. package/src/internal/session-engine.ts +152 -39
  463. package/src/internal/session-run-log.ts +18 -16
  464. package/src/internal/start-log-store.ts +174 -0
  465. package/src/internal/storage-coordinator.ts +19 -16
  466. package/src/internal/tool-catalog.ts +9 -6
  467. package/src/internal/tool-policy.ts +39 -9
  468. package/src/internal/turn-cost.ts +47 -4
  469. package/src/internal/v2-hosting.ts +38 -0
  470. package/src/otel.ts +38 -0
  471. package/src/storage-protocol.ts +126 -79
  472. package/src/storage.ts +5 -0
  473. package/src/tools.ts +18 -0
  474. package/src/types.ts +213 -14
  475. package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +0 -1
  476. package/dist/docs/assets/concepts.md.lwAgBIMI.js +0 -1
  477. package/dist/docs/assets/index.md.Bb4k8kUm.js +0 -5
  478. package/dist/docs/assets/skills_framework-map.md.BTi817yv.js +0 -1
  479. package/dist/playground/assets/index-BszoQDc6.css +0 -1
  480. /package/dist/docs/assets/{concepts.md.lwAgBIMI.lean.js → concepts.md.rPzW2HZN.lean.js} +0 -0
  481. /package/dist/docs/assets/{guides_cloud-runtime.md.CkYbjnAX.lean.js → guides_cloud-runtime.md.BRirbRAN.lean.js} +0 -0
  482. /package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.lean.js → reference_http-api.md.oySXBO8o.lean.js} +0 -0
  483. /package/dist/docs/assets/{reference_skills.md.BFW9retM.lean.js → reference_skills.md.l2ezAcaN.lean.js} +0 -0
  484. /package/dist/docs/assets/{reference_tools.md.CvAHsdSp.lean.js → reference_tools.md.B1up2r9W.lean.js} +0 -0
@@ -0,0 +1,708 @@
1
+ /**
2
+ * A Cursor plugin directory read as an extension tree: skills, commands, agents, and MCP servers under the plugin's own names.
3
+ */
4
+
5
+ import { readFile } from "node:fs/promises";
6
+ import { basename, dirname, extname, isAbsolute, join } from "node:path";
7
+ import { z } from "zod";
8
+ import type {
9
+ ConnectionTransport,
10
+ DiscoveredConnection,
11
+ DiscoveredSkill,
12
+ } from "../../types.js";
13
+ import { parseYamlFrontmatter } from "../frontmatter.js";
14
+ import {
15
+ type DiscoveryContext,
16
+ displayPath,
17
+ errorMessage,
18
+ isBlank,
19
+ } from "./context.js";
20
+ import { isDirectory, isFile, sortedEntries, walkFiles } from "./fs.js";
21
+ import { skillDescription, skillFiles } from "./skills.js";
22
+
23
+ /** One `agents/*.md` file: a subagent the plugin ships. */
24
+ export interface CursorPluginAgent {
25
+ name: string;
26
+ description?: string;
27
+ /** Model id; absent inherits the parent agent's model. */
28
+ model?: string;
29
+ prompt: string;
30
+ }
31
+
32
+ /** What a plugin contributes, under its own (unprefixed) names. */
33
+ export interface CursorPluginTree {
34
+ description?: string;
35
+ /** `skills/` and `commands/`; a command is a user-invoked skill. */
36
+ skills: DiscoveredSkill[];
37
+ connections: DiscoveredConnection[];
38
+ /** Servers the plugin declares that the mount overlays; left uncompiled. */
39
+ overlaidServers: string[];
40
+ agents: CursorPluginAgent[];
41
+ }
42
+
43
+ /** The plugin directory being read. */
44
+ interface PluginDir {
45
+ ctx: DiscoveryContext;
46
+ root: string;
47
+ manifestPath: string;
48
+ variables: Record<string, string>;
49
+ }
50
+
51
+ type JsonRecord = Record<string, unknown>;
52
+
53
+ /** First match wins, as in Cursor. */
54
+ const MANIFEST_PATHS = [
55
+ ".cursor-plugin/plugin.json",
56
+ ".claude-plugin/plugin.json",
57
+ "plugin.json",
58
+ ];
59
+ /** Probed in order; the first file to name a server defines it. */
60
+ const MCP_CONFIG_FILES = [".mcp.json", "mcp.json"];
61
+ const MARKDOWN_EXTENSIONS = new Set([".md", ".mdc", ".markdown"]);
62
+ const COMMAND_EXTENSIONS = new Set([...MARKDOWN_EXTENSIONS, ".txt"]);
63
+ /** `${NAME}`, `${NAME:-default}`, and the user-mcp.json spelling `${env:NAME}`. */
64
+ const PLACEHOLDER =
65
+ /\$\{(?:env:([A-Za-z_][A-Za-z0-9_]*)|([^:}]+)(?::-([^}]*))?)\}/g;
66
+ const PLUGIN_ROOT_VARIABLES = new Set([
67
+ "CURSOR_PLUGIN_ROOT",
68
+ "CLAUDE_PLUGIN_ROOT",
69
+ ]);
70
+
71
+ /** A component slot's declaration: one directory or a list of paths. */
72
+ const pathsSchema = z
73
+ .union([z.string(), z.array(z.string())])
74
+ .transform((value) => (typeof value === "string" ? [value] : value));
75
+
76
+ /** A blank or null value reads as absent, as a missing key would. */
77
+ const text = z
78
+ .string()
79
+ .nullish()
80
+ .transform((value) =>
81
+ value === undefined || value === null || value.trim() === ""
82
+ ? undefined
83
+ : value
84
+ );
85
+
86
+ const manifestSchema = z.object({
87
+ description: text.optional(),
88
+ skills: pathsSchema.optional(),
89
+ commands: pathsSchema.optional(),
90
+ agents: pathsSchema.optional(),
91
+ rules: z.unknown().optional(),
92
+ hooks: z.unknown().optional(),
93
+ mcpServers: z
94
+ .union([
95
+ z.string(),
96
+ z.record(z.unknown()),
97
+ z.array(z.union([z.string(), z.record(z.unknown())])),
98
+ ])
99
+ .optional()
100
+ .transform((value) => {
101
+ const items =
102
+ value === undefined || Array.isArray(value) ? (value ?? []) : [value];
103
+ return {
104
+ paths: items.filter((item) => typeof item === "string"),
105
+ inline: items.filter((item) => typeof item !== "string"),
106
+ };
107
+ }),
108
+ });
109
+
110
+ type Manifest = z.infer<typeof manifestSchema>;
111
+ type McpServers = Manifest["mcpServers"];
112
+
113
+ const frontmatterSchema = z.object({
114
+ name: text.optional(),
115
+ description: text.optional(),
116
+ model: text.optional(),
117
+ });
118
+
119
+ type Frontmatter = z.infer<typeof frontmatterSchema>;
120
+
121
+ /** One `mcpServers` entry after placeholder expansion. */
122
+ const mcpServerSchema = z.object({
123
+ type: z.string().optional(),
124
+ url: z.string().optional(),
125
+ headers: z.record(z.string()).optional(),
126
+ command: z.string().optional(),
127
+ args: z.array(z.string()).optional(),
128
+ env: z.record(z.string()).optional(),
129
+ cwd: z.string().optional(),
130
+ envFile: z.string().optional(),
131
+ /** Cursor's static OAuth client hint. */
132
+ auth: z.record(z.unknown()).optional(),
133
+ /** Claude's spelling of the same hint. */
134
+ oauth: z.record(z.unknown()).optional(),
135
+ /** Cursor disables unlisted tools; an empty list would disable them all. */
136
+ enabledTools: z.array(z.string()).nonempty().optional(),
137
+ });
138
+
139
+ type McpServer = z.infer<typeof mcpServerSchema>;
140
+
141
+ export async function readCursorPlugin(
142
+ ctx: DiscoveryContext,
143
+ root: string,
144
+ mountPath: string,
145
+ variables: Record<string, string>,
146
+ overlaid: ReadonlySet<string>
147
+ ): Promise<CursorPluginTree | undefined> {
148
+ const manifest = await readManifest(ctx, root, mountPath);
149
+ if (manifest === undefined) {
150
+ return undefined;
151
+ }
152
+ const plugin: PluginDir = {
153
+ ctx,
154
+ root,
155
+ manifestPath: manifest.path,
156
+ variables,
157
+ };
158
+ const skills = await loadPluginSkills(plugin, manifest.data.skills);
159
+ for (const command of await loadPluginCommands(
160
+ plugin,
161
+ manifest.data.commands
162
+ )) {
163
+ if (skills.some((skill) => skill.name === command.name)) {
164
+ ctx.diagnostics.push({
165
+ severity: "warning",
166
+ path: displayPath(ctx, root),
167
+ message: `Plugin command "${command.name}" has the same name as a skill; the skill wins. Ignoring the command.`,
168
+ });
169
+ continue;
170
+ }
171
+ skills.push(command);
172
+ }
173
+ await warnUnmountedSlots(plugin, manifest.data);
174
+ return {
175
+ description: manifest.data.description,
176
+ skills,
177
+ ...(await loadPluginConnections(
178
+ plugin,
179
+ manifest.data.mcpServers,
180
+ overlaid
181
+ )),
182
+ agents: await loadPluginAgents(plugin, manifest.data.agents),
183
+ };
184
+ }
185
+
186
+ async function readManifest(
187
+ ctx: DiscoveryContext,
188
+ root: string,
189
+ mountPath: string
190
+ ): Promise<{ data: Manifest; path: string } | undefined> {
191
+ for (const rel of MANIFEST_PATHS) {
192
+ const path = join(root, rel);
193
+ if (!(await isFile(path))) {
194
+ continue;
195
+ }
196
+ const data = await readJson(ctx, path);
197
+ if (data === undefined) {
198
+ return undefined;
199
+ }
200
+ const parsed = manifestSchema.safeParse(data);
201
+ if (parsed.success) {
202
+ return { data: parsed.data, path };
203
+ }
204
+ ctx.diagnostics.push({
205
+ severity: "error",
206
+ path: displayPath(ctx, path),
207
+ message: `The plugin manifest is malformed: ${firstIssue(parsed.error)}.`,
208
+ });
209
+ return undefined;
210
+ }
211
+ ctx.diagnostics.push({
212
+ severity: "error",
213
+ path: displayPath(ctx, mountPath),
214
+ message: `${displayPath(ctx, root)} is not a Cursor plugin: it has no ${MANIFEST_PATHS.join(", ")}.`,
215
+ });
216
+ return undefined;
217
+ }
218
+
219
+ /** Slots Cursor applies through the IDE that have no agent-sdk mapping yet. */
220
+ async function warnUnmountedSlots(
221
+ plugin: PluginDir,
222
+ manifest: Manifest
223
+ ): Promise<void> {
224
+ const unmounted: string[] = [];
225
+ if (
226
+ manifest.rules !== undefined ||
227
+ (await isDirectory(join(plugin.root, "rules")))
228
+ ) {
229
+ unmounted.push("rules");
230
+ }
231
+ if (
232
+ manifest.hooks !== undefined ||
233
+ (await isFile(join(plugin.root, "hooks", "hooks.json")))
234
+ ) {
235
+ unmounted.push("hooks");
236
+ }
237
+ if (unmounted.length === 0) {
238
+ return;
239
+ }
240
+ plugin.ctx.diagnostics.push({
241
+ severity: "warning",
242
+ path: displayPath(plugin.ctx, plugin.root),
243
+ message: `Cursor plugin ${unmounted.join(" and ")} are not mounted yet; skills, commands, agents, and MCP servers are. Ignoring.`,
244
+ });
245
+ }
246
+
247
+ async function loadPluginSkills(
248
+ plugin: PluginDir,
249
+ declared: string[] | undefined
250
+ ): Promise<DiscoveredSkill[]> {
251
+ const dirs: string[] = [];
252
+ if (declared === undefined) {
253
+ if (await isFile(join(plugin.root, "SKILL.md"))) {
254
+ dirs.push(plugin.root);
255
+ }
256
+ dirs.push(...(await skillDirsIn(join(plugin.root, "skills"))));
257
+ }
258
+ for (const path of declaredPaths(plugin, declared ?? [])) {
259
+ if (basename(path) === "SKILL.md" && (await isFile(path))) {
260
+ dirs.push(dirname(path));
261
+ } else if (await isFile(join(path, "SKILL.md"))) {
262
+ dirs.push(path);
263
+ } else {
264
+ dirs.push(...(await skillDirsIn(path)));
265
+ }
266
+ }
267
+ const skills: DiscoveredSkill[] = [];
268
+ for (const dir of dirs) {
269
+ const skill = await readSkillDir(plugin, dir);
270
+ if (skill !== undefined && !skills.some((s) => s.name === skill.name)) {
271
+ skills.push(skill);
272
+ }
273
+ }
274
+ return skills;
275
+ }
276
+
277
+ /** Immediate subdirectories holding a SKILL.md. */
278
+ async function skillDirsIn(dir: string): Promise<string[]> {
279
+ if (!(await isDirectory(dir))) {
280
+ return [];
281
+ }
282
+ const dirs: string[] = [];
283
+ for (const entry of await sortedEntries(dir)) {
284
+ const path = join(dir, entry.name);
285
+ if (entry.isDirectory() && (await isFile(join(path, "SKILL.md")))) {
286
+ dirs.push(path);
287
+ }
288
+ }
289
+ return dirs;
290
+ }
291
+
292
+ async function readSkillDir(
293
+ plugin: PluginDir,
294
+ dir: string
295
+ ): Promise<DiscoveredSkill | undefined> {
296
+ const skillMdPath = join(dir, "SKILL.md");
297
+ const { data, body } = await readMarkdown(plugin, skillMdPath);
298
+ const name = componentName(plugin, data.name ?? basename(dir), skillMdPath);
299
+ if (name === undefined) {
300
+ return undefined;
301
+ }
302
+ return {
303
+ name,
304
+ description: skillDescription(name, data.description, body),
305
+ markdown: body.trim(),
306
+ files: await skillFiles(dir),
307
+ };
308
+ }
309
+
310
+ async function loadPluginCommands(
311
+ plugin: PluginDir,
312
+ declared: string[] | undefined
313
+ ): Promise<DiscoveredSkill[]> {
314
+ const skills: DiscoveredSkill[] = [];
315
+ for (const path of await componentFiles(
316
+ plugin,
317
+ declared,
318
+ "commands",
319
+ COMMAND_EXTENSIONS
320
+ )) {
321
+ const { data, body } = await readMarkdown(plugin, path);
322
+ const name = componentName(plugin, data.name ?? fileStem(path), path);
323
+ if (name === undefined) {
324
+ continue;
325
+ }
326
+ skills.push({
327
+ name,
328
+ description: skillDescription(name, data.description, body),
329
+ markdown: body.trim(),
330
+ files: {},
331
+ });
332
+ }
333
+ return skills;
334
+ }
335
+
336
+ async function loadPluginAgents(
337
+ plugin: PluginDir,
338
+ declared: string[] | undefined
339
+ ): Promise<CursorPluginAgent[]> {
340
+ const agents: CursorPluginAgent[] = [];
341
+ for (const path of await componentFiles(
342
+ plugin,
343
+ declared,
344
+ "agents",
345
+ MARKDOWN_EXTENSIONS
346
+ )) {
347
+ const { data, body } = await readMarkdown(plugin, path);
348
+ const name = componentName(plugin, data.name ?? fileStem(path), path);
349
+ if (name === undefined || agents.some((agent) => agent.name === name)) {
350
+ continue;
351
+ }
352
+ if (isBlank(body)) {
353
+ plugin.ctx.diagnostics.push({
354
+ severity: "warning",
355
+ path: displayPath(plugin.ctx, path),
356
+ message: "Plugin agent has no prompt body; ignoring.",
357
+ });
358
+ continue;
359
+ }
360
+ agents.push({
361
+ name,
362
+ description: data.description,
363
+ model: data.model === "inherit" ? undefined : data.model,
364
+ prompt: body.trim(),
365
+ });
366
+ }
367
+ return agents;
368
+ }
369
+
370
+ /**
371
+ * The plugin's MCP servers as connections. A server the mount overlays is
372
+ * reported by name and never compiled, so its placeholders need no values.
373
+ */
374
+ async function loadPluginConnections(
375
+ plugin: PluginDir,
376
+ declared: McpServers,
377
+ overlaid: ReadonlySet<string>
378
+ ): Promise<Pick<CursorPluginTree, "connections" | "overlaidServers">> {
379
+ const servers = new Map<string, { raw: unknown; path: string }>();
380
+ for (const file of MCP_CONFIG_FILES) {
381
+ const path = join(plugin.root, file);
382
+ if (!(await isFile(path))) {
383
+ continue;
384
+ }
385
+ for (const [name, raw] of Object.entries(await readMcpFile(plugin, path))) {
386
+ if (!servers.has(name)) {
387
+ servers.set(name, { raw, path });
388
+ }
389
+ }
390
+ }
391
+ // The manifest's own `mcpServers` wins on a name both declare.
392
+ for (const path of declaredPaths(plugin, declared.paths)) {
393
+ for (const [name, raw] of Object.entries(await readMcpFile(plugin, path))) {
394
+ servers.set(name, { raw, path });
395
+ }
396
+ }
397
+ for (const inline of declared.inline) {
398
+ for (const [name, raw] of Object.entries(mcpServersOf(inline))) {
399
+ servers.set(name, { raw, path: plugin.manifestPath });
400
+ }
401
+ }
402
+ const connections: DiscoveredConnection[] = [];
403
+ const overlaidServers: string[] = [];
404
+ for (const [rawName, { raw, path }] of servers) {
405
+ const name = componentName(plugin, rawName, path);
406
+ if (name === undefined) {
407
+ continue;
408
+ }
409
+ if (overlaid.has(name)) {
410
+ overlaidServers.push(name);
411
+ continue;
412
+ }
413
+ const connection = serverConnection(plugin, name, raw, path);
414
+ if (connection !== undefined) {
415
+ connections.push(connection);
416
+ }
417
+ }
418
+ return { connections, overlaidServers };
419
+ }
420
+
421
+ async function readMcpFile(
422
+ plugin: PluginDir,
423
+ path: string
424
+ ): Promise<Record<string, unknown>> {
425
+ const data = await readJson(plugin.ctx, path);
426
+ return isRecord(data) ? mcpServersOf(data) : {};
427
+ }
428
+
429
+ /** `{ mcpServers: { ... } }`, or a bare map of server-like entries. */
430
+ function mcpServersOf(data: JsonRecord): Record<string, unknown> {
431
+ if (isRecord(data.mcpServers)) {
432
+ return data.mcpServers;
433
+ }
434
+ const servers: Record<string, unknown> = {};
435
+ for (const [name, value] of Object.entries(data)) {
436
+ if (isRecord(value) && ("command" in value || "url" in value)) {
437
+ servers[name] = value;
438
+ }
439
+ }
440
+ return servers;
441
+ }
442
+
443
+ function serverConnection(
444
+ plugin: PluginDir,
445
+ name: string,
446
+ raw: unknown,
447
+ path: string
448
+ ): DiscoveredConnection | undefined {
449
+ const unresolved = new Set<string>();
450
+ const expanded = expandPlaceholders(
451
+ raw,
452
+ (key) => {
453
+ if (PLUGIN_ROOT_VARIABLES.has(key)) {
454
+ return plugin.root;
455
+ }
456
+ return lookupVariable(plugin.variables, key) ?? process.env[key];
457
+ },
458
+ unresolved
459
+ );
460
+ if (unresolved.size > 0) {
461
+ plugin.ctx.diagnostics.push({
462
+ severity: "error",
463
+ path: displayPath(plugin.ctx, path),
464
+ message: `MCP server "${name}" needs ${[...unresolved].map((v) => `\${${v}}`).join(", ")}. Pass it in cursorPlugin({ variables }) or set it in the environment.`,
465
+ });
466
+ return undefined;
467
+ }
468
+ const parsed = mcpServerSchema.safeParse(expanded);
469
+ if (!parsed.success) {
470
+ plugin.ctx.diagnostics.push({
471
+ severity: "error",
472
+ path: displayPath(plugin.ctx, path),
473
+ message: `MCP server "${name}" is malformed: ${firstIssue(parsed.error)}.`,
474
+ });
475
+ return undefined;
476
+ }
477
+ const transport = serverTransport(plugin, name, parsed.data, path);
478
+ if (transport === undefined) {
479
+ return undefined;
480
+ }
481
+ const enabledTools = parsed.data.enabledTools;
482
+ return {
483
+ name,
484
+ transport,
485
+ // Cursor scopes the model to `enabledTools`; here that is an advertised allowlist.
486
+ advertiseTools: enabledTools === undefined ? undefined : true,
487
+ tools: enabledTools,
488
+ };
489
+ }
490
+
491
+ function serverTransport(
492
+ plugin: PluginDir,
493
+ name: string,
494
+ server: McpServer,
495
+ path: string
496
+ ): ConnectionTransport | undefined {
497
+ if (server.url !== undefined) {
498
+ const type =
499
+ server.type === "sse"
500
+ ? "sse"
501
+ : server.type === "http"
502
+ ? "http"
503
+ : undefined;
504
+ return {
505
+ type,
506
+ url: server.url,
507
+ headers: server.headers,
508
+ // Either client hint means the server speaks OAuth; the host PKCE flow
509
+ // (`mcp oauth`) owns it here.
510
+ oauth:
511
+ server.auth !== undefined || server.oauth !== undefined
512
+ ? true
513
+ : undefined,
514
+ };
515
+ }
516
+ if (server.command !== undefined) {
517
+ if (server.envFile !== undefined) {
518
+ plugin.ctx.diagnostics.push({
519
+ severity: "warning",
520
+ path: displayPath(plugin.ctx, path),
521
+ message: `MCP server "${name}" sets envFile, which is not supported; pass its variables in cursorPlugin({ variables }).`,
522
+ });
523
+ }
524
+ return {
525
+ type: server.type === "stdio" ? "stdio" : undefined,
526
+ command: server.command,
527
+ args: server.args,
528
+ env: server.env,
529
+ cwd: server.cwd,
530
+ };
531
+ }
532
+ plugin.ctx.diagnostics.push({
533
+ severity: "error",
534
+ path: displayPath(plugin.ctx, path),
535
+ message: `MCP server "${name}" declares neither url nor command.`,
536
+ });
537
+ return undefined;
538
+ }
539
+
540
+ function expandPlaceholders(
541
+ value: unknown,
542
+ lookup: (key: string) => string | undefined,
543
+ unresolved: Set<string>
544
+ ): unknown {
545
+ if (typeof value === "string") {
546
+ return value.replace(
547
+ PLACEHOLDER,
548
+ (match, envKey?: string, key?: string, fallback?: string) => {
549
+ const name = envKey ?? key ?? "";
550
+ const resolved = lookup(name) ?? fallback;
551
+ if (resolved === undefined) {
552
+ unresolved.add(name);
553
+ return match;
554
+ }
555
+ return resolved;
556
+ }
557
+ );
558
+ }
559
+ if (Array.isArray(value)) {
560
+ return value.map((item) => expandPlaceholders(item, lookup, unresolved));
561
+ }
562
+ if (isRecord(value)) {
563
+ const out: JsonRecord = {};
564
+ for (const [key, item] of Object.entries(value)) {
565
+ out[key] = expandPlaceholders(item, lookup, unresolved);
566
+ }
567
+ return out;
568
+ }
569
+ return value;
570
+ }
571
+
572
+ /**
573
+ * Exact name first, then case-insensitive, as the Cursor loader resolves
574
+ * install variables: the Datadog plugin templates `${dd_site}` while its
575
+ * declared variable is `DD_SITE`.
576
+ */
577
+ function lookupVariable(
578
+ variables: Record<string, string>,
579
+ key: string
580
+ ): string | undefined {
581
+ if (variables[key] !== undefined) {
582
+ return variables[key];
583
+ }
584
+ const lower = key.toLowerCase();
585
+ return Object.entries(variables).find(
586
+ ([name]) => name.toLowerCase() === lower
587
+ )?.[1];
588
+ }
589
+
590
+ /**
591
+ * Files a component slot resolves to: the manifest's declaration (files and
592
+ * directories, walked) or the conventional folder.
593
+ */
594
+ async function componentFiles(
595
+ plugin: PluginDir,
596
+ declared: string[] | undefined,
597
+ folder: string,
598
+ extensions: Set<string>
599
+ ): Promise<string[]> {
600
+ const roots =
601
+ declared === undefined
602
+ ? [join(plugin.root, folder)]
603
+ : declaredPaths(plugin, declared);
604
+ const files: string[] = [];
605
+ for (const path of roots) {
606
+ if (await isDirectory(path)) {
607
+ files.push(...(await walkFiles(path)));
608
+ } else if (await isFile(path)) {
609
+ files.push(path);
610
+ }
611
+ }
612
+ return files.filter((file) => extensions.has(extname(file)));
613
+ }
614
+
615
+ /** Manifest paths resolve against the plugin root; escaping ones are refused, as in Cursor. */
616
+ function declaredPaths(plugin: PluginDir, declared: string[]): string[] {
617
+ const paths: string[] = [];
618
+ for (const item of declared) {
619
+ const rel = item.replace(/^\.\//, "");
620
+ if (rel.includes("..") || isAbsolute(rel) || rel.includes("://")) {
621
+ plugin.ctx.diagnostics.push({
622
+ severity: "warning",
623
+ path: displayPath(plugin.ctx, plugin.manifestPath),
624
+ message: `Plugin manifest path "${item}" leaves the plugin directory; ignoring.`,
625
+ });
626
+ continue;
627
+ }
628
+ paths.push(join(plugin.root, rel));
629
+ }
630
+ return paths;
631
+ }
632
+
633
+ async function readJson(ctx: DiscoveryContext, path: string): Promise<unknown> {
634
+ try {
635
+ return JSON.parse(await readFile(path, "utf8")) as unknown;
636
+ } catch (error) {
637
+ ctx.diagnostics.push({
638
+ severity: "error",
639
+ path: displayPath(ctx, path),
640
+ message: `Failed to parse ${basename(path)}: ${errorMessage(error)}`,
641
+ });
642
+ return undefined;
643
+ }
644
+ }
645
+
646
+ /** Frontmatter the reader understands; a malformed block warns and reads as empty. */
647
+ async function readMarkdown(
648
+ plugin: PluginDir,
649
+ path: string
650
+ ): Promise<{ data: Frontmatter; body: string }> {
651
+ const { data, body, error } = parseYamlFrontmatter(
652
+ await readFile(path, "utf8")
653
+ );
654
+ const parsed = frontmatterSchema.safeParse(data);
655
+ const problem =
656
+ error ?? (parsed.success ? undefined : firstIssue(parsed.error));
657
+ if (problem !== undefined) {
658
+ plugin.ctx.diagnostics.push({
659
+ severity: "warning",
660
+ path: displayPath(plugin.ctx, path),
661
+ message: `Frontmatter is malformed (${problem}); using the file name and body.`,
662
+ });
663
+ }
664
+ return { data: parsed.success ? parsed.data : {}, body };
665
+ }
666
+
667
+ /**
668
+ * Cursor lowercases and hyphenates component names; `_` and `.` fold to `-`
669
+ * as well so the name fits the tool-name rule and can never carry `__`.
670
+ */
671
+ function componentName(
672
+ plugin: PluginDir,
673
+ raw: string,
674
+ path: string
675
+ ): string | undefined {
676
+ const name = raw
677
+ .trim()
678
+ .toLowerCase()
679
+ .replace(/[^a-z0-9]+/g, "-")
680
+ .replace(/^-+|-+$/g, "");
681
+ if (name !== "") {
682
+ return name;
683
+ }
684
+ plugin.ctx.diagnostics.push({
685
+ severity: "error",
686
+ path: displayPath(plugin.ctx, path),
687
+ message: `Plugin component name "${raw}" has no usable characters; ignoring.`,
688
+ });
689
+ return undefined;
690
+ }
691
+
692
+ /** `headers: Expected object, received array`; the path names the field. */
693
+ function firstIssue(error: z.ZodError): string {
694
+ const issue = error.issues[0];
695
+ if (issue === undefined) {
696
+ return "invalid";
697
+ }
698
+ const path = issue.path.join(".");
699
+ return path === "" ? issue.message : `${path}: ${issue.message}`;
700
+ }
701
+
702
+ function fileStem(path: string): string {
703
+ return basename(path, extname(path));
704
+ }
705
+
706
+ function isRecord(value: unknown): value is JsonRecord {
707
+ return typeof value === "object" && value !== null && !Array.isArray(value);
708
+ }