@cursor/july 0.1.95 → 0.1.97

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 (424) hide show
  1. package/AGENTS.md +3 -4
  2. package/README.md +3 -2
  3. package/dist/bin/agent-serve.js +14 -3
  4. package/dist/channels/deployments/types.d.ts +1 -1
  5. package/dist/channels/deployments/types.d.ts.map +1 -1
  6. package/dist/channels/deployments/types.js +1 -0
  7. package/dist/channels/origin/api.d.ts +72 -15
  8. package/dist/channels/origin/api.d.ts.map +1 -1
  9. package/dist/channels/origin/api.js +185 -28
  10. package/dist/channels/origin/binding.d.ts +13 -2
  11. package/dist/channels/origin/binding.d.ts.map +1 -1
  12. package/dist/channels/origin/binding.js +41 -25
  13. package/dist/channels/origin/checks.d.ts +6 -6
  14. package/dist/channels/origin/checks.js +6 -6
  15. package/dist/channels/origin/cursor-account.d.ts +5 -3
  16. package/dist/channels/origin/cursor-account.d.ts.map +1 -1
  17. package/dist/channels/origin/cursor-account.js +5 -3
  18. package/dist/channels/origin/index.d.ts +1 -0
  19. package/dist/channels/origin/index.d.ts.map +1 -1
  20. package/dist/channels/origin/index.js +1 -0
  21. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  22. package/dist/channels/origin/origin-channel.js +3 -0
  23. package/dist/channels/origin/reactions.d.ts +56 -0
  24. package/dist/channels/origin/reactions.d.ts.map +1 -0
  25. package/dist/channels/origin/reactions.js +67 -0
  26. package/dist/channels/origin/types.d.ts +11 -0
  27. package/dist/channels/origin/types.d.ts.map +1 -1
  28. package/dist/channels/slack/api.d.ts +9 -0
  29. package/dist/channels/slack/api.d.ts.map +1 -1
  30. package/dist/channels/slack/api.js +36 -5
  31. package/dist/channels/slack/approvals.d.ts +16 -0
  32. package/dist/channels/slack/approvals.d.ts.map +1 -1
  33. package/dist/channels/slack/approvals.js +86 -0
  34. package/dist/channels/slack/cli-project.d.ts +19 -0
  35. package/dist/channels/slack/cli-project.d.ts.map +1 -0
  36. package/dist/channels/slack/cli-project.js +234 -0
  37. package/dist/channels/slack/defaults.d.ts.map +1 -1
  38. package/dist/channels/slack/defaults.js +110 -81
  39. package/dist/channels/slack/dispatch.d.ts +7 -1
  40. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  41. package/dist/channels/slack/dispatch.js +47 -23
  42. package/dist/channels/slack/inbound.d.ts +8 -0
  43. package/dist/channels/slack/inbound.d.ts.map +1 -1
  44. package/dist/channels/slack/inbound.js +32 -0
  45. package/dist/channels/slack/init.d.ts +3 -2
  46. package/dist/channels/slack/init.d.ts.map +1 -1
  47. package/dist/channels/slack/init.js +5 -5
  48. package/dist/channels/slack/interactive.d.ts +2 -1
  49. package/dist/channels/slack/interactive.d.ts.map +1 -1
  50. package/dist/channels/slack/interactive.js +15 -4
  51. package/dist/channels/slack/live-delivery.d.ts +26 -29
  52. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  53. package/dist/channels/slack/live-delivery.js +172 -73
  54. package/dist/channels/slack/manifest.d.ts +1 -1
  55. package/dist/channels/slack/manifest.d.ts.map +1 -1
  56. package/dist/channels/slack/manifest.js +6 -2
  57. package/dist/channels/slack/nudge-carrier.d.ts +2 -0
  58. package/dist/channels/slack/nudge-carrier.d.ts.map +1 -1
  59. package/dist/channels/slack/nudge-carrier.js +48 -1
  60. package/dist/channels/slack/setup.d.ts +1 -1
  61. package/dist/channels/slack/setup.d.ts.map +1 -1
  62. package/dist/channels/slack/setup.js +10 -6
  63. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  64. package/dist/channels/slack/slack-channel.js +3 -2
  65. package/dist/channels/slack/tool-approval-events.d.ts.map +1 -1
  66. package/dist/channels/slack/tool-approval-events.js +91 -1
  67. package/dist/docs/404.html +2 -2
  68. package/dist/docs/ab.html +4 -4
  69. package/dist/docs/assets/{app.BBj0klBO.js → app.B3rWNYE1.js} +1 -1
  70. package/dist/docs/assets/chunks/@localSearchIndexroot.BU9nHdnQ.js +1 -0
  71. package/dist/docs/assets/chunks/{VPLocalSearchBox.CUEXpL78.js → VPLocalSearchBox.C1lhqJJR.js} +1 -1
  72. package/dist/docs/assets/chunks/{theme.DabmQnia.js → theme.B40_SXuv.js} +2 -2
  73. package/dist/docs/assets/{deployment.md.D9msOFOW.js → deployment.md.MFPKqsqI.js} +2 -2
  74. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.js → guides_mcp-oauth.md.CN-6YmTJ.js} +4 -4
  75. package/dist/docs/assets/{guides_mcp-oauth.md.DPYmBCbV.lean.js → guides_mcp-oauth.md.CN-6YmTJ.lean.js} +1 -1
  76. package/dist/docs/assets/guides_slack.md.VDXQV3ja.js +22 -0
  77. package/dist/docs/assets/guides_slack.md.VDXQV3ja.lean.js +1 -0
  78. package/dist/docs/assets/index.md.CVeRUOeZ.js +5 -0
  79. package/dist/docs/assets/{index.md.BoHaMdeZ.lean.js → index.md.CVeRUOeZ.lean.js} +1 -1
  80. package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.js → reference_agent-config.md.BHeYMgme.js} +1 -1
  81. package/dist/docs/assets/{reference_cli.md.BsMOxDvh.js → reference_cli.md.RyZf5OTE.js} +10 -6
  82. package/dist/docs/assets/{reference_cli.md.BsMOxDvh.lean.js → reference_cli.md.RyZf5OTE.lean.js} +1 -1
  83. package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.js → reference_connections.md.DxldvyIB.js} +4 -3
  84. package/dist/docs/assets/{reference_http-api.md.D89k1mdm.js → reference_http-api.md.5zOAbV86.js} +1 -1
  85. package/dist/docs/assets/reference_sessions.md.NxFP_CAC.js +1 -0
  86. package/dist/docs/assets/{reference_tools.md.BHeXn2id.js → reference_tools.md.B84gw9Ii.js} +1 -1
  87. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.js +2 -0
  88. package/dist/docs/assets/templates_agents-md.md.CXSMZljE.lean.js +1 -0
  89. package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.js +2 -0
  90. package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.lean.js +1 -0
  91. package/dist/docs/assets/troubleshooting.md.DCiPBhYs.js +1 -0
  92. package/dist/docs/building-with-agents.html +4 -4
  93. package/dist/docs/concepts.html +4 -4
  94. package/dist/docs/deployment.html +7 -7
  95. package/dist/docs/deployment.md +5 -4
  96. package/dist/docs/evals.html +4 -4
  97. package/dist/docs/guides/agent-to-agent.html +4 -4
  98. package/dist/docs/guides/cloud-runtime.html +4 -4
  99. package/dist/docs/guides/convert-automation.html +4 -4
  100. package/dist/docs/guides/github.html +4 -4
  101. package/dist/docs/guides/human-in-the-loop.html +4 -4
  102. package/dist/docs/guides/mcp-oauth.html +8 -8
  103. package/dist/docs/guides/mcp-oauth.md +26 -8
  104. package/dist/docs/guides/opentelemetry.html +4 -4
  105. package/dist/docs/guides/slack.html +17 -33
  106. package/dist/docs/guides/slack.md +92 -201
  107. package/dist/docs/guides/webhooks.html +4 -4
  108. package/dist/docs/hashmap.json +1 -1
  109. package/dist/docs/hillclimbing.html +4 -4
  110. package/dist/docs/index.html +6 -6
  111. package/dist/docs/index.md +7 -3
  112. package/dist/docs/llms-full.txt +398 -653
  113. package/dist/docs/llms.txt +3 -2
  114. package/dist/docs/quickstart.html +4 -4
  115. package/dist/docs/reference/agent-config.html +6 -6
  116. package/dist/docs/reference/agent-config.md +2 -2
  117. package/dist/docs/reference/artifacts.html +4 -4
  118. package/dist/docs/reference/channels.html +4 -4
  119. package/dist/docs/reference/cli.html +14 -10
  120. package/dist/docs/reference/cli.md +39 -16
  121. package/dist/docs/reference/connections.html +9 -8
  122. package/dist/docs/reference/connections.md +6 -3
  123. package/dist/docs/reference/hooks.html +4 -4
  124. package/dist/docs/reference/http-api.html +6 -6
  125. package/dist/docs/reference/http-api.md +2 -1
  126. package/dist/docs/reference/instructions.html +4 -4
  127. package/dist/docs/reference/playground.html +4 -4
  128. package/dist/docs/reference/project-layout.html +4 -4
  129. package/dist/docs/reference/prompt.html +4 -4
  130. package/dist/docs/reference/schedules.html +4 -4
  131. package/dist/docs/reference/sessions.html +5 -5
  132. package/dist/docs/reference/sessions.md +4 -2
  133. package/dist/docs/reference/skills.html +4 -4
  134. package/dist/docs/reference/subagents.html +4 -4
  135. package/dist/docs/reference/tools.html +6 -6
  136. package/dist/docs/reference/tools.md +9 -2
  137. package/dist/docs/scaffolding-agents.html +4 -4
  138. package/dist/docs/storage.html +4 -4
  139. package/dist/docs/templates/agentic-owners.html +4 -4
  140. package/dist/docs/templates/agents-md.html +28 -0
  141. package/dist/docs/templates/agents-md.md +105 -0
  142. package/dist/docs/templates/code-wiki.html +28 -0
  143. package/dist/docs/templates/code-wiki.md +91 -0
  144. package/dist/docs/templates/demo.html +5 -5
  145. package/dist/docs/templates/pr-autofixer.html +4 -4
  146. package/dist/docs/templates/security-help.html +4 -4
  147. package/dist/docs/templates/security-reviewer.html +5 -5
  148. package/dist/docs/templates/triage.html +4 -4
  149. package/dist/docs/troubleshooting.html +5 -5
  150. package/dist/docs/troubleshooting.md +2 -2
  151. package/dist/evals/run-facts.d.ts.map +1 -1
  152. package/dist/evals/run-facts.js +27 -0
  153. package/dist/files-backends/cursor-hosted.d.ts +26 -4
  154. package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
  155. package/dist/files-backends/cursor-hosted.js +32 -4
  156. package/dist/internal/advertise-tools.d.ts +2 -0
  157. package/dist/internal/advertise-tools.d.ts.map +1 -1
  158. package/dist/internal/advertise-tools.js +30 -10
  159. package/dist/internal/approval-gate.d.ts +12 -13
  160. package/dist/internal/approval-gate.d.ts.map +1 -1
  161. package/dist/internal/approval-gate.js +16 -21
  162. package/dist/internal/bounded.d.ts +7 -0
  163. package/dist/internal/bounded.d.ts.map +1 -0
  164. package/dist/internal/bounded.js +32 -0
  165. package/dist/internal/chat-client.js +10 -0
  166. package/dist/internal/cli-deploy.d.ts +5 -0
  167. package/dist/internal/cli-deploy.d.ts.map +1 -1
  168. package/dist/internal/cli-deploy.js +57 -18
  169. package/dist/internal/cli-mcp-oauth.js +8 -18
  170. package/dist/internal/cli-slack-manual.d.ts +24 -2
  171. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  172. package/dist/internal/cli-slack-manual.js +251 -20
  173. package/dist/internal/cli-slack.d.ts +9 -2
  174. package/dist/internal/cli-slack.d.ts.map +1 -1
  175. package/dist/internal/cli-slack.js +29 -82
  176. package/dist/internal/conversation-mirror.d.ts +11 -8
  177. package/dist/internal/conversation-mirror.d.ts.map +1 -1
  178. package/dist/internal/conversation-mirror.js +116 -55
  179. package/dist/internal/cursor/account-mcp.d.ts +1 -0
  180. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  181. package/dist/internal/cursor/account-mcp.js +17 -0
  182. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  183. package/dist/internal/cursor/backend-client.js +22 -48
  184. package/dist/internal/cursor/session-token.d.ts +45 -0
  185. package/dist/internal/cursor/session-token.d.ts.map +1 -0
  186. package/dist/internal/cursor/session-token.js +99 -0
  187. package/dist/internal/cursor-agent-template.d.ts +1 -1
  188. package/dist/internal/cursor-agent-template.d.ts.map +1 -1
  189. package/dist/internal/cursor-agent-template.js +2 -0
  190. package/dist/internal/deploy-client.d.ts +17 -0
  191. package/dist/internal/deploy-client.d.ts.map +1 -1
  192. package/dist/internal/deploy-client.js +31 -10
  193. package/dist/internal/env-file.d.ts +19 -0
  194. package/dist/internal/env-file.d.ts.map +1 -0
  195. package/dist/internal/env-file.js +90 -0
  196. package/dist/internal/framework-file-storage.d.ts +61 -0
  197. package/dist/internal/framework-file-storage.d.ts.map +1 -0
  198. package/dist/internal/framework-file-storage.js +210 -0
  199. package/dist/internal/framework-storage-selection.d.ts +11 -5
  200. package/dist/internal/framework-storage-selection.d.ts.map +1 -1
  201. package/dist/internal/framework-storage-selection.js +38 -11
  202. package/dist/internal/hosted-delivery-protocol.d.ts +7 -0
  203. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  204. package/dist/internal/hosted-delivery-protocol.js +7 -0
  205. package/dist/internal/hosted-delivery.d.ts +13 -0
  206. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  207. package/dist/internal/hosted-delivery.js +64 -19
  208. package/dist/internal/hosted-execution-diag.d.ts +48 -0
  209. package/dist/internal/hosted-execution-diag.d.ts.map +1 -0
  210. package/dist/internal/hosted-execution-diag.js +150 -0
  211. package/dist/internal/http-channel.d.ts.map +1 -1
  212. package/dist/internal/http-channel.js +81 -1
  213. package/dist/internal/init-project.d.ts.map +1 -1
  214. package/dist/internal/init-project.js +4 -0
  215. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  216. package/dist/internal/install-cursor-skills.js +1 -3
  217. package/dist/internal/logs-client.d.ts +5 -0
  218. package/dist/internal/logs-client.d.ts.map +1 -1
  219. package/dist/internal/logs-client.js +5 -0
  220. package/dist/internal/managed-delivery.d.ts +80 -0
  221. package/dist/internal/managed-delivery.d.ts.map +1 -0
  222. package/dist/internal/managed-delivery.js +86 -0
  223. package/dist/internal/mcp-endpoint.js +2 -3
  224. package/dist/internal/mcp-host.d.ts +10 -0
  225. package/dist/internal/mcp-host.d.ts.map +1 -1
  226. package/dist/internal/mcp-host.js +57 -8
  227. package/dist/internal/mcp-oauth-on-demand.d.ts +68 -0
  228. package/dist/internal/mcp-oauth-on-demand.d.ts.map +1 -0
  229. package/dist/internal/mcp-oauth-on-demand.js +287 -0
  230. package/dist/internal/mcp-oauth-persist.d.ts +42 -0
  231. package/dist/internal/mcp-oauth-persist.d.ts.map +1 -0
  232. package/dist/internal/mcp-oauth-persist.js +92 -0
  233. package/dist/internal/mcp-oauth.d.ts +1 -0
  234. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  235. package/dist/internal/mcp-oauth.js +10 -2
  236. package/dist/internal/otel/collector.d.ts.map +1 -1
  237. package/dist/internal/otel/collector.js +22 -9
  238. package/dist/internal/runtime-dispatch-runner.d.ts +5 -1
  239. package/dist/internal/runtime-dispatch-runner.d.ts.map +1 -1
  240. package/dist/internal/runtime-dispatch-runner.js +7 -0
  241. package/dist/internal/sdk-runner.d.ts +11 -0
  242. package/dist/internal/sdk-runner.d.ts.map +1 -1
  243. package/dist/internal/sdk-runner.js +39 -8
  244. package/dist/internal/server.d.ts +3 -0
  245. package/dist/internal/server.d.ts.map +1 -1
  246. package/dist/internal/server.js +49 -21
  247. package/dist/internal/session-engine.d.ts +101 -3
  248. package/dist/internal/session-engine.d.ts.map +1 -1
  249. package/dist/internal/session-engine.js +577 -46
  250. package/dist/internal/sessions-client.d.ts +9 -7
  251. package/dist/internal/sessions-client.d.ts.map +1 -1
  252. package/dist/internal/sessions-client.js +3 -1
  253. package/dist/internal/steering.d.ts +15 -0
  254. package/dist/internal/steering.d.ts.map +1 -0
  255. package/dist/internal/steering.js +18 -0
  256. package/dist/internal/storage-coordinator.d.ts +7 -0
  257. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  258. package/dist/internal/storage-coordinator.js +28 -5
  259. package/dist/internal/storage-roles.d.ts +5 -0
  260. package/dist/internal/storage-roles.d.ts.map +1 -1
  261. package/dist/internal/stream-progress.d.ts.map +1 -1
  262. package/dist/internal/stream-progress.js +10 -0
  263. package/dist/internal/tool-policy.d.ts +9 -1
  264. package/dist/internal/tool-policy.d.ts.map +1 -1
  265. package/dist/internal/tool-policy.js +13 -0
  266. package/dist/internal/trajectory.d.ts.map +1 -1
  267. package/dist/internal/trajectory.js +10 -0
  268. package/dist/internal/turn-outbox.d.ts +24 -0
  269. package/dist/internal/turn-outbox.d.ts.map +1 -0
  270. package/dist/internal/turn-outbox.js +80 -0
  271. package/dist/playground/assets/{index-CZA1uEWA.js → index-DrkI6y5O.js} +51 -51
  272. package/dist/playground/assets/index-DzNGwm7q.css +1 -0
  273. package/dist/playground/index.html +2 -2
  274. package/dist/storage-backends/cursor-hosted.d.ts +9 -6
  275. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  276. package/dist/storage-backends/cursor-hosted.js +16 -3
  277. package/dist/storage.d.ts +8 -0
  278. package/dist/storage.d.ts.map +1 -1
  279. package/dist/types.d.ts +65 -8
  280. package/dist/types.d.ts.map +1 -1
  281. package/docs/README.md +7 -3
  282. package/docs/deployment.md +5 -4
  283. package/docs/guides/mcp-oauth.md +26 -8
  284. package/docs/guides/slack.md +93 -202
  285. package/docs/reference/agent-config.md +2 -2
  286. package/docs/reference/cli.md +39 -16
  287. package/docs/reference/connections.md +6 -3
  288. package/docs/reference/http-api.md +2 -1
  289. package/docs/reference/sessions.md +4 -2
  290. package/docs/reference/tools.md +9 -2
  291. package/docs/templates/agents-md.md +110 -0
  292. package/docs/templates/code-wiki.md +96 -0
  293. package/docs/troubleshooting.md +2 -2
  294. package/package.json +2 -2
  295. package/skills/ab/SKILL.md +13 -97
  296. package/skills/create-agent/SKILL.md +124 -223
  297. package/skills/debug/SKILL.md +34 -68
  298. package/skills/evals/SKILL.md +55 -180
  299. package/skills/framework-map/SKILL.md +83 -145
  300. package/skills/github/SKILL.md +53 -111
  301. package/skills/hillclimb/SKILL.md +40 -163
  302. package/skills/mcp-auth/SKILL.md +51 -107
  303. package/skills/otel/SKILL.md +22 -68
  304. package/skills/setup-slack/SKILL.md +91 -212
  305. package/src/bin/agent-serve.ts +13 -1
  306. package/src/channels/deployments/types.ts +1 -0
  307. package/src/channels/origin/api.ts +264 -33
  308. package/src/channels/origin/binding.ts +57 -28
  309. package/src/channels/origin/checks.ts +6 -6
  310. package/src/channels/origin/cursor-account.ts +5 -3
  311. package/src/channels/origin/index.ts +1 -0
  312. package/src/channels/origin/origin-channel.ts +4 -0
  313. package/src/channels/origin/reactions.ts +82 -0
  314. package/src/channels/origin/types.ts +11 -0
  315. package/src/channels/slack/api.ts +41 -5
  316. package/src/channels/slack/approvals.ts +105 -0
  317. package/src/channels/slack/cli-project.ts +267 -0
  318. package/src/channels/slack/defaults.ts +122 -93
  319. package/src/channels/slack/dispatch.ts +56 -22
  320. package/src/channels/slack/inbound.ts +43 -0
  321. package/src/channels/slack/init.ts +10 -5
  322. package/src/channels/slack/interactive.ts +35 -9
  323. package/src/channels/slack/live-delivery.ts +235 -114
  324. package/src/channels/slack/manifest.ts +6 -2
  325. package/src/channels/slack/nudge-carrier.ts +48 -1
  326. package/src/channels/slack/setup.ts +10 -6
  327. package/src/channels/slack/slack-channel.ts +3 -0
  328. package/src/channels/slack/tool-approval-events.ts +93 -0
  329. package/src/evals/run-facts.ts +32 -0
  330. package/src/files-backends/cursor-hosted.ts +40 -7
  331. package/src/internal/advertise-tools.ts +49 -12
  332. package/src/internal/approval-gate.ts +20 -29
  333. package/src/internal/bounded.ts +28 -0
  334. package/src/internal/chat-client.ts +19 -0
  335. package/src/internal/cli-deploy.ts +91 -9
  336. package/src/internal/cli-mcp-oauth.ts +7 -21
  337. package/src/internal/cli-slack-manual.ts +350 -18
  338. package/src/internal/cli-slack.ts +40 -84
  339. package/src/internal/conversation-mirror.ts +145 -69
  340. package/src/internal/cursor/account-mcp.ts +21 -0
  341. package/src/internal/cursor/backend-client.ts +34 -58
  342. package/src/internal/cursor/session-token.ts +115 -0
  343. package/src/internal/cursor-agent-template.ts +2 -0
  344. package/src/internal/deploy-client.ts +43 -0
  345. package/src/internal/env-file.ts +84 -0
  346. package/src/internal/framework-file-storage.ts +228 -0
  347. package/src/internal/framework-storage-selection.ts +51 -11
  348. package/src/internal/hosted-delivery-protocol.ts +7 -0
  349. package/src/internal/hosted-delivery.ts +107 -24
  350. package/src/internal/hosted-execution-diag.ts +207 -0
  351. package/src/internal/http-channel.ts +99 -0
  352. package/src/internal/init-project.ts +4 -0
  353. package/src/internal/install-cursor-skills.ts +1 -4
  354. package/src/internal/logs-client.ts +5 -0
  355. package/src/internal/managed-delivery.ts +125 -0
  356. package/src/internal/mcp-endpoint.ts +13 -4
  357. package/src/internal/mcp-host.ts +77 -11
  358. package/src/internal/mcp-oauth-on-demand.ts +352 -0
  359. package/src/internal/mcp-oauth-persist.ts +127 -0
  360. package/src/internal/mcp-oauth.ts +17 -1
  361. package/src/internal/otel/collector.ts +30 -0
  362. package/src/internal/runtime-dispatch-runner.ts +10 -0
  363. package/src/internal/sdk-runner.ts +56 -8
  364. package/src/internal/server.ts +61 -9
  365. package/src/internal/session-engine.ts +723 -60
  366. package/src/internal/sessions-client.ts +17 -8
  367. package/src/internal/steering.ts +17 -0
  368. package/src/internal/storage-coordinator.ts +38 -8
  369. package/src/internal/storage-roles.ts +7 -0
  370. package/src/internal/stream-progress.ts +19 -0
  371. package/src/internal/tool-policy.ts +18 -0
  372. package/src/internal/trajectory.ts +10 -0
  373. package/src/internal/turn-outbox.ts +85 -0
  374. package/src/storage-backends/cursor-hosted.ts +22 -8
  375. package/src/storage.ts +12 -0
  376. package/src/types.ts +70 -9
  377. package/templates/agents-md/README.md +39 -0
  378. package/templates/agents-md/agent/agent.ts +8 -0
  379. package/templates/agents-md/agent/channels/github.ts +10 -0
  380. package/templates/agents-md/agent/channels/queue.ts +28 -0
  381. package/templates/agents-md/agent/channels/slack.ts +9 -0
  382. package/templates/agents-md/agent/instructions.md +39 -0
  383. package/templates/agents-md/agent/lib/collect.ts +439 -0
  384. package/templates/agents-md/agent/lib/config.ts +8 -0
  385. package/templates/agents-md/agent/lib/paths.ts +51 -0
  386. package/templates/agents-md/agent/schedules/weekly.ts +17 -0
  387. package/templates/agents-md/agent/tools/apply_agents.ts +226 -0
  388. package/templates/agents-md/evals/agents.eval.ts +135 -0
  389. package/templates/agents-md/evals/evals.config.ts +5 -0
  390. package/templates/agents-md/init.json +38 -0
  391. package/templates/agents-md/package.json +18 -0
  392. package/templates/agents-md/tsconfig.json +12 -0
  393. package/templates/code-wiki/README.md +34 -0
  394. package/templates/code-wiki/agent/agent.ts +8 -0
  395. package/templates/code-wiki/agent/channels/github.ts +144 -0
  396. package/templates/code-wiki/agent/instructions.md +39 -0
  397. package/templates/code-wiki/agent/lib/repos.ts +5 -0
  398. package/templates/code-wiki/agent/lib/wiki.ts +22 -0
  399. package/templates/code-wiki/agent/tools/apply_wiki.ts +219 -0
  400. package/templates/code-wiki/evals/evals.config.ts +5 -0
  401. package/templates/code-wiki/evals/wiki.eval.ts +132 -0
  402. package/templates/code-wiki/init.json +25 -0
  403. package/templates/code-wiki/package.json +18 -0
  404. package/templates/code-wiki/tsconfig.json +12 -0
  405. package/dist/docs/assets/chunks/@localSearchIndexroot.oqPawjiD.js +0 -1
  406. package/dist/docs/assets/guides_slack.md.C32HsdKk.js +0 -38
  407. package/dist/docs/assets/guides_slack.md.C32HsdKk.lean.js +0 -1
  408. package/dist/docs/assets/index.md.BoHaMdeZ.js +0 -5
  409. package/dist/docs/assets/reference_sessions.md.D0mIh4KK.js +0 -1
  410. package/dist/docs/assets/troubleshooting.md.Ctv3T8C2.js +0 -1
  411. package/dist/docs/design/agsh.md +0 -406
  412. package/dist/internal/deployment-scm-event-stream.d.ts +0 -116
  413. package/dist/internal/deployment-scm-event-stream.d.ts.map +0 -1
  414. package/dist/internal/deployment-scm-event-stream.js +0 -474
  415. package/dist/playground/assets/index-CF7hUDnQ.css +0 -1
  416. package/docs/design/agsh.md +0 -406
  417. package/src/internal/deployment-scm-event-stream.ts +0 -593
  418. /package/dist/docs/assets/{deployment.md.D9msOFOW.lean.js → deployment.md.MFPKqsqI.lean.js} +0 -0
  419. /package/dist/docs/assets/{reference_agent-config.md.Cp_x38Nl.lean.js → reference_agent-config.md.BHeYMgme.lean.js} +0 -0
  420. /package/dist/docs/assets/{reference_connections.md.BH8Oc0D0.lean.js → reference_connections.md.DxldvyIB.lean.js} +0 -0
  421. /package/dist/docs/assets/{reference_http-api.md.D89k1mdm.lean.js → reference_http-api.md.5zOAbV86.lean.js} +0 -0
  422. /package/dist/docs/assets/{reference_sessions.md.D0mIh4KK.lean.js → reference_sessions.md.NxFP_CAC.lean.js} +0 -0
  423. /package/dist/docs/assets/{reference_tools.md.BHeXn2id.lean.js → reference_tools.md.B84gw9Ii.lean.js} +0 -0
  424. /package/dist/docs/assets/{troubleshooting.md.Ctv3T8C2.lean.js → troubleshooting.md.DCiPBhYs.lean.js} +0 -0
