@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
@@ -260,6 +260,13 @@ export interface AgentkitDeployStatus {
260
260
  status: AgentkitCustomerStatus;
261
261
  progress: AgentkitDeployProgress;
262
262
  statusMessage: string | null;
263
+ /** Why the bake failed. Null/absent unless `status` is `failed`. */
264
+ lastError?: string | null;
265
+ /**
266
+ * `owner/name` scopes the deployment's GitHub/Origin channels watch.
267
+ * Absent on control planes that predate the field.
268
+ */
269
+ repositories?: string[];
263
270
  }
264
271
 
265
272
  export const TERMINAL_AGENTKIT_DEPLOY_STATUSES: ReadonlySet<AgentkitCustomerStatus> =
@@ -350,6 +357,8 @@ const agentkitDeployStatusSchema = z
350
357
  "stopped",
351
358
  ]),
352
359
  statusMessage: z.string().nullable(),
360
+ // Optional: backends that predate the v2 bake-failure column omit it.
361
+ lastError: z.string().nullable().optional(),
353
362
  })
354
363
  .passthrough();
355
364
 
@@ -598,6 +607,8 @@ export class AgentServeDeployClient {
598
607
  agentPath?: string;
599
608
  components?: AgentkitDeployComponent[];
600
609
  repositories?: string[];
610
+ /** Redeploy an existing Cursor-managed (multi-tenant) product. */
611
+ multiTenant?: boolean;
601
612
  }): Promise<AgentkitDeployAccepted> {
602
613
  const slugError = validateDeploymentSlug(args.slug);
603
614
  if (slugError !== undefined) {
@@ -626,6 +637,7 @@ export class AgentServeDeployClient {
626
637
  args.repositories !== undefined && args.repositories.length > 0
627
638
  ? args.repositories
628
639
  : undefined,
640
+ ...(args.multiTenant === true ? { multiTenant: true } : {}),
629
641
  },
630
642
  context: { verb: "deploy", slug: args.slug },
631
643
  });
@@ -890,6 +902,37 @@ export class AgentServeDeployClient {
890
902
  }
891
903
  }
892
904
 
905
+ const MCP_GATEWAY_PATH =
906
+ /^\/internal\/agent-serve\/mcp\/(\d+)\/([^/]+)(?:\/tools)?\/?$/;
907
+
908
+ /**
909
+ * Inverse of {@link AgentServeDeployClient.mcpGatewayUrl}. Also accepts
910
+ * the hosted `--cloud-tools-url` form (`…/tools`).
911
+ */
912
+ export function parseAgentServeMcpGatewayUrl(
913
+ url: string
914
+ ): { teamId: number; slug: string } | undefined {
915
+ let parsed: URL;
916
+ try {
917
+ parsed = new URL(url);
918
+ } catch {
919
+ return undefined;
920
+ }
921
+ const match = MCP_GATEWAY_PATH.exec(parsed.pathname);
922
+ if (match === null) {
923
+ return undefined;
924
+ }
925
+ const teamId = Number.parseInt(match[1]!, 10);
926
+ if (!Number.isInteger(teamId) || teamId <= 0) {
927
+ return undefined;
928
+ }
929
+ const slug = decodeURIComponent(match[2]!);
930
+ if (validateDeploymentSlug(slug) !== undefined) {
931
+ return undefined;
932
+ }
933
+ return { teamId, slug };
934
+ }
935
+
893
936
  // ============================================================================
894
937
  // Error mapping (HTTP → actionable human messages)
