@cursor/bdk 0.2.2 → 0.2.4

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 (697) hide show
  1. package/AGENTS.md +1 -1
  2. package/dist/bin/agent-serve.js +32 -8
  3. package/dist/channels/github/auth.d.ts.map +1 -1
  4. package/dist/channels/github/auth.js +36 -5
  5. package/dist/channels/slack/attachments.d.ts +2 -1
  6. package/dist/channels/slack/attachments.d.ts.map +1 -1
  7. package/dist/channels/slack/attachments.js +19 -9
  8. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  9. package/dist/channels/slack/dispatch.js +26 -24
  10. package/dist/channels/slack/thread-context.d.ts +21 -11
  11. package/dist/channels/slack/thread-context.d.ts.map +1 -1
  12. package/dist/channels/slack/thread-context.js +75 -27
  13. package/dist/connections.d.ts +1 -1
  14. package/dist/connections.js +1 -1
  15. package/dist/docs/404.html +2 -2
  16. package/dist/docs/assets/{app.DtYVVVyK.js → app.4kQ8Db_q.js} +4 -4
  17. package/dist/docs/assets/chunks/@localSearchIndexroot.CvuAJ0My.js +1 -0
  18. package/dist/docs/assets/chunks/{VPLocalSearchBox.D47xT7J4.js → VPLocalSearchBox.DY1RwB8Q.js} +1 -1
  19. package/dist/docs/assets/chunks/{arc.CDJ6xzxR.js → arc.CxE_fSPK.js} +1 -1
  20. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.l1Xnjd3N.js → architectureDiagram-Q4EWVU46.CPX426ui.js} +1 -1
  21. package/dist/docs/assets/chunks/{baseUniq.x-finShZ.js → baseUniq.CB52JrKG.js} +1 -1
  22. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.COC3qynH.js → blockDiagram-DXYQGD6D.J0cNaQCL.js} +1 -1
  23. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.DdQO850E.js → c4Diagram-AHTNJAMY.DJn3vEGT.js} +1 -1
  24. package/dist/docs/assets/chunks/channel.BoNycAoN.js +1 -0
  25. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.Dpn8omLk.js → chunk-4BX2VUAB.Dao618F6.js} +1 -1
  26. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.C0XWStUN.js → chunk-4TB4RGXK.QW8Rhjai.js} +1 -1
  27. package/dist/docs/assets/chunks/{chunk-55IACEB6.DsKSZfIM.js → chunk-55IACEB6.DfRLLKF_.js} +1 -1
  28. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.dNU6JDu6.js → chunk-EDXVE4YY.CIV2ApKQ.js} +1 -1
  29. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.DN41fxKE.js → chunk-FMBD7UC4.BEheSuxp.js} +1 -1
  30. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.COpKCZus.js → chunk-OYMX7WX6.CUN88ENB.js} +1 -1
  31. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.HDB-azx2.js → chunk-QZHKN3VN.CgqCs8b_.js} +1 -1
  32. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.DEeX_a2j.js → chunk-YZCP3GAM.iCH0nnTJ.js} +1 -1
  33. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.C4x07Gkj.js +1 -0
  34. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.C4x07Gkj.js +1 -0
  35. package/dist/docs/assets/chunks/clone.Db22cH_-.js +1 -0
  36. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.C3yGL2A8.js → cose-bilkent-S5V4N54A.BLcUxhWE.js} +1 -1
  37. package/dist/docs/assets/chunks/{dagre-KV5264BT.Bpl24en4.js → dagre-KV5264BT.Ep7LofOm.js} +1 -1
  38. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.nFco6seU.js → diagram-5BDNPKRD.Bzf4GSQ4.js} +1 -1
  39. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.DXhA6DWR.js → diagram-G4DWMVQ6.DD6Jh-eM.js} +1 -1
  40. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.8GoOYcwk.js → diagram-MMDJMWI5.oOIl8bWd.js} +1 -1
  41. package/dist/docs/assets/chunks/{diagram-TYMM5635.DDBlqvlJ.js → diagram-TYMM5635.DHs85Ade.js} +1 -1
  42. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.vl_N81P4.js → erDiagram-SMLLAGMA.BIb5ghCk.js} +1 -1
  43. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.Cteg8g7I.js → flowDiagram-DWJPFMVM.DV4paY9k.js} +1 -1
  44. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.D4aMhlMM.js → ganttDiagram-T4ZO3ILL.AyEKA6_v.js} +1 -1
  45. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.DF_J0D4q.js → gitGraphDiagram-UUTBAWPF.BltiCDFo.js} +1 -1
  46. package/dist/docs/assets/chunks/{graph.DJs0LDCf.js → graph.DzuEYGdC.js} +1 -1
  47. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.Bb-4RQwg.js → infoDiagram-42DDH7IO.BV2l981J.js} +1 -1
  48. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DEtQRSbc.js → ishikawaDiagram-UXIWVN3A.BA4Izf-m.js} +1 -1
  49. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.DhQQ75FA.js → journeyDiagram-VCZTEJTY.DjaFbFS3.js} +1 -1
  50. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.C4gEw3Rk.js → kanban-definition-6JOO6SKY.CfTFieDs.js} +1 -1
  51. package/dist/docs/assets/chunks/{layout.DT-PGlXa.js → layout.DzfWqTBV.js} +1 -1
  52. package/dist/docs/assets/chunks/{linear.BMMe__JW.js → linear.BO6mpulV.js} +1 -1
  53. package/dist/docs/assets/chunks/{min.XyaU9K9Q.js → min.BGgTadgT.js} +1 -1
  54. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CbBM6xZ-.js → mindmap-definition-QFDTVHPH.DPuIXVWY.js} +1 -1
  55. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DFJoIVou.js → pieDiagram-DEJITSTG.BOnl3bBg.js} +1 -1
  56. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.CQjkDYqb.js → quadrantDiagram-34T5L4WZ.DNB6Ckdc.js} +1 -1
  57. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.D-mK-JQu.js → requirementDiagram-MS252O5E.D5-Qo7vb.js} +1 -1
  58. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.BStQInpd.js → sankeyDiagram-XADWPNL6.8t65cesf.js} +1 -1
  59. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.CA_eooPJ.js → sequenceDiagram-FGHM5R23.CaG07BdS.js} +1 -1
  60. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BXl-b7ad.js → stateDiagram-FHFEXIEX.TKOweTB6.js} +1 -1
  61. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.CuqmyQc4.js +1 -0
  62. package/dist/docs/assets/chunks/{theme.q37tOs4x.js → theme.Dx-JhpTB.js} +2 -2
  63. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.vjuaGOSe.js → timeline-definition-GMOUNBTQ.fE53zQ2s.js} +1 -1
  64. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.BxduJl-F.js → vennDiagram-DHZGUBPP.DJsZZaJg.js} +1 -1
  65. package/dist/docs/assets/chunks/wardley-RL74JXVD.844kyrjl.js +162 -0
  66. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.D1z3ds0D.js → wardleyDiagram-NUSXRM2D.CMZ-Ru_t.js} +1 -1
  67. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.CRU5Ti9b.js → xychartDiagram-5P7HB3ND.XXrhBc7a.js} +1 -1
  68. package/dist/docs/assets/{deployment.md.nGo1yIsa.js → deployment.md.UhnJIMr-.js} +6 -9
  69. package/dist/docs/assets/{deployment.md.nGo1yIsa.lean.js → deployment.md.UhnJIMr-.lean.js} +1 -1
  70. package/dist/docs/assets/{guides_github.md.C2_DSWlE.js → guides_github.md.Bq9kQU9B.js} +9 -3
  71. package/dist/docs/assets/{guides_github.md.C2_DSWlE.lean.js → guides_github.md.Bq9kQU9B.lean.js} +1 -1
  72. package/dist/docs/assets/{guides_jev.md.BNDm14Gy.js → guides_jev.md.CRcgmjDb.js} +2 -2
  73. package/dist/docs/assets/{guides_jev.md.BNDm14Gy.lean.js → guides_jev.md.CRcgmjDb.lean.js} +1 -1
  74. package/dist/docs/assets/{guides_slack.md.ZbHQETOT.js → guides_slack.md.diqqXTTm.js} +2 -2
  75. package/dist/docs/assets/{guides_slack.md.ZbHQETOT.lean.js → guides_slack.md.diqqXTTm.lean.js} +1 -1
  76. package/dist/docs/assets/{quickstart.md.wG4shE1f.js → quickstart.md.CHpHPBUN.js} +5 -3
  77. package/dist/docs/assets/{quickstart.md.wG4shE1f.lean.js → quickstart.md.CHpHPBUN.lean.js} +1 -1
  78. package/dist/docs/assets/{reference_agent-config.md.DzGI777n.js → reference_agent-config.md.Cj5uBKp4.js} +1 -1
  79. package/dist/docs/assets/{reference_artifacts.md.CFMNPreZ.js → reference_artifacts.md.CQfKq8F2.js} +1 -1
  80. package/dist/docs/assets/reference_cli.md.DgeLTO18.js +91 -0
  81. package/dist/docs/assets/reference_cli.md.DgeLTO18.lean.js +1 -0
  82. package/dist/docs/assets/{reference_connections.md._XpKiOaF.js → reference_connections.md.COq--gAm.js} +7 -3
  83. package/dist/docs/assets/{reference_connections.md._XpKiOaF.lean.js → reference_connections.md.COq--gAm.lean.js} +1 -1
  84. package/dist/docs/assets/{reference_evals.md.DqNyHMA6.js → reference_evals.md.CJm3uCUm.js} +4 -4
  85. package/dist/docs/assets/{reference_evals.md.DqNyHMA6.lean.js → reference_evals.md.CJm3uCUm.lean.js} +1 -1
  86. package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.js → reference_extensions.md.pa2tN-e4.js} +4 -3
  87. package/dist/docs/assets/{reference_extensions.md.CPPrkWlJ.lean.js → reference_extensions.md.pa2tN-e4.lean.js} +1 -1
  88. package/dist/docs/assets/{reference_skills.md.CRFTxt9M.js → reference_skills.md.Cy00QMKS.js} +3 -3
  89. package/dist/docs/assets/{reference_skills.md.CRFTxt9M.lean.js → reference_skills.md.Cy00QMKS.lean.js} +1 -1
  90. package/dist/docs/assets/troubleshooting.md.Cw5PKa3t.js +1 -0
  91. package/dist/docs/assets/{troubleshooting.md.BzZSu1Gz.lean.js → troubleshooting.md.Cw5PKa3t.lean.js} +1 -1
  92. package/dist/docs/building-with-agents.html +35 -35
  93. package/dist/docs/deployment.html +41 -44
  94. package/dist/docs/deployment.md +49 -16
  95. package/dist/docs/evals.html +35 -35
  96. package/dist/docs/guides/agent-to-agent.html +35 -35
  97. package/dist/docs/guides/bitbucket.html +35 -35
  98. package/dist/docs/guides/cloud-agents.html +35 -35
  99. package/dist/docs/guides/convert-automation.html +35 -35
  100. package/dist/docs/guides/github.html +43 -37
  101. package/dist/docs/guides/github.md +34 -0
  102. package/dist/docs/guides/gitlab.html +35 -35
  103. package/dist/docs/guides/grokbot-agents.html +35 -35
  104. package/dist/docs/guides/hooks.html +35 -35
  105. package/dist/docs/guides/improve.html +35 -35
  106. package/dist/docs/guides/jev.html +37 -37
  107. package/dist/docs/guides/jev.md +7 -0
  108. package/dist/docs/guides/mcp-oauth.html +35 -35
  109. package/dist/docs/guides/opentelemetry.html +35 -35
  110. package/dist/docs/guides/slack.html +37 -37
  111. package/dist/docs/guides/slack.md +5 -0
  112. package/dist/docs/guides/webhooks.html +35 -35
  113. package/dist/docs/hashmap.json +1 -1
  114. package/dist/docs/hillclimbing.html +35 -35
  115. package/dist/docs/index.html +35 -35
  116. package/dist/docs/llms-full.txt +223 -94
  117. package/dist/docs/quickstart.html +40 -38
  118. package/dist/docs/quickstart.md +7 -1
  119. package/dist/docs/reference/agent-config.html +37 -37
  120. package/dist/docs/reference/agent-config.md +1 -1
  121. package/dist/docs/reference/artifacts.html +37 -37
  122. package/dist/docs/reference/artifacts.md +1 -1
  123. package/dist/docs/reference/channels.html +35 -35
  124. package/dist/docs/reference/cli.html +55 -61
  125. package/dist/docs/reference/cli.md +65 -63
  126. package/dist/docs/reference/connections.html +42 -38
  127. package/dist/docs/reference/connections.md +28 -2
  128. package/dist/docs/reference/evals.html +39 -39
  129. package/dist/docs/reference/evals.md +6 -7
  130. package/dist/docs/reference/extensions.html +39 -38
  131. package/dist/docs/reference/extensions.md +13 -0
  132. package/dist/docs/reference/hooks.html +35 -35
  133. package/dist/docs/reference/http-api.html +35 -35
  134. package/dist/docs/reference/instructions.html +35 -35
  135. package/dist/docs/reference/playground.html +35 -35
  136. package/dist/docs/reference/project-layout.html +35 -35
  137. package/dist/docs/reference/prompt.html +35 -35
  138. package/dist/docs/reference/schedules.html +35 -35
  139. package/dist/docs/reference/sessions.html +35 -35
  140. package/dist/docs/reference/skills.html +38 -38
  141. package/dist/docs/reference/subagents.html +35 -35
  142. package/dist/docs/reference/tools.html +35 -35
  143. package/dist/docs/templates/agentic-owners.html +35 -35
  144. package/dist/docs/templates/security-reviewer.html +35 -35
  145. package/dist/docs/templates/thermo-quality-review.html +35 -35
  146. package/dist/docs/templates/thermo-review.html +35 -35
  147. package/dist/docs/templates/triage.html +35 -35
  148. package/dist/docs/troubleshooting.html +36 -36
  149. package/dist/docs/troubleshooting.md +7 -3
  150. package/dist/extensions/cursor-grokbot-agents/extension.d.ts +77 -0
  151. package/dist/extensions/cursor-grokbot-agents/extension.d.ts.map +1 -0
  152. package/dist/extensions/cursor-grokbot-agents/extension.js +63 -0
  153. package/dist/extensions/cursor-grokbot-agents/lib/agents.d.ts +11 -0
  154. package/dist/extensions/cursor-grokbot-agents/lib/agents.d.ts.map +1 -0
  155. package/dist/extensions/cursor-grokbot-agents/lib/agents.js +31 -0
  156. package/dist/extensions/cursor-grokbot-agents/lib/backend.d.ts +56 -0
  157. package/dist/extensions/cursor-grokbot-agents/lib/backend.d.ts.map +1 -0
  158. package/dist/extensions/cursor-grokbot-agents/lib/backend.js +158 -0
  159. package/dist/extensions/cursor-grokbot-agents/lib/contacts.d.ts +28 -0
  160. package/dist/extensions/cursor-grokbot-agents/lib/contacts.d.ts.map +1 -0
  161. package/dist/extensions/cursor-grokbot-agents/lib/contacts.js +59 -0
  162. package/dist/extensions/cursor-grokbot-agents/lib/conversation.d.ts +53 -0
  163. package/dist/extensions/cursor-grokbot-agents/lib/conversation.d.ts.map +1 -0
  164. package/dist/extensions/cursor-grokbot-agents/lib/conversation.js +206 -0
  165. package/dist/extensions/cursor-grokbot-agents/lib/inputs.d.ts +4 -0
  166. package/dist/extensions/cursor-grokbot-agents/lib/inputs.d.ts.map +1 -0
  167. package/dist/extensions/cursor-grokbot-agents/lib/inputs.js +15 -0
  168. package/dist/extensions/cursor-grokbot-agents/lib/lock.d.ts +12 -0
  169. package/dist/extensions/cursor-grokbot-agents/lib/lock.d.ts.map +1 -0
  170. package/dist/extensions/cursor-grokbot-agents/lib/lock.js +25 -0
  171. package/dist/extensions/cursor-grokbot-agents/skills/consult.md +40 -0
  172. package/dist/extensions/cursor-grokbot-agents/tools/ask.d.ts +4 -0
  173. package/dist/extensions/cursor-grokbot-agents/tools/ask.d.ts.map +1 -0
  174. package/dist/extensions/cursor-grokbot-agents/tools/ask.js +37 -0
  175. package/dist/extensions/cursor-grokbot-agents/tools/check.d.ts +4 -0
  176. package/dist/extensions/cursor-grokbot-agents/tools/check.d.ts.map +1 -0
  177. package/dist/extensions/cursor-grokbot-agents/tools/check.js +32 -0
  178. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.d.ts +4 -0
  179. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.d.ts.map +1 -0
  180. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.js +24 -0
  181. package/dist/extensions/cursor-grokbot-agents/tools/list.d.ts +4 -0
  182. package/dist/extensions/cursor-grokbot-agents/tools/list.d.ts.map +1 -0
  183. package/dist/extensions/cursor-grokbot-agents/tools/list.js +34 -0
  184. package/dist/extensions/jev/extension.d.ts +3 -0
  185. package/dist/extensions/jev/extension.d.ts.map +1 -1
  186. package/dist/extensions/jev/extension.js +10 -1
  187. package/dist/extensions/jev/lib/evaluate.d.ts +4 -0
  188. package/dist/extensions/jev/lib/evaluate.d.ts.map +1 -1
  189. package/dist/extensions/jev/lib/evaluate.js +6 -2
  190. package/dist/extensions.d.ts +4 -2
  191. package/dist/extensions.d.ts.map +1 -1
  192. package/dist/extensions.js +5 -2
  193. package/dist/internal/cli-ax.d.ts +1 -0
  194. package/dist/internal/cli-ax.d.ts.map +1 -1
  195. package/dist/internal/cli-ax.js +43 -10
  196. package/dist/internal/cli-deploy.d.ts +5 -1
  197. package/dist/internal/cli-deploy.d.ts.map +1 -1
  198. package/dist/internal/cli-deploy.js +41 -9
  199. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  200. package/dist/internal/cli-mcp-oauth.js +2 -1
  201. package/dist/internal/cli-skills.d.ts +1 -1
  202. package/dist/internal/cli-skills.d.ts.map +1 -1
  203. package/dist/internal/cli-skills.js +5 -5
  204. package/dist/internal/connection-env.d.ts +31 -0
  205. package/dist/internal/connection-env.d.ts.map +1 -0
  206. package/dist/internal/connection-env.js +84 -0
  207. package/dist/internal/cursor/backend-client.js +5 -0
  208. package/dist/internal/deploy-client.d.ts +30 -6
  209. package/dist/internal/deploy-client.d.ts.map +1 -1
  210. package/dist/internal/deploy-client.js +45 -9
  211. package/dist/internal/discovery/agent-config.d.ts +6 -5
  212. package/dist/internal/discovery/agent-config.d.ts.map +1 -1
  213. package/dist/internal/discovery/agent-config.js +29 -28
  214. package/dist/internal/discovery/agent.js +1 -1
  215. package/dist/internal/discovery/connections.d.ts.map +1 -1
  216. package/dist/internal/discovery/connections.js +11 -0
  217. package/dist/internal/discovery/extensions.d.ts.map +1 -1
  218. package/dist/internal/discovery/extensions.js +12 -0
  219. package/dist/internal/hosted-delivery-protocol.d.ts +36 -11
  220. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  221. package/dist/internal/hosted-delivery-protocol.js +31 -8
  222. package/dist/internal/hosted-delivery.d.ts +2 -2
  223. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  224. package/dist/internal/hosted-delivery.js +228 -48
  225. package/dist/internal/hosting.d.ts +10 -2
  226. package/dist/internal/hosting.d.ts.map +1 -1
  227. package/dist/internal/hosting.js +33 -3
  228. package/dist/internal/install-cursor-skills.d.ts +20 -24
  229. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  230. package/dist/internal/install-cursor-skills.js +50 -48
  231. package/dist/internal/legacy-command-guard.d.ts +2 -0
  232. package/dist/internal/legacy-command-guard.d.ts.map +1 -1
  233. package/dist/internal/legacy-command-guard.js +10 -1
  234. package/dist/internal/mcp-host.d.ts +6 -0
  235. package/dist/internal/mcp-host.d.ts.map +1 -1
  236. package/dist/internal/mcp-host.js +35 -16
  237. package/dist/internal/sdk-runner.d.ts +2 -0
  238. package/dist/internal/sdk-runner.d.ts.map +1 -1
  239. package/dist/internal/sdk-runner.js +10 -0
  240. package/dist/internal/server.d.ts.map +1 -1
  241. package/dist/internal/server.js +11 -1
  242. package/dist/internal/session-engine.d.ts.map +1 -1
  243. package/dist/internal/session-engine.js +9 -5
  244. package/dist/types.d.ts +29 -3
  245. package/dist/types.d.ts.map +1 -1
  246. package/docs/deployment.md +49 -16
  247. package/docs/guides/github.md +34 -0
  248. package/docs/guides/jev.md +7 -0
  249. package/docs/guides/slack.md +5 -0
  250. package/docs/quickstart.md +7 -1
  251. package/docs/reference/agent-config.md +1 -1
  252. package/docs/reference/artifacts.md +1 -1
  253. package/docs/reference/cli.md +65 -63
  254. package/docs/reference/connections.md +28 -2
  255. package/docs/reference/evals.md +6 -7
  256. package/docs/reference/extensions.md +13 -0
  257. package/docs/troubleshooting.md +7 -3
  258. package/package.json +1 -11
  259. package/scripts/install-cursor-skills.mjs +1 -1
  260. package/skills/create-agent/SKILL.md +1 -1
  261. package/skills/debug/SKILL.md +1 -1
  262. package/skills/deploy/SKILL.md +1 -1
  263. package/skills/evals/SKILL.md +1 -1
  264. package/skills/framework-map/SKILL.md +1 -1
  265. package/skills/github/SKILL.md +1 -1
  266. package/skills/hillclimb/SKILL.md +1 -1
  267. package/skills/mcp-auth/SKILL.md +1 -1
  268. package/skills/otel/SKILL.md +1 -1
  269. package/skills/setup-slack/SKILL.md +1 -1
  270. package/templates/agents-md/bot/lib/collect.ts +1 -4
  271. package/templates/code-wiki/bot/channels/github.ts +2 -2
  272. package/templates/demo/bot/channels/github.ts +5 -1
  273. package/templates/pr-autofixer/bot/lib/start-drive.ts +4 -4
  274. package/templates/triage/bot/lib/types.ts +6 -6
  275. package/dist/docs/assets/chunks/@localSearchIndexroot.BgTA2tV1.js +0 -1
  276. package/dist/docs/assets/chunks/channel.B2nMEx82.js +0 -1
  277. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.D8iCH2ve.js +0 -1
  278. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.D8iCH2ve.js +0 -1
  279. package/dist/docs/assets/chunks/clone.5XNLjby0.js +0 -1
  280. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.yGM2uLZQ.js +0 -1
  281. package/dist/docs/assets/chunks/wardley-RL74JXVD.DKfyIejL.js +0 -162
  282. package/dist/docs/assets/reference_cli.md.BK2QUH67.js +0 -97
  283. package/dist/docs/assets/reference_cli.md.BK2QUH67.lean.js +0 -1
  284. package/dist/docs/assets/troubleshooting.md.BzZSu1Gz.js +0 -1
  285. package/src/artifacts.ts +0 -68
  286. package/src/bin/agent-serve.ts +0 -1833
  287. package/src/channels/bitbucket/api.ts +0 -891
  288. package/src/channels/bitbucket/binding.ts +0 -417
  289. package/src/channels/bitbucket/bitbucket-channel.ts +0 -162
  290. package/src/channels/bitbucket/bitbucket-webhook.ts +0 -519
  291. package/src/channels/bitbucket/checks.ts +0 -146
  292. package/src/channels/bitbucket/cursor-account.ts +0 -106
  293. package/src/channels/bitbucket/defaults.ts +0 -100
  294. package/src/channels/bitbucket/events.ts +0 -74
  295. package/src/channels/bitbucket/index.ts +0 -51
  296. package/src/channels/bitbucket/replay.ts +0 -421
  297. package/src/channels/bitbucket/state.ts +0 -59
  298. package/src/channels/bitbucket/types.ts +0 -261
  299. package/src/channels/change-monitors/change-monitors-channel.ts +0 -63
  300. package/src/channels/change-monitors/index.ts +0 -8
  301. package/src/channels/change-monitors/types.ts +0 -42
  302. package/src/channels/checks.ts +0 -185
  303. package/src/channels/deployments/deployments-channel.ts +0 -224
  304. package/src/channels/deployments/index.ts +0 -25
  305. package/src/channels/deployments/types.ts +0 -92
  306. package/src/channels/github/api.ts +0 -526
  307. package/src/channels/github/auth.ts +0 -254
  308. package/src/channels/github/binding.ts +0 -233
  309. package/src/channels/github/checks.ts +0 -145
  310. package/src/channels/github/cursor-account.ts +0 -303
  311. package/src/channels/github/defaults.ts +0 -168
  312. package/src/channels/github/events.ts +0 -67
  313. package/src/channels/github/forward.ts +0 -359
  314. package/src/channels/github/github-channel.ts +0 -2334
  315. package/src/channels/github/index.ts +0 -54
  316. package/src/channels/github/progress.ts +0 -365
  317. package/src/channels/github/replay.ts +0 -372
  318. package/src/channels/github/state.ts +0 -124
  319. package/src/channels/github/types.ts +0 -590
  320. package/src/channels/gitlab/api.ts +0 -329
  321. package/src/channels/gitlab/binding.ts +0 -231
  322. package/src/channels/gitlab/checks.ts +0 -228
  323. package/src/channels/gitlab/cursor-account.ts +0 -105
  324. package/src/channels/gitlab/defaults.ts +0 -80
  325. package/src/channels/gitlab/events.ts +0 -37
  326. package/src/channels/gitlab/gitlab-channel.ts +0 -160
  327. package/src/channels/gitlab/gitlab-webhook.ts +0 -509
  328. package/src/channels/gitlab/index.ts +0 -44
  329. package/src/channels/gitlab/replay.ts +0 -328
  330. package/src/channels/gitlab/state.ts +0 -55
  331. package/src/channels/gitlab/types.ts +0 -247
  332. package/src/channels/issues/index.ts +0 -9
  333. package/src/channels/issues/issues-channel.ts +0 -45
  334. package/src/channels/issues/types.ts +0 -38
  335. package/src/channels/origin/api.ts +0 -507
  336. package/src/channels/origin/binding.ts +0 -114
  337. package/src/channels/origin/checks.ts +0 -250
  338. package/src/channels/origin/cursor-account.ts +0 -58
  339. package/src/channels/origin/defaults.ts +0 -140
  340. package/src/channels/origin/events.ts +0 -35
  341. package/src/channels/origin/index.ts +0 -35
  342. package/src/channels/origin/origin-channel.ts +0 -815
  343. package/src/channels/origin/origin-webhook.ts +0 -296
  344. package/src/channels/origin/reactions.ts +0 -72
  345. package/src/channels/origin/state.ts +0 -54
  346. package/src/channels/origin/types.ts +0 -295
  347. package/src/channels/slack/agentic-delivery.ts +0 -634
  348. package/src/channels/slack/agentic-posted.ts +0 -135
  349. package/src/channels/slack/agentic-signals.ts +0 -231
  350. package/src/channels/slack/api.ts +0 -761
  351. package/src/channels/slack/approvals.ts +0 -279
  352. package/src/channels/slack/assistant.ts +0 -76
  353. package/src/channels/slack/attachments.ts +0 -596
  354. package/src/channels/slack/auth.ts +0 -127
  355. package/src/channels/slack/blocks.ts +0 -131
  356. package/src/channels/slack/bot-mentions.ts +0 -318
  357. package/src/channels/slack/channel-watch.ts +0 -314
  358. package/src/channels/slack/cli-project.ts +0 -249
  359. package/src/channels/slack/code-fences.ts +0 -171
  360. package/src/channels/slack/constants.ts +0 -38
  361. package/src/channels/slack/credentials.ts +0 -88
  362. package/src/channels/slack/defaults.ts +0 -714
  363. package/src/channels/slack/dispatch.ts +0 -1060
  364. package/src/channels/slack/doctor.ts +0 -338
  365. package/src/channels/slack/eval-directive.ts +0 -306
  366. package/src/channels/slack/event-id-dedupe.ts +0 -30
  367. package/src/channels/slack/external-policy.ts +0 -75
  368. package/src/channels/slack/footer.ts +0 -106
  369. package/src/channels/slack/inbound.ts +0 -416
  370. package/src/channels/slack/index.ts +0 -53
  371. package/src/channels/slack/init.ts +0 -169
  372. package/src/channels/slack/interactive.ts +0 -406
  373. package/src/channels/slack/links.ts +0 -23
  374. package/src/channels/slack/live-delivery.ts +0 -489
  375. package/src/channels/slack/log.ts +0 -70
  376. package/src/channels/slack/manifest.ts +0 -240
  377. package/src/channels/slack/message-body.ts +0 -82
  378. package/src/channels/slack/nudge-carrier.ts +0 -224
  379. package/src/channels/slack/nudge-store.ts +0 -334
  380. package/src/channels/slack/paint-start.ts +0 -93
  381. package/src/channels/slack/placeholder.ts +0 -358
  382. package/src/channels/slack/pr-ref.ts +0 -74
  383. package/src/channels/slack/progress-delivery.ts +0 -138
  384. package/src/channels/slack/reasoning-card.ts +0 -125
  385. package/src/channels/slack/reasoning-chip.ts +0 -41
  386. package/src/channels/slack/recording-sink.ts +0 -167
  387. package/src/channels/slack/redact.ts +0 -6
  388. package/src/channels/slack/reply-options.ts +0 -279
  389. package/src/channels/slack/setup.ts +0 -125
  390. package/src/channels/slack/slack-channel.ts +0 -744
  391. package/src/channels/slack/socket-mode.ts +0 -140
  392. package/src/channels/slack/stop.ts +0 -25
  393. package/src/channels/slack/stream.ts +0 -66
  394. package/src/channels/slack/thread-context.ts +0 -485
  395. package/src/channels/slack/tool-approval-events.ts +0 -233
  396. package/src/channels/slack/tool-cards.ts +0 -198
  397. package/src/channels/slack/tool-chip.ts +0 -34
  398. package/src/channels/slack/types.ts +0 -787
  399. package/src/channels/slack/upload.ts +0 -137
  400. package/src/channels.ts +0 -543
  401. package/src/connections.ts +0 -153
  402. package/src/dashboard-session-url.ts +0 -30
  403. package/src/evals/assertions.ts +0 -688
  404. package/src/evals/expect.ts +0 -250
  405. package/src/evals/judge.ts +0 -329
  406. package/src/evals/loaders.ts +0 -111
  407. package/src/evals/matchers.ts +0 -223
  408. package/src/evals/reporters.ts +0 -257
  409. package/src/evals/results.ts +0 -130
  410. package/src/evals/run-facts.ts +0 -306
  411. package/src/evals.ts +0 -709
  412. package/src/extensions/cursor-cloud-agents/extension.ts +0 -131
  413. package/src/extensions/cursor-cloud-agents/lib/backend.ts +0 -386
  414. package/src/extensions/cursor-cloud-agents/lib/channels.ts +0 -11
  415. package/src/extensions/cursor-cloud-agents/lib/fleet.ts +0 -98
  416. package/src/extensions/cursor-cloud-agents/lib/inputs.ts +0 -5
  417. package/src/extensions/cursor-cloud-agents/lib/repos.ts +0 -80
  418. package/src/extensions/cursor-cloud-agents/lib/transcript.ts +0 -19
  419. package/src/extensions/cursor-cloud-agents/skills/handoff.md +0 -37
  420. package/src/extensions/cursor-cloud-agents/tools/cancel.ts +0 -21
  421. package/src/extensions/cursor-cloud-agents/tools/dump.ts +0 -47
  422. package/src/extensions/cursor-cloud-agents/tools/get.ts +0 -18
  423. package/src/extensions/cursor-cloud-agents/tools/launch.ts +0 -62
  424. package/src/extensions/cursor-cloud-agents/tools/list.ts +0 -31
  425. package/src/extensions/cursor-cloud-agents/tools/reply.ts +0 -36
  426. package/src/extensions/improve/extension.ts +0 -69
  427. package/src/extensions/improve/skills/yourself.ts +0 -50
  428. package/src/extensions/jev/extension.ts +0 -95
  429. package/src/extensions/jev/lib/evaluate.ts +0 -266
  430. package/src/extensions/jev/skills/gated-write.md +0 -25
  431. package/src/extensions/jev/skills/questions.md +0 -33
  432. package/src/extensions/jev/tools/evaluate.ts +0 -82
  433. package/src/extensions/slack-communication/evals/harness.ts +0 -705
  434. package/src/extensions/slack-communication/evals/slack-communication.eval.ts +0 -830
  435. package/src/extensions/slack-communication/evals/slack-placeholder.eval.ts +0 -172
  436. package/src/extensions/slack-communication/extension.ts +0 -44
  437. package/src/extensions/slack-communication/skills/slack-voice.ts +0 -56
  438. package/src/extensions/slack-communication/tools/delete-message.ts +0 -33
  439. package/src/extensions/slack-communication/tools/edit-message.ts +0 -42
  440. package/src/extensions/slack-communication/tools/post-card.ts +0 -28
  441. package/src/extensions/slack-communication/tools/post-file.ts +0 -82
  442. package/src/extensions/slack-communication/tools/post-update.ts +0 -40
  443. package/src/extensions/slack-communication/tools/react.ts +0 -30
  444. package/src/extensions/slack-communication/tools/set-status.ts +0 -21
  445. package/src/extensions.ts +0 -179
  446. package/src/files-backends/agent-store-presigned-url.ts +0 -11
  447. package/src/files-backends/cursor-hosted.ts +0 -1212
  448. package/src/files-backends/local-fs.ts +0 -163
  449. package/src/files.ts +0 -293
  450. package/src/filesystem.ts +0 -2005
  451. package/src/hooks.ts +0 -30
  452. package/src/index.ts +0 -259
  453. package/src/internal/advertise-tools.ts +0 -370
  454. package/src/internal/approval-gate.ts +0 -103
  455. package/src/internal/artifacts-store.ts +0 -836
  456. package/src/internal/as-of.ts +0 -257
  457. package/src/internal/auth.ts +0 -46
  458. package/src/internal/authored-alias-hooks.ts +0 -138
  459. package/src/internal/authored-loaders.ts +0 -188
  460. package/src/internal/bounded-int.ts +0 -24
  461. package/src/internal/bounded.ts +0 -25
  462. package/src/internal/brand.ts +0 -28
  463. package/src/internal/browser-origin-guard.ts +0 -67
  464. package/src/internal/builtin-tools/artifacts.ts +0 -62
  465. package/src/internal/builtin-tools/index.ts +0 -53
  466. package/src/internal/builtin-tools/reminders.ts +0 -145
  467. package/src/internal/channel-dispatch.ts +0 -129
  468. package/src/internal/channel-route-dispatch.ts +0 -58
  469. package/src/internal/channel-state.ts +0 -83
  470. package/src/internal/chat-client.ts +0 -594
  471. package/src/internal/cli-ax.ts +0 -2273
  472. package/src/internal/cli-bitbucket.ts +0 -438
  473. package/src/internal/cli-convert-automation.ts +0 -335
  474. package/src/internal/cli-cursor.ts +0 -282
  475. package/src/internal/cli-deploy.ts +0 -2486
  476. package/src/internal/cli-docs.ts +0 -192
  477. package/src/internal/cli-github.ts +0 -806
  478. package/src/internal/cli-gitlab.ts +0 -452
  479. package/src/internal/cli-images.ts +0 -672
  480. package/src/internal/cli-manifest.ts +0 -56
  481. package/src/internal/cli-mcp-oauth.ts +0 -395
  482. package/src/internal/cli-mcp.ts +0 -808
  483. package/src/internal/cli-skills.ts +0 -99
  484. package/src/internal/cli-slack-manual.ts +0 -418
  485. package/src/internal/cli-slack.ts +0 -874
  486. package/src/internal/cloud-merge.ts +0 -51
  487. package/src/internal/cloud-turn-cost.ts +0 -159
  488. package/src/internal/continuation-channel.ts +0 -233
  489. package/src/internal/continuation-identity.ts +0 -935
  490. package/src/internal/conversation-mirror.ts +0 -423
  491. package/src/internal/convert-automation/convert-workflow.ts +0 -1377
  492. package/src/internal/convert-automation/slug.ts +0 -29
  493. package/src/internal/convert-automation/types.ts +0 -212
  494. package/src/internal/cron.ts +0 -76
  495. package/src/internal/cursor/account-mcp.ts +0 -692
  496. package/src/internal/cursor/backend-client.ts +0 -978
  497. package/src/internal/cursor/bound-secret-file.ts +0 -101
  498. package/src/internal/cursor/credentials.ts +0 -560
  499. package/src/internal/cursor/cursor-api-transport.ts +0 -65
  500. package/src/internal/cursor/github-credentials.ts +0 -228
  501. package/src/internal/cursor/hosted-bound-secrets.ts +0 -71
  502. package/src/internal/cursor/hosted-deployment-secrets.ts +0 -100
  503. package/src/internal/cursor/hosted-store-secrets.ts +0 -152
  504. package/src/internal/cursor/session-token.ts +0 -111
  505. package/src/internal/cursor/store-api-client.ts +0 -323
  506. package/src/internal/cursor-account-mcp-auth.ts +0 -303
  507. package/src/internal/cursor-agent-template.ts +0 -50
  508. package/src/internal/cursor-deployment-relay.ts +0 -315
  509. package/src/internal/cursor-event-relay.ts +0 -675
  510. package/src/internal/cursor-relay-core.ts +0 -563
  511. package/src/internal/deferred-channel-session.ts +0 -61
  512. package/src/internal/deploy-client.ts +0 -1504
  513. package/src/internal/deploy-manifest.ts +0 -361
  514. package/src/internal/deploy-source.ts +0 -144
  515. package/src/internal/describe-error.ts +0 -32
  516. package/src/internal/dev-mode.ts +0 -20
  517. package/src/internal/discovery/agent-config.ts +0 -288
  518. package/src/internal/discovery/agent.ts +0 -381
  519. package/src/internal/discovery/channels.ts +0 -100
  520. package/src/internal/discovery/connections.ts +0 -505
  521. package/src/internal/discovery/context.ts +0 -38
  522. package/src/internal/discovery/cursor-plugin.ts +0 -628
  523. package/src/internal/discovery/extension-overlay.ts +0 -247
  524. package/src/internal/discovery/extensions.ts +0 -490
  525. package/src/internal/discovery/fs.ts +0 -103
  526. package/src/internal/discovery/hooks.ts +0 -63
  527. package/src/internal/discovery/info.ts +0 -174
  528. package/src/internal/discovery/instructions.ts +0 -98
  529. package/src/internal/discovery/modules.ts +0 -107
  530. package/src/internal/discovery/names.ts +0 -45
  531. package/src/internal/discovery/project.ts +0 -319
  532. package/src/internal/discovery/reminders.ts +0 -65
  533. package/src/internal/discovery/runtime.ts +0 -158
  534. package/src/internal/discovery/schedules.ts +0 -120
  535. package/src/internal/discovery/seed-files.ts +0 -34
  536. package/src/internal/discovery/services.ts +0 -151
  537. package/src/internal/discovery/skills.ts +0 -174
  538. package/src/internal/discovery/subagent.ts +0 -138
  539. package/src/internal/discovery/tools.ts +0 -170
  540. package/src/internal/discovery.ts +0 -27
  541. package/src/internal/distribution.ts +0 -126
  542. package/src/internal/docs-site.ts +0 -248
  543. package/src/internal/duration.ts +0 -37
  544. package/src/internal/env-file.ts +0 -83
  545. package/src/internal/eval-judge-model.ts +0 -142
  546. package/src/internal/eval-run-store.ts +0 -585
  547. package/src/internal/eval-runner.ts +0 -823
  548. package/src/internal/evals-client.ts +0 -475
  549. package/src/internal/event-log.ts +0 -342
  550. package/src/internal/event-mapper.ts +0 -811
  551. package/src/internal/expected-delivery-failure.ts +0 -34
  552. package/src/internal/factory-resource-channel.ts +0 -103
  553. package/src/internal/filesystem/errors.ts +0 -207
  554. package/src/internal/filesystem/format.ts +0 -253
  555. package/src/internal/filesystem/merge.ts +0 -192
  556. package/src/internal/filesystem/nearest.ts +0 -112
  557. package/src/internal/filesystem/scratch.ts +0 -239
  558. package/src/internal/filesystem/sdk-schemas.ts +0 -204
  559. package/src/internal/filesystem/tools.ts +0 -804
  560. package/src/internal/filesystem/walk.ts +0 -366
  561. package/src/internal/fixtures/units-server.ts +0 -52
  562. package/src/internal/framework-file-storage.ts +0 -357
  563. package/src/internal/framework-storage-selection.ts +0 -156
  564. package/src/internal/frontmatter.ts +0 -108
  565. package/src/internal/github-fanout.ts +0 -144
  566. package/src/internal/guest-network.ts +0 -391
  567. package/src/internal/handleAgentServeTrigger.ts +0 -286
  568. package/src/internal/host-files.ts +0 -341
  569. package/src/internal/host-kv.ts +0 -81
  570. package/src/internal/host-otel.ts +0 -231
  571. package/src/internal/host-platforms.ts +0 -170
  572. package/src/internal/hosted-admission-adapter.ts +0 -47
  573. package/src/internal/hosted-admission-context.ts +0 -37
  574. package/src/internal/hosted-catch-protocol.ts +0 -112
  575. package/src/internal/hosted-catch.ts +0 -179
  576. package/src/internal/hosted-delivery-protocol.ts +0 -787
  577. package/src/internal/hosted-delivery.ts +0 -1152
  578. package/src/internal/hosted-execution-diag.ts +0 -291
  579. package/src/internal/hosted-execution-flush.ts +0 -136
  580. package/src/internal/hosted-execution-latency.ts +0 -301
  581. package/src/internal/hosted-managed-automation.ts +0 -116
  582. package/src/internal/hosting.ts +0 -107
  583. package/src/internal/http-channel-define.ts +0 -25
  584. package/src/internal/http-channel.ts +0 -669
  585. package/src/internal/http-control-plane-session.ts +0 -110
  586. package/src/internal/ids.ts +0 -39
  587. package/src/internal/incoming-headers-to-fetch.ts +0 -45
  588. package/src/internal/init-interview.ts +0 -360
  589. package/src/internal/init-project.ts +0 -711
  590. package/src/internal/init-scaffold.ts +0 -182
  591. package/src/internal/inline-stdio-define-stub.ts +0 -4
  592. package/src/internal/inline-stdio-mcp.ts +0 -230
  593. package/src/internal/install-cursor-skills.ts +0 -601
  594. package/src/internal/is-record.ts +0 -3
  595. package/src/internal/json-schema.ts +0 -95
  596. package/src/internal/legacy-command-guard.ts +0 -54
  597. package/src/internal/listen-port.ts +0 -85
  598. package/src/internal/local-control-plane.ts +0 -442
  599. package/src/internal/local-env.ts +0 -59
  600. package/src/internal/local-ingress.ts +0 -90
  601. package/src/internal/log-ring.ts +0 -59
  602. package/src/internal/logs-client.ts +0 -477
  603. package/src/internal/map-pool.ts +0 -39
  604. package/src/internal/mcp-endpoint.ts +0 -747
  605. package/src/internal/mcp-host.ts +0 -481
  606. package/src/internal/mcp-oauth-on-demand.ts +0 -337
  607. package/src/internal/mcp-oauth-persist.ts +0 -118
  608. package/src/internal/mcp-oauth.ts +0 -549
  609. package/src/internal/net.ts +0 -29
  610. package/src/internal/open-browser.ts +0 -41
  611. package/src/internal/otel/attrs.ts +0 -16
  612. package/src/internal/otel/collector.ts +0 -937
  613. package/src/internal/otel/config.ts +0 -287
  614. package/src/internal/otel/http.ts +0 -122
  615. package/src/internal/otel/mcp.ts +0 -56
  616. package/src/internal/otel/propagation.ts +0 -17
  617. package/src/internal/otel/runtime.ts +0 -441
  618. package/src/internal/package-inline-stdio.ts +0 -114
  619. package/src/internal/peer-connections.ts +0 -96
  620. package/src/internal/platform-schedule-sync.ts +0 -75
  621. package/src/internal/platform-timers.ts +0 -365
  622. package/src/internal/playground/static.ts +0 -278
  623. package/src/internal/playground/toolchain.ts +0 -270
  624. package/src/internal/playground-proxy.ts +0 -564
  625. package/src/internal/process-memory-telemetry.ts +0 -334
  626. package/src/internal/project-layout.ts +0 -31
  627. package/src/internal/prompt-context.ts +0 -116
  628. package/src/internal/reminder-control-plane-protocol.ts +0 -482
  629. package/src/internal/reminder-runner.ts +0 -1559
  630. package/src/internal/reminder-schedule.ts +0 -104
  631. package/src/internal/reminder-store.ts +0 -176
  632. package/src/internal/request-error-status.ts +0 -95
  633. package/src/internal/request-headers.ts +0 -21
  634. package/src/internal/resolve-prod-target.ts +0 -334
  635. package/src/internal/resolved-connections.ts +0 -190
  636. package/src/internal/router.ts +0 -143
  637. package/src/internal/run-client.ts +0 -354
  638. package/src/internal/runtime-dispatch-runner.ts +0 -50
  639. package/src/internal/sanitize-mcp-tool-name.ts +0 -31
  640. package/src/internal/schedule-runner.ts +0 -154
  641. package/src/internal/scm/pr-url.ts +0 -245
  642. package/src/internal/sdk-runner.ts +0 -948
  643. package/src/internal/serve-restart.ts +0 -113
  644. package/src/internal/server.ts +0 -3135
  645. package/src/internal/session-cost.ts +0 -208
  646. package/src/internal/session-engine.ts +0 -5618
  647. package/src/internal/session-links.ts +0 -84
  648. package/src/internal/session-run-log.ts +0 -535
  649. package/src/internal/session-store.ts +0 -307
  650. package/src/internal/session-urls.ts +0 -32
  651. package/src/internal/sessions-client.ts +0 -239
  652. package/src/internal/skill-catalog.ts +0 -66
  653. package/src/internal/skills-sync.ts +0 -55
  654. package/src/internal/slack-provision-client.ts +0 -544
  655. package/src/internal/slack-thread-key.ts +0 -11
  656. package/src/internal/sleep.ts +0 -3
  657. package/src/internal/start-log-store.ts +0 -164
  658. package/src/internal/steering.ts +0 -17
  659. package/src/internal/storage-coordinator.ts +0 -800
  660. package/src/internal/storage-roles.ts +0 -86
  661. package/src/internal/storage.ts +0 -1
  662. package/src/internal/store-api-protocol.ts +0 -205
  663. package/src/internal/store-mirror.ts +0 -73
  664. package/src/internal/stream-progress.ts +0 -294
  665. package/src/internal/terminal-style.ts +0 -133
  666. package/src/internal/testing/factory-resource-fixtures.ts +0 -84
  667. package/src/internal/testing/scm-continuation-fixtures.ts +0 -285
  668. package/src/internal/tool-catalog.ts +0 -104
  669. package/src/internal/tool-policy.ts +0 -222
  670. package/src/internal/tool-result.ts +0 -50
  671. package/src/internal/trajectory.ts +0 -418
  672. package/src/internal/turn-cost.ts +0 -136
  673. package/src/internal/turn-governor.ts +0 -145
  674. package/src/internal/turn-lease-store.ts +0 -144
  675. package/src/internal/turn-outbox.ts +0 -77
  676. package/src/internal/update-check.ts +0 -517
  677. package/src/internal/v2-hosting.ts +0 -52
  678. package/src/internal/workspace-sync.ts +0 -114
  679. package/src/internal/workspace.ts +0 -505
  680. package/src/kv/memory-kv.ts +0 -94
  681. package/src/kv.ts +0 -18
  682. package/src/memory.ts +0 -487
  683. package/src/otel-public.ts +0 -24
  684. package/src/otel.ts +0 -320
  685. package/src/prompt.ts +0 -80
  686. package/src/reminders.ts +0 -65
  687. package/src/schedules.ts +0 -31
  688. package/src/skills.ts +0 -27
  689. package/src/storage-backends/cursor-hosted-v2.ts +0 -204
  690. package/src/storage-backends/cursor-hosted.ts +0 -388
  691. package/src/storage-backends/file-kv.ts +0 -276
  692. package/src/storage-protocol.ts +0 -261
  693. package/src/storage.ts +0 -408
  694. package/src/tools.ts +0 -166
  695. package/src/types.ts +0 -3766
  696. /package/dist/docs/assets/{reference_agent-config.md.DzGI777n.lean.js → reference_agent-config.md.Cj5uBKp4.lean.js} +0 -0
  697. /package/dist/docs/assets/{reference_artifacts.md.CFMNPreZ.lean.js → reference_artifacts.md.CQfKq8F2.lean.js} +0 -0
