@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
@@ -21,8 +21,11 @@
21
21
  import type { ChannelEventHandlers } from "../../types.js";
22
22
  import { postMessage, setThreadStatus, updateMessage } from "./api.js";
23
23
  import {
24
+ authThreadStatus,
24
25
  buildApprovalBlocks,
26
+ buildAuthBlocks,
25
27
  buildResolvedApprovalBlocks,
28
+ buildResolvedAuthBlocks,
26
29
  } from "./approvals.js";
27
30
  import { SLACK_DEFAULT_LOADING_MESSAGES } from "./constants.js";
28
31
  import { defaultSlackLog, type SlackLog } from "./log.js";
@@ -132,5 +135,95 @@ export function buildToolApprovalEvents(
132
135
  decision: event.data.decision,
133
136
  });
134
137
  },
138
+
139
+ async "action.auth_requested"(event, channel, ctx) {
140
+ const log = getLog();
141
+ const state = channel.state;
142
+ if (state.channelId === null || state.threadTs === null) {
143
+ return;
144
+ }
145
+ const blocks = buildAuthBlocks({
146
+ sessionId: ctx.session.id,
147
+ callId: event.data.callId,
148
+ toolName: event.data.toolName,
149
+ connection: event.data.connection,
150
+ authUrl: event.data.authUrl,
151
+ });
152
+ try {
153
+ const posted = await postMessage({
154
+ botToken,
155
+ channel: state.channelId,
156
+ threadTs: state.threadTs,
157
+ text: `Authorization required for \`${event.data.connection}\``,
158
+ blocks,
159
+ });
160
+ channel.state.approvalMessageByCallId = {
161
+ ...(state.approvalMessageByCallId ?? {}),
162
+ [event.data.callId]: posted.ts,
163
+ };
164
+ await setThreadStatus({
165
+ botToken,
166
+ channelId: state.channelId,
167
+ threadTs: state.threadTs,
168
+ status: authThreadStatus(event.data.connection),
169
+ loadingMessages: [
170
+ authThreadStatus(event.data.connection),
171
+ ...SLACK_DEFAULT_LOADING_MESSAGES,
172
+ ],
173
+ });
174
+ log.info("auth card posted", {
175
+ call_id: event.data.callId,
176
+ connection: event.data.connection,
177
+ message_ts: posted.ts,
178
+ });
179
+ } catch (error) {
180
+ log.warn("auth card post failed", {
181
+ call_id: event.data.callId,
182
+ error: error instanceof Error ? error.message : String(error),
183
+ });
184
+ }
185
+ },
186
+
187
+ async "action.auth_resolved"(event, channel) {
188
+ const log = getLog();
189
+ const state = channel.state;
190
+ const messageTs = state.approvalMessageByCallId?.[event.data.callId];
191
+ if (
192
+ state.channelId !== null &&
193
+ messageTs !== undefined &&
194
+ messageTs !== ""
195
+ ) {
196
+ const blocks = buildResolvedAuthBlocks({
197
+ connection: event.data.connection,
198
+ decision: event.data.decision,
199
+ byUserId: event.data.by,
200
+ });
201
+ const verb =
202
+ event.data.decision === "approve" ? "Connected" : "Cancelled";
203
+ await updateMessage({
204
+ botToken,
205
+ channel: state.channelId,
206
+ ts: messageTs,
207
+ text: `${verb} — ${event.data.connection}`,
208
+ blocks,
209
+ });
210
+ const next = { ...(state.approvalMessageByCallId ?? {}) };
211
+ delete next[event.data.callId];
212
+ channel.state.approvalMessageByCallId = next;
213
+ }
214
+ if (state.channelId !== null && state.threadTs !== null) {
215
+ await setThreadStatus({
216
+ botToken,
217
+ channelId: state.channelId,
218
+ threadTs: state.threadTs,
219
+ status: "Working…",
220
+ loadingMessages: [...SLACK_DEFAULT_LOADING_MESSAGES],
221
+ });
222
+ }
223
+ log.info("auth resolved in slack", {
224
+ call_id: event.data.callId,
225
+ decision: event.data.decision,
226
+ });
227
+ },
135
228
  };
136
229
  }
@@ -182,6 +182,38 @@ export function deriveRunFacts(events: readonly SessionEvent[]): EvalRunFacts {
182
182
  }
183
183
  break;
184
184
  }