@@ -26,6 +26,47 @@ import type {
26
26
  import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
27
27
  import { createHostMcpOAuthProvider } from "./mcp-oauth.js";
28
28
 
29
+ export class McpNeedsAuthError extends Error {
30
+ readonly connection: string;
31
+
32
+ constructor(connection: string, cause?: unknown) {
33
+ super(
34
+ `MCP connection "${connection}" needs authorization. Run \`${CLI} mcp oauth ${connection}\`.`
35
+ );
36
+ this.name = "McpNeedsAuthError";
37
+ this.connection = connection;
38
+ if (cause !== undefined) {
39
+ this.cause = cause;
40
+ }
41
+ }
42
+ }
43
+
44
+ export function isMcpNeedsAuthError(
45
+ error: unknown
46
+ ): error is McpNeedsAuthError {
47
+ return error instanceof McpNeedsAuthError;
48
+ }
49
+
50
+ export function hostMcpCallNeedsAuth(result: HostMcpCallResult): boolean {
51
+ if (result.isError !== true) {
52
+ return false;
53
+ }
54
+ const text = result.content
55
+ .map((part) => (part.type === "text" ? part.text : ""))
56
+ .join("\n");
57
+ return text.includes("needsAuth") || text.includes("needs authorization");
58
+ }
59
+
60
+ function throwIfCallNeedsAuth(
61
+ connection: string,
62
+ result: HostMcpCallResult
63
+ ): HostMcpCallResult {
64
+ if (hostMcpCallNeedsAuth(result)) {
65
+ throw new McpNeedsAuthError(connection);
66
+ }
67
+ return result;
68
+ }
69
+
29
70
  interface OpenedConnection {
30
71
  client: Client;
31
72
  close: () => Promise<void>;
@@ -46,6 +87,7 @@ export interface HostMcpOneOff {
46
87
  export class McpHost implements HostMcpRegistry {
47
88
  private readonly byName = new Map<string, DiscoveredConnection>();
48
89
  private readonly clients = new Map<string, Promise<OpenedConnection>>();
90
+ private oauthRedirectUrl: string | undefined;
49
91
 
50
92
  constructor(connections: DiscoveredConnection[]) {
51
93
  for (const connection of connections) {
@@ -53,6 +95,11 @@ export class McpHost implements HostMcpRegistry {
53
95
  }
54
96
  }
55
97
 
98
+ /** Public serve callback for host OAuth (not the CLI loopback port on pods). */
99
+ setOAuthRedirectUrl(url: string): void {
100
+ this.oauthRedirectUrl = url;
101
+ }
102
+
56
103
  /**
57
104
  * Register a connection after construction (serve-time resolved peers).
58
105
  * Clients open lazily on first use, so adding before first call is safe.
@@ -82,10 +129,11 @@ export class McpHost implements HostMcpRegistry {
82
129
  * mapping as registry calls.
83
130
  */
84
131
  oneOff(connection: DiscoveredConnection): HostMcpOneOff {
132
+ const redirectUrl = this.oauthRedirectUrl;
85
133
  const withFreshClient = async <T>(
86
134
  run: (client: Client) => Promise<T>
87
135
  ): Promise<T> => {
88
- const opened = await openConnection(connection);
136
+ const opened = await openConnection(connection, redirectUrl);
89
137
  try {
90
138
  return await run(opened.client);
91
139
  } finally {
@@ -104,7 +152,10 @@ export class McpHost implements HostMcpRegistry {
104
152
  name: toolName,
105
153
  arguments: args,
106
154
  });
107
- return normalizeCallResult(result);
155
+ return throwIfCallNeedsAuth(
156
+ connection.name,
157
+ normalizeCallResult(result)
158
+ );
108
159
  }),
109
160
  };
110
161
  }
@@ -119,10 +170,23 @@ export class McpHost implements HostMcpRegistry {
119
170
  name: toolName,
120
171
  arguments: args,
121
172
  });
122
- return normalizeCallResult(result);
173
+ return throwIfCallNeedsAuth(connectionName, normalizeCallResult(result));
123
174
  });