895
938
  // ============================================================================
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Shared `.env` / `.env.local` writers for CLI commands that mint tokens.
3
+ */
4
+
5
+ import { chmod, readFile, writeFile } from "node:fs/promises";
6
+ import { join } from "node:path";
7
+
8
+ function isErrnoException(error: unknown): error is NodeJS.ErrnoException {
9
+ return error instanceof Error && "code" in error;
10
+ }
11
+
12
+ async function readOptionalFile(path: string): Promise<string> {
13
+ try {
14
+ return await readFile(path, "utf8");
15
+ } catch (error) {
16
+ if (isErrnoException(error) && error.code === "ENOENT") {
17
+ return "";
18
+ }
19
+ throw error;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Append `KEY=value` lines to an env file, replacing every existing line
25
+ * for the same key instead of appending duplicates. Creates the file when
26
+ * missing.
27
+ */
28
+ export async function upsertEnvFile(
29
+ path: string,
30
+ entries: Array<{ key: string; value: string }>
31
+ ): Promise<void> {
32
+ const existing = await readOptionalFile(path);
33
+ const lines =
34
+ existing === "" ? [] : existing.replace(/\r?\n$/, "").split(/\r?\n/);
35
+ // A stale `export KEY=…` line would shadow or duplicate the bare line
36
+ // under some loaders; treat both spellings as the same entry.
37
+ const matchesKey = (line: string, key: string): boolean =>
38
+ line.startsWith(`${key}=`) || line.startsWith(`export ${key}=`);
39
+ for (const { key, value } of entries) {
40
+ const next = `${key}=${value}`;
41
+ let replaced = false;
42
+ for (let i = 0; i < lines.length; ) {
43
+ if (!matchesKey(lines[i] ?? "", key)) {
44
+ i += 1;
45
+ continue;
46
+ }
47
+ if (replaced) {
48
+ lines.splice(i, 1);
49
+ continue;
50
+ }
51
+ lines[i] = next;
52
+ replaced = true;
53
+ i += 1;
54
+ }
55
+ if (!replaced) {
56
+ lines.push(next);
57
+ }
58
+ }
59
+ // writeFile's mode only applies on create; clamp pre-existing files too.
60
+ await writeFile(path, `${lines.join("\n")}\n`, { mode: 0o600 });
61
+ await chmod(path, 0o600);
62
+ }
63
+
64
+ /**
65
+ * Ensure the agent directory's .gitignore covers .env.local (create or
66
+ * append). A bare `.env` line does not count — that pattern matches only
67
+ * the file literally named .env.
68
+ */
69
+ export async function ensureEnvLocalGitignored(dir: string): Promise<boolean> {
70
+ const path = join(dir, ".gitignore");
71
+ const existing = await readOptionalFile(path);
72
+ const covered = existing
73
+ .split(/\r?\n/)
74
+ .some((line) => /^\.env(\.local\*?|\.\*|\*)$/.test(line.trim()));
75
+ if (covered) {
76
+ return false;
77
+ }
78
+ const next =
79
+ existing === "" || existing.endsWith("\n")
80
+ ? `${existing}.env.local\n`
81
+ : `${existing}\n.env.local\n`;
82
+ await writeFile(path, next);
83
+ return true;
84
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Framework-level file storage for v2 hosted engines.
3
+ *
4
+ * Hosted deployments carry two file stores with different audiences:
5
+ *
6
+ * - the **user-level** store (`AGENT_SERVE_STORE_SOURCE_ID`) holds
7
+ * author-facing bytes — `ctx.host.files`, skills, memory, artifacts — and
8
+ * is browsable from the dashboard and mountable on cloud-runtime VMs;
9
+ * - the **framework-level** store (`AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID`)
10
+ * holds engine-owned session state — session records, event transcripts,
11
+ * the continuation index, and the SDK conversation mirror — and is never
12
+ * exposed to authors or models.
13
+ *
14
+ * This module puts framework session state on the framework store. The
15
+ * {@link storageKeys} scheme was designed for exactly this: keys are a
16
+ * stable versioned contract that sinks may route on, so
17
+ * {@link composeFrameworkStorage} splits one {@link StorageConfig} by key
18
+ * kind — `session` / `session-events` / `continuation` go to the framework
19
+ * file store (file-shaped; the store accepts values up to 64 MiB per
20
+ * object without chunking, versus the KV proxy's 1 MiB row cap), while
21
+ * author `kv`, eval runs, A/B samples, and conditional writes stay on the
22
+ * control-plane KV proxy (the dashboard reads them there, and CAS needs a
23
+ * database).
24
+ *
25
+ * v2 only, by construction: the composite is selected in
26
+ * framework-storage-selection.ts, which v1 never reaches with a
27
+ * platform-selected definition.
28
+ */
29
+
30
+ import type { FileSink } from "../files.js";
31
+ import type { StorageConfig, StorageEntry } from "../storage.js";
32
+ import { STORAGE_KEY_ROOT } from "../storage-protocol.js";
33
+ import type { JsonValue } from "../types.js";
34
+ import { mapBounded } from "./bounded.js";
35
+
36
+ /**
37
+ * Key kinds (`agentkit/v1/{agent}/{kind}/…`) that live on the framework
38
+ * file store. Everything else stays on the KV sink.
39
+ */
40
+ const FRAMEWORK_FILE_KINDS: ReadonlySet<string> = new Set([
41
+ "session",
42
+ "session-events",
43
+ "continuation",
44
+ ]);
45
+
46
+ /**
47
+ * Whether a framework-minted key (or list prefix) belongs on the framework
48
+ * file store. Prefixes used by the coordinator are always at least
49
+ * kind-scoped (`…/{agent}/session/`), so a prefix routes wholly to one side.
50
+ */
51
+ export function isFrameworkFileKey(key: string): boolean {
52
+ if (!key.startsWith(`${STORAGE_KEY_ROOT}/`)) {
53
+ return false;
54
+ }
55
+ const rest = key.slice(STORAGE_KEY_ROOT.length + 1);
56
+ const agentEnd = rest.indexOf("/");
57
+ if (agentEnd === -1) {
58
+ return false;
59
+ }
60
+ const afterAgent = rest.slice(agentEnd + 1);
61
+ const kindEnd = afterAgent.indexOf("/");
62
+ const kind = kindEnd === -1 ? afterAgent : afterAgent.slice(0, kindEnd);
63
+ return FRAMEWORK_FILE_KINDS.has(kind);
64
+ }
65
+
66
+ /** The KV core over a {@link FileSink}: one JSON document per key. */
67
+ export type FileSinkStorageCore = Required<
68
+ Pick<StorageConfig, "put" | "get" | "delete" | "list">
69
+ >;
70
+
71
+ /**
72
+ * Adapt a {@link FileSink} to the `defineStorage` KV core. Storage keys are
73
+ * framework-minted (URI-encoded, length-bounded segments — see
74
+ * {@link storageKeys}), so they are used as file keys verbatim; values are
75
+ * stored as JSON bytes. Parse failures throw: on the lazy-restore path a
76
+ * corrupt document must fail the follow-up rather than read as a miss, and
77
+ * the startup bulk restore already logs-and-skips a throwing `list`.
78
+ */
79
+ /** Parallel per-key reads backing `list` (each is presign + object GET). */
80
+ const LIST_READ_CONCURRENCY = 8;
81
+
82
+ /**
83
+ * A storage key whose path the file store cannot represent (an empty, `.`,
84
+ * or `..` segment — possible only through caller-controlled segments such
85
+ * as continuation tokens or a caller-supplied session id). Such an object
86
+ * can never exist in the store, so reads are a definitive miss rather than
87
+ * a per-request 400 that the lazy-restore path would propagate forever.
88
+ */
89
+ function isUnrepresentableFileKey(key: string): boolean {
90
+ return key
91
+ .split("/")
92
+ .some((segment) => segment === "" || segment === "." || segment === "..");
93
+ }
94
+
95
+ export function fileSinkStorageCore(sink: FileSink): FileSinkStorageCore {
96
+ return {
97
+ async put(key, value): Promise<void> {
98
+ if (isUnrepresentableFileKey(key)) {
99
+ // Loud rather than silent: the coordinator logs and drops failed
100
+ // mirror writes (at-most-once), and awaited callers must not
101
+ // believe an impossible write landed.
102
+ throw new Error(
103
+ `framework file storage: key "${key}" has a path segment the store cannot represent`
104
+ );
105
+ }
106
+ await sink.put(key, new TextEncoder().encode(JSON.stringify(value)));
107
+ },
108
+ async get(key): Promise<JsonValue | undefined> {
109
+ if (isUnrepresentableFileKey(key)) {
110
+ return undefined;
111
+ }
112
+ const body = await sink.get(key);
113
+ if (body === undefined) {
114
+ return undefined;
115
+ }
116
+ return decodeDocument(key, body instanceof Uint8Array ? body : body.body);
117
+ },
118
+ async delete(key): Promise<void> {
119
+ if (isUnrepresentableFileKey(key)) {
120
+ return;
121
+ }
122
+ await sink.delete(key);
123
+ },
124
+ async list(prefix): Promise<StorageEntry[]> {
125
+ const entries = await sink.list(prefix);
126
+ // FileSink.list returns metadata only, so each value is its own
127
+ // read; bound the fan-out — a bulk read here sits on restore paths.
128
+ const bodies = await mapBounded(entries, LIST_READ_CONCURRENCY, (entry) =>
129
+ sink.get(entry.key)
130
+ );
131
+ const out: StorageEntry[] = [];
132
+ for (let index = 0; index < entries.length; index += 1) {
133
+ const entry = entries[index];
134
+ const body = bodies[index];
135
+ if (entry === undefined || body === undefined) {
136
+ // Deleted between list and read; a miss is not corruption.
137
+ continue;
138
+ }
139
+ out.push({
140
+ key: entry.key,
141
+ value: decodeDocument(
142
+ entry.key,
143
+ body instanceof Uint8Array ? body : body.body
144
+ ),
145
+ });
146
+ }
147
+ return out;
148
+ },
149
+ };
150
+ }
151
+
152
+ function decodeDocument(key: string, bytes: Uint8Array): JsonValue {
153
+ try {
154
+ return JSON.parse(new TextDecoder().decode(bytes)) as JsonValue;
155
+ } catch (error) {
156
+ throw new Error(
157
+ `framework file storage: stored document at "${key}" is not JSON (${
158
+ error instanceof Error ? error.message : String(error)
159
+ })`
160
+ );
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Split one storage core by key kind: framework session state to `files`,
166
+ * everything else to `kv`. Spread over the KV backend when building the
167
+ * full definition so its `evals` / `abs` groups (and the cursor-hosted
168
+ * marker) ride along untouched; wrap the KV `cas` group with
169
+ * {@link frameworkGuardedCas} rather than spreading it as-is.
170
+ */
171
+ export function composeFrameworkStorage(input: {
172
+ kv: FileSinkStorageCore;
173
+ files: FileSinkStorageCore;
174
+ }): FileSinkStorageCore & Pick<StorageConfig, "listNewest"> {
175
+ const route = (key: string): FileSinkStorageCore =>
176
+ isFrameworkFileKey(key) ? input.files : input.kv;
177
+ return {
178
+ put: (key, value, ctx) => route(key).put(key, value, ctx),
179
+ get: (key, ctx) => route(key).get(key, ctx),
180
+ delete: (key, ctx) => route(key).delete(key, ctx),
181
+ list: (prefix, ctx) => route(prefix).list(prefix, ctx),
182
+ // Session records — the only `listNewest` consumer — are framework file
183
+ // keys, and the file store has no write-time ordering. Spreading the KV
184
+ // backend's `listNewest` through would query rows that live elsewhere
185
+ // (stale KV leftovers, or nothing), so the composed core explicitly has
186
+ // none and the engine falls back to the routed `list`.
187
+ listNewest: undefined,
188
+ };
189
+ }
190
+
191
+ /**
192
+ * The KV backend's conditional writes, refusing framework-file keys.
193
+ *
194
+ * CAS runs on the KV proxy (a database row version); the plain core routes
195
+ * framework session state to the file store. A future coordination path
196
+ * that CASes a `session/` or `continuation/` key would otherwise read and
197
+ * write a different store than the plain path — silent split-brain. Fail
198
+ * loudly instead; nothing in the package CASes those kinds today.
199
+ */
200
+ export function frameworkGuardedCas(
201
+ cas: NonNullable<StorageConfig["cas"]>
202
+ ): NonNullable<StorageConfig["cas"]> {
203
+ const refuse = (key: string): void => {
204
+ if (isFrameworkFileKey(key)) {
205
+ throw new Error(
206
+ `framework file storage: conditional writes are KV-only, but "${key}" routes to the framework file store`
207
+ );
208
+ }
209
+ };
210
+ return {
211
+ getWithVersion: (key, ctx) => {
212
+ refuse(key);
213
+ return cas.getWithVersion(key, ctx);
214
+ },
215
+ putIfAbsent: (key, value, ctx) => {
216
+ refuse(key);
217
+ return cas.putIfAbsent(key, value, ctx);
218
+ },
219
+ putIfVersion: (key, value, expectedVersion, ctx) => {
220
+ refuse(key);
221
+ return cas.putIfVersion(key, value, expectedVersion, ctx);
222
+ },
223
+ listKeys: (prefix, ctx) => {
224
+ refuse(prefix);
225
+ return cas.listKeys(prefix, ctx);
226
+ },
227
+ };
228
+ }
@@ -17,11 +17,17 @@
17
17
  *
18
18
  * - **Cursor-managed hosting** (the deployment-generation environment
19
19
  * variable is set, same signal that registers `GET /v1/manifest`):
20
- * the Cursor-hosted backend, so session records, event chunks, `host.kv`,
21
- * eval runs, and A/B samples land in the control plane and survive pod
22
- * replacement. The API key resolves through the full credential chain on
23
- * every call because hosted freeze snapshots listen unsigned and the
24
- * binder drops the key file after restore.
20
+ * the Cursor-hosted backend. When the deployment carries a
21
+ * **framework-level file store**
22
+ * (`AGENT_SERVE_FRAMEWORK_STORE_SOURCE_ID`), session records, event
23
+ * transcripts, and the continuation index live there file-shaped state
24
+ * on file storage, apart from the author-facing user store — while
25
+ * `host.kv`, eval runs, A/B samples, and conditional writes stay on the
26
+ * control-plane KV proxy (see framework-file-storage.ts). Without one
27
+ * (a deploy predating framework-store provisioning), everything goes to
28
+ * the KV proxy as before. The API key resolves through the full
29
+ * credential chain on every call because hosted freeze snapshots listen
30
+ * unsigned and the binder drops the key file after restore.
25
31
  * - **Self-hosted**: no mirror. `--state-root` is the durable copy, which
26
32
  * is correct when the operator owns the disk.
27
33
  *
@@ -34,11 +40,20 @@
34
40
  * pod's filesystem.
35
41
  */
36
42
 
43
+ import {
44
+ cursorFrameworkStoreSourceId,
45
+ cursorHostedFiles,
46
+ } from "../files-backends/cursor-hosted.js";
37
47
  import { defineStorage, type StorageDefinition } from "../storage.js";
38
48
  import { cursorHostedStorage } from "../storage-backends/cursor-hosted.js";
39
49
  import type { AgentArchitecture } from "../types.js";
40
50
  import { resolveApiKeySync } from "./cursor/credentials.js";
41
51
  import { AGENT_SERVE_GENERATION_ENV_VAR } from "./cursor-relay-core.js";
52
+ import {
53
+ composeFrameworkStorage,
54
+ fileSinkStorageCore,
55
+ frameworkGuardedCas,
56
+ } from "./framework-file-storage.js";
42
57
 
43
58
  export interface FrameworkStorageSelectionInput {
44
59
  /** `agent/storage.ts`, when the author wrote one (v1 only: discovery rejects it on v2). */
@@ -75,13 +90,38 @@ export function selectFrameworkStorageDefinition(
75
90
  // Self-hosted v2: the state root is the durable copy.
76
91
  return undefined;
77
92
  }
93
+ // Hosted v2 pods wake per delivery: bulk-restoring up to the default
94
+ // 1000 sessions on every boot is waste (and against the file-store
95
+ // backend it is per-key HTTP round trips before the listener even
96
+ // comes up). Follow-ups restore lazily by continuation or session id;
97
+ // GET /v1/sessions lists from the sink either way.
98
+ const policy = { restore: "off" } as const;
99
+ // Full chain (env → key file → stored login): frozen engines listen
100
+ // unsigned and bind CURSOR_API_KEY_FILE at task time, after this
101
+ // definition is constructed.
102
+ const resolveApiKey = (): string | undefined => resolveApiKeySync()?.apiKey;
103
+ const kv = cursorHostedStorage({ resolveApiKey });
104
+ const frameworkStoreId = cursorFrameworkStoreSourceId(
105
+ env as NodeJS.ProcessEnv
106
+ );
107
+ if (frameworkStoreId === undefined) {
108
+ return defineStorage({ name: "cursor-hosted", policy, ...kv });
109
+ }
110
+ // Framework session state on the framework-level file store; author kv,
111
+ // evals, and A/B tables stay on the KV proxy (spread from `kv`, which
112
+ // also carries the cursor-hosted marker for GET /v1/sessions).
78
113
  return defineStorage({
79
- name: "cursor-hosted",
80
- ...cursorHostedStorage({
81
- // Full chain (env → key file → stored login): frozen engines listen
82
- // unsigned and bind CURSOR_API_KEY_FILE at task time, after this
83
- // definition is constructed.
84
- apiKey: () => resolveApiKeySync()?.apiKey,
114
+ name: "cursor-hosted (framework files)",
115
+ policy,
116
+ ...kv,
117
+ ...composeFrameworkStorage({
118
+ kv,
119
+ files: fileSinkStorageCore(
120
+ cursorHostedFiles({ storeSourceId: frameworkStoreId, resolveApiKey })
121
+ ),
85
122
  }),
123
+ // CAS stays on the KV proxy but must refuse framework-file keys, or a
124
+ // future coordination path would split-brain against the plain core.
125
+ cas: frameworkGuardedCas(kv.cas),
86
126
  });
87
127
  }
@@ -2,6 +2,13 @@ export const HOSTED_DELIVERY_PROTOCOL_VERSION = 2;
2
2
  export const HOSTED_DELIVERY_HEADER = "x-agent-sdk-hosted-delivery";
3
3
  export const HOSTED_ADMISSION_PATH = "/v1/internal/hosted-admission";
4
4
  export const HOSTED_EXECUTION_PATH = "/v1/internal/hosted-execution";
5
+ /**
6
+ * Filename under the serve `--state-root` (not the per-slug SessionEngine
7
+ * dir). Hosted freeze uses `/workspace/.agent-serve`; the Temporal host
8
+ * reads this path after hosted-execution and logs it on the activity span.
9
+ * Must match `AGENT_SERVE_ENGINE_HOSTED_EXECUTION_DIAG_PATH` basename.
10
+ */
11
+ export const HOSTED_EXECUTION_DIAG_FILENAME = "hosted-execution.json";
5
12
 
6
13
  export type HostedAdmissionManagedAutomation = {
7
14
  automationUuid: string;
@@ -27,6 +27,12 @@ import {
27
27
  parseHostedAdmission,
28
28
  parseHostedExecution,
29
29
  } from "./hosted-delivery-protocol.js";
30
+ import {
31
+ abortReasonFromTurnStatus,
32
+ HOSTED_EXECUTION_DIAG_RUNNING_STATUS,
33
+ hostedExecutionDiagId,
34
+ writeHostedExecutionDiag,
35
+ } from "./hosted-execution-diag.js";
30
36
  import { recordHostedManagedAutomation } from "./hosted-managed-automation.js";
31
37
  import { errorResponse, readJsonObject } from "./http-channel.js";
32
38
  import type { Router } from "./router.js";
@@ -245,6 +251,19 @@ export function registerHostedDeliveryRoute(input: {
245
251
  channelId: string,
246
252
  sessionPublicId?: string
247
253
  ): ChannelHandlerArgs;
254
+ /**
255
+ * Await the session's durable mirror (dispatch chain + storage queue)
256
+ * before the execution reply: the control plane may park the pod the
257
+ * moment the reply lands, and a shed session-record flush would strand
258
+ * the conversation on the next wake.
259
+ */
260
+ drainSessionDurability?(sessionId: string): Promise<void>;
261
+ /**
262
+ * Serve `--state-root` (not the per-slug SessionEngine dir). Hosted
263
+ * freeze is `/workspace/.agent-serve`; the Temporal host reads
264
+ * `hosted-execution.json` from that path after the POST returns.
265
+ */
266
+ stateRoot?: string;
248
267
  }): void {
249
268
  const pending = new Map<
250
269
  string,
@@ -376,36 +395,100 @@ export function registerHostedDeliveryRoute(input: {
376
395
  }
377
396
  admitted.sessionPublicId = execution.sessionPublicId;
378
397
  admitted.execution ??= (async (): Promise<ExecutionReply> => {
379
- const args = input.buildHandlerArgs(
380
- admitted.send.channelId,
381
- execution.sessionPublicId
382
- );
383
- const session = await args.send(admitted.send.message, {
384
- ...admitted.send.options,
385
- mailboxContinuation: {
386
- key: admitted.send.mailboxContinuationKey,
387
- },
398
+ const startedAt = performance.now();
399
+ const executionId = hostedExecutionDiagId(execution.admissionToken);
400
+ const writeDiag = async (fields: {
401
+ sessionId: string;
402
+ turnStatus: string;
403
+ message?: string;
404
+ abortReason?:
405
+ | ReturnType<typeof abortReasonFromTurnStatus>
406
+ | "execute_throw";
407
+ }): Promise<void> => {
408
+ if (input.stateRoot === undefined) {
409
+ return;
410
+ }
411
+ const message =
412
+ fields.message === undefined
413
+ ? undefined
414
+ : boundedMessage(fields.message);
415
+ await writeHostedExecutionDiag(input.stateRoot, {
416
+ v: 1,
417
+ executionId,
418
+ writtenAt: new Date().toISOString(),
419
+ sessionPublicId: execution.sessionPublicId,
420
+ sessionId: fields.sessionId,
421
+ turnStatus: fields.turnStatus,
422
+ durationMs: Math.max(0, Math.round(performance.now() - startedAt)),
423
+ ...(message === undefined ? {} : { message }),
424
+ ...(message !== undefined && /abort/i.test(message)
425
+ ? { signalAborted: true }
426
+ : {}),
427
+ ...(fields.abortReason === undefined
428
+ ? {}
429
+ : { abortReason: fields.abortReason }),
430
+ });
431
+ };
432
+ // Claim the file before the turn runs. The host reads it after its
433
+ // own POST returns, which for a 9-minute timeout is while this turn
434
+ // is still going; without this marker that read would surface the
435
+ // PREVIOUS delivery's terminal record as if it were this one's.
436
+ await writeDiag({
437
+ sessionId: "",
438
+ turnStatus: HOSTED_EXECUTION_DIAG_RUNNING_STATUS,
388
439
  });
389
- const outcome = await session.waitForCompletion();
390
- if (outcome.status !== "finished") {
440
+ try {
441
+ const args = input.buildHandlerArgs(
442
+ admitted.send.channelId,
443
+ execution.sessionPublicId
444
+ );
445
+ const session = await args.send(admitted.send.message, {
446
+ ...admitted.send.options,
447
+ mailboxContinuation: {
448
+ key: admitted.send.mailboxContinuationKey,
449
+ },
450
+ });
451
+ const outcome = await session.waitForCompletion();
452
+ // Failed turns drain too: their record/continuation updates must
453
+ // survive the park just like a finished turn's.
454
+ await input.drainSessionDurability?.(session.id);
455
+ await writeDiag({
456
+ sessionId: session.id,
457
+ turnStatus: outcome.status,
458
+ message: outcome.errorMessage,
459
+ abortReason: abortReasonFromTurnStatus(
460
+ outcome.status,
461
+ outcome.errorMessage
462
+ ),
463
+ });
464
+ if (outcome.status !== "finished") {
465
+ return {
466
+ status: 503,
467
+ body: {
468
+ ok: false,
469
+ error: "turn_failed",
470
+ turnStatus: outcome.status,
471
+ message: outcome.errorMessage,
472
+ },
473
+ };
474
+ }
391
475
  return {
392
- status: 503,
476
+ status: 200,
393
477
  body: {
394
- ok: false,
395
- error: "turn_failed",
396
- turnStatus: outcome.status,
397
- message: outcome.errorMessage,
478
+ ok: true,
479
+ v: HOSTED_DELIVERY_PROTOCOL_VERSION,
480
+ outcome: "send",
398
481
  },
399
482
  };
483
+ } catch (error) {
484
+ await writeDiag({
485
+ sessionId: "",
486
+ turnStatus: "error",
487
+ message: error instanceof Error ? error.message : String(error),
488
+ abortReason: "execute_throw",
489
+ });
490
+ throw error;
400
491
  }
401
- return {
402
- status: 200,
403
- body: {
404
- ok: true,
405
- v: HOSTED_DELIVERY_PROTOCOL_VERSION,
406
- outcome: "send",
407
- },
408
- };
409
492
  })();
410
493
  const reply = await admitted.execution;
411
494
  return finish(Response.json(reply.body, { status: reply.status }));