185
+ case "action.auth_requested": {
186
+ const request: EvalInputRequestFact = {
187
+ callId: event.data.callId,
188
+ toolName: event.data.toolName,
189
+ args: {
190
+ connection: event.data.connection,
191
+ authUrl: event.data.authUrl,
192
+ },
193
+ resolved: false,
194
+ };
195
+ inputRequests.push(request);
196
+ inputRequestsByCallId.set(event.data.callId, request);
197
+ break;
198
+ }
199
+ case "action.auth_resolved": {
200
+ const request = inputRequestsByCallId.get(event.data.callId);
201
+ if (request !== undefined) {
202
+ request.resolved = true;
203
+ request.decision = event.data.decision;
204
+ }
205
+ const fact = ensureCall(
206
+ event.data.callId,
207
+ event.data.toolName,
208
+ event.turnId,
209
+ event.data.parentCallId
210
+ );
211
+ fact.approvalDecision = event.data.decision;
212
+ if (event.data.decision === "deny") {
213
+ fact.status = "rejected";
214
+ }
215
+ break;
216
+ }
185
217
  case "subagent.called": {
186
218
  const existing = subagentsByCallId.get(event.data.callId);
187
219
  if (existing === undefined) {
@@ -71,6 +71,19 @@ const AGENT_SERVE_FILES_PATH = "/v0/agent-serve-files";
71
71
  export const AGENT_SERVE_STORE_SOURCE_ID_ENV_VAR =
72
72
  "AGENT_SERVE_STORE_SOURCE_ID";
73
73
 
74
+ /**
75
+ * The deployment's **framework-level** file store, distinct from the
76
+ * user-level store above. The user store carries author-facing bytes
77
+ * (`ctx.host.files`, skills, memory, artifacts) and is browsable and
78
+ * mountable; the framework store carries engine-owned session state —
79
+ * session records, event transcripts, continuation index, and the SDK
80
+ * conversation mirror — and is never exposed to authors or models.
81
+ * Provisioned by the v2 deploy pipeline alongside the user store; v1
82
+ * deployments have only the user store.
83
+ */
84
+ export const AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID_ENV_VAR =
85
+ "AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID";
86
+
74
87
  /** Cap on the per-process etag cache; a miss costs a lookup, not correctness. */
75
88
  const MAX_REMEMBERED_ETAGS = 1_000;
76
89
 
@@ -101,6 +114,20 @@ export function isCursorHostedFilesAvailable(
101
114
  return sourceId !== undefined && sourceId !== "";
102
115
  }
103
116
 
117
+ /**
118
+ * The framework-level store's source id, or `undefined` when the deployment
119
+ * has none (v1, self-hosted, or a v2 deploy predating framework-store
120
+ * provisioning). Same detection posture as
121
+ * {@link isCursorHostedFilesAvailable}: keyed on the id alone — a missing
122
+ * credential must fail loudly at use, not silently deselect the store.
123
+ */
124
+ export function cursorFrameworkStoreSourceId(
125
+ env: NodeJS.ProcessEnv = process.env
126
+ ): string | undefined {
127
+ const sourceId = env[AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID_ENV_VAR]?.trim();
128
+ return sourceId === undefined || sourceId === "" ? undefined : sourceId;
129
+ }
130
+
104
131
  /**
105
132
  * Local `serve`/`run` with a personal `CURSOR_API_KEY` can address
106
133
  * `/v0/agent-serve-files/user`. Hosted deployments have a store source id
@@ -125,12 +152,15 @@ export function isCursorUserStoreFilesAvailable(
125
152
  export interface CursorHostedFilesOptions {
126
153
  /** Control-plane base URL (default: `CURSOR_API_BASE_URL`, else api.cursor.com). */
127
154
  baseUrl?: string;
155
+ /** Bearer credential (default: `CURSOR_API_KEY`). */
156
+ apiKey?: string;
128
157
  /**
129
- * Bearer credential (default: `CURSOR_API_KEY`). A function is re-resolved
130
- * on every call — hosted freeze snapshots listen unsigned and bind the key
131
- * file after serve start.
158
+ * Lazy credential, re-resolved on every call and preferred over
159
+ * {@link apiKey} — hosted freeze snapshots listen unsigned and bind the
160
+ * key file after serve start. Kept separate so `apiKey` stays a plain
161
+ * string.
132
162
  */
133
- apiKey?: string | (() => string | undefined);
163
+ resolveApiKey?: () => string | undefined;
134
164
  /** File store to address (default: `AGENT_SERVE_STORE_SOURCE_ID`). */
135
165
  storeSourceId?: string;
136
166
  /** Test seam; defaults to global fetch. */
@@ -253,7 +283,11 @@ export function cursorHostedFiles(
253
283
  }
254
284
  out.push(toEntry(file, file.path));
255
285
  }
256
- return out;
286
+ // The FileSink contract promises key order, and transcript-chunk
287
+ // consumers depend on it (chunk keys are zero-padded so key order
288
+ // is append order). The server happens to scan in order today; do
289
+ // not let that be the only thing holding the contract.
290
+ return out.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
257
291
  }