124
175
  }
125
176
 
177
+ async dropClient(name: string): Promise<void> {
178
+ const pending = this.clients.get(name);
179
+ this.clients.delete(name);
180
+ if (pending === undefined) {
181
+ return;
182
+ }
183
+ try {
184
+ await (await pending).close();
185
+ } catch {
186
+ // Best-effort teardown.
187
+ }
188
+ }
189
+
126
190
  async close(): Promise<void> {
127
191
  const opened = await Promise.allSettled([...this.clients.values()]);
128
192
  this.clients.clear();
@@ -198,7 +262,7 @@ export class McpHost implements HostMcpRegistry {
198
262
  `Unknown MCP connection "${name}". Authored MCP connections: ${known}.`
199
263
  );
200
264
  }
201
- return openConnection(connection);
265
+ return openConnection(connection, this.oauthRedirectUrl);
202
266
  }
203
267
  }
204
268
 
@@ -283,13 +347,14 @@ function toToolInfo(tool: {
283
347
  }
284
348
 
285
349
  async function openConnection(
286
- connection: DiscoveredConnection
350
+ connection: DiscoveredConnection,
351
+ oauthRedirectUrl?: string
287
352
  ): Promise<OpenedConnection> {
288
353
  const client = new Client({
289
354
  name: "agent-serve",
290
355
  version: "0.1.0",
291
356
  });
292
- const transport = await createTransport(connection);
357
+ const transport = await createTransport(connection, oauthRedirectUrl);
293
358
  try {
294
359
  await client.connect(transport);
295
360
  } catch (error) {
@@ -297,10 +362,7 @@ async function openConnection(
297
362
  error instanceof UnauthorizedError &&
298
363
  isOauthHttpTransport(connection.transport)
299
364
  ) {
300
- throw new Error(
301
- `MCP connection "${connection.name}" needs authorization. Run \`${CLI} mcp oauth ${connection.name}\`.`,
302
- { cause: error }
303
- );
365
+ throw new McpNeedsAuthError(connection.name, error);
304
366
  }
305
367
  throw error;
306
368
  }
@@ -322,7 +384,10 @@ async function openConnection(
322
384
  };
323
385
  }
324
386
 
325
- async function createTransport(connection: DiscoveredConnection) {
387
+ async function createTransport(
388
+ connection: DiscoveredConnection,
389
+ oauthRedirectUrl?: string
390
+ ) {
326
391
  const transport = connection.transport;
327
392
  if ("agent" in transport) {
328
393
  // Peers are resolved to concrete URLs by the serve host before any call
@@ -365,6 +430,7 @@ async function createTransport(connection: DiscoveredConnection) {
365
430
  ? await createHostMcpOAuthProvider({
366
431
  identifier: connection.name,
367
432
  resourceUrl: transport.url,
433
+ redirectUrl: oauthRedirectUrl,
368
434
  })
369
435
  : undefined;
370
436
 
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Mid-run host MCP OAuth: mint an authUrl, finish on the public serve
3
+ * callback (file tokens). Deployment secrets persist from the
4
+ * authenticated park, not from that callback.
5
+ *
6
+ * CLI `mcp oauth` still uses the loopback callback. This path is recovery
7
+ * and first-use without a separate `--store` step.
8
+ */
9
+
10
+ import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
11
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
12
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
13
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
14
+ import { describeError } from "./describe-error.js";
15
+ import { LOG_PREFIX } from "./distribution.js";
16
+ import {
17
+ createHostMcpOAuthProvider,
18
+ FileMcpOAuthStore,
19
+ MCP_OAUTH_CALLBACK_URL,
20
+ } from "./mcp-oauth.js";
21
+ import {
22
+ type McpOauthSecretsTarget,
23
+ type ResolveHostedMcpOauthSecretsArgs,
24
+ resolveHostedMcpOauthSecretsTarget,
25
+ upsertHostMcpOauthSecrets,
26
+ } from "./mcp-oauth-persist.js";
27
+
28
+ export function mcpOauthServeCallbackPath(basePath = ""): string {
29
+ return `${basePath}/v1/mcp-oauth/callback`;
30
+ }
31
+
32
+ export function mcpOauthServeCallbackUrl(
33
+ origin: string,
34
+ basePath = ""
35
+ ): string {
36
+ return `${origin.replace(/\/$/, "")}${mcpOauthServeCallbackPath(basePath)}`;
37
+ }
38
+
39
+ export type BeginHostMcpOauthResult =
40
+ | { status: "authorized" }
41
+ | {
42
+ status: "needs_auth";
43
+ authUrl: string;
44
+ state: string;
45
+ finish: (code: string) => Promise<void>;
46
+ abort: () => Promise<void>;
47
+ };
48
+
49
+ export async function beginHostMcpOauth(args: {
50
+ connection: string;
51
+ url: string;
52
+ type?: "http" | "sse";
53
+ headers?: Record<string, string>;
54
+ redirectUrl: string;
55
+ store?: FileMcpOAuthStore;
56
+ }): Promise<BeginHostMcpOauthResult> {
57
+ let authorizationUrl: URL | undefined;
58
+ const provider = await createHostMcpOAuthProvider({
59
+ identifier: args.connection,
60
+ resourceUrl: args.url,
61
+ store: args.store,
62
+ redirectUrl: args.redirectUrl,
63
+ onRedirect: (url) => {
64
+ authorizationUrl = url;
65
+ },
66
+ });
67
+
68
+ const client = new Client({ name: "agent-sdk-mcp-oauth", version: "0.1.0" });
69
+ const url = new URL(args.url);
70
+ const requestInit =
71
+ args.headers === undefined ? undefined : { headers: args.headers };
72
+
73
+ const makeTransport = ():
74
+ | StreamableHTTPClientTransport
75
+ | SSEClientTransport => {
76
+ if (args.type === "sse") {
77
+ return new SSEClientTransport(url, {
78
+ authProvider: provider,
79
+ requestInit,
80
+ });
81
+ }
82
+ return new StreamableHTTPClientTransport(url, {
83
+ authProvider: provider,
84
+ requestInit,
85
+ });
86
+ };
87
+
88
+ const transport = makeTransport();
89
+ try {
90
+ await client.connect(transport);
91
+ await client.close().catch(() => undefined);
92
+ return { status: "authorized" };
93
+ } catch (error) {
94
+ if (!(error instanceof UnauthorizedError)) {
95
+ throw error;
96
+ }
97
+ }
98
+
99
+ const redirect = authorizationUrl ?? provider.lastRedirectUrl;
100
+ if (redirect === undefined) {
101
+ throw new Error(
102
+ `Auth required for "${args.connection}" but no authorization URL was provided.`
103
+ );
104
+ }
105
+ const state = redirect.searchParams.get("state") ?? "";
106
+ if (state === "") {
107
+ throw new Error(
108
+ `Auth required for "${args.connection}" but the authorization URL had no state.`
109
+ );
110
+ }
111
+
112
+ return {
113
+ status: "needs_auth",
114
+ authUrl: redirect.toString(),
115
+ state,
116
+ finish: async (code: string) => {
117
+ await transport.finishAuth(code);
118
+ await transport.close?.().catch(() => undefined);
119
+ },
120
+ abort: async () => {
121
+ await transport.close?.().catch(() => undefined);
122
+ },
123
+ };
124
+ }
125
+
126
+ type BoundAttempt = {
127
+ connection: string;
128
+ resourceUrl: string;
129
+ finish: (code: string) => Promise<void>;
130
+ abort: () => Promise<void>;
131
+ sessionId?: string;
132
+ callId?: string;
133
+ };
134
+
135
+ export type McpOauthCompleteResult = {
136
+ connection: string;
137
+ sessionId?: string;
138
+ callId?: string;
139
+ };
140
+
141
+ export class McpOauthOnDemandHub {
142
+ private readonly attempts = new Map<string, BoundAttempt>();
143
+ private readonly completed = new Map<string, BoundAttempt>();
144
+ private readonly finishing = new Map<
145
+ string,
146
+ Promise<McpOauthCompleteResult>
147
+ >();
148
+ private readonly aborted = new Set<string>();
149
+ callbackUrl: string | undefined;
150
+ secrets?: McpOauthSecretsTarget;
151
+ // Identity only — resolve the key at persist, after freeze bind.
152
+ secretsBind?: ResolveHostedMcpOauthSecretsArgs;
153
+ logger?: (line: string) => void;
154
+ private store?: FileMcpOAuthStore;
155
+
156
+ async mint(args: {
157
+ connection: string;
158
+ url: string;
159
+ type?: "http" | "sse";
160
+ headers?: Record<string, string>;
161
+ sessionId?: string;
162
+ }): Promise<{ authUrl: string; state: string } | { authorized: true }> {
163
+ const redirectUrl = this.callbackUrl ?? MCP_OAUTH_CALLBACK_URL;
164
+ const store = this.fileStore();
165
+ const started = await beginHostMcpOauth({
166
+ connection: args.connection,
167
+ url: args.url,
168
+ type: args.type,
169
+ headers: args.headers,
170
+ redirectUrl,
171
+ store,
172
+ });
173
+ if (started.status === "authorized") {
174
+ return { authorized: true };
175
+ }
176
+ this.attempts.set(started.state, {
177
+ connection: args.connection,
178
+ resourceUrl: args.url,
179
+ finish: started.finish,
180
+ abort: started.abort,
181
+ sessionId: args.sessionId,
182
+ });
183
+ return { authUrl: started.authUrl, state: started.state };
184
+ }
185
+
186
+ async abortCall(sessionId: string, callId: string): Promise<void> {
187
+ await this.dropWhere(
188
+ (attempt) => attempt.sessionId === sessionId && attempt.callId === callId,
189
+ true
190
+ );
191
+ }
192
+
193
+ async abortSession(sessionId: string): Promise<void> {
194
+ await this.dropWhere((attempt) => attempt.sessionId === sessionId, false);
195
+ }
196
+
197
+ async close(): Promise<void> {
198
+ await this.dropWhere(() => true, true);
199
+ }
200
+
201
+ private async dropWhere(
202
+ match: (attempt: BoundAttempt) => boolean,
203
+ includeCompleted: boolean
204
+ ): Promise<void> {
205
+ const jobs: Array<Promise<void>> = [];
206
+ for (const [state, attempt] of this.attempts) {
207
+ if (!match(attempt)) {
208
+ continue;
209
+ }
210
+ this.aborted.add(state);
211
+ this.attempts.delete(state);
212
+ jobs.push(attempt.abort().catch(() => undefined));
213
+ }
214
+ if (includeCompleted) {
215
+ for (const [state, attempt] of this.completed) {
216
+ if (!match(attempt)) {
217
+ continue;
218
+ }
219
+ this.aborted.add(state);
220
+ this.completed.delete(state);
221
+ }
222
+ }
223
+ await Promise.all(jobs);
224
+ }
225
+
226
+ bind(
227
+ state: string,
228
+ sessionId: string,
229
+ callId: string
230
+ ): "pending" | "already_done" | "unknown" {
231
+ const live = this.attempts.get(state);
232
+ if (live !== undefined) {
233
+ live.sessionId = sessionId;
234
+ live.callId = callId;
235
+ return "pending";
236
+ }
237
+ const done = this.completed.get(state);
238
+ if (done !== undefined) {
239
+ done.sessionId = sessionId;
240
+ done.callId = callId;
241
+ return "already_done";
242
+ }
243
+ return "unknown";
244
+ }
245
+
246
+ async complete(state: string, code: string): Promise<McpOauthCompleteResult> {
247
+ if (this.aborted.has(state)) {
248
+ throw new Error("Unknown OAuth state.");
249
+ }
250
+ const pending = this.finishing.get(state);
251
+ if (pending !== undefined) {
252
+ return await pending;
253
+ }
254
+ const attempt = this.attempts.get(state);
255
+ if (attempt === undefined) {
256
+ throw new Error("Unknown OAuth state.");
257
+ }
258
+ const run = this.finishAttempt(state, attempt, code);
259
+ this.finishing.set(state, run);
260
+ return await run;
261
+ }
262
+
263
+ private async finishAttempt(
264
+ state: string,
265
+ attempt: BoundAttempt,
266
+ code: string
267
+ ): Promise<McpOauthCompleteResult> {
268
+ try {
269
+ await attempt.finish(code);
270
+ this.attempts.delete(state);
271
+ if (!this.aborted.has(state)) {
272
+ this.completed.set(state, attempt);
273
+ }
274
+ return {
275
+ connection: attempt.connection,
276
+ sessionId: attempt.sessionId,
277
+ callId: attempt.callId,
278
+ };
279
+ } finally {
280
+ this.finishing.delete(state);
281
+ }
282
+ }
283
+
284
+ private fileStore(): FileMcpOAuthStore {
285
+ this.store ??= new FileMcpOAuthStore();
286
+ return this.store;
287
+ }
288
+
289
+ async persistFor(connection: string, resourceUrl: string): Promise<void> {
290
+ const target =
291
+ this.secrets ??
292
+ resolveHostedMcpOauthSecretsTarget(this.secretsBind ?? {});
293
+ if (target === undefined) {
294
+ return;
295
+ }
296
+ const store = this.fileStore();
297
+ const tokens = await store.loadTokens(connection, resourceUrl);
298
+ if (tokens === undefined || tokens.access_token.trim() === "") {
299
+ return;
300
+ }
301
+ const client = await store.loadClientInformation(connection, resourceUrl);
302
+ try {
303
+ const names = await upsertHostMcpOauthSecrets({
304
+ connection,
305
+ tokens,
306
+ clientId: client?.client_id,
307
+ target,
308
+ });
309
+ this.logger?.(
310
+ `${LOG_PREFIX} MCP OAuth tokens stored on the deployment (${names.join(", ")}).`
311
+ );
312
+ } catch (error) {
313
+ this.logger?.(
314
+ `${LOG_PREFIX} MCP OAuth persist failed for "${connection}": ${describeError(error)}`
315
+ );
316
+ }
317
+ }
318
+
319
+ async handleCallback(request: Request): Promise<Response> {
320
+ const url = new URL(request.url);
321
+ const code = url.searchParams.get("code");
322
+ const state = url.searchParams.get("state") ?? "";
323
+ if (this.aborted.has(state)) {
324
+ return oauthHtml(404, "<h1>Not found</h1>");
325
+ }
326
+ if (this.completed.has(state)) {
327
+ return oauthHtml(200, "<h1>Authorized</h1><p>Return to the agent.</p>");
328
+ }
329
+ if (!this.attempts.has(state)) {
330
+ return oauthHtml(404, "<h1>Not found</h1>");
331
+ }
332
+ if (code !== null && code !== "") {
333
+ try {
334
+ await this.complete(state, code);
335
+ } catch {
336
+ return oauthHtml(400, "<h1>Authorization failed</h1>");
337
+ }
338
+ if (this.aborted.has(state)) {
339
+ return oauthHtml(404, "<h1>Not found</h1>");
340
+ }
341
+ return oauthHtml(200, "<h1>Authorized</h1><p>Return to the agent.</p>");
342
+ }
343
+ return oauthHtml(400, "<h1>Authorization failed</h1>");
344
+ }
345
+ }
346
+
347
+ function oauthHtml(status: number, body: string): Response {
348
+ return new Response(`<!doctype html><html><body>${body}</body></html>`, {
349
+ status,
350
+ headers: { "content-type": "text/html; charset=utf-8" },
351
+ });
352
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Deployment-secret upsert for host MCP OAuth (`mcp oauth --store` and
3
+ * hosted Connect). File writes stay on FileMcpOAuthStore / the OAuth
4
+ * provider. Resolve the `--store` client at persist time so v2 freeze
5
+ * bind can drop the key after listen.
6
+ */
7
+
8
+ import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
9
+ import { AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR } from "../storage-backends/cursor-hosted.js";
10
+ import {
11
+ cursorExternalApiUrl,
12
+ resolveApiKeySync,
13
+ } from "./cursor/credentials.js";
14
+ import {
15
+ AgentServeDeployClient,
16
+ parseAgentServeMcpGatewayUrl,
17
+ } from "./deploy-client.js";
18
+ import { mcpOauthSecretNames } from "./mcp-oauth.js";
19
+
20
+ export type McpOauthSecretsClient = {
21
+ setSecrets(args: {
22
+ teamId: number;
23
+ slug: string;
24
+ secrets: Array<{ name: string; value: string }>;
25
+ }): Promise<string[]>;
26
+ };
27
+
28
+ export type McpOauthSecretsTarget = {
29
+ client: McpOauthSecretsClient;
30
+ teamId: number;
31
+ slug: string;
32
+ };
33
+
34
+ function mcpOauthSecretsPayload(args: {
35
+ connection: string;
36
+ tokens: OAuthTokens;
37
+ clientId?: string;
38
+ }): Array<{ name: string; value: string }> {
39
+ const names = mcpOauthSecretNames(args.connection);
40
+ const secrets: Array<{ name: string; value: string }> = [
41
+ { name: names.accessToken, value: args.tokens.access_token },
42
+ ];
43
+ const refresh = args.tokens.refresh_token?.trim();
44
+ if (refresh !== undefined && refresh !== "") {
45
+ secrets.push({ name: names.refreshToken, value: refresh });
46
+ }
47
+ const clientId = args.clientId?.trim();
48
+ if (clientId !== undefined && clientId !== "") {
49
+ secrets.push({ name: names.clientId, value: clientId });
50
+ }
51
+ return secrets;
52
+ }
53
+
54
+ export async function upsertHostMcpOauthSecrets(args: {
55
+ connection: string;
56
+ tokens: OAuthTokens;
57
+ clientId?: string;
58
+ target: McpOauthSecretsTarget;
59
+ }): Promise<string[]> {
60
+ const payload = mcpOauthSecretsPayload(args);
61
+ if (payload.length === 0) {
62
+ return [];
63
+ }
64
+ return await args.target.client.setSecrets({
65
+ teamId: args.target.teamId,
66
+ slug: args.target.slug,
67
+ secrets: payload,
68
+ });
69
+ }
70
+
71
+ export type ResolveHostedMcpOauthSecretsArgs = {
72
+ slug?: string;
73
+ team?: string;
74
+ apiKey?: string;
75
+ cloudToolsUrl?: string;
76
+ env?: NodeJS.ProcessEnv;
77
+ };
78
+
79
+ /**
80
+ * Bind the CLI `--store` client when this process is a hosted engine
81
+ * (`AGENT_SERVE_DEPLOYMENT_ID`) and a live API key is present.
82
+ * Self-hosted / no deployment / unsigned: undefined.
83
+ */
84
+ export function resolveHostedMcpOauthSecretsTarget(
85
+ args: ResolveHostedMcpOauthSecretsArgs = {}
86
+ ): McpOauthSecretsTarget | undefined {
87
+ const env = args.env ?? process.env;
88
+ const deploymentId = env[AGENT_SERVE_DEPLOYMENT_ID_ENV_VAR]?.trim();
89
+ if (deploymentId === undefined || deploymentId === "") {
90
+ return undefined;
91
+ }
92
+ const resolved = resolveApiKeySync(
93
+ args.apiKey === undefined ? undefined : { apiKey: args.apiKey }
94
+ );
95
+ if (resolved === undefined) {
96
+ return undefined;
97
+ }
98
+ const fromUrl =
99
+ args.cloudToolsUrl === undefined
100
+ ? undefined
101
+ : parseAgentServeMcpGatewayUrl(args.cloudToolsUrl);
102
+ const slug =
103
+ args.slug !== undefined && args.slug !== "" ? args.slug : fromUrl?.slug;
104
+ const teamId = parseTeamId(args.team) ?? fromUrl?.teamId;
105
+ if (slug === undefined || teamId === undefined) {
106
+ return undefined;
107
+ }
108
+ return {
109
+ client: new AgentServeDeployClient({
110
+ backendUrl: cursorExternalApiUrl(),
111
+ apiKey: resolved.apiKey,
112
+ }),
113
+ teamId,
114
+ slug,
115
+ };
116
+ }
117
+
118
+ function parseTeamId(team: string | undefined): number | undefined {
119
+ if (team === undefined || team === "") {
120
+ return undefined;
121
+ }
122
+ const teamId = Number.parseInt(team, 10);
123
+ if (!Number.isInteger(teamId) || teamId <= 0) {
124
+ return undefined;
125
+ }
126
+ return teamId;
127
+ }
@@ -411,13 +411,25 @@ export class HostMcpOAuthProvider implements OAuthClientProvider {
411
411
  }
412
412
  }
413
413
 
414
+ function clientForRedirect(
415
+ info: OAuthClientInformationFull | undefined,
416
+ redirectUrl: string
417
+ ): OAuthClientInformationFull | undefined {
418
+ if (info === undefined || !info.redirect_uris.includes(redirectUrl)) {
419
+ return undefined;
420
+ }
421
+ return info;
422
+ }
423
+
414
424
  export async function createHostMcpOAuthProvider(args: {
415
425
  identifier: string;
416
426
  resourceUrl: string;
417
427
  store?: FileMcpOAuthStore;
418
428
  onRedirect?: (url: URL) => void;
429
+ redirectUrl?: string;
419
430
  }): Promise<HostMcpOAuthProvider> {
420
431
  const store = args.store ?? new FileMcpOAuthStore();
432
+ const redirectUrl = args.redirectUrl ?? MCP_OAUTH_CALLBACK_URL;
421
433
  const [fileTokens, fileClient, omitResourceIndicator] = await Promise.all([
422
434
  store.loadTokens(args.identifier, args.resourceUrl),
423
435
  store.loadClientInformation(args.identifier, args.resourceUrl),
@@ -427,8 +439,12 @@ export async function createHostMcpOAuthProvider(args: {
427
439
  identifier: args.identifier,
428
440
  resourceUrl: args.resourceUrl,
429
441
  store,
442
+ redirectUrl,
430
443
  tokens: fileTokens ?? tokensFromEnv(args.identifier),
431
- clientInformation: fileClient ?? clientIdFromEnv(args.identifier),
444
+ clientInformation: clientForRedirect(
445
+ fileClient ?? clientIdFromEnv(args.identifier),
446
+ redirectUrl
447
+ ),
432
448
  onRedirect: args.onRedirect,
433
449
  omitResourceIndicator,
434
450
  });