@@ -1,2486 +0,0 @@
1
- /**
2
- * `agent-sdk deploy | deployments | deployment | stop | delete | rotate-token |
3
- * secrets set|list|unset` — Heroku-style deploys
4
- * onto Cursor's managed agent-serve hosting.
5
- *
6
- * All intelligence is server-side (backend/server/src/agentServe/); these
7
- * handlers resolve parameters (credentials, team, slug, the project's
8
- * `hosting` / `architecture` manifest block), call the v1 agent-serve or
9
- * v2 agentsdk management API through `deploy-client.ts`, poll status, and
10
- * render.
11
- */
12
-
13
- import { basename, resolve } from "node:path";
14
- import { catchAuthDeclaration, isPublicEndpointPolicy } from "../channels.js";
15
- import {
16
- type AgentArchitecture,
17
- type AgentHostingOptions,
18
- isCursorAccountTransport,
19
- } from "../types.js";
20
- import { CursorBackendClient } from "./cursor/backend-client.js";
21
- import { cursorExternalApiUrl, resolveApiKey, SIGN_IN_HINT } from "./cursor/credentials.js";
22
- import { authorizeCursorAccountConnectors } from "./cursor-account-mcp-auth.js";
23
- import { readDeployTemplate } from "./cursor-agent-template.js";
24
- import {
25
- type AgentkitCancelRunsResult,
26
- type AgentkitDeployAccepted,
27
- type AgentkitDeployComponent,
28
- type AgentkitDeploymentListItem,
29
- type AgentkitDeployStatus,
30
- type AgentkitStopAccepted,
31
- AgentServeDeployClient,
32
- type DeleteAccepted,
33
- type DeployAccepted,
34
- DeployApiError,
35
- type Deployment,
36
- type DeploymentDetail,
37
- type DeploymentProgress,
38
- type DeploySource,
39
- deploymentServiceAccountId,
40
- type SecretInfo,
41
- type StopAccepted,
42
- slugFromDirectoryName,
43
- TERMINAL_AGENTKIT_DEPLOY_STATUSES,
44
- TERMINAL_DEPLOY_STATUSES,
45
- validateDeploymentSlug,
46
- } from "./deploy-client.js";
47
- import { type GitRunner, inferDeployGitSource } from "./deploy-source.js";
48
- import { describeError } from "./describe-error.js";
49
- import {
50
- type ChildAgentDir,
51
- formatDiagnostics,
52
- hasErrorDiagnostics,
53
- isAgentProjectDir,
54
- listChildAgentDirs,
55
- loadAgentProject,
56
- } from "./discovery.js";
57
- import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
58
- import {
59
- isReservedSecretName,
60
- isValidCursorEventRepo,
61
- validateSettableSecretName,
62
- } from "./hosting.js";
63
- import { deploymentArchitecture, rejectV2ForLegacyCommand } from "./legacy-command-guard.js";
64
- import { deployProgressLabel, sanitizeCustomerError } from "./logs-client.js";
65
- import { sleep } from "./sleep.js";
66
- import { stderrPalette } from "./terminal-style.js";
67
-
68
- const DEFAULT_POLL_INTERVAL_MS = 3_000;
69
- const DEFAULT_DEPLOY_TIMEOUT_MS = 10 * 60 * 1000;
70
- /** `--multi-tenant` HTTP deploy is Anysphere-only (team id 1). */
71
- const MULTI_TENANT_HTTP_DEPLOY_TEAM_ID = 1;
72
-
73
- /** One agent directory selected for deploy (single or multi-agent parent). */
74
- export type DeployTarget = ChildAgentDir;
75
-
76
- /**
77
- * Interactive / test seam: pick which agents under a multi-agent parent to
78
- * deploy. Return `null` to cancel.
79
- */
80
- export type ChooseDeployTargets = (
81
- agents: readonly DeployTarget[],
82
- ) => Promise<DeployTarget[] | null>;
83
-
84
- export interface DeployCliOptions {
85
- dir?: string;
86
- slug?: string;
87
- /**
88
- * deploy `--all`: when `--dir` is a multi-agent parent, deploy every
89
- * child agent (skips the interactive picker).
90
- */
91
- all?: boolean;
92
- /** `--team <id>`; resolved from the account when omitted. */
93
- team?: string;
94
- json?: boolean;
95
- noWait?: boolean;
96
- /** v2 stop: also request cancellation for every active session run. */
97
- cancelRuns?: boolean;
98
- apiKey?: string;
99
- /**
100
- * deploy `--repo <url>`: https git repo the control plane builds from.
101
- * Optional — inferred from `git remote origin` when omitted inside an
102
- * agent project checkout.
103
- */
104
- repo?: string;
105
- /**
106
- * deploy `--ref <ref>`: git ref to build. Optional — inferred from the
107
- * current branch (or HEAD SHA if detached) when omitted; otherwise the
108
- * server uses the repo's default branch.
109
- */
110
- ref?: string;
111
- /**
112
- * deploy `--path <agentPath>`: agent directory relative to the repo root.
113
- * Optional — inferred from `--dir` vs the git toplevel when omitted.
114
- */
115
- path?: string;
116
- /** deploy `--cursor-events-repo <owner/name>` (repeatable). */
117
- cursorEventsRepos?: string[];
118
- /** deploy `--allow-domain <domain>` (repeatable; unioned with the manifest). */
119
- allowDomains?: string[];
120
- /**
121
- * deploy `--multi-tenant`: add a release to an existing Cursor-managed
122
- * (multi-tenant) product. Hidden Anysphere-only flag. Cannot create a
123
- * new multi-tenant application.
124
- */
125
- multiTenant?: boolean;
126
- /** Test seams. */
127
- fetchImpl?: typeof fetch;
128
- /** Inject the connector-auth browser opener (tests; also forces interactive). */
129
- openBrowserImpl?: (url: string) => void;
130
- sleepImpl?: (ms: number) => Promise<void>;
131
- connectorPollIntervalMs?: number;
132
- connectorPollTimeoutMs?: number;
133
- /** Inject git probing for deploy source inference (tests). */
134
- git?: GitRunner;
135
- /** Inject the multi-agent picker (tests / non-interactive hosts). */
136
- chooseTargets?: ChooseDeployTargets;
137
- pollIntervalMs?: number;
138
- timeoutMs?: number;
139
- out?: (text: string) => void;
140
- err?: (text: string) => void;
141
- /** `secrets set` value input (hidden prompt on a TTY, lines otherwise). */
142
- stdin?: SecretInputStream;
143
- /**
144
- * Opt in to `NAME=VALUE` argv secrets. Default is names only (hidden
145
- * prompt / stdin) so values never land in shell history or agent-captured
146
- * terminals.
147
- */
148
- fromArgv?: boolean;
149
- }
150
-
151
- /** Minimal stdin surface `secrets set` reads values from (test-injectable). */
152
- export type SecretInputStream = NodeJS.ReadableStream & {
153
- isTTY?: boolean;
154
- setRawMode?: (mode: boolean) => void;
155
- };
156
-
157
- export interface DeployCliContext {
158
- client: AgentServeDeployClient;
159
- teamId: number;
160
- apiKey: string;
161
- backendUrl: string;
162
- json: boolean;
163
- noWait: boolean;
164
- pollIntervalMs: number;
165
- timeoutMs: number;
166
- out: (text: string) => void;
167
- err: (text: string) => void;
168
- }
169
-
170
- export interface ResolveDeployAuthOptions {
171
- team?: string;
172
- apiKey?: string;
173
- fetchImpl?: typeof fetch;
174
- /** Quiet team-resolution chatter (default: write to stderr). */
175
- err?: (text: string) => void;
176
- }
177
-
178
- export interface ResolvedDeployAuth {
179
- client: AgentServeDeployClient;
180
- teamId: number;
181
- /** The resolved account credential, for dashboard RPCs beside the deploy API. */
182
- apiKey: string;
183
- backendUrl: string;
184
- }
185
-
186
- /**
187
- * Credentials → deploy client → team id. Shared by deploy commands and
188
- * `--prod` AX routing. Returns an exit code (error already rendered) on
189
- * failure.
190
- */
191
- export async function resolveDeployAuth(
192
- options: ResolveDeployAuthOptions,
193
- ): Promise<ResolvedDeployAuth | number> {
194
- const err = options.err ?? ((text: string) => void process.stderr.write(text));
195
-
196
- const resolved = await resolveApiKey(
197
- options.apiKey === undefined ? undefined : { apiKey: options.apiKey },
198
- );
199
- if (resolved === undefined) {
200
- err(`Not signed in to Cursor. ${SIGN_IN_HINT}\n`);
201
- return 1;
202
- }
203
- // The deployment management routes live on the external API host
204
- // (api.cursor.com), not the default backend (api2.cursor.sh) — see
205
- // cursorExternalApiUrl. GetMe below stays on the resolved backend.
206
- const client = new AgentServeDeployClient({
207
- backendUrl: cursorExternalApiUrl(),
208
- apiKey: resolved.apiKey,
209
- fetchImpl: options.fetchImpl,
210
- });
211
-
212
- let teamId: number;
213
- if (options.team !== undefined) {
214
- teamId = Number.parseInt(options.team, 10);
215
- if (Number.isNaN(teamId) || teamId <= 0) {
216
- err(`Invalid --team: ${options.team} (expected a positive team id)\n`);
217
- return 1;
218
- }
219
- } else {
220
- const account = new CursorBackendClient({
221
- backendUrl: resolved.backendUrl,
222
- apiKey: resolved.apiKey,
223
- fetchImpl: options.fetchImpl,
224
- });
225
- let identity: Awaited<ReturnType<CursorBackendClient["getMe"]>>;
226
- try {
227
- identity = await account.getMe();
228
- } catch (error) {
229
- err(
230
- `Could not resolve your team from the Cursor account: ${describeError(error)}\nPass --team <id> explicitly.\n`,
231
- );
232
- return 1;
233
- }
234
- if (identity.teamId === undefined || identity.teamId <= 0) {
235
- err(
236
- "This Cursor account has no default team; pass --team <id> (find it in the Cursor dashboard URL).\n",
237
- );
238
- return 1;
239
- }
240
- teamId = identity.teamId;
241
- const dim = stderrPalette().dim;
242
- err(
243
- `${dim(
244
- `Using team ${teamId}${identity.teamName === undefined ? "" : ` (${identity.teamName})`}`,
245
- )}\n${dim(" the account's team — pass --team to override.")}\n`,
246
- );
247
- }
248
-
249
- return {
250
- client,
251
- teamId,
252
- apiKey: resolved.apiKey,
253
- backendUrl: resolved.backendUrl,
254
- };
255
- }
256
-
257
- /**
258
- * Shared preamble: credentials → client → team id. Returns an exit code
259
- * (with the error already rendered) when resolution fails.
260
- */
261
- export async function prepare(options: DeployCliOptions): Promise<DeployCliContext | number> {
262
- const out = options.out ?? ((text: string) => void process.stdout.write(text));
263
- const err = options.err ?? ((text: string) => void process.stderr.write(text));
264
-
265
- const auth = await resolveDeployAuth({
266
- team: options.team,
267
- apiKey: options.apiKey,
268
- fetchImpl: options.fetchImpl,
269
- err,
270
- });
271
- if (typeof auth === "number") {
272
- return auth;
273
- }
274
-
275
- return {
276
- client: auth.client,
277
- teamId: auth.teamId,
278
- apiKey: auth.apiKey,
279
- backendUrl: auth.backendUrl,
280
- json: options.json === true,
281
- noWait: options.noWait === true,
282
- pollIntervalMs: options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,
283
- timeoutMs: options.timeoutMs ?? DEFAULT_DEPLOY_TIMEOUT_MS,
284
- out,
285
- err,
286
- };
287
- }
288
-
289
- // ============================================================================
290
- // deploy
291
- // ============================================================================
292
-
293
- export async function cmdDeploy(options: DeployCliOptions): Promise<number> {
294
- const ctx = await prepare(options);
295
- if (typeof ctx === "number") {
296
- return ctx;
297
- }
298
-
299
- if (options.multiTenant === true && ctx.teamId !== MULTI_TENANT_HTTP_DEPLOY_TEAM_ID) {
300
- ctx.err("--multi-tenant is not available for this team.\n");
301
- return 1;
302
- }
303
-
304
- const targets = await resolveDeployTargets(options, ctx);
305
- if (typeof targets === "number") {
306
- return targets;
307
- }
308
-
309
- if (targets.length === 1) {
310
- return deployOne(ctx, options, targets[0]!);
311
- }
312
-
313
- // Multi-agent parent: when every child declares `architecture: "v2"`,
314
- // the v2 control plane models sibling agents as release components of
315
- // ONE application, so deploy them together (one app, one component per
316
- // child) instead of minting a separate application per child. Mixed and
317
- // v1 parents keep the per-child sequential deploys.
318
- const manifests: DeployManifest[] = [];
319
- for (const target of targets) {
320
- manifests.push(await readDeployManifest(target.dir));
321
- }
322
- if (manifests.every(manifest => manifest.architecture === "v2")) {
323
- return deployAgentsdkApplication(ctx, options, targets, {
324
- // `persistent` is per child agent, like `agentPath`: each release
325
- // component carries its own.
326
- componentPersistent: Object.fromEntries(
327
- targets.map((target, index) => [target.slug, manifests[index]?.persistent === true]),
328
- ),
329
- componentImage: Object.fromEntries(
330
- targets.flatMap((target, index) =>
331
- manifests[index]?.image === undefined ? [] : [[target.slug, manifests[index].image]],
332
- ),
333
- ),
334
- hasScmChannels: manifests.some(manifest => manifest.hasScmChannels),
335
- declaredSecretNames: [
336
- ...new Set(manifests.flatMap(manifest => manifest.hosting?.secretNames ?? [])),
337
- ],
338
- hasDeploymentsChannels: manifests.some(manifest => manifest.hasDeploymentsChannels),
339
- });
340
- }
341
- if (!ctx.json && manifests.some(manifest => manifest.architecture === "v2")) {
342
- ctx.err(
343
- `warning: agents under this parent mix architectures; deploying each separately (v2 children become standalone single-component applications).\n`,
344
- );
345
- }
346
-
347
- // --path is per-agent (relative to the repo root). When deploying several
348
- // agents, ignore a shared --path so each target can infer its own path.
349
- let deployOptions = options;
350
- if (options.path !== undefined) {
351
- if (!ctx.json) {
352
- ctx.err(
353
- `warning: ignoring --path ${JSON.stringify(options.path)} for a multi-agent deploy; each agent infers its own path from git.\n`,
354
- );
355
- }
356
- deployOptions = { ...options, path: undefined };
357
- }
358
-
359
- // Multi-agent batch: deploy sequentially; --json emits an array.
360
- const jsonResults: unknown[] = [];
361
- let failures = 0;
362
- for (const [index, target] of targets.entries()) {
363
- if (!ctx.json) {
364
- ctx.err(`\n=== [${index + 1}/${targets.length}] Deploying ${target.slug} ===\n`);
365
- }
366
- const before = jsonResults.length;
367
- const code = await deployOne(ctx, deployOptions, target, {
368
- jsonCollect: ctx.json ? jsonResults : undefined,
369
- });
370
- if (code !== 0) {
371
- failures += 1;
372
- if (ctx.json && jsonResults.length === before) {
373
- jsonResults.push({ slug: target.slug, error: "deploy failed" });
374
- }
375
- }
376
- }
377
- if (ctx.json) {
378
- ctx.out(`${JSON.stringify(jsonResults, null, 2)}\n`);
379
- } else if (failures > 0) {
380
- ctx.err(`\n${failures} of ${targets.length} deploy(s) failed.\n`);
381
- } else {
382
- ctx.err(`\nDeployed ${targets.length} agents.\n`);
383
- }
384
- return failures === 0 ? 0 : 1;
385
- }
386
-
387
- /**
388
- * Resolve which agent directory(ies) to deploy from `--dir` / `--slug` /
389
- * `--all`, with an interactive picker when a multi-agent parent is on a TTY.
390
- */
391
- async function resolveDeployTargets(
392
- options: DeployCliOptions,
393
- ctx: DeployCliContext,
394
- ): Promise<DeployTarget[] | number> {
395
- const dir = resolve(options.dir ?? ".");
396
-
397
- if (options.slug !== undefined) {
398
- const slugError = validateDeploymentSlug(options.slug);
399
- if (slugError !== undefined) {
400
- ctx.err(`${slugError}\n`);
401
- return 1;
402
- }
403
- }
404
- if (options.all === true && options.slug !== undefined) {
405
- ctx.err("Pass either --slug or --all, not both.\n");
406
- return 1;
407
- }
408
-
409
- if (await isAgentProjectDir(dir)) {
410
- if (options.all === true) {
411
- ctx.err(
412
- `--all requires a multi-agent parent directory (several child agents under --dir); ${dir} is a single agent project.\n`,
413
- );
414
- return 1;
415
- }
416
- let slug: string;
417
- if (options.slug !== undefined) {
418
- slug = options.slug;
419
- } else {
420
- const derived = slugFromDirectoryName(basename(dir));
421
- if (derived === undefined) {
422
- ctx.err(
423
- `Could not derive a deployment slug from the directory name ${JSON.stringify(basename(dir))}; pass --slug.\n`,
424
- );
425
- return 1;
426
- }
427
- slug = derived;
428
- if (!ctx.json) {
429
- ctx.err(`Deploying as "${slug}" (from the directory name).\n`);
430
- }
431
- }
432
- return [{ slug, dir }];
433
- }
434
-
435
- let children: ChildAgentDir[];
436
- try {
437
- children = await listChildAgentDirs(dir);
438
- } catch (error) {
439
- ctx.err(`${describeError(error)}\n`);
440
- return 1;
441
- }
442
- // Deploy slugs are lowercase-only; normalize directory names the same way
443
- // single-agent deploy does so MixedCase child dirs still deploy.
444
- children = children.flatMap(child => {
445
- const slug = slugFromDirectoryName(basename(child.dir));
446
- if (slug === undefined) {
447
- return [];
448
- }
449
- return [{ slug, dir: child.dir }];
450
- });
451
-
452
- if (children.length === 0) {
453
- if (options.all === true) {
454
- ctx.err(`--all requires child agent projects under --dir; none found in ${dir}.\n`);
455
- return 1;
456
- }
457
- // Bare-slug deploy against a non-agent directory (still requires --repo).
458
- let slug: string;
459
- if (options.slug !== undefined) {
460
- slug = options.slug;
461
- } else {
462
- const derived = slugFromDirectoryName(basename(dir));
463
- if (derived === undefined) {
464
- ctx.err(
465
- `No agent projects under ${dir}, and could not derive a slug from ${JSON.stringify(basename(dir))}; pass --slug or --dir <agent>.\n`,
466
- );
467
- return 1;
468
- }
469
- slug = derived;
470
- if (!ctx.json) {
471
- ctx.err(`Deploying as "${slug}" (no agent project at ${dir}).\n`);
472
- }
473
- }
474
- return [{ slug, dir }];
475
- }
476
-
477
- if (children.length === 1) {
478
- const only = children[0]!;
479
- if (options.all === true) {
480
- // One child is fine for --all (degenerate multi-agent parent).
481
- } else if (options.slug !== undefined && options.slug.toLowerCase() !== only.slug) {
482
- ctx.err(`No agent "${options.slug}" under ${dir}; found "${only.slug}".\n`);
483
- return 1;
484
- }
485
- if (!ctx.json) {
486
- ctx.err(`Deploying "${only.slug}" (only agent under ${basename(dir)}).\n`);
487
- }
488
- return [only];
489
- }
490
-
491
- // Multiple children.
492
- if (options.all === true) {
493
- if (!ctx.json) {
494
- ctx.err(
495
- `Deploying all ${children.length} agents under ${basename(dir)}: ${children.map(c => c.slug).join(", ")}.\n`,
496
- );
497
- }
498
- return [...children];
499
- }
500
-
501
- if (options.slug !== undefined) {
502
- const wanted = options.slug.toLowerCase();
503
- const match = children.find(child => child.slug === wanted);
504
- if (match === undefined) {
505
- ctx.err(
506
- `No agent "${options.slug}" under ${dir}.\n` +
507
- formatAgentList(children) +
508
- `Pass --slug <name> or --all.\n`,
509
- );
510
- return 1;
511
- }
512
- return [match];
513
- }
514
-
515
- // An all-v2 parent deploys as ONE application (siblings are components
516
- // of a single app on the v2 control plane), so "deploy the parent" is
517
- // unambiguous and needs no picker or --all. A child that is v1 — or
518
- // fails to load — keeps the interactive picker below.
519
- if (await allChildrenAreV2(children)) {
520
- if (!ctx.json) {
521
- ctx.err(
522
- `Deploying all ${children.length} v2 agents under ${basename(dir)} as one application (pass --slug <name> to deploy a single agent standalone).\n`,
523
- );
524
- }
525
- return [...children];
526
- }
527
-
528
- const chooser =
529
- options.chooseTargets ??
530
- (agents =>
531
- promptChooseDeployTargets(agents, {
532
- err: ctx.err,
533
- stdin: options.stdin ?? process.stdin,
534
- interactive:
535
- ctx.json !== true &&
536
- (options.stdin ?? process.stdin).isTTY === true &&
537
- process.stderr.isTTY === true,
538
- }));
539
- const chosen = await chooser(children);
540
- if (chosen === null) {
541
- ctx.err("Deploy cancelled.\n");
542
- return 1;
543
- }
544
- if (chosen.length === 0) {
545
- ctx.err(
546
- `Multiple agents under ${dir}:\n` +
547
- formatAgentList(children) +
548
- `Pass --slug <name> or --all (or re-run on a TTY to pick interactively).\n`,
549
- );
550
- return 1;
551
- }
552
- return chosen;
553
- }
554
-
555
- function formatAgentList(agents: readonly DeployTarget[]): string {
556
- return agents.map((agent, i) => ` ${i + 1}) ${agent.slug}\n`).join("");
557
- }
558
-
559
- /**
560
- * True when every child agent project loads and declares
561
- * `architecture: "v2"`. Broken projects count as not-v2 so target
562
- * resolution falls back to the picker instead of failing the whole deploy
563
- * on a child the user might not even select.
564
- */
565
- async function allChildrenAreV2(children: readonly DeployTarget[]): Promise<boolean> {
566
- for (const child of children) {
567
- try {
568
- if ((await readDeployManifest(child.dir)).architecture !== "v2") {
569
- return false;
570
- }
571
- } catch {
572
- return false;
573
- }
574
- }
575
- return true;
576
- }
577
-
578
- /**
579
- * TTY picker for multi-agent parents. Non-interactive callers get `[]`
580
- * so {@link resolveDeployTargets} can print the --slug/--all hint.
581
- */
582
- export async function promptChooseDeployTargets(
583
- agents: readonly DeployTarget[],
584
- options: {
585
- err: (text: string) => void;
586
- stdin: SecretInputStream;
587
- interactive: boolean;
588
- },
589
- ): Promise<DeployTarget[] | null> {
590
- options.err(`Multiple agents (${agents.length}):\n` + formatAgentList(agents) + ` a) all\n`);
591
- if (!options.interactive) {
592
- return [];
593
- }
594
- options.err('Deploy which? Enter a number, slug, "all", or "q" to cancel: ');
595
- const readLine = createLineReader(options.stdin);
596
- // createLineReader pauses until data; ensure stdin is flowing on a TTY.
597
- options.stdin.resume?.();
598
- const answer = (await readLine())?.trim().toLowerCase();
599
- if (answer === undefined || answer === "q" || answer === "quit") {
600
- return null;
601
- }
602
- if (answer === "a" || answer === "all" || answer === "*") {
603
- return [...agents];
604
- }
605
- const asIndex = Number.parseInt(answer, 10);
606
- if (
607
- !Number.isNaN(asIndex) &&
608
- String(asIndex) === answer &&
609
- asIndex >= 1 &&
610
- asIndex <= agents.length
611
- ) {
612
- return [agents[asIndex - 1]!];
613
- }
614
- const bySlug = agents.find(agent => agent.slug.toLowerCase() === answer);
615
- if (bySlug !== undefined) {
616
- return [bySlug];
617
- }
618
- options.err(
619
- `Unrecognized choice ${JSON.stringify(answer)} — expected 1–${agents.length}, a slug, "all", or "q". Aborting.\n`,
620
- );
621
- return null;
622
- }
623
-
624
- async function deployOne(
625
- ctx: DeployCliContext,
626
- options: DeployCliOptions,
627
- target: DeployTarget,
628
- extras?: { jsonCollect?: unknown[] },
629
- ): Promise<number> {
630
- const { dir, slug } = target;
631
-
632
- // Fill --repo/--ref/--path from the local git checkout when omitted so
633
- // `agent-sdk deploy` inside an agent directory is enough. Only probe git
634
- // for real agent projects (avoids ambient monorepo remotes when someone
635
- // deploys a bare --slug). Explicit flags always win.
636
- const isAgent = await isAgentProjectDir(dir);
637
- const needsGitInference =
638
- isAgent &&
639
- (options.repo === undefined || options.ref === undefined || options.path === undefined);
640
- const inferred = needsGitInference
641
- ? await inferDeployGitSource(dir, {
642
- ...(options.git === undefined ? {} : { git: options.git }),
643
- })
644
- : {};
645
- const gitRepoUrl = options.repo ?? inferred.gitRepoUrl;
646
- const gitRef = options.ref ?? inferred.gitRef;
647
- const agentPath = options.path ?? inferred.agentPath;
648
-
649
- if (gitRepoUrl !== undefined && !gitRepoUrl.startsWith("https://")) {
650
- ctx.err(`Invalid --repo: ${gitRepoUrl} (expected an https:// git repository URL)\n`);
651
- return 1;
652
- }
653
- if (gitRepoUrl === undefined) {
654
- ctx.err(
655
- `Could not resolve an https:// git repository URL for this deploy.\n` +
656
- ` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n`,
657
- );
658
- return 1;
659
- }
660
- for (const repo of options.cursorEventsRepos ?? []) {
661
- if (!isValidCursorEventRepo(repo)) {
662
- ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
663
- return 1;
664
- }
665
- }
666
-
667
- if (!ctx.json && gitRepoUrl !== undefined) {
668
- const inferredBits: string[] = [];
669
- if (options.repo === undefined && inferred.gitRepoUrl !== undefined) {
670
- inferredBits.push("repo");
671
- }
672
- if (options.ref === undefined && inferred.gitRef !== undefined) {
673
- inferredBits.push("ref");
674
- }
675
- if (options.path === undefined && inferred.agentPath !== undefined) {
676
- inferredBits.push("path");
677
- }
678
- ctx.err(
679
- ` source: ${gitRepoUrl}${gitRef === undefined ? "" : ` @ ${gitRef}`}\n` +
680
- (agentPath === undefined ? "" : ` path: ${agentPath}\n`) +
681
- (inferredBits.length === 0
682
- ? ""
683
- : ` (inferred ${inferredBits.join(", ")} from git; pass --repo/--ref/--path to override)\n`),
684
- );
685
- }
686
-
687
- // The package manifest (`defineAgent({ hosting })`) is the source of
688
- // truth for egress domains and expected secret names; flags override or
689
- // augment it. Directories without an agent project have no manifest. The same load supplies the
690
- // cursorAccount connection refs for the post-deploy connector auth and
691
- // the channels declared public via `publicEndpoint()`.
692
- const manifest = isAgent ? await readDeployManifest(dir) : undefined;
693
- const hosting = manifest?.hosting;
694
- const egressAllowedDomains = [
695
- ...new Set([...(hosting?.egressDomains ?? []), ...(options.allowDomains ?? [])]),
696
- ];
697
- const publicRoutePaths = (manifest?.publicChannelIds ?? []).map(
698
- channelId => `/v1/channels/${channelId}`,
699
- );
700
- if (!ctx.json && manifest?.httpChannelPublicEndpoint === true) {
701
- ctx.err(
702
- `warning: publicEndpoint() on the built-in HTTP channel has no effect on hosting — only custom channels (/v1/channels/…) can be public; the session API always requires the alias token.\n`,
703
- );
704
- }
705
- if (!ctx.json && publicRoutePaths.length > 0) {
706
- // Security-relevant surface change: say exactly what will be reachable
707
- // without the alias token before the deploy is accepted.
708
- ctx.err(
709
- ` public: ${publicRoutePaths.join(", ")} (served WITHOUT the alias token — these channels authenticate requests themselves)\n`,
710
- );
711
- }
712
- const deadSecretChannels = manifest?.publicChannelIdsWithDeadSecretPolicies ?? [];
713
- if (!ctx.json && deadSecretChannels.length > 0) {
714
- ctx.err(
715
- `warning: ${deadSecretChannels
716
- .map(channelId => `/v1/channels/${channelId}`)
717
- .join(
718
- ", ",
719
- )}: publicEndpoint() sits beside sharedSecretAuth()/hmacSignatureAuth() — auth chains are any-of, so every request is admitted and those secret policies never run. Drop publicEndpoint() to enforce them, or drop them to make the intent explicit.\n`,
720
- );
721
- }
722
-
723
- if (manifest?.architecture === "v2") {
724
- if (!ctx.json) {
725
- ctx.err(
726
- ` architecture: v2${manifest.persistent ? " (persistent)" : ""}${manifest.image === undefined ? "" : `\n image: ${manifest.image}`}\n`,
727
- );
728
- }
729
- return deployOneAgentsdk(ctx, extras, {
730
- persistent: manifest.persistent,
731
- image: manifest.image,
732
- slug,
733
- gitRepoUrl,
734
- gitRef,
735
- agentPath,
736
- repositories: options.cursorEventsRepos,
737
- hasScmChannels: manifest.hasScmChannels,
738
- declaredSecretNames: hosting?.secretNames,
739
- hasDeploymentsChannels: manifest.hasDeploymentsChannels,
740
- multiTenant: options.multiTenant === true,
741
- });
742
- }
743
-
744
- if (options.multiTenant === true) {
745
- ctx.err(
746
- "--multi-tenant is only valid for architecture: v2 deploys (Cursor-managed products).\n",
747
- );
748
- return 1;
749
- }
750
-
751
- // Today's only source shape: the control plane builds from a git ref.
752
- // See DeploySource for the artifact seam.
753
- const source: DeploySource = {
754
- kind: "git-ref",
755
- gitRepoUrl,
756
- ...(gitRef === undefined ? {} : { gitRef }),
757
- ...(agentPath === undefined ? {} : { agentPath }),
758
- ...(options.cursorEventsRepos === undefined || options.cursorEventsRepos.length === 0
759
- ? {}
760
- : { cursorEventRepos: options.cursorEventsRepos }),
761
- ...(egressAllowedDomains.length === 0 ? {} : { egressAllowedDomains }),
762
- publicRoutePaths: publicRoutePaths.length === 0 ? undefined : publicRoutePaths,
763
- // Deliberately NO manifest here: the control plane captures it from the
764
- // provisioned engine (`GET /v1/manifest` after the health probe), which
765
- // is the single write path for deploy manifests. `july manifest` remains
766
- // available for local visibility only.
767
- };
768
-
769
- let accepted: DeployAccepted;
770
- try {
771
- accepted = await ctx.client.deploy({
772
- teamId: ctx.teamId,
773
- slug,
774
- source,
775
- template: readDeployTemplate(dir),
776
- });
777
- } catch (error) {
778
- return renderApiError(error, ctx.err);
779
- }
780
-
781
- const aliasUrl = ctx.client.aliasUrl(accepted.engineAlias);
782
- if (!ctx.json && accepted.aliasToken !== undefined) {
783
- ctx.out(aliasTokenBlock(accepted.aliasToken));
784
- }
785
-
786
- if (ctx.noWait) {
787
- if (extras?.jsonCollect !== undefined) {
788
- extras.jsonCollect.push(accepted);
789
- } else if (ctx.json) {
790
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
791
- } else {
792
- ctx.out(
793
- `Deploy accepted: ${slug} (team ${ctx.teamId}, generation ${accepted.generation}, ${accepted.deploymentKind})\n` +
794
- ` alias: ${aliasUrl}\n` +
795
- `Check progress with \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.\n`,
796
- );
797
- }
798
- return 0;
799
- }
800
-
801
- let detail: DeploymentDetail;
802
- try {
803
- detail = await pollUntil(ctx, slug, TERMINAL_DEPLOY_STATUSES, () =>
804
- ctx.client.getDeployment({ teamId: ctx.teamId, slug }),
805
- );
806
- } catch (error) {
807
- return renderApiError(error, ctx.err);
808
- }
809
-
810
- warnMissingSecrets(ctx, slug, hosting?.secretNames, detail.secretNames);
811
-
812
- const payload =
813
- accepted.aliasToken === undefined ? detail : { ...detail, aliasToken: accepted.aliasToken };
814
-
815
- if (extras?.jsonCollect !== undefined) {
816
- extras.jsonCollect.push(payload);
817
- return detail.status === "running" ? 0 : 1;
818
- }
819
-
820
- if (ctx.json) {
821
- ctx.out(`${JSON.stringify(payload, null, 2)}\n`);
822
- return detail.status === "running" ? 0 : 1;
823
- }
824
-
825
- if (detail.status !== "running") {
826
- ctx.err(`Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`);
827
- return 1;
828
- }
829
- const deployedPublicRoutes = detail.publicRoutePaths ?? [];
830
- ctx.out(
831
- `Deployed ${slug} (team ${ctx.teamId})\n` +
832
- ` status: running\n` +
833
- ` generation: ${detail.generation}\n` +
834
- ` kind: ${detail.deploymentKind}\n` +
835
- ` alias: ${aliasUrl}\n` +
836
- ` playground: ${aliasUrl}/playground (sign in with the alias token)\n` +
837
- ` open: ${CLI} playground --prod --slug ${slug} --team ${ctx.teamId}\n` +
838
- // Paste-ready webhook URLs: these subtrees skip the alias token, so
839
- // the channel handler must verify deliveries (webhook signatures).
840
- deployedPublicRoutes
841
- .map(path => ` public: ${aliasUrl}${path} (no alias token)\n`)
842
- .join(""),
843
- );
844
-
845
- await runPostDeployConnectorAuth(ctx, options, {
846
- slug,
847
- connections: manifest?.cursorAccountConnections ?? [],
848
- serviceAccountId: deploymentServiceAccountId(detail),
849
- });
850
- return 0;
851
- }
852
-
853
- /**
854
- * Multi-agent parent whose children all declare `architecture: "v2"`:
855
- * deploy ONE application whose release carries a component per child. The
856
- * application slug derives from the parent directory name; each component
857
- * key is the child's slug and its path is the child directory relative to
858
- * the repo root (a shared --path names the parent's directory in the repo).
859
- */
860
- async function deployAgentsdkApplication(
861
- ctx: DeployCliContext,
862
- options: DeployCliOptions,
863
- targets: readonly DeployTarget[],
864
- declarations: {
865
- /** Per child slug: `persistent: true` on that agent's manifest. */
866
- componentPersistent: Record<string, boolean>;
867
- /** Per child slug: `hosting.image` on that agent's manifest. */
868
- componentImage: Record<string, string>;
869
- hasScmChannels: boolean;
870
- declaredSecretNames: string[];
871
- hasDeploymentsChannels: boolean;
872
- },
873
- ): Promise<number> {
874
- const parentDir = resolve(options.dir ?? ".");
875
- const slug = slugFromDirectoryName(basename(parentDir));
876
- if (slug === undefined) {
877
- ctx.err(
878
- `Could not derive an application slug from the parent directory name ${JSON.stringify(basename(parentDir))} — rename it (deploy slugs use lowercase letters, digits, '-' or '_').\n`,
879
- );
880
- return 1;
881
- }
882
-
883
- const needsGitInference =
884
- options.repo === undefined || options.ref === undefined || options.path === undefined;
885
- const inferred = needsGitInference
886
- ? await inferDeployGitSource(parentDir, {
887
- ...(options.git === undefined ? {} : { git: options.git }),
888
- })
889
- : {};
890
- const gitRepoUrl = options.repo ?? inferred.gitRepoUrl;
891
- const gitRef = options.ref ?? inferred.gitRef;
892
- const parentPath = options.path ?? inferred.agentPath;
893
-
894
- if (gitRepoUrl !== undefined && !gitRepoUrl.startsWith("https://")) {
895
- ctx.err(`Invalid --repo: ${gitRepoUrl} (expected an https:// git repository URL)\n`);
896
- return 1;
897
- }
898
- if (gitRepoUrl === undefined) {
899
- ctx.err(
900
- `Could not resolve an https:// git repository URL for this deploy.\n` +
901
- ` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n`,
902
- );
903
- return 1;
904
- }
905
- for (const repo of options.cursorEventsRepos ?? []) {
906
- if (!isValidCursorEventRepo(repo)) {
907
- ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
908
- return 1;
909
- }
910
- }
911
-
912
- const components: AgentkitDeployComponent[] = targets.map(target => ({
913
- componentKey: target.slug,
914
- agentPath: [parentPath, basename(target.dir)]
915
- .filter((part): part is string => part !== undefined && part !== "")
916
- .join("/"),
917
- persistent: declarations.componentPersistent[target.slug] === true,
918
- image: declarations.componentImage[target.slug],
919
- }));
920
-
921
- if (!ctx.json) {
922
- ctx.err(
923
- `Deploying "${slug}" as one v2 application with ${targets.length} components (slug from the parent directory name).\n` +
924
- ` architecture: v2\n` +
925
- ` source: ${gitRepoUrl}${gitRef === undefined ? "" : ` @ ${gitRef}`}\n` +
926
- components
927
- .map(
928
- component =>
929
- ` component: ${component.componentKey} (${component.agentPath ?? "."})${component.persistent ? " persistent" : ""}${component.image === undefined ? "" : ` image ${component.image}`}\n`,
930
- )
931
- .join(""),
932
- );
933
- }
934
-
935
- return deployOneAgentsdk(ctx, undefined, {
936
- // Multi-component: the flag travels on each component instead.
937
- persistent: false,
938
- slug,
939
- gitRepoUrl,
940
- gitRef,
941
- agentPath: undefined,
942
- components,
943
- repositories: options.cursorEventsRepos,
944
- hasScmChannels: declarations.hasScmChannels,
945
- declaredSecretNames: declarations.declaredSecretNames,
946
- hasDeploymentsChannels: declarations.hasDeploymentsChannels,
947
- multiTenant: options.multiTenant === true,
948
- });
949
- }
950
-
951
- /**
952
- * `architecture: "v2"` deploy: POST `/internal/agentsdk/deployments` and
953
- * poll the matching GET. The v2 accept path starts freeze bake; it does
954
- * not mint an engine alias or alias token.
955
- */
956
- async function deployOneAgentsdk(
957
- ctx: DeployCliContext,
958
- extras: { jsonCollect?: unknown[] } | undefined,
959
- args: {
960
- slug: string;
961
- gitRepoUrl: string;
962
- gitRef: string | undefined;
963
- agentPath: string | undefined;
964
- components?: AgentkitDeployComponent[];
965
- repositories: string[] | undefined;
966
- /** Any component declares a GitHub/Origin channel. */
967
- hasScmChannels: boolean;
968
- /** Union of application component secret declarations. */
969
- declaredSecretNames?: string[];
970
- /** Any component declares a deployments channel (same repo scope). */
971
- hasDeploymentsChannels?: boolean;
972
- /** Redeploy an existing Cursor-managed product. */
973
- multiTenant: boolean;
974
- /**
975
- * `persistent: true` in a single agent's manifest. Multi-component
976
- * deploys pass `false` here and flag each component instead.
977
- */
978
- persistent: boolean;
979
- /** `hosting.image` of a single agent; components carry their own. */
980
- image?: string;
981
- },
982
- ): Promise<number> {
983
- const { slug } = args;
984
- const componentsLine =
985
- args.components === undefined
986
- ? ""
987
- : ` components: ${args.components.map(component => component.componentKey).join(", ")}\n`;
988
- if (args.multiTenant && !ctx.json) {
989
- ctx.err(" multi-tenant: existing product\n");
990
- }
991
- let accepted: AgentkitDeployAccepted;
992
- try {
993
- accepted = await ctx.client.deployAgentkit({
994
- teamId: ctx.teamId,
995
- slug,
996
- gitRepoUrl: args.gitRepoUrl,
997
- gitRef: args.gitRef,
998
- agentPath: args.agentPath,
999
- components: args.components,
1000
- repositories: args.repositories,
1001
- ...(args.multiTenant ? { multiTenant: true } : {}),
1002
- persistent: args.persistent,
1003
- image: args.image,
1004
- });
1005
- } catch (error) {
1006
- return renderApiError(error, ctx.err, {
1007
- multiTenant: args.multiTenant,
1008
- teamId: ctx.teamId,
1009
- });
1010
- }
1011
-
1012
- if (ctx.noWait) {
1013
- if (extras?.jsonCollect !== undefined) {
1014
- extras.jsonCollect.push(accepted);
1015
- } else if (ctx.json) {
1016
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1017
- } else {
1018
- ctx.out(
1019
- `Deploy accepted: ${slug} (team ${ctx.teamId}, v2)\n` +
1020
- ` application: ${accepted.applicationId}\n` +
1021
- ` release: ${accepted.releaseId}\n` +
1022
- componentsLine,
1023
- );
1024
- }
1025
- return 0;
1026
- }
1027
-
1028
- let detail: AgentkitDeployStatus;
1029
- try {
1030
- detail = await pollUntil(ctx, slug, TERMINAL_AGENTKIT_DEPLOY_STATUSES, () =>
1031
- ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug }),
1032
- );
1033
- } catch (error) {
1034
- return renderApiError(error, ctx.err);
1035
- }
1036
-
1037
- if (extras?.jsonCollect !== undefined) {
1038
- extras.jsonCollect.push(detail);
1039
- return detail.status === "running" ? 0 : 1;
1040
- }
1041
-
1042
- if (ctx.json) {
1043
- ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1044
- return detail.status === "running" ? 0 : 1;
1045
- }
1046
-
1047
- if (detail.status !== "running") {
1048
- ctx.err(`Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`);
1049
- return 1;
1050
- }
1051
- warnMissingSecrets(ctx, slug, args.declaredSecretNames, detail.secretNames);
1052
- const watchesRepositories = args.hasScmChannels || args.hasDeploymentsChannels === true;
1053
- ctx.out(
1054
- `Deployed ${slug} (team ${ctx.teamId})\n` +
1055
- ` status: running\n` +
1056
- ` architecture: v2\n` +
1057
- ` application: ${detail.applicationId}\n` +
1058
- ` release: ${detail.releaseId}\n` +
1059
- (args.components === undefined
1060
- ? ""
1061
- : ` components: ${args.components
1062
- .map(component => component.componentKey)
1063
- .join(", ")}\n`) +
1064
- (detail.repositories === undefined || !watchesRepositories
1065
- ? ""
1066
- : ` watching: ${detail.repositories.length === 0 ? "(nothing)" : detail.repositories.join(", ")}\n`),
1067
- );
1068
- // An agent with GitHub/Origin/deployments channels bound to no repository
1069
- // scope gets no deliveries at all (deployments channels receive the
1070
- // watched repos' deployment events), which is otherwise invisible here.
1071
- if (watchesRepositories && detail.repositories?.length === 0) {
1072
- ctx.err(
1073
- `warning: ${slug} watches no repositories, so its GitHub/Origin/deployments channels receive no events.\n` +
1074
- ` Redeploy with --cursor-events-repo <owner>/<name> to set the scope.\n`,
1075
- );
1076
- }
1077
- return 0;
1078
- }
1079
-
1080
- /**
1081
- * Post-deploy connector authorization for `cursorAccount` connections: the
1082
- * agent's connectors execute with tokens owned by the deployment's service
1083
- * account, which start out unauthorized. On a TTY this runs the dashboard's
1084
- * Authenticate flow inline (browser OAuth per connector, already-authorized
1085
- * ones skipped); otherwise it reports status only. Never affects the deploy
1086
- * outcome — anything left unauthorized just gets a playground-page pointer.
1087
- */
1088
- async function runPostDeployConnectorAuth(
1089
- ctx: DeployCliContext,
1090
- options: DeployCliOptions,
1091
- args: {
1092
- slug: string;
1093
- connections: DeployManifest["cursorAccountConnections"];
1094
- serviceAccountId: string | undefined;
1095
- },
1096
- ): Promise<void> {
1097
- if (args.connections.length === 0) {
1098
- return;
1099
- }
1100
-
1101
- const { serviceAccountId } = args;
1102
- if (serviceAccountId === undefined) {
1103
- ctx.err(
1104
- `warning: this agent uses Cursor account connectors, but the deployment has no service account; redeploy to mint one.\n`,
1105
- );
1106
- return;
1107
- }
1108
-
1109
- const backendClient = new CursorBackendClient({
1110
- backendUrl: ctx.backendUrl,
1111
- apiKey: ctx.apiKey,
1112
- fetchImpl: options.fetchImpl,
1113
- });
1114
-
1115
- const interactive =
1116
- options.openBrowserImpl !== undefined ||
1117
- (process.stdout.isTTY === true && process.stdin.isTTY === true);
1118
-
1119
- let anyUnauthorized = false;
1120
- for (const ref of args.connections) {
1121
- ctx.out(
1122
- `\nThis agent uses Cursor account connectors (connection "${ref.name}"${
1123
- ref.servers === undefined || ref.servers.length === 0 ? "" : `: ${ref.servers.join(", ")}`
1124
- }).\n`,
1125
- );
1126
- try {
1127
- const result = await authorizeCursorAccountConnectors({
1128
- backendClient,
1129
- teamId: ctx.teamId,
1130
- slug: args.slug,
1131
- serviceAccountId,
1132
- connectionName: ref.name,
1133
- servers: ref.servers,
1134
- interactive,
1135
- out: ctx.out,
1136
- err: ctx.err,
1137
- openBrowserImpl: options.openBrowserImpl,
1138
- sleep: options.sleepImpl,
1139
- pollIntervalMs: options.connectorPollIntervalMs,
1140
- pollTimeoutMs: options.connectorPollTimeoutMs,
1141
- });
1142
- if (result.pending.length > 0 || result.errored.length > 0) {
1143
- anyUnauthorized = true;
1144
- if (result.pending.length > 0) {
1145
- ctx.out(`Connectors not authorized yet: ${result.pending.join(", ")}.\n`);
1146
- }
1147
- }
1148
- } catch (error) {
1149
- anyUnauthorized = true;
1150
- ctx.err(
1151
- `warning: could not check connector authorization for "${ref.name}": ${describeError(error)}\n`,
1152
- );
1153
- }
1154
- }
1155
-
1156
- if (anyUnauthorized) {
1157
- ctx.out(
1158
- `You can authorize connectors at the playground page (cursor.com dashboard → Deployed Agents → ${args.slug}) or with \`${CLI} mcp oauth <connection>\`.\n`,
1159
- );
1160
- }
1161
- }
1162
-
1163
- interface DeployManifest {
1164
- hosting: AgentHostingOptions | undefined;
1165
- architecture: AgentArchitecture | undefined;
1166
- persistent: boolean;
1167
- /** `hosting.image`, the team container image this agent runs in. */
1168
- image: string | undefined;
1169
- /** `cursorAccount` connections declared by the agent. */
1170
- cursorAccountConnections: Array<{
1171
- name: string;
1172
- servers: string[] | undefined;
1173
- }>;
1174
- /**
1175
- * Channels whose authored auth chain contains `publicEndpoint()`: their
1176
- * `/v1/channels/<id>` subtree is served through the stable alias WITHOUT
1177
- * `X-Agent-Alias-Token` (the channel authenticates deliveries itself).
1178
- */
1179
- publicChannelIds: string[];
1180
- /**
1181
- * Public channels whose auth chain also carries `sharedSecretAuth` /
1182
- * `hmacSignatureAuth`. Chains are any-of, so `publicEndpoint()` admits
1183
- * every request and those secret policies never gate anything — locally
1184
- * or on the control plane; surfaced as a warning.
1185
- */
1186
- publicChannelIdsWithDeadSecretPolicies: string[];
1187
- /**
1188
- * `publicEndpoint()` on the built-in HTTP channel — a no-op on hosting
1189
- * (only `/v1/channels/…` subtrees can be public); surfaced as a warning.
1190
- */
1191
- httpChannelPublicEndpoint: boolean;
1192
- /**
1193
- * The agent has GitHub/Origin channels, so it only receives deliveries
1194
- * while the deployment is bound to at least one `owner/name` scope.
1195
- */
1196
- hasScmChannels: boolean;
1197
- /**
1198
- * The agent has deployments channels; deploy-source edges derive from
1199
- * the same watched-repo set as GitHub/Origin, so it too receives
1200
- * nothing while the deployment watches no repositories.
1201
- */
1202
- hasDeploymentsChannels: boolean;
1203
- }
1204
-
1205
- /**
1206
- * Read the deploy-relevant bits of the project manifest at `dir` in one
1207
- * load: the `hosting` block, the agent's cursorAccount connections, and the
1208
- * channels declared public via `publicEndpoint()`.
1209
- */
1210
- async function readDeployManifest(dir: string): Promise<DeployManifest> {
1211
- const project = await loadAgentProject(dir);
1212
- // Fail here, before anything is dispatched: a project with error
1213
- // diagnostics (e.g. agent/storage.ts on architecture v2) would only be
1214
- // refused later by `serve` inside the hosted build, wasting a bake.
1215
- if (hasErrorDiagnostics(project)) {
1216
- throw new Error(
1217
- `Refusing to deploy ${project.name} — it has errors:\n${formatDiagnostics(
1218
- project.diagnostics.filter(d => d.severity === "error"),
1219
- )}`,
1220
- );
1221
- }
1222
- return {
1223
- hosting: project.agent.hosting,
1224
- architecture: project.agent.architecture,
1225
- persistent: project.agent.persistent === true,
1226
- image: project.agent.hosting?.image,
1227
- cursorAccountConnections: project.agent.connections.flatMap(connection =>
1228
- isCursorAccountTransport(connection.transport)
1229
- ? [{ name: connection.name, servers: connection.transport.servers }]
1230
- : [],
1231
- ),
1232
- publicChannelIds: project.channels
1233
- .filter(channel => (channel.definition.auth ?? []).some(isPublicEndpointPolicy))
1234
- .map(channel => channel.id),
1235
- publicChannelIdsWithDeadSecretPolicies: project.channels
1236
- .filter(channel => {
1237
- const auth = channel.definition.auth ?? [];
1238
- return (
1239
- auth.some(isPublicEndpointPolicy) &&
1240
- auth.some(policy => {
1241
- const kind = catchAuthDeclaration(policy)?.kind;
1242
- return kind !== undefined && kind !== "public";
1243
- })
1244
- );
1245
- })
1246
- .map(channel => channel.id),
1247
- httpChannelPublicEndpoint: (project.httpChannel.auth ?? []).some(isPublicEndpointPolicy),
1248
- hasScmChannels: project.channels.some(channel => {
1249
- const kind = channel.definition.meta?.kind;
1250
- return kind === "github" || kind === "origin";
1251
- }),
1252
- hasDeploymentsChannels: project.channels.some(
1253
- channel => channel.definition.meta?.kind === "deployments",
1254
- ),
1255
- };
1256
- }
1257
-
1258
- /**
1259
- * Friendly post-deploy nudge: the manifest declares secrets the agent
1260
- * expects, but the deployment does not have them all set yet.
1261
- */
1262
- function warnMissingSecrets(
1263
- ctx: DeployCliContext,
1264
- slug: string,
1265
- declared: string[] | undefined,
1266
- set: string[] | undefined,
1267
- ): void {
1268
- if (declared === undefined || declared.length === 0) {
1269
- return;
1270
- }
1271
- const setNames = new Set(set ?? []);
1272
- // Platform-managed names (CURSOR_*, hosted storage) are injected by the
1273
- // control plane and never appear in secrets list — do not warn on them.
1274
- const missing = declared.filter(name => !setNames.has(name) && !isReservedSecretName(name));
1275
- if (missing.length === 0) {
1276
- return;
1277
- }
1278
- ctx.err(
1279
- `warning: secrets declared in the agent manifest but not set on ${slug}: ${missing.join(", ")}\n` +
1280
- ` set them with \`${CLI} secrets set ${slug} ${missing.join(" ")}\`\n`,
1281
- );
1282
- }
1283
-
1284
- // ============================================================================
1285
- // deployments (list)
1286
- // ============================================================================
1287
-
1288
- export async function cmdDeployments(options: DeployCliOptions): Promise<number> {
1289
- const ctx = await prepare(options);
1290
- if (typeof ctx === "number") {
1291
- return ctx;
1292
- }
1293
- let deployments: Deployment[];
1294
- try {
1295
- deployments = await ctx.client.listDeployments({ teamId: ctx.teamId });
1296
- } catch (error) {
1297
- return renderApiError(error, ctx.err);
1298
- }
1299
- let applications: AgentkitDeploymentListItem[] = [];
1300
- try {
1301
- applications = await ctx.client.listAgentkitDeployments({
1302
- teamId: ctx.teamId,
1303
- });
1304
- } catch (error) {
1305
- // Older control planes 404 this route; keep listing v1.
1306
- if (!(error instanceof DeployApiError && error.status === 404)) {
1307
- return renderApiError(error, ctx.err);
1308
- }
1309
- }
1310
- if (ctx.json) {
1311
- // Empty v2 list keeps `{ deployments }` for v1-only parsers.
1312
- ctx.out(
1313
- `${JSON.stringify(
1314
- applications.length === 0 ? { deployments } : { deployments, applications },
1315
- null,
1316
- 2,
1317
- )}\n`,
1318
- );
1319
- return 0;
1320
- }
1321
- if (deployments.length === 0 && applications.length === 0) {
1322
- ctx.out(`No deployments on team ${ctx.teamId}. Create one with \`${CLI} deploy\`.\n`);
1323
- return 0;
1324
- }
1325
- ctx.out(
1326
- `${renderTable(
1327
- ["SLUG", "ARCH", "STATUS", "GEN", "KIND", "UPDATED"],
1328
- [
1329
- ...deployments.map(d => [
1330
- d.slug,
1331
- "v1",
1332
- d.status,
1333
- String(d.generation),
1334
- d.deploymentKind,
1335
- d.desiredUpdatedAt ?? "",
1336
- ]),
1337
- ...applications.map(application => [
1338
- application.slug,
1339
- "v2",
1340
- application.status,
1341
- "-",
1342
- "application",
1343
- application.deployments
1344
- .map(row => row.desiredUpdatedAt)
1345
- .sort()
1346
- .at(-1) ?? "",
1347
- ]),
1348
- ],
1349
- )}\n`,
1350
- );
1351
- return 0;
1352
- }
1353
-
1354
- // ============================================================================
1355
- // deployment <slug> (detail)
1356
- // ============================================================================
1357
-
1358
- export async function cmdDeploymentStatus(
1359
- slug: string | undefined,
1360
- options: DeployCliOptions,
1361
- ): Promise<number> {
1362
- if (slug === undefined || slug === "") {
1363
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1364
- `Usage: ${CLI} deployment <slug> [--team <id>] [--json]\n`,
1365
- );
1366
- return 1;
1367
- }
1368
- const ctx = await prepare(options);
1369
- if (typeof ctx === "number") {
1370
- return ctx;
1371
- }
1372
- // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
1373
- // GET goes first. A v2 404 (missing slug, or an older backend) falls
1374
- // through to the v1 agent-serve detail.
1375
- try {
1376
- const detail = await ctx.client.getAgentkitDeploy({
1377
- teamId: ctx.teamId,
1378
- slug,
1379
- });
1380
- renderAgentkitDeploymentStatus(ctx, detail);
1381
- return 0;
1382
- } catch (error) {
1383
- if (!(error instanceof DeployApiError) || error.status !== 404) {
1384
- return renderApiError(error, ctx.err);
1385
- }
1386
- }
1387
- let detail: DeploymentDetail;
1388
- try {
1389
- detail = await ctx.client.getDeployment({ teamId: ctx.teamId, slug });
1390
- } catch (error) {
1391
- return renderApiError(error, ctx.err);
1392
- }
1393
- if (ctx.json) {
1394
- ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1395
- return 0;
1396
- }
1397
- const aliasUrl = ctx.client.aliasUrl(detail.engineAlias);
1398
- const lines = [`${detail.slug} (team ${detail.teamId})`, ` status: ${detail.status}`];
1399
- if (detail.progress !== undefined) {
1400
- lines.push(` progress: ${detail.progress}`);
1401
- }
1402
- if (
1403
- detail.statusMessage !== null &&
1404
- detail.statusMessage !== undefined &&
1405
- detail.statusMessage.trim() !== ""
1406
- ) {
1407
- lines.push(` step: ${detail.statusMessage}`);
1408
- }
1409
- lines.push(
1410
- ` generation: ${detail.generation}`,
1411
- ` kind: ${detail.deploymentKind}`,
1412
- ` alias: ${aliasUrl}`,
1413
- ` playground: ${aliasUrl}/playground`,
1414
- );
1415
- if (detail.gitRepoUrl !== null && detail.gitRepoUrl !== undefined) {
1416
- lines.push(` repo: ${detail.gitRepoUrl} @ ${detail.gitRef ?? ""}`);
1417
- }
1418
- if (detail.serviceAccountId !== undefined && detail.serviceAccountId !== null) {
1419
- lines.push(` service account: ${detail.serviceAccountId}`);
1420
- }
1421
- if (detail.agentStoreSourceId !== undefined) {
1422
- // The durable file store's address: GET /v0/agent-serve-files/<id> lists
1423
- // it, and the pod sees it as AGENT_SERVE_STORE_SOURCE_ID.
1424
- lines.push(` file store: ${detail.agentStoreSourceId}`);
1425
- }
1426
- if (detail.egressAllowedDomains !== undefined && detail.egressAllowedDomains.length > 0) {
1427
- lines.push(` egress: ${detail.egressAllowedDomains.join(", ")}`);
1428
- }
1429
- if (detail.publicRoutePaths !== undefined && detail.publicRoutePaths.length > 0) {
1430
- // Served through the alias WITHOUT X-Agent-Alias-Token (the channel
1431
- // authenticates deliveries itself).
1432
- for (const path of detail.publicRoutePaths) {
1433
- lines.push(` public: ${aliasUrl}${path} (no alias token)`);
1434
- }
1435
- }
1436
- if (detail.secretNames !== undefined && detail.secretNames.length > 0) {
1437
- lines.push(` secrets: ${detail.secretNames.join(", ")}`);
1438
- }
1439
- if (detail.podCredentialMaskedKey !== undefined && detail.podCredentialMaskedKey !== null) {
1440
- lines.push(` pod credential: ${detail.podCredentialMaskedKey}`);
1441
- }
1442
- if (detail.engineUrl !== null && detail.engineUrl !== undefined) {
1443
- lines.push(` engine: ${detail.engineUrl}`);
1444
- }
1445
- if (
1446
- detail.engineAccess !== null &&
1447
- detail.engineAccess !== undefined &&
1448
- typeof detail.engineAccess === "object"
1449
- ) {
1450
- lines.push(
1451
- ` engine access: ${detail.engineAccess.url} (expires ${detail.engineAccess.expiresAt})`,
1452
- );
1453
- }
1454
- if (detail.lastError !== null && detail.lastError !== undefined) {
1455
- lines.push(` last error: ${sanitizeCustomerError(detail.lastError)}`);
1456
- }
1457
- if (detail.desiredUpdatedAt !== undefined) {
1458
- lines.push(` updated: ${detail.desiredUpdatedAt}`);
1459
- }
1460
- ctx.out(`${lines.join("\n")}\n`);
1461
- return 0;
1462
- }
1463
-
1464
- function renderAgentkitDeploymentStatus(ctx: DeployCliContext, detail: AgentkitDeployStatus): void {
1465
- if (ctx.json) {
1466
- ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1467
- return;
1468
- }
1469
- const lines = [
1470
- `${detail.slug} (team ${detail.teamId})`,
1471
- ` status: ${detail.status}`,
1472
- ` architecture: v2`,
1473
- ` application: ${detail.applicationId}`,
1474
- ` release: ${detail.releaseId}`,
1475
- ` progress: ${detail.progress}`,
1476
- ];
1477
- if (detail.statusMessage !== null && detail.statusMessage.trim() !== "") {
1478
- lines.push(` step: ${detail.statusMessage}`);
1479
- }
1480
- if (detail.repositories !== undefined) {
1481
- lines.push(
1482
- ` watching: ${
1483
- detail.repositories.length === 0 ? "(nothing)" : detail.repositories.join(", ")
1484
- }`,
1485
- );
1486
- }
1487
- if (detail.secretNames !== undefined && detail.secretNames.length > 0) {
1488
- lines.push(` secrets: ${detail.secretNames.join(", ")}`);
1489
- }
1490
- if (detail.lastError !== null && detail.lastError !== undefined) {
1491
- lines.push(` last error: ${sanitizeCustomerError(detail.lastError)}`);
1492
- }
1493
- ctx.out(`${lines.join("\n")}\n`);
1494
- }
1495
-
1496
- // ============================================================================
1497
- // stop <slug>
1498
- // ============================================================================
1499
-
1500
- export async function cmdStop(
1501
- slug: string | undefined,
1502
- options: DeployCliOptions,
1503
- ): Promise<number> {
1504
- if (slug === undefined || slug === "") {
1505
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1506
- `Usage: ${CLI} stop <slug> [--team <id>] [--json] [--no-wait]\n`,
1507
- );
1508
- return 1;
1509
- }
1510
- const ctx = await prepare(options);
1511
- if (typeof ctx === "number") {
1512
- return ctx;
1513
- }
1514
- // Stop takes only a slug, so there is no manifest to dispatch on (unlike
1515
- // deploy). The v2 agentsdk control plane goes first: v1 endpoints refuse
1516
- // `architecture: "v2"` slugs with a 409 rather than a 404, so v1-first
1517
- // could not fall through. A v2 404 (including an older backend without
1518
- // the `/internal/agentsdk` mount) falls back to the v1 stop.
1519
- let architecture: "v1" | "v2" = "v2";
1520
- let accepted: StopAccepted | AgentkitStopAccepted;
1521
- try {
1522
- accepted = await ctx.client.stopAgentkit({
1523
- teamId: ctx.teamId,
1524
- slug,
1525
- cancelRuns: options.cancelRuns,
1526
- });
1527
- } catch (error) {
1528
- if (!(error instanceof DeployApiError) || error.status !== 404) {
1529
- return renderApiError(error, ctx.err);
1530
- }
1531
- if (options.cancelRuns === true) {
1532
- ctx.err(
1533
- `Canceling active runs while stopping is supported only for Agent SDK v2 deployments.\n`,
1534
- );
1535
- return 1;
1536
- }
1537
- try {
1538
- accepted = await ctx.client.stopDeployment({ teamId: ctx.teamId, slug });
1539
- architecture = "v1";
1540
- } catch (v1Error) {
1541
- return renderApiError(v1Error, ctx.err);
1542
- }
1543
- }
1544
- const cancellation = "cancellation" in accepted ? accepted.cancellation : undefined;
1545
- const stoppedGlobally = "scope" in accepted && accepted.scope === "global";
1546
- if (ctx.noWait) {
1547
- if (ctx.json) {
1548
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1549
- } else {
1550
- ctx.out(
1551
- stoppedGlobally
1552
- ? `Stop accepted for ${slug} across all tenants (status: ${accepted.status}).\n`
1553
- : `Stop accepted for ${slug} (status: ${accepted.status}).\n`,
1554
- );
1555
- }
1556
- return cancellation?.failed === 0 || cancellation === undefined ? 0 : 1;
1557
- }
1558
- let detail: DeploymentDetail | AgentkitDeployStatus;
1559
- try {
1560
- detail =
1561
- architecture === "v2"
1562
- ? await pollUntil(ctx, slug, new Set(["stopped"]), () =>
1563
- ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug }),
1564
- )
1565
- : await pollUntil(ctx, slug, new Set(["stopped"]), () =>
1566
- ctx.client.getDeployment({ teamId: ctx.teamId, slug }),
1567
- );
1568
- } catch (error) {
1569
- return renderApiError(error, ctx.err);
1570
- }
1571
- if (ctx.json) {
1572
- ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1573
- } else if (stoppedGlobally) {
1574
- ctx.out(
1575
- `Stopped ${slug} across all tenants (team ${ctx.teamId}); resume with \`${CLI} start ${slug}\`.\n`,
1576
- );
1577
- } else {
1578
- ctx.out(`Stopped ${slug} (team ${ctx.teamId}).\n`);
1579
- }
1580
- if (cancellation !== undefined) {
1581
- return writeCancellationStarted(ctx, cancellation, slug);
1582
- }
1583
- return 0;
1584
- }
1585
-
1586
- function writeCancellationStarted(
1587
- ctx: { out: (text: string) => void; err: (text: string) => void },
1588
- cancellation: AgentkitCancelRunsResult,
1589
- slug: string,
1590
- ): number {
1591
- ctx.out(`Started cancellation across ${cancellation.batchesStarted} deployment batch(es).\n`);
1592
- if (cancellation.sessionsMarkedFailed !== undefined) {
1593
- ctx.out(`Marked ${cancellation.sessionsMarkedFailed} factory session(s) failed.\n`);
1594
- }
1595
- if (cancellation.failed > 0) {
1596
- ctx.err(
1597
- `Failed to start ${cancellation.failed} cancellation batch(es); retry with \`${CLI} cancel-runs ${slug}\`.\n`,
1598
- );
1599
- return 1;
1600
- }
1601
- return 0;
1602
- }
1603
-
1604
- export async function cmdStart(
1605
- slug: string | undefined,
1606
- options: DeployCliOptions,
1607
- ): Promise<number> {
1608
- if (slug === undefined || slug === "") {
1609
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1610
- `Usage: ${CLI} start <slug> [--team <id>] [--json]\n`,
1611
- );
1612
- return 1;
1613
- }
1614
- const ctx = await prepare(options);
1615
- if (typeof ctx === "number") {
1616
- return ctx;
1617
- }
1618
- try {
1619
- const accepted = await ctx.client.startAgentkit({
1620
- teamId: ctx.teamId,
1621
- slug,
1622
- });
1623
- if (ctx.json) {
1624
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1625
- } else {
1626
- ctx.out(`Started ${slug} (team ${ctx.teamId}).\n`);
1627
- }
1628
- return 0;
1629
- } catch (error) {
1630
- return renderApiError(error, ctx.err);
1631
- }
1632
- }
1633
-
1634
- export async function cmdKill(
1635
- slug: string | undefined,
1636
- options: DeployCliOptions,
1637
- ): Promise<number> {
1638
- if (slug === undefined || slug === "") {
1639
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1640
- `Usage: ${CLI} kill <slug> [--team <id>] [--json]\n`,
1641
- );
1642
- return 1;
1643
- }
1644
- const ctx = await prepare(options);
1645
- if (typeof ctx === "number") {
1646
- return ctx;
1647
- }
1648
- let accepted: AgentkitStopAccepted;
1649
- try {
1650
- accepted = await ctx.client.killAgentkit({ teamId: ctx.teamId, slug });
1651
- } catch (error) {
1652
- return renderApiError(error, ctx.err);
1653
- }
1654
- if (ctx.json) {
1655
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1656
- } else {
1657
- ctx.out(
1658
- accepted.scope === "global"
1659
- ? `Killed ${slug} across all tenants (team ${ctx.teamId}): deploys locked, admission stopped.\n`
1660
- : `Killed ${slug} (team ${ctx.teamId}): deploys locked, admission stopped.\n`,
1661
- );
1662
- ctx.out(
1663
- `Resume traffic with \`${CLI} unlock-deploys ${slug}\` then \`${CLI} start ${slug}\`.\n`,
1664
- );
1665
- ctx.out(`Unlock deploys with \`${CLI} unlock-deploys ${slug}\`.\n`);
1666
- }
1667
- if (accepted.cancellation !== undefined) {
1668
- return writeCancellationStarted(ctx, accepted.cancellation, slug);
1669
- }
1670
- return 0;
1671
- }
1672
-
1673
- export async function cmdUnlockDeploys(
1674
- slug: string | undefined,
1675
- options: DeployCliOptions,
1676
- ): Promise<number> {
1677
- if (slug === undefined || slug === "") {
1678
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1679
- `Usage: ${CLI} unlock-deploys <slug> [--team <id>] [--json]\n`,
1680
- );
1681
- return 1;
1682
- }
1683
- const ctx = await prepare(options);
1684
- if (typeof ctx === "number") {
1685
- return ctx;
1686
- }
1687
- try {
1688
- const accepted = await ctx.client.unlockAgentkitDeploys({
1689
- teamId: ctx.teamId,
1690
- slug,
1691
- });
1692
- if (ctx.json) {
1693
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1694
- } else {
1695
- ctx.out(`Unlocked deploys for ${slug} (team ${ctx.teamId}).\n`);
1696
- }
1697
- return 0;
1698
- } catch (error) {
1699
- return renderApiError(error, ctx.err);
1700
- }
1701
- }
1702
-
1703
- export async function cmdCancelRuns(
1704
- slug: string | undefined,
1705
- options: DeployCliOptions,
1706
- ): Promise<number> {
1707
- if (slug === undefined || slug === "") {
1708
- (options.err ?? ((text: string) => void process.stderr.write(text)))(
1709
- `Usage: ${CLI} cancel-runs <slug> [--team <id>] [--json]\n`,
1710
- );
1711
- return 1;
1712
- }
1713
- const ctx = await prepare(options);
1714
- if (typeof ctx === "number") {
1715
- return ctx;
1716
- }
1717
- let result: AgentkitCancelRunsResult;
1718
- try {
1719
- result = await ctx.client.cancelAgentkitRuns({
1720
- teamId: ctx.teamId,
1721
- slug,
1722
- });
1723
- } catch (error) {
1724
- return renderApiError(error, ctx.err);
1725
- }
1726
- if (ctx.json) {
1727
- ctx.out(`${JSON.stringify(result, null, 2)}\n`);
1728
- } else {
1729
- ctx.out(`Started cancellation across ${result.batchesStarted} deployment batch(es).\n`);
1730
- if (result.sessionsMarkedFailed !== undefined) {
1731
- ctx.out(`Marked ${result.sessionsMarkedFailed} factory session(s) failed.\n`);
1732
- }
1733
- }
1734
- if (result.failed > 0) {
1735
- ctx.err(`Failed to start ${result.failed} cancellation batch(es).\n`);
1736
- return 1;
1737
- }
1738
- return 0;
1739
- }
1740
-
1741
- // ============================================================================
1742
- // event-repos <slug> --repo <owner/name>...
1743
- // ============================================================================
1744
-
1745
- export async function cmdEventRepos(
1746
- slug: string | undefined,
1747
- repositories: string[],
1748
- options: DeployCliOptions,
1749
- ): Promise<number> {
1750
- if (slug === undefined || slug === "") {
1751
- (options.err ?? ((text: string) => void process.stderr.write(text)))(
1752
- `Usage: ${CLI} event-repos <slug> --repo <owner/name>... [--team <id>] [--json]\n`,
1753
- );
1754
- return 1;
1755
- }
1756
- const ctx = await prepare(options);
1757
- if (typeof ctx === "number") {
1758
- return ctx;
1759
- }
1760
- let configured: string[];
1761
- try {
1762
- configured = await ctx.client.setAgentkitEventRepositories({
1763
- teamId: ctx.teamId,
1764
- slug,
1765
- repositories,
1766
- });
1767
- } catch (error) {
1768
- return renderApiError(error, ctx.err);
1769
- }
1770
- if (ctx.json) {
1771
- ctx.out(`${JSON.stringify({ repositories: configured }, null, 2)}\n`);
1772
- } else if (configured.length === 0) {
1773
- ctx.out(`${slug} now watches no repositories.\n`);
1774
- } else {
1775
- ctx.out(`${slug} now watches ${configured.join(", ")}.\n`);
1776
- }
1777
- return 0;
1778
- }
1779
-
1780
- // ============================================================================
1781
- // upgrade <slug>
1782
- // ============================================================================
1783
-
1784
- /** Release ids are uuids; anything else the user typed is a version. */
1785
- const RELEASE_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1786
-
1787
- export async function cmdUpgrade(
1788
- args: { slug: string | undefined; release: string | undefined },
1789
- options: DeployCliOptions,
1790
- ): Promise<number> {
1791
- const { slug, release } = args;
1792
- if (slug === undefined || slug === "") {
1793
- (options.err ?? ((text: string) => void process.stderr.write(text)))(
1794
- `Usage: ${CLI} upgrade <slug> [--release <id|version>] [--team <id>] [--json]\n`,
1795
- );
1796
- return 1;
1797
- }
1798
- const ctx = await prepare(options);
1799
- if (typeof ctx === "number") {
1800
- return ctx;
1801
- }
1802
- const selector = release?.trim() ?? "";
1803
- let releaseId: string;
1804
- try {
1805
- releaseId = await ctx.client.upgradeAgentkitInstall({
1806
- teamId: ctx.teamId,
1807
- slug,
1808
- ...(selector === ""
1809
- ? {}
1810
- : RELEASE_ID_RE.test(selector)
1811
- ? { releaseId: selector }
1812
- : { version: selector }),
1813
- });
1814
- } catch (error) {
1815
- return renderApiError(error, ctx.err);
1816
- }
1817
- if (ctx.json) {
1818
- ctx.out(`${JSON.stringify({ releaseId }, null, 2)}\n`);
1819
- } else {
1820
- ctx.out(`${slug} now runs release ${releaseId}.\n`);
1821
- }
1822
- return 0;
1823
- }
1824
-
1825
- // ============================================================================
1826
- // delete <slug>
1827
- // ============================================================================
1828
-
1829
- export async function cmdDelete(
1830
- slug: string | undefined,
1831
- options: DeployCliOptions,
1832
- ): Promise<number> {
1833
- if (slug === undefined || slug === "") {
1834
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1835
- `Usage: ${CLI} delete <slug> [--team <id>] [--json] [--no-wait]\n`,
1836
- );
1837
- return 1;
1838
- }
1839
- const ctx = await prepare(options);
1840
- if (typeof ctx === "number") {
1841
- return ctx;
1842
- }
1843
- // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
1844
- // DELETE goes first. A v2 404 (missing slug, or an older backend)
1845
- // falls through to the v1 agent-serve delete.
1846
- let architecture: "v1" | "v2" = "v2";
1847
- let accepted: DeleteAccepted | AgentkitStopAccepted;
1848
- try {
1849
- accepted = await ctx.client.deleteAgentkit({ teamId: ctx.teamId, slug });
1850
- } catch (error) {
1851
- if (!(error instanceof DeployApiError) || error.status !== 404) {
1852
- return renderApiError(error, ctx.err);
1853
- }
1854
- try {
1855
- accepted = await ctx.client.deleteDeployment({
1856
- teamId: ctx.teamId,
1857
- slug,
1858
- });
1859
- architecture = "v1";
1860
- } catch (v1Error) {
1861
- return renderApiError(v1Error, ctx.err);
1862
- }
1863
- }
1864
- if (ctx.noWait) {
1865
- if (ctx.json) {
1866
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1867
- } else {
1868
- ctx.out(`Delete accepted for ${slug} (status: ${accepted.status}).\n`);
1869
- }
1870
- return 0;
1871
- }
1872
- try {
1873
- await pollUntilGone(ctx, slug, () =>
1874
- architecture === "v2"
1875
- ? ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug })
1876
- : ctx.client.getDeployment({ teamId: ctx.teamId, slug }),
1877
- );
1878
- } catch (error) {
1879
- return renderApiError(error, ctx.err);
1880
- }
1881
- if (ctx.json) {
1882
- ctx.out(`${JSON.stringify({ slug, status: "deleted" }, null, 2)}\n`);
1883
- } else {
1884
- ctx.out(`Deleted ${slug} (team ${ctx.teamId}).\n`);
1885
- }
1886
- return 0;
1887
- }
1888
-
1889
- // ============================================================================
1890
- // rotate-token <slug>
1891
- // ============================================================================
1892
-
1893
- export async function cmdRotateToken(
1894
- slug: string | undefined,
1895
- options: DeployCliOptions,
1896
- ): Promise<number> {
1897
- if (slug === undefined || slug === "") {
1898
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
1899
- `Usage: ${CLI} rotate-token <slug> [--team <id>]\n`,
1900
- );
1901
- return 1;
1902
- }
1903
- const ctx = await prepare(options);
1904
- if (typeof ctx === "number") {
1905
- return ctx;
1906
- }
1907
- let aliasToken: string;
1908
- try {
1909
- const architecture = await deploymentArchitecture({
1910
- client: ctx.client,
1911
- teamId: ctx.teamId,
1912
- slug,
1913
- });
1914
- aliasToken =
1915
- architecture === "v2"
1916
- ? await ctx.client.rotateAgentsdkAliasToken({
1917
- teamId: ctx.teamId,
1918
- slug,
1919
- })
1920
- : await ctx.client.rotateAliasToken({
1921
- teamId: ctx.teamId,
1922
- slug,
1923
- });
1924
- } catch (error) {
1925
- return renderApiError(error, ctx.err);
1926
- }
1927
- if (ctx.json) {
1928
- ctx.out(`${JSON.stringify({ aliasToken }, null, 2)}\n`);
1929
- return 0;
1930
- }
1931
- ctx.out(
1932
- `Rotated the alias token for ${slug}. The old token stopped working immediately.\n${aliasTokenBlock(aliasToken)}`,
1933
- );
1934
- return 0;
1935
- }
1936
-
1937
- // ============================================================================
1938
- // secrets set|list|unset
1939
- // ============================================================================
1940
-
1941
- async function secretDeploymentArchitecture(
1942
- ctx: DeployCliContext,
1943
- slug: string,
1944
- ): Promise<"v1" | "v2"> {
1945
- return deploymentArchitecture({
1946
- client: ctx.client,
1947
- teamId: ctx.teamId,
1948
- slug,
1949
- });
1950
- }
1951
-
1952
- export async function cmdSecretsSet(
1953
- slug: string | undefined,
1954
- specs: string[],
1955
- options: DeployCliOptions,
1956
- ): Promise<number> {
1957
- const usageErr = options.err ?? ((t: string) => void process.stderr.write(t));
1958
- if (slug === undefined || slug === "" || specs.length === 0) {
1959
- usageErr(
1960
- `Usage: ${CLI} secrets set <slug> NAME [NAME2 ...] [--team <id>] [--json]\n` +
1961
- ` Enter values at the hidden prompt, or pipe one line per NAME.\n` +
1962
- ` Opt-in (leaks into argv / agent terminals): NAME=VALUE … --from-argv\n`,
1963
- );
1964
- return 1;
1965
- }
1966
-
1967
- // Parse and validate every name before prompting for any value, so a
1968
- // typo in the last name cannot waste typed-in secrets.
1969
- const parsed: Array<{ name: string; value?: string }> = [];
1970
- for (const spec of specs) {
1971
- const eq = spec.indexOf("=");
1972
- const name = eq === -1 ? spec : spec.slice(0, eq);
1973
- const nameError = validateSettableSecretName(name);
1974
- if (nameError !== undefined) {
1975
- usageErr(`${nameError}\n`);
1976
- return 1;
1977
- }
1978
- parsed.push(eq === -1 ? { name } : { name, value: spec.slice(eq + 1) });
1979
- }
1980
- const hasArgvValues = parsed.some(entry => entry.value !== undefined);
1981
- if (hasArgvValues && options.fromArgv !== true) {
1982
- usageErr(
1983
- `Refusing NAME=VALUE on argv (shows up in shell history and agent-captured terminals).\n` +
1984
- `Pass names only:\n` +
1985
- ` ${CLI} secrets set ${slug} NAME\n` +
1986
- `Hidden prompt on a TTY; one stdin line per NAME when piped.\n` +
1987
- `Or redirect a file: ${CLI} secrets set ${slug} NAME < ./secret.txt\n`,
1988
- );
1989
- return 1;
1990
- }
1991
- if (hasArgvValues) {
1992
- usageErr(
1993
- `warning: --from-argv puts secret values in argv (shell history and agent-captured terminals).\n`,
1994
- );
1995
- }
1996
-
1997
- const ctx = await prepare(options);
1998
- if (typeof ctx === "number") {
1999
- return ctx;
2000
- }
2001
-
2002
- const stdin = options.stdin ?? process.stdin;
2003
- const readValue = createSecretValueReader(stdin, ctx.err);
2004
- const secrets: Array<{ name: string; value: string }> = [];
2005
- for (const entry of parsed) {
2006
- secrets.push({
2007
- name: entry.name,
2008
- value: entry.value ?? (await readValue(entry.name)),
2009
- });
2010
- }
2011
-
2012
- let secretNames: string[];
2013
- let architecture: "v1" | "v2";
2014
- try {
2015
- architecture = await secretDeploymentArchitecture(ctx, slug);
2016
- secretNames =
2017
- architecture === "v2"
2018
- ? await ctx.client.setAgentkitSecrets({
2019
- teamId: ctx.teamId,
2020
- slug,
2021
- secrets,
2022
- })
2023
- : await ctx.client.setSecrets({
2024
- teamId: ctx.teamId,
2025
- slug,
2026
- secrets,
2027
- });
2028
- } catch (error) {
2029
- return renderApiError(error, ctx.err);
2030
- }
2031
- if (ctx.json) {
2032
- ctx.out(`${JSON.stringify({ secretNames }, null, 2)}\n`);
2033
- return 0;
2034
- }
2035
- ctx.out(
2036
- `Set ${secrets.length} secret${secrets.length === 1 ? "" : "s"} on ${slug}.\n` +
2037
- `Secrets now set: ${secretNames.join(", ")}\n` +
2038
- (architecture === "v2"
2039
- ? `The next task picks them up; no redeploy is required.\n`
2040
- : `The engine picks them up on its next deploy.\n`),
2041
- );
2042
- return 0;
2043
- }
2044
-
2045
- export async function cmdSecretsList(
2046
- slug: string | undefined,
2047
- options: DeployCliOptions,
2048
- ): Promise<number> {
2049
- if (slug === undefined || slug === "") {
2050
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
2051
- `Usage: ${CLI} secrets list <slug> [--team <id>] [--json]\n`,
2052
- );
2053
- return 1;
2054
- }
2055
- const ctx = await prepare(options);
2056
- if (typeof ctx === "number") {
2057
- return ctx;
2058
- }
2059
- let secrets: SecretInfo[];
2060
- try {
2061
- const architecture = await secretDeploymentArchitecture(ctx, slug);
2062
- secrets =
2063
- architecture === "v2"
2064
- ? await ctx.client.listAgentkitSecrets({ teamId: ctx.teamId, slug })
2065
- : await ctx.client.listSecrets({ teamId: ctx.teamId, slug });
2066
- } catch (error) {
2067
- return renderApiError(error, ctx.err);
2068
- }
2069
- if (ctx.json) {
2070
- ctx.out(`${JSON.stringify({ secrets }, null, 2)}\n`);
2071
- return 0;
2072
- }
2073
- if (secrets.length === 0) {
2074
- ctx.out(`No secrets set on ${slug}. Add one with \`${CLI} secrets set ${slug} NAME\`.\n`);
2075
- return 0;
2076
- }
2077
- ctx.out(
2078
- `${renderTable(
2079
- ["NAME", "CREATED"],
2080
- secrets.map(secret => [secret.name, secret.createdAt]),
2081
- )}\n`,
2082
- );
2083
- return 0;
2084
- }
2085
-
2086
- export async function cmdSecretsUnset(
2087
- slug: string | undefined,
2088
- name: string | undefined,
2089
- options: DeployCliOptions,
2090
- ): Promise<number> {
2091
- if (slug === undefined || slug === "" || name === undefined || name === "") {
2092
- (options.err ?? ((t: string) => void process.stderr.write(t)))(
2093
- `Usage: ${CLI} secrets unset <slug> NAME [--team <id>]\n`,
2094
- );
2095
- return 1;
2096
- }
2097
- const ctx = await prepare(options);
2098
- if (typeof ctx === "number") {
2099
- return ctx;
2100
- }
2101
- try {
2102
- const architecture = await secretDeploymentArchitecture(ctx, slug);
2103
- if (architecture === "v2") {
2104
- await ctx.client.deleteAgentkitSecret({
2105
- teamId: ctx.teamId,
2106
- slug,
2107
- name,
2108
- });
2109
- } else {
2110
- await ctx.client.deleteSecret({ teamId: ctx.teamId, slug, name });
2111
- }
2112
- } catch (error) {
2113
- if (error instanceof DeployApiError && error.status === 404) {
2114
- ctx.err(
2115
- `No secret named ${name} on deployment ${slug} — check \`${CLI} secrets list ${slug}\` (and the slug / --team).\n`,
2116
- );
2117
- return 1;
2118
- }
2119
- return renderApiError(error, ctx.err);
2120
- }
2121
- if (ctx.json) {
2122
- ctx.out(`${JSON.stringify({ removed: name }, null, 2)}\n`);
2123
- } else {
2124
- ctx.out(`Removed secret ${name} from ${slug}.\n`);
2125
- }
2126
- return 0;
2127
- }
2128
-
2129
- /**
2130
- * Returns a reader for interactive secret values: hidden (no-echo) prompt
2131
- * when `stdin` is a TTY, otherwise one line per secret from the piped
2132
- * stream. One reader per command so piped lines are consumed in order.
2133
- */
2134
- function createSecretValueReader(
2135
- stdin: SecretInputStream,
2136
- err: (text: string) => void,
2137
- ): (name: string) => Promise<string> {
2138
- if (stdin.isTTY === true) {
2139
- return name => promptHidden(stdin, err, `Value for ${name}: `);
2140
- }
2141
- const readLine = createLineReader(stdin);
2142
- return async name => {
2143
- const line = await readLine();
2144
- if (line === undefined) {
2145
- throw new DeployApiError(
2146
- `stdin ended before a value for ${name} was provided (pipe one line per secret).`,
2147
- 0,
2148
- );
2149
- }
2150
- return line;
2151
- };
2152
- }
2153
-
2154
- /** Longest mask run drawn while typing a secret; the count carries the rest. */
2155
- const SECRET_MASK_MAX_WIDTH = 24;
2156
-
2157
- /**
2158
- * One line of typing feedback for the hidden prompt. Echoing the value would
2159
- * leak it, so the line carries a bounded mask plus the exact character count —
2160
- * enough to see that keystrokes, backspaces, and pasted values landed. The
2161
- * mask is clamped to the terminal width so the redraw stays on one line.
2162
- */
2163
- function renderSecretPromptLine(
2164
- prompt: string,
2165
- length: number,
2166
- dim: (text: string) => string,
2167
- ): string {
2168
- const count = `${length} char${length === 1 ? "" : "s"}`;
2169
- const room = (process.stderr.columns ?? 80) - prompt.length - count.length - 2;
2170
- const maskWidth = Math.max(0, Math.min(length, SECRET_MASK_MAX_WIDTH, room));
2171
- // `·` over `•`: the rest of the CLI's progress output already uses it, and
2172
- // fonts that ship no bullet glyph draw a tofu box in its place.
2173
- const mask = "·".repeat(maskWidth);
2174
- const body = mask === "" ? count : `${mask} ${count}`;
2175
- return `\r\u001b[2K${prompt}${dim(body)}`;
2176
- }
2177
-
2178
- /**
2179
- * Raw-mode hidden prompt: never echoes the value, redraws a mask + character
2180
- * count as it is typed, supports backspace and Ctrl-C.
2181
- */
2182
- function promptHidden(
2183
- stdin: SecretInputStream,
2184
- err: (text: string) => void,
2185
- prompt: string,
2186
- ): Promise<string> {
2187
- return new Promise((resolvePromise, reject) => {
2188
- const { dim } = stderrPalette();
2189
- let value = "";
2190
- const draw = (): void => {
2191
- err(renderSecretPromptLine(prompt, value.length, dim));
2192
- };
2193
- draw();
2194
- stdin.setRawMode?.(true);
2195
- stdin.resume();
2196
- const cleanup = (): void => {
2197
- stdin.off("data", onData);
2198
- stdin.setRawMode?.(false);
2199
- stdin.pause();
2200
- draw();
2201
- err("\n");
2202
- };
2203
- const onData = (chunk: Buffer | string): void => {
2204
- const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
2205
- for (const ch of text) {
2206
- if (ch === "\r" || ch === "\n") {
2207
- cleanup();
2208
- resolvePromise(value);
2209
- return;
2210
- }
2211
- if (ch === "\u0003") {
2212
- cleanup();
2213
- reject(new DeployApiError("Aborted.", 0));
2214
- return;
2215
- }
2216
- if (ch === "\u007f" || ch === "\b") {
2217
- value = value.slice(0, -1);
2218
- continue;
2219
- }
2220
- value += ch;
2221
- }
2222
- // One redraw per chunk keeps a pasted value from flooding the terminal.
2223
- draw();
2224
- };
2225
- stdin.on("data", onData);
2226
- });
2227
- }
2228
-
2229
- /** Buffered line reader over a piped stream; undefined once it ends. */
2230
- export function createLineReader(stream: NodeJS.ReadableStream): () => Promise<string | undefined> {
2231
- let buffer = "";
2232
- let ended = false;
2233
- const waiters: Array<(line: string | undefined) => void> = [];
2234
-
2235
- const drain = (): void => {
2236
- while (waiters.length > 0) {
2237
- const newline = buffer.indexOf("\n");
2238
- if (newline !== -1) {
2239
- const line = buffer.slice(0, newline).replace(/\r$/, "");
2240
- buffer = buffer.slice(newline + 1);
2241
- waiters.shift()?.(line);
2242
- continue;
2243
- }
2244
- if (!ended) {
2245
- return;
2246
- }
2247
- // Stream ended: a trailing unterminated line still counts once.
2248
- const rest = buffer;
2249
- buffer = "";
2250
- waiters.shift()?.(rest === "" ? undefined : rest.replace(/\r$/, ""));
2251
- }
2252
- };
2253
-
2254
- stream.on("data", (chunk: Buffer | string) => {
2255
- buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
2256
- drain();
2257
- });
2258
- stream.on("end", () => {
2259
- ended = true;
2260
- drain();
2261
- });
2262
- stream.resume();
2263
-
2264
- return () =>
2265
- new Promise(resolvePromise => {
2266
- waiters.push(resolvePromise);
2267
- drain();
2268
- });
2269
- }
2270
-
2271
- // ============================================================================
2272
- // Polling + rendering helpers
2273
- // ============================================================================
2274
-
2275
- /**
2276
- * Poll deployment status every `pollIntervalMs` until it lands in
2277
- * `terminal` (single-line progress on a TTY, one line per transition
2278
- * otherwise). Prefers customer `statusMessage` / `progress` over raw
2279
- * status so create → checkout → start is visible. Throws DeployApiError
2280
- * on request failures or timeout.
2281
- */
2282
- async function pollUntil<
2283
- T extends {
2284
- status: string;
2285
- progress?: DeploymentProgress;
2286
- statusMessage?: string | null;
2287
- },
2288
- >(
2289
- ctx: DeployCliContext,
2290
- slug: string,
2291
- terminal: ReadonlySet<T["status"]>,
2292
- fetchDetail: () => Promise<T>,
2293
- ): Promise<T> {
2294
- const startedAt = Date.now();
2295
- const tty = process.stderr.isTTY === true;
2296
- let lastLabel: string | undefined;
2297
- let sawProgress = false;
2298
-
2299
- const report = (detail: T): void => {
2300
- if (ctx.json) {
2301
- return;
2302
- }
2303
- const label = deployProgressLabel(detail);
2304
- const elapsed = Math.round((Date.now() - startedAt) / 1000);
2305
- if (tty) {
2306
- ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
2307
- sawProgress = true;
2308
- } else if (label !== lastLabel) {
2309
- ctx.err(`${slug}: ${label}\n`);
2310
- }
2311
- lastLabel = label;
2312
- };
2313
- const finishProgressLine = (): void => {
2314
- if (tty && sawProgress) {
2315
- ctx.err("\n");
2316
- }
2317
- };
2318
-
2319
- for (;;) {
2320
- let detail: T;
2321
- try {
2322
- detail = await fetchDetail();
2323
- } catch (error: unknown) {
2324
- // Capacity / rate-limit on GET is not a bake failure. The v2 accept
2325
- // already started freeze; keep polling until the wait budget expires.
2326
- if (isTransientDeployStatusError(error) && Date.now() - startedAt < ctx.timeoutMs) {
2327
- if (!ctx.json) {
2328
- const elapsed = Math.round((Date.now() - startedAt) / 1000);
2329
- const label = "Waiting for status (server busy)";
2330
- if (tty) {
2331
- ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
2332
- sawProgress = true;
2333
- } else if (label !== lastLabel) {
2334
- ctx.err(`${slug}: ${label}\n`);
2335
- }
2336
- lastLabel = label;
2337
- }
2338
- const waitMs = transientDeployStatusWaitMs(error, ctx.pollIntervalMs);
2339
- const remaining = ctx.timeoutMs - (Date.now() - startedAt);
2340
- await sleep(Math.max(0, Math.min(waitMs, remaining)));
2341
- continue;
2342
- }
2343
- finishProgressLine();
2344
- throw error;
2345
- }
2346
- report(detail);
2347
- if (terminal.has(detail.status)) {
2348
- finishProgressLine();
2349
- return detail;
2350
- }
2351
- if (Date.now() - startedAt >= ctx.timeoutMs) {
2352
- finishProgressLine();
2353
- const last = deployProgressLabel(detail);
2354
- throw new DeployApiError(
2355
- `Timed out after ${Math.round(ctx.timeoutMs / 1000)}s waiting for ${slug} (last: ${last}). It may still converge — check \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.`,
2356
- 0,
2357
- );
2358
- }
2359
- await sleep(ctx.pollIntervalMs);
2360
- }
2361
- }
2362
-
2363
- /** Load-shed / rate-limit on status GET — the deploy itself may still be baking. */
2364
- function isTransientDeployStatusError(error: unknown): error is DeployApiError {
2365
- return error instanceof DeployApiError && (error.status === 503 || error.status === 429);
2366
- }
2367
-
2368
- function transientDeployStatusWaitMs(error: DeployApiError, pollIntervalMs: number): number {
2369
- if (
2370
- error.status === 429 &&
2371
- error.retryAfterSeconds !== undefined &&
2372
- error.retryAfterSeconds > 0
2373
- ) {
2374
- return Math.max(pollIntervalMs, error.retryAfterSeconds * 1000);
2375
- }
2376
- return pollIntervalMs;
2377
- }
2378
-
2379
- /**
2380
- * Wait until GET 404s (the delete reconciler purged the record). Treats
2381
- * other errors as failures. Throws DeployApiError on timeout.
2382
- */
2383
- async function pollUntilGone(
2384
- ctx: DeployCliContext,
2385
- slug: string,
2386
- getDetail: () => Promise<{
2387
- status: string;
2388
- progress?: DeploymentProgress;
2389
- statusMessage?: string | null;
2390
- }>,
2391
- ): Promise<void> {
2392
- const startedAt = Date.now();
2393
- const tty = process.stderr.isTTY === true;
2394
- let sawProgress = false;
2395
- const report = (label: string): void => {
2396
- if (ctx.json) {
2397
- return;
2398
- }
2399
- const elapsed = Math.round((Date.now() - startedAt) / 1000);
2400
- if (tty) {
2401
- ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
2402
- sawProgress = true;
2403
- }
2404
- };
2405
- const finishProgressLine = (): void => {
2406
- if (tty && sawProgress) {
2407
- ctx.err("\n");
2408
- }
2409
- };
2410
-
2411
- for (;;) {
2412
- try {
2413
- const detail = await getDetail();
2414
- report(deployProgressLabel(detail));
2415
- } catch (error: unknown) {
2416
- if (error instanceof DeployApiError && error.status === 404) {
2417
- finishProgressLine();
2418
- return;
2419
- }
2420
- finishProgressLine();
2421
- throw error;
2422
- }
2423
- if (Date.now() - startedAt >= ctx.timeoutMs) {
2424
- finishProgressLine();
2425
- throw new DeployApiError(
2426
- `Timed out after ${Math.round(ctx.timeoutMs / 1000)}s waiting for ${slug} to disappear. It may still be deleting — check \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.`,
2427
- 0,
2428
- );
2429
- }
2430
- await sleep(ctx.pollIntervalMs);
2431
- }
2432
- }
2433
-
2434
- function aliasTokenBlock(aliasToken: string): string {
2435
- return (
2436
- `\n Alias token (shown ONCE — save it now, it cannot be retrieved again):\n\n` +
2437
- ` ${aliasToken}\n\n` +
2438
- ` Send it as the X-Agent-Alias-Token header on requests to the alias URL,\n` +
2439
- ` or paste it into the hosted playground (<alias>/playground) sign-in gate.\n` +
2440
- ` Lost tokens: \`${CLI} rotate-token <slug>\` mints a replacement.\n\n`
2441
- );
2442
- }
2443
-
2444
- /**
2445
- * `: <reason>` suffix for a deploy that ended in a non-running state, or
2446
- * empty when the control plane recorded no reason.
2447
- */
2448
- function deployFailureDetail(lastError: string | null | undefined): string {
2449
- if (lastError === null || lastError === undefined || lastError.trim() === "") {
2450
- return "";
2451
- }
2452
- return `: ${sanitizeCustomerError(lastError.trim())}`;
2453
- }
2454
-
2455
- export function renderApiError(
2456
- error: unknown,
2457
- err: (text: string) => void,
2458
- context?: { multiTenant?: boolean; teamId?: number },
2459
- ): number {
2460
- if (error instanceof DeployApiError) {
2461
- err(`${error.message}\n`);
2462
- if (error.status === 409 && error.message.includes("application multiTenant does not match")) {
2463
- if (context?.multiTenant === true) {
2464
- err("This slug is a single-tenant application. Redeploy it without --multi-tenant.\n");
2465
- } else if (context?.teamId === MULTI_TENANT_HTTP_DEPLOY_TEAM_ID) {
2466
- err(
2467
- "This slug is a Cursor-managed (multi-tenant) product. Redeploy it with --multi-tenant.\n",
2468
- );
2469
- }
2470
- }
2471
- return 1;
2472
- }
2473
- throw error;
2474
- }
2475
-
2476
- export function renderTable(header: string[], rows: string[][]): string {
2477
- const widths = header.map((h, i) =>
2478
- Math.max(h.length, ...rows.map(row => (row[i] ?? "").length)),
2479
- );
2480
- const renderRow = (row: string[]): string =>
2481
- row
2482
- .map((cell, i) => cell.padEnd(widths[i] ?? 0))
2483
- .join(" ")
2484
- .trimEnd();
2485
- return [renderRow(header), ...rows.map(renderRow)].join("\n");
2486
- }