258
292
  // The unscoped listing was truncated (`complete: false`) and has no
259
293
  // continuation to follow. `list()` promises the whole scope, so rather
@@ -626,8 +660,7 @@ function resolveStoreSourceId(options: CursorHostedFilesOptions): string {
626
660
  }
627
661
 
628
662
  function resolveApiKey(options: CursorHostedFilesOptions): string {
629
- const configured =
630
- typeof options.apiKey === "function" ? options.apiKey() : options.apiKey;
663
+ const configured = options.resolveApiKey?.() ?? options.apiKey;
631
664
  const key = (configured ?? process.env.CURSOR_API_KEY)?.trim();
632
665
  if (key === undefined || key === "") {
633
666
  throw new Error(
@@ -27,6 +27,8 @@
27
27
  * `defineConnection({ effects })` filters the listing before names are
28
28
  * assigned: only tools whose MCP annotations classify as an intended
29
29
  * effect are advertised. Unclassified tools are omitted, not guessed.
30
+ * Tools whose `annotations.title` is `do-not-call` are dropped as well
31
+ * (vendor host-UI / MCP Apps helpers that still carry `readOnlyHint`).
30
32
  */
31
33
 
32
34
  import type {
@@ -116,26 +118,49 @@ export async function resolveAdvertisedTools(args: {
116
118
  return [];
117
119
  }
118
120
  const sourceFor = args.sourceFor ?? sourceForConnection;
121
+ // Each connection's listing is a network round trip against a distinct
122
+ // server (auth callback, MCP initialize, tools/list), so they run
123
+ // concurrently; the fan-out is bounded by the agent's declared
124
+ // connections. Name assignment below stays in declaration order so
125
+ // collision suffixes do not depend on which server answered first.
126
+ type Listing =
127
+ | {
128
+ connection: DiscoveredConnection;
129
+ ok: true;
130
+ source: AdvertisedToolSource;
131
+ listed: HostMcpToolInfo[];
132
+ }
133
+ | { connection: DiscoveredConnection; ok: false; error: unknown };
134
+ const listings = await Promise.all(
135
+ advertising.map(async (connection): Promise<Listing> => {
136
+ try {
137
+ const source = await sourceFor(connection, args.session, args.hostMcp);
138
+ const listed = await source.listTools();
139
+ return { connection, ok: true, source, listed };
140
+ } catch (error) {
141
+ return { connection, ok: false, error };
142
+ }
143
+ })
144
+ );
119
145
  const claimed = new Set(args.agent.tools.map((tool) => tool.name));
120
146
  const resolved: DiscoveredTool[] = [];
121
- for (const connection of advertising) {
122
- let listed: HostMcpToolInfo[];
123
- let source: AdvertisedToolSource;
124
- try {
125
- source = await sourceFor(connection, args.session, args.hostMcp);
126
- listed = await source.listTools();
127
- } catch (error) {
147
+ for (const listing of listings) {
148
+ const { connection } = listing;
149
+ if (!listing.ok) {
128
150
  if (args.onConnectionError !== undefined) {
129
- args.onConnectionError(connection.name, error);
151
+ args.onConnectionError(connection.name, listing.error);
130
152
  continue;
131
153
  }
132
154
  throw new Error(
133
- `Failed to list tools on advertised connection "${connection.name}": ${describeError(error)}`,
134
- { cause: error }
155
+ `Failed to list tools on advertised connection "${connection.name}": ${describeError(listing.error)}`,
156
+ { cause: listing.error }
135
157
  );
136
158
  }
137
- const intended = listed.filter((info) =>
138
- matchesIntendedEffects(info.annotations, connection.effects)
159
+ const { source, listed } = listing;
160
+ const intended = listed.filter(
161
+ (info) =>
162
+ !isDoNotCallTool(info.annotations) &&
163
+ matchesIntendedEffects(info.annotations, connection.effects)
139
164
  );
140
165
  const exposed = exposeListedTools(intended, claimed);
141
166
  for (const { info, exposedName } of exposed) {
@@ -232,6 +257,18 @@ function exposeListedTools(
232
257
  }));
233
258
  }
234
259
 
260
+ /**
261
+ * Vendors (Datadog MCP Apps) stamp host-UI-only helpers with this title.
262
+ * They still look like reads (`readOnlyHint: true`), so the effects
263
+ * filter would keep them. The model and agsh should not see them; the
264
+ * raw MCP listing stays intact for the host.
265
+ */
266
+ const DO_NOT_CALL_TITLE = "do-not-call";
267
+
268
+ function isDoNotCallTool(annotations: McpToolAnnotations | undefined): boolean {
269
+ return annotations?.title?.trim() === DO_NOT_CALL_TITLE;
270
+ }
271
+
235
272
  function matchesIntendedEffects(
236
273
  annotations: McpToolAnnotations | undefined,
237
274
  effects: readonly ToolEffect[] | undefined
@@ -1,13 +1,12 @@
1
1
  /**
2
- * In-memory gate for human-in-the-loop tool approvals. The session
3
- * engine parks inside a server-tool `execute` by awaiting
4
- * {@link ApprovalGate.wait}; HTTP (or the playground) unblocks via
5
- * {@link ApprovalGate.resolve}.
2
+ * In-memory gate for human-in-the-loop parks. The session engine parks
3
+ * inside a server-tool `execute` by awaiting {@link ApprovalGate.wait};
4
+ * HTTP (or the playground) unblocks via {@link ApprovalGate.resolve}.
6
5
  *
7
- * Pending approvals are also mirrored onto {@link SessionRecord} for
8
- * durability of the *list* across reloads. After a process restart the
9
- * in-flight SDK tool callback is gone, so resolve returns false and
10
- * the host treats the approval as interrupted.
6
+ * Used for `needsApproval` and MCP on-demand auth. Pending rows are also
7
+ * mirrored onto {@link SessionRecord} for durability of the *list* across
8
+ * reloads. After a process restart the in-flight SDK tool callback is gone,
9
+ * so resolve returns false and the host treats the park as interrupted.
11
10
  */
12
11
 
13
12
  import type { ApprovalDecision, PendingApproval } from "../types.js";
@@ -21,33 +20,25 @@ export interface ApprovalResolution {
21
20
  by?: string;
22
21
  }
23
22
 
24
- interface Waiter {
25
- meta: PendingApproval;
23
+ interface Waiter<T> {
24
+ meta: T;
26
25
  resolve: (resolution: ApprovalResolution) => void;
27
26
  }
28
27
 
29
- export class ApprovalGate {
30
- private readonly waiters = new Map<string, Waiter>();
28
+ export class ApprovalGate<T extends { callId: string } = PendingApproval> {
29
+ private readonly waiters = new Map<string, Waiter<T>>();
31
30
 
32
- wait(
33
- meta: PendingApproval & { sessionId: string }
34
- ): Promise<ApprovalResolution> {
35
- const key = approvalKey(meta.sessionId, meta.callId);
31
+ wait(sessionId: string, meta: T): Promise<ApprovalResolution> {
32
+ const key = approvalKey(sessionId, meta.callId);
36
33
  const existing = this.waiters.get(key);
37
34
  if (existing !== undefined) {
38
35
  throw new Error(
39
- `Approval already pending for session ${meta.sessionId} call ${meta.callId}`
36
+ `Approval already pending for session ${sessionId} call ${meta.callId}`
40
37
  );
41
38
  }
42
39
  return new Promise<ApprovalResolution>((resolveDecision) => {
43
40
  this.waiters.set(key, {
44
- meta: {
45
- callId: meta.callId,
46
- turnId: meta.turnId,
47
- toolName: meta.toolName,
48
- args: meta.args,
49
- requestedAt: meta.requestedAt,
50
- },
41
+ meta,
51
42
  resolve: resolveDecision,
52
43
  });
53
44
  });
@@ -69,11 +60,11 @@ export class ApprovalGate {
69
60
  return false;
70
61
  }
71
62
  this.waiters.delete(key);
63
+ const by =
64
+ resolvedBy === undefined || resolvedBy === "" ? undefined : resolvedBy;
72
65
  waiter.resolve({
73
66
  decision,
74
- ...(resolvedBy === undefined || resolvedBy === ""
75
- ? {}
76
- : { by: resolvedBy }),
67
+ by,
77
68
  });
78
69
  return true;
79
70
  }
@@ -82,9 +73,9 @@ export class ApprovalGate {
82
73
  return this.waiters.has(approvalKey(sessionId, callId));
83
74
  }
84
75
 
85
- list(sessionId: string): PendingApproval[] {
76
+ list(sessionId: string): T[] {
86
77
  const prefix = `${sessionId}\0`;
87
- const out: PendingApproval[] = [];
78
+ const out: T[] = [];
88
79
  for (const [key, waiter] of this.waiters) {
89
80
  if (key.startsWith(prefix)) {
90
81
  out.push(waiter.meta);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Bounded-concurrency map, in input order. Local rather than
3
+ * `@anysphere/utils`: this published package cannot depend on monorepo
4
+ * internals.
5
+ */
6
+ export async function mapBounded<T, R>(
7
+ items: readonly T[],
8
+ max: number,
9
+ run: (item: T) => Promise<R>
10
+ ): Promise<R[]> {
11
+ const out = new Array<R>(items.length);
12
+ let nextIndex = 0;
13
+ const workers = Array.from(
14
+ { length: Math.min(max, items.length) },
15
+ async () => {
16
+ for (;;) {
17
+ const index = nextIndex;
18
+ nextIndex += 1;
19
+ if (index >= items.length) {
20
+ return;
21
+ }
22
+ out[index] = await run(items[index] as T);
23
+ }
24
+ }
25
+ );
26
+ await Promise.all(workers);
27
+ return out;
28
+ }
@@ -483,6 +483,25 @@ async function streamTurn(args: StreamTurnArgs): Promise<number> {
483
483
  );
484
484
  continue;
485
485
  }
486
+ if (event.type === "action.auth_requested") {
487
+ closeAssistant();
488
+ write(
489
+ ` ${c.yellow("⏸")} ${c.bold(event.data.connection)} ${c.dim(
490
+ "awaiting MCP authorization"
491
+ )}\n`
492
+ );
493
+ continue;
494
+ }
495
+ if (event.type === "action.auth_resolved") {
496
+ const mark =
497
+ event.data.decision === "approve" ? c.green("✓") : c.red("✗");
498
+ write(
499
+ ` ${mark} ${c.bold(event.data.connection)} ${c.dim(
500
+ event.data.decision === "approve" ? "connected" : "denied"
501
+ )}\n`
502
+ );
503
+ continue;
504
+ }
486
505
  if (event.type === "action.result") {
487
506
  if (
488
507
  event.data.toolName === "task" &&
@@ -49,6 +49,8 @@ import {
49
49
  import { type GitRunner, inferDeployGitSource } from "./deploy-source.js";
50
50
  import {
51
51
  type ChildAgentDir,
52
+ formatDiagnostics,
53
+ hasErrorDiagnostics,
52
54
  isAgentProjectDir,
53
55
  listChildAgentDirs,
54
56
  loadAgentProject,
@@ -110,6 +112,11 @@ export interface DeployCliOptions {
110
112
  cursorEventsRepos?: string[];
111
113
  /** deploy `--allow-domain <domain>` (repeatable; unioned with the manifest). */
112
114
  allowDomains?: string[];
115
+ /**
116
+ * deploy `--multi-tenant`: add a release to an existing Cursor-managed
117
+ * (multi-tenant) product. Cannot create a new multi-tenant application.
118
+ */
119
+ multiTenant?: boolean;
113
120
  /** Test seams. */
114
121
  fetchImpl?: typeof fetch;
115
122
  /** Inject the connector-auth browser opener (tests; also forces interactive). */
@@ -309,7 +316,9 @@ export async function cmdDeploy(options: DeployCliOptions): Promise<number> {
309
316
  manifests.push(await readDeployManifest(target.dir));
310
317
  }
311
318
  if (manifests.every((manifest) => manifest.architecture === "v2")) {
312
- return deployAgentsdkApplication(ctx, options, targets);
319
+ return deployAgentsdkApplication(ctx, options, targets, {
320
+ hasScmChannels: manifests.some((manifest) => manifest.hasScmChannels),
321
+ });
313
322
  }
314
323
  if (
315
324
  !ctx.json &&
@@ -720,9 +729,18 @@ async function deployOne(
720
729
  gitRef,
721
730
  agentPath,
722
731
  repositories: options.cursorEventsRepos,
732
+ hasScmChannels: manifest.hasScmChannels,
733
+ multiTenant: options.multiTenant === true,
723
734
  });
724
735
  }
725
736
 
737
+ if (options.multiTenant === true) {
738
+ ctx.err(
739
+ "--multi-tenant is only valid for architecture: v2 deploys (Cursor-managed products).\n"
740
+ );
741
+ return 1;
742
+ }
743
+
726
744
  // Today's only source shape: the control plane builds from a git ref.
727
745
  // See DeploySource for the artifact seam.
728
746
  const source: DeploySource = {
@@ -802,11 +820,9 @@ async function deployOne(
802
820
  }
803
821
 
804
822
  if (detail.status !== "running") {
805
- const errorDetail =
806
- detail.lastError === null || detail.lastError === undefined
807
- ? ""
808
- : `: ${sanitizeCustomerError(detail.lastError)}`;
809
- ctx.err(`Deployment ${slug} ended ${detail.status}${errorDetail}\n`);
823
+ ctx.err(
824
+ `Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`
825
+ );
810
826
  return 1;
811
827
  }
812
828
  const deployedPublicRoutes = detail.publicRoutePaths ?? [];
@@ -843,7 +859,8 @@ async function deployOne(
843
859
  async function deployAgentsdkApplication(
844
860
  ctx: DeployCliContext,
845
861
  options: DeployCliOptions,
846
- targets: readonly DeployTarget[]
862
+ targets: readonly DeployTarget[],
863
+ declarations: { hasScmChannels: boolean }
847
864
  ): Promise<number> {
848
865
  const parentDir = resolve(options.dir ?? ".");
849
866
  const slug = slugFromDirectoryName(basename(parentDir));
@@ -924,6 +941,8 @@ async function deployAgentsdkApplication(
924
941
  agentPath: undefined,
925
942
  components,
926
943
  repositories: options.cursorEventsRepos,
944
+ hasScmChannels: declarations.hasScmChannels,
945
+ multiTenant: options.multiTenant === true,
927
946
  });
928
947
  }
929
948
 
@@ -942,6 +961,10 @@ async function deployOneAgentsdk(
942
961
  agentPath: string | undefined;
943
962
  components?: AgentkitDeployComponent[];
944
963
  repositories: string[] | undefined;
964
+ /** Any component declares a GitHub/Origin channel. */
965
+ hasScmChannels: boolean;
966
+ /** Redeploy an existing Cursor-managed product. */
967
+ multiTenant: boolean;
945
968
  }
946
969
  ): Promise<number> {
947
970
  const { slug } = args;
@@ -951,6 +974,9 @@ async function deployOneAgentsdk(
951
974
  : ` components: ${args.components
952
975
  .map((component) => component.componentKey)
953
976
  .join(", ")}\n`;
977
+ if (args.multiTenant && !ctx.json) {
978
+ ctx.err(" multi-tenant: existing product\n");
979
+ }
954
980
  let accepted: AgentkitDeployAccepted;
955
981
  try {
956
982
  accepted = await ctx.client.deployAgentkit({
@@ -961,6 +987,7 @@ async function deployOneAgentsdk(
961
987
  agentPath: args.agentPath,
962
988
  components: args.components,
963
989
  repositories: args.repositories,
990
+ ...(args.multiTenant ? { multiTenant: true } : {}),
964
991
  });
965
992
  } catch (error) {
966
993
  return renderApiError(error, ctx.err);
@@ -1002,7 +1029,9 @@ async function deployOneAgentsdk(
1002
1029
  }
1003
1030
 
1004
1031
  if (detail.status !== "running") {
1005
- ctx.err(`Deployment ${slug} ended ${detail.status}\n`);
1032
+ ctx.err(
1033
+ `Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`
1034
+ );
1006
1035
  return 1;
1007
1036
  }
1008
1037
  ctx.out(
@@ -1015,8 +1044,19 @@ async function deployOneAgentsdk(
1015
1044
  ? ""
1016
1045
  : ` components: ${args.components
1017
1046
  .map((component) => component.componentKey)
1018
- .join(", ")}\n`)
1047
+ .join(", ")}\n`) +
1048
+ (detail.repositories === undefined || !args.hasScmChannels
1049
+ ? ""
1050
+ : ` watching: ${detail.repositories.length === 0 ? "(nothing)" : detail.repositories.join(", ")}\n`)
1019
1051
  );
1052
+ // An agent with GitHub/Origin channels bound to no repository scope gets
1053
+ // no deliveries at all, which is otherwise invisible in this output.
1054
+ if (args.hasScmChannels && detail.repositories?.length === 0) {
1055
+ ctx.err(
1056
+ `warning: ${slug} watches no repositories, so its GitHub/Origin channels receive no events.\n` +
1057
+ ` Redeploy with --cursor-events-repo <owner>/<name> to set the scope.\n`
1058
+ );
1059
+ }
1020
1060
  return 0;
1021
1061
  }
1022
1062
 
@@ -1126,6 +1166,11 @@ interface DeployManifest {
1126
1166
  * (only `/v1/channels/…` subtrees can be public); surfaced as a warning.
1127
1167
  */
1128
1168
  httpChannelPublicEndpoint: boolean;
1169
+ /**
1170
+ * The agent has GitHub/Origin channels, so it only receives deliveries
1171
+ * while the deployment is bound to at least one `owner/name` scope.
1172
+ */
1173
+ hasScmChannels: boolean;
1129
1174
  }
1130
1175
 
1131
1176
  /**
@@ -1135,6 +1180,16 @@ interface DeployManifest {
1135
1180
  */
1136
1181
  async function readDeployManifest(dir: string): Promise<DeployManifest> {
1137
1182
  const project = await loadAgentProject(dir);
1183
+ // Fail here, before anything is dispatched: a project with error
1184
+ // diagnostics (e.g. agent/storage.ts on architecture v2) would only be
1185
+ // refused later by `serve` inside the hosted build, wasting a bake.
1186
+ if (hasErrorDiagnostics(project)) {
1187
+ throw new Error(
1188
+ `Refusing to deploy ${project.name} — it has errors:\n${formatDiagnostics(
1189
+ project.diagnostics.filter((d) => d.severity === "error")
1190
+ )}`
1191
+ );
1192
+ }
1138
1193
  return {
1139
1194
  hosting: project.agent.hosting,
1140
1195
  architecture: project.agent.architecture,
@@ -1151,6 +1206,10 @@ async function readDeployManifest(dir: string): Promise<DeployManifest> {
1151
1206
  httpChannelPublicEndpoint: (project.httpChannel.auth ?? []).some(
1152
1207
  isPublicEndpointPolicy
1153
1208
  ),
1209
+ hasScmChannels: project.channels.some((channel) => {
1210
+ const kind = channel.definition.meta?.kind;
1211
+ return kind === "github" || kind === "origin";
1212
+ }),
1154
1213
  };
1155
1214
  }
1156
1215
 
@@ -1926,9 +1985,32 @@ function aliasTokenBlock(aliasToken: string): string {
1926
1985
  );
1927
1986
  }
1928
1987
 
1988
+ /**
1989
+ * `: <reason>` suffix for a deploy that ended in a non-running state, or
1990
+ * empty when the control plane recorded no reason.
1991
+ */
1992
+ function deployFailureDetail(lastError: string | null | undefined): string {
1993
+ if (
1994
+ lastError === null ||
1995
+ lastError === undefined ||
1996
+ lastError.trim() === ""
1997
+ ) {
1998
+ return "";
1999
+ }
2000
+ return `: ${sanitizeCustomerError(lastError.trim())}`;
2001
+ }
2002
+
1929
2003
  function renderApiError(error: unknown, err: (text: string) => void): number {
1930
2004
  if (error instanceof DeployApiError) {
1931
2005
  err(`${error.message}\n`);
2006
+ if (
2007
+ error.status === 409 &&
2008
+ error.message.includes("application multiTenant does not match")
2009
+ ) {
2010
+ err(
2011
+ "This slug is a Cursor-managed (multi-tenant) product. Redeploy it with --multi-tenant.\n"
2012
+ );
2013
+ }
1932
2014
  return 1;
1933
2015
  }
1934
2016
  throw error;