@cursor/bdk 0.2.9 → 0.2.11

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 (569) hide show
  1. package/dist/artifacts.js +3 -5
  2. package/dist/bin/agent-serve.js +803 -812
  3. package/dist/channels/bitbucket/api.js +305 -321
  4. package/dist/channels/bitbucket/binding.js +97 -61
  5. package/dist/channels/bitbucket/bitbucket-channel.d.ts +15 -1
  6. package/dist/channels/bitbucket/bitbucket-channel.d.ts.map +1 -1
  7. package/dist/channels/bitbucket/bitbucket-channel.js +95 -42
  8. package/dist/channels/bitbucket/bitbucket-webhook.d.ts +11 -0
  9. package/dist/channels/bitbucket/bitbucket-webhook.d.ts.map +1 -1
  10. package/dist/channels/bitbucket/bitbucket-webhook.js +214 -204
  11. package/dist/channels/bitbucket/checks.js +9 -21
  12. package/dist/channels/bitbucket/cursor-account.js +1 -1
  13. package/dist/channels/bitbucket/defaults.js +14 -4
  14. package/dist/channels/bitbucket/events.js +1 -2
  15. package/dist/channels/bitbucket/index.d.ts +6 -2
  16. package/dist/channels/bitbucket/index.d.ts.map +1 -1
  17. package/dist/channels/bitbucket/index.js +6 -2
  18. package/dist/channels/bitbucket/replay.js +80 -56
  19. package/dist/channels/bitbucket/state.js +16 -7
  20. package/dist/channels/bitbucket/types.d.ts +11 -2
  21. package/dist/channels/bitbucket/types.d.ts.map +1 -1
  22. package/dist/channels/checks.js +18 -28
  23. package/dist/channels/deployments/deployments-channel.js +26 -34
  24. package/dist/channels/github/api.js +216 -210
  25. package/dist/channels/github/auth.d.ts +5 -1
  26. package/dist/channels/github/auth.d.ts.map +1 -1
  27. package/dist/channels/github/auth.js +157 -174
  28. package/dist/channels/github/binding.js +48 -39
  29. package/dist/channels/github/checks.js +9 -14
  30. package/dist/channels/github/cursor-account.js +6 -11
  31. package/dist/channels/github/defaults.js +105 -130
  32. package/dist/channels/github/forward.js +13 -17
  33. package/dist/channels/github/github-channel.d.ts +43 -2
  34. package/dist/channels/github/github-channel.d.ts.map +1 -1
  35. package/dist/channels/github/github-channel.js +1228 -958
  36. package/dist/channels/github/progress.js +145 -146
  37. package/dist/channels/github/replay.js +30 -39
  38. package/dist/channels/github/state.js +40 -16
  39. package/dist/channels/github/types.d.ts +30 -6
  40. package/dist/channels/github/types.d.ts.map +1 -1
  41. package/dist/channels/gitlab/api.js +100 -114
  42. package/dist/channels/gitlab/binding.js +52 -33
  43. package/dist/channels/gitlab/checks.js +28 -29
  44. package/dist/channels/gitlab/cursor-account.js +1 -1
  45. package/dist/channels/gitlab/defaults.js +9 -3
  46. package/dist/channels/gitlab/gitlab-channel.d.ts +16 -1
  47. package/dist/channels/gitlab/gitlab-channel.d.ts.map +1 -1
  48. package/dist/channels/gitlab/gitlab-channel.js +95 -42
  49. package/dist/channels/gitlab/gitlab-webhook.d.ts +10 -1
  50. package/dist/channels/gitlab/gitlab-webhook.d.ts.map +1 -1
  51. package/dist/channels/gitlab/gitlab-webhook.js +282 -249
  52. package/dist/channels/gitlab/index.d.ts +6 -2
  53. package/dist/channels/gitlab/index.d.ts.map +1 -1
  54. package/dist/channels/gitlab/index.js +6 -2
  55. package/dist/channels/gitlab/replay.js +50 -27
  56. package/dist/channels/gitlab/state.js +14 -6
  57. package/dist/channels/gitlab/types.d.ts +13 -2
  58. package/dist/channels/gitlab/types.d.ts.map +1 -1
  59. package/dist/channels/origin/api.js +100 -116
  60. package/dist/channels/origin/binding.js +15 -16
  61. package/dist/channels/origin/checks.js +30 -28
  62. package/dist/channels/origin/defaults.js +50 -65
  63. package/dist/channels/origin/origin-channel.js +266 -272
  64. package/dist/channels/origin/origin-webhook.js +70 -88
  65. package/dist/channels/origin/reactions.js +9 -21
  66. package/dist/channels/origin/state.js +13 -5
  67. package/dist/channels/slack/agentic-delivery.js +426 -478
  68. package/dist/channels/slack/agentic-posted.js +9 -10
  69. package/dist/channels/slack/agentic-signals.js +2 -3
  70. package/dist/channels/slack/api.js +417 -427
  71. package/dist/channels/slack/approvals.js +1 -1
  72. package/dist/channels/slack/assistant.js +37 -47
  73. package/dist/channels/slack/attachments.js +188 -206
  74. package/dist/channels/slack/auth.js +8 -6
  75. package/dist/channels/slack/bot-mentions.js +31 -45
  76. package/dist/channels/slack/channel-watch.js +42 -48
  77. package/dist/channels/slack/cli-project.js +112 -137
  78. package/dist/channels/slack/code-fences.js +3 -5
  79. package/dist/channels/slack/constants.js +2 -2
  80. package/dist/channels/slack/credentials.js +23 -38
  81. package/dist/channels/slack/defaults.js +292 -331
  82. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  83. package/dist/channels/slack/dispatch.js +533 -460
  84. package/dist/channels/slack/doctor.js +200 -214
  85. package/dist/channels/slack/eval-directive.js +79 -96
  86. package/dist/channels/slack/event-id-dedupe.js +1 -1
  87. package/dist/channels/slack/external-policy.js +26 -39
  88. package/dist/channels/slack/footer.js +28 -41
  89. package/dist/channels/slack/inbound.d.ts +1 -0
  90. package/dist/channels/slack/inbound.d.ts.map +1 -1
  91. package/dist/channels/slack/inbound.js +50 -31
  92. package/dist/channels/slack/init.d.ts +1 -5
  93. package/dist/channels/slack/init.d.ts.map +1 -1
  94. package/dist/channels/slack/init.js +42 -59
  95. package/dist/channels/slack/interactive.d.ts +9 -3
  96. package/dist/channels/slack/interactive.d.ts.map +1 -1
  97. package/dist/channels/slack/interactive.js +160 -162
  98. package/dist/channels/slack/links.js +1 -2
  99. package/dist/channels/slack/live-delivery.js +172 -190
  100. package/dist/channels/slack/manifest.d.ts.map +1 -1
  101. package/dist/channels/slack/manifest.js +44 -23
  102. package/dist/channels/slack/message-body.js +2 -2
  103. package/dist/channels/slack/nudge-carrier.js +30 -42
  104. package/dist/channels/slack/nudge-store.js +164 -191
  105. package/dist/channels/slack/paint-start.js +66 -81
  106. package/dist/channels/slack/placeholder.js +123 -152
  107. package/dist/channels/slack/pr-ref.js +1 -1
  108. package/dist/channels/slack/progress-delivery.js +65 -78
  109. package/dist/channels/slack/reasoning-card.js +36 -49
  110. package/dist/channels/slack/recording-sink.js +12 -24
  111. package/dist/channels/slack/reply-options.js +7 -12
  112. package/dist/channels/slack/self-identity.js +27 -35
  113. package/dist/channels/slack/sender-name.d.ts +12 -3
  114. package/dist/channels/slack/sender-name.d.ts.map +1 -1
  115. package/dist/channels/slack/sender-name.js +57 -61
  116. package/dist/channels/slack/setup.js +2 -4
  117. package/dist/channels/slack/slack-channel.d.ts +6 -4
  118. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  119. package/dist/channels/slack/slack-channel.js +441 -308
  120. package/dist/channels/slack/socket-mode.js +38 -52
  121. package/dist/channels/slack/thread-context.js +143 -160
  122. package/dist/channels/slack/tool-approval-events.js +149 -166
  123. package/dist/channels/slack/tool-cards.js +6 -11
  124. package/dist/channels/slack/tool-chip.js +1 -2
  125. package/dist/channels/slack/types.d.ts +15 -17
  126. package/dist/channels/slack/types.d.ts.map +1 -1
  127. package/dist/channels/slack/upload.js +84 -97
  128. package/dist/channels/slack/user-info.js +27 -41
  129. package/dist/channels.js +9 -20
  130. package/dist/dashboard-session-url.js +3 -4
  131. package/dist/docs/404.html +2 -2
  132. package/dist/docs/assets/{app.BNhEdGa8.js → app.DXI7bwox.js} +4 -4
  133. package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.js → building-with-agents.md.Df87rAe1.js} +1 -1
  134. package/dist/docs/assets/chunks/@localSearchIndexroot.CtLtpWcx.js +1 -0
  135. package/dist/docs/assets/chunks/{VPLocalSearchBox.DIdUV1Ph.js → VPLocalSearchBox.BrbO5mEe.js} +1 -1
  136. package/dist/docs/assets/chunks/{arc.lELI4_SR.js → arc.BOG1yms8.js} +1 -1
  137. package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.iCMdvuoM.js → architectureDiagram-Q4EWVU46.C0hsMZnZ.js} +1 -1
  138. package/dist/docs/assets/chunks/{baseUniq.C1-nDJBf.js → baseUniq.H044KjKs.js} +1 -1
  139. package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.ClemzBox.js → blockDiagram-DXYQGD6D.BsRW6GoB.js} +1 -1
  140. package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.BqTak6cR.js → c4Diagram-AHTNJAMY.B9HV5PFR.js} +1 -1
  141. package/dist/docs/assets/chunks/channel.CBwrU9rP.js +1 -0
  142. package/dist/docs/assets/chunks/{chunk-4BX2VUAB.CUS3qs_R.js → chunk-4BX2VUAB.CPoT_ajl.js} +1 -1
  143. package/dist/docs/assets/chunks/{chunk-4TB4RGXK.dz5fdHcl.js → chunk-4TB4RGXK.DZBwWuCL.js} +1 -1
  144. package/dist/docs/assets/chunks/{chunk-55IACEB6.D6BEBmve.js → chunk-55IACEB6.CZ3yTiyq.js} +1 -1
  145. package/dist/docs/assets/chunks/{chunk-EDXVE4YY.B5uK4ID9.js → chunk-EDXVE4YY.6DfvHSd8.js} +1 -1
  146. package/dist/docs/assets/chunks/{chunk-FMBD7UC4.PgOJgNQs.js → chunk-FMBD7UC4.CpBj8HfK.js} +1 -1
  147. package/dist/docs/assets/chunks/{chunk-OYMX7WX6.CvkTrCii.js → chunk-OYMX7WX6.BdKo8YqS.js} +1 -1
  148. package/dist/docs/assets/chunks/{chunk-QZHKN3VN.BnSfKYsB.js → chunk-QZHKN3VN.BnXNyxJx.js} +1 -1
  149. package/dist/docs/assets/chunks/{chunk-YZCP3GAM.MZH6v5UC.js → chunk-YZCP3GAM.Cg1OcF8G.js} +1 -1
  150. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CbC_mrvB.js +1 -0
  151. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CbC_mrvB.js +1 -0
  152. package/dist/docs/assets/chunks/clone.BTvFyY1a.js +1 -0
  153. package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.BBbw_YZi.js → cose-bilkent-S5V4N54A.1SP8al9c.js} +1 -1
  154. package/dist/docs/assets/chunks/{dagre-KV5264BT.CNJB2l7E.js → dagre-KV5264BT.DS1L6hJt.js} +1 -1
  155. package/dist/docs/assets/chunks/{diagram-5BDNPKRD.BQzlnFfq.js → diagram-5BDNPKRD.ChsausbG.js} +1 -1
  156. package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.DkgqqZMz.js → diagram-G4DWMVQ6.3XsptNWj.js} +1 -1
  157. package/dist/docs/assets/chunks/{diagram-MMDJMWI5.DIT8L7H_.js → diagram-MMDJMWI5.DPA9Dk_P.js} +1 -1
  158. package/dist/docs/assets/chunks/{diagram-TYMM5635.3xLPZWGJ.js → diagram-TYMM5635.BVswXWrB.js} +1 -1
  159. package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.5_IHz8jF.js → erDiagram-SMLLAGMA.BSak5OSP.js} +1 -1
  160. package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.BGUCXz8A.js → flowDiagram-DWJPFMVM.CQgN4TTz.js} +1 -1
  161. package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.DbfFavS1.js → ganttDiagram-T4ZO3ILL.GrT0kA4a.js} +1 -1
  162. package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.D2yKdeNW.js → gitGraphDiagram-UUTBAWPF.CdS7Ucll.js} +1 -1
  163. package/dist/docs/assets/chunks/{graph.CSCxwHba.js → graph.BVqKRmRo.js} +1 -1
  164. package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.FDeb6xHY.js → infoDiagram-42DDH7IO.C3C9FRto.js} +1 -1
  165. package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DbeYs9VL.js → ishikawaDiagram-UXIWVN3A.2FuAh_Zj.js} +1 -1
  166. package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.CWjKINpx.js → journeyDiagram-VCZTEJTY.CaHMfK4b.js} +1 -1
  167. package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.B4FrAlwz.js → kanban-definition-6JOO6SKY.CjhIUwcA.js} +1 -1
  168. package/dist/docs/assets/chunks/{layout.DFGxQ9ab.js → layout.CGU3gfSf.js} +1 -1
  169. package/dist/docs/assets/chunks/{linear.BmjZ-G59.js → linear.DaihpW_n.js} +1 -1
  170. package/dist/docs/assets/chunks/{min.DZSxulMW.js → min.BS-j8kHQ.js} +1 -1
  171. package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.CHLi3-aN.js → mindmap-definition-QFDTVHPH.BVJ1Bbnk.js} +1 -1
  172. package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.DteG-CkU.js → pieDiagram-DEJITSTG.Cz1WIv9r.js} +1 -1
  173. package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D458ipN3.js → quadrantDiagram-34T5L4WZ.DKLFxcjy.js} +1 -1
  174. package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.DcFgUxst.js → requirementDiagram-MS252O5E.BHegiK7x.js} +1 -1
  175. package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.BwQAMmSA.js → sankeyDiagram-XADWPNL6.DYkY6yPc.js} +1 -1
  176. package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.B_Xdsrh9.js → sequenceDiagram-FGHM5R23.DYQ1QUrI.js} +1 -1
  177. package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.CdfDW6-C.js → stateDiagram-FHFEXIEX.Iru8BsFo.js} +1 -1
  178. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.BYXl4LW6.js +1 -0
  179. package/dist/docs/assets/chunks/{theme.sfdL3srp.js → theme.DaplWQhQ.js} +2 -2
  180. package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.56-4hXaC.js → timeline-definition-GMOUNBTQ.BwFA8hiX.js} +1 -1
  181. package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.CvZSQBO7.js → vennDiagram-DHZGUBPP.CZ60W1C_.js} +1 -1
  182. package/dist/docs/assets/chunks/{wardley-RL74JXVD.C9qc8k39.js → wardley-RL74JXVD.iXazD3Z7.js} +1 -1
  183. package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.D9s0nihi.js → wardleyDiagram-NUSXRM2D.B69D2r8-.js} +1 -1
  184. package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.BVJSpYrC.js → xychartDiagram-5P7HB3ND.CLPZEIU9.js} +1 -1
  185. package/dist/docs/assets/{deployment.md.BdqTiGdc.js → deployment.md.BYuEcDBv.js} +2 -2
  186. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.js → guides_bitbucket.md.CKUayYtD.js} +3 -3
  187. package/dist/docs/assets/{guides_bitbucket.md.BB6fqD-M.lean.js → guides_bitbucket.md.CKUayYtD.lean.js} +1 -1
  188. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.js → guides_github.md.TuNiZAOQ.js} +4 -4
  189. package/dist/docs/assets/{guides_github.md.Cr1Xlf-m.lean.js → guides_github.md.TuNiZAOQ.lean.js} +1 -1
  190. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.js → guides_gitlab.md.CtNI4fSH.js} +4 -4
  191. package/dist/docs/assets/{guides_gitlab.md.CMpmFi4M.lean.js → guides_gitlab.md.CtNI4fSH.lean.js} +1 -1
  192. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.js +7 -0
  193. package/dist/docs/assets/guides_migrate.md.sCAvvlC6.lean.js +1 -0
  194. package/dist/docs/assets/{reference_cli.md.GwugN3n-.js → reference_cli.md.dYCAL2lB.js} +4 -3
  195. package/dist/docs/assets/reference_cli.md.dYCAL2lB.lean.js +1 -0
  196. package/dist/docs/assets/troubleshooting.md.x-GBa7wN.js +1 -0
  197. package/dist/docs/assets/{troubleshooting.md.Bscj6ODe.lean.js → troubleshooting.md.x-GBa7wN.lean.js} +1 -1
  198. package/dist/docs/building-with-agents.html +37 -37
  199. package/dist/docs/building-with-agents.md +2 -0
  200. package/dist/docs/deployment.html +38 -38
  201. package/dist/docs/deployment.md +7 -0
  202. package/dist/docs/evals.html +36 -36
  203. package/dist/docs/guides/agent-to-agent.html +35 -35
  204. package/dist/docs/guides/bitbucket.html +38 -38
  205. package/dist/docs/guides/bitbucket.md +9 -1
  206. package/dist/docs/guides/cloud-agents.html +35 -35
  207. package/dist/docs/guides/convert-automation.html +35 -35
  208. package/dist/docs/guides/github.html +39 -39
  209. package/dist/docs/guides/github.md +20 -4
  210. package/dist/docs/guides/gitlab.html +38 -38
  211. package/dist/docs/guides/gitlab.md +9 -1
  212. package/dist/docs/guides/grokbot-agents.html +35 -35
  213. package/dist/docs/guides/hooks.html +35 -35
  214. package/dist/docs/guides/improve.html +35 -35
  215. package/dist/docs/guides/jev.html +35 -35
  216. package/dist/docs/guides/mcp-oauth.html +35 -35
  217. package/dist/docs/guides/migrate.html +66 -0
  218. package/dist/docs/guides/migrate.md +122 -0
  219. package/dist/docs/guides/opentelemetry.html +35 -35
  220. package/dist/docs/guides/slack.html +35 -35
  221. package/dist/docs/guides/webhooks.html +35 -35
  222. package/dist/docs/hashmap.json +1 -1
  223. package/dist/docs/hillclimbing.html +35 -35
  224. package/dist/docs/index.html +35 -35
  225. package/dist/docs/llms-full.txt +214 -6
  226. package/dist/docs/llms.txt +1 -0
  227. package/dist/docs/quickstart.html +35 -35
  228. package/dist/docs/reference/agent-config.html +35 -35
  229. package/dist/docs/reference/artifacts.html +35 -35
  230. package/dist/docs/reference/channels.html +35 -35
  231. package/dist/docs/reference/cli.html +39 -38
  232. package/dist/docs/reference/cli.md +39 -0
  233. package/dist/docs/reference/connections.html +35 -35
  234. package/dist/docs/reference/evals.html +35 -35
  235. package/dist/docs/reference/extensions.html +35 -35
  236. package/dist/docs/reference/hooks.html +35 -35
  237. package/dist/docs/reference/http-api.html +35 -35
  238. package/dist/docs/reference/instructions.html +35 -35
  239. package/dist/docs/reference/playground.html +35 -35
  240. package/dist/docs/reference/project-layout.html +35 -35
  241. package/dist/docs/reference/prompt.html +35 -35
  242. package/dist/docs/reference/schedules.html +35 -35
  243. package/dist/docs/reference/sessions.html +35 -35
  244. package/dist/docs/reference/skills.html +35 -35
  245. package/dist/docs/reference/subagents.html +35 -35
  246. package/dist/docs/reference/tools.html +35 -35
  247. package/dist/docs/templates/agentic-owners.html +35 -35
  248. package/dist/docs/templates/grokbot-agents.html +35 -35
  249. package/dist/docs/templates/security-reviewer.html +35 -35
  250. package/dist/docs/templates/thermo-quality-review.html +35 -35
  251. package/dist/docs/templates/thermo-review.html +35 -35
  252. package/dist/docs/templates/triage.html +35 -35
  253. package/dist/docs/troubleshooting.html +36 -36
  254. package/dist/docs/troubleshooting.md +1 -0
  255. package/dist/evals/assertions.js +20 -34
  256. package/dist/evals/expect.js +3 -6
  257. package/dist/evals/judge.js +5 -8
  258. package/dist/evals/loaders.js +45 -62
  259. package/dist/evals/matchers.js +2 -3
  260. package/dist/evals/reporters.js +43 -67
  261. package/dist/evals/results.js +1 -1
  262. package/dist/evals/run-facts.js +5 -6
  263. package/dist/evals.js +27 -15
  264. package/dist/extensions/cursor-cloud-agents/extension.js +4 -1
  265. package/dist/extensions/cursor-cloud-agents/lib/backend.js +100 -126
  266. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +22 -38
  267. package/dist/extensions/cursor-cloud-agents/lib/repos.js +8 -10
  268. package/dist/extensions/cursor-cloud-agents/lib/transcript.js +2 -3
  269. package/dist/extensions/cursor-cloud-agents/lib/watch.js +52 -66
  270. package/dist/extensions/cursor-cloud-agents/reminders/cloud-agent-stop-watch.js +29 -40
  271. package/dist/extensions/cursor-cloud-agents/tools/cancel.js +6 -17
  272. package/dist/extensions/cursor-cloud-agents/tools/dump.js +25 -36
  273. package/dist/extensions/cursor-cloud-agents/tools/get.js +3 -14
  274. package/dist/extensions/cursor-cloud-agents/tools/launch.js +13 -21
  275. package/dist/extensions/cursor-cloud-agents/tools/list.js +8 -19
  276. package/dist/extensions/cursor-cloud-agents/tools/reply.js +5 -16
  277. package/dist/extensions/cursor-grokbot-agents/extension.js +4 -1
  278. package/dist/extensions/cursor-grokbot-agents/lib/agents.js +3 -3
  279. package/dist/extensions/cursor-grokbot-agents/lib/backend.js +53 -73
  280. package/dist/extensions/cursor-grokbot-agents/lib/contacts.js +10 -23
  281. package/dist/extensions/cursor-grokbot-agents/lib/conversation.js +112 -132
  282. package/dist/extensions/cursor-grokbot-agents/lib/lock.js +1 -2
  283. package/dist/extensions/cursor-grokbot-agents/tools/ask.js +5 -16
  284. package/dist/extensions/cursor-grokbot-agents/tools/check.js +4 -15
  285. package/dist/extensions/cursor-grokbot-agents/tools/interrupt.js +2 -13
  286. package/dist/extensions/cursor-grokbot-agents/tools/list.js +11 -23
  287. package/dist/extensions/jev/extension.js +3 -3
  288. package/dist/extensions/jev/lib/evaluate.js +43 -60
  289. package/dist/extensions/jev/tools/evaluate.js +6 -17
  290. package/dist/extensions/slack-communication/tools/post-file.js +1 -1
  291. package/dist/extensions.js +3 -5
  292. package/dist/files-backends/cursor-hosted.js +504 -523
  293. package/dist/files-backends/local-fs.js +72 -134
  294. package/dist/files.js +3 -3
  295. package/dist/filesystem.js +562 -861
  296. package/dist/index.js +16 -35
  297. package/dist/internal/advertise-tools.js +74 -86
  298. package/dist/internal/artifacts-store.js +298 -361
  299. package/dist/internal/as-of.js +2 -4
  300. package/dist/internal/authored-alias-hooks.js +6 -4
  301. package/dist/internal/authored-loaders.js +37 -52
  302. package/dist/internal/bounded-int.js +1 -2
  303. package/dist/internal/bounded.js +13 -24
  304. package/dist/internal/brand.js +1 -1
  305. package/dist/internal/browser-origin-guard.js +4 -4
  306. package/dist/internal/builtin-tools/artifacts.js +15 -27
  307. package/dist/internal/builtin-tools/index.js +2 -3
  308. package/dist/internal/builtin-tools/reminders.js +33 -52
  309. package/dist/internal/channel-architecture.d.ts +21 -0
  310. package/dist/internal/channel-architecture.d.ts.map +1 -0
  311. package/dist/internal/channel-architecture.js +41 -0
  312. package/dist/internal/channel-dispatch.js +3 -4
  313. package/dist/internal/channel-route-dispatch.js +40 -51
  314. package/dist/internal/channel-state.js +1 -1
  315. package/dist/internal/chat-client.js +319 -340
  316. package/dist/internal/cli-ax.js +1262 -1294
  317. package/dist/internal/cli-bitbucket.js +244 -272
  318. package/dist/internal/cli-convert-automation.js +137 -151
  319. package/dist/internal/cli-cursor.js +126 -147
  320. package/dist/internal/cli-deploy.d.ts.map +1 -1
  321. package/dist/internal/cli-deploy.js +1457 -1507
  322. package/dist/internal/cli-docs.js +130 -147
  323. package/dist/internal/cli-github.js +437 -476
  324. package/dist/internal/cli-gitlab.js +259 -288
  325. package/dist/internal/cli-images.js +266 -334
  326. package/dist/internal/cli-manifest.js +25 -37
  327. package/dist/internal/cli-mcp-oauth.js +228 -247
  328. package/dist/internal/cli-mcp.js +358 -383
  329. package/dist/internal/cli-migrate.js +73 -90
  330. package/dist/internal/cli-skills.js +35 -47
  331. package/dist/internal/cli-slack-manual.d.ts +0 -1
  332. package/dist/internal/cli-slack-manual.d.ts.map +1 -1
  333. package/dist/internal/cli-slack-manual.js +175 -204
  334. package/dist/internal/cli-slack.d.ts +1 -1
  335. package/dist/internal/cli-slack.d.ts.map +1 -1
  336. package/dist/internal/cli-slack.js +416 -456
  337. package/dist/internal/cloud-merge.js +7 -3
  338. package/dist/internal/cloud-turn-cost.js +8 -1
  339. package/dist/internal/connection-env.js +5 -6
  340. package/dist/internal/continuation-channel.js +10 -7
  341. package/dist/internal/continuation-identity.js +85 -67
  342. package/dist/internal/conversation-mirror.js +112 -131
  343. package/dist/internal/convert-automation/convert-workflow.js +21 -31
  344. package/dist/internal/cron.js +3 -3
  345. package/dist/internal/cursor/account-mcp.js +147 -146
  346. package/dist/internal/cursor/backend-client.js +290 -320
  347. package/dist/internal/cursor/bound-secret-file.js +3 -3
  348. package/dist/internal/cursor/credentials.js +127 -142
  349. package/dist/internal/cursor/cursor-api-transport.js +4 -8
  350. package/dist/internal/cursor/github-credentials.js +91 -108
  351. package/dist/internal/cursor/hosted-bound-secrets.js +3 -4
  352. package/dist/internal/cursor/hosted-deployment-secrets.js +1 -1
  353. package/dist/internal/cursor/hosted-store-secrets.js +5 -9
  354. package/dist/internal/cursor/session-token.js +36 -48
  355. package/dist/internal/cursor/store-api-client.js +77 -92
  356. package/dist/internal/cursor-account-mcp-auth.js +132 -149
  357. package/dist/internal/cursor-agent-template.js +1 -1
  358. package/dist/internal/cursor-deployment-relay.js +33 -54
  359. package/dist/internal/cursor-event-relay.js +65 -59
  360. package/dist/internal/cursor-relay-core.js +258 -286
  361. package/dist/internal/deferred-channel-session.js +3 -12
  362. package/dist/internal/deploy-client.d.ts.map +1 -1
  363. package/dist/internal/deploy-client.js +413 -475
  364. package/dist/internal/deploy-manifest.d.ts +17 -0
  365. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  366. package/dist/internal/deploy-manifest.js +71 -21
  367. package/dist/internal/deploy-source.js +31 -43
  368. package/dist/internal/discovery/agent-config.js +45 -59
  369. package/dist/internal/discovery/agent.js +276 -280
  370. package/dist/internal/discovery/channels.js +67 -80
  371. package/dist/internal/discovery/connections.js +286 -296
  372. package/dist/internal/discovery/context.js +2 -13
  373. package/dist/internal/discovery/cursor-plugin.js +223 -259
  374. package/dist/internal/discovery/extension-overlay.js +104 -131
  375. package/dist/internal/discovery/extensions.js +276 -281
  376. package/dist/internal/discovery/fs.js +56 -79
  377. package/dist/internal/discovery/hooks.js +39 -50
  378. package/dist/internal/discovery/info.js +17 -19
  379. package/dist/internal/discovery/instructions.js +58 -71
  380. package/dist/internal/discovery/modules.js +45 -58
  381. package/dist/internal/discovery/project.d.ts.map +1 -1
  382. package/dist/internal/discovery/project.js +192 -215
  383. package/dist/internal/discovery/reminders.js +41 -52
  384. package/dist/internal/discovery/runtime.js +1 -1
  385. package/dist/internal/discovery/schedules.js +71 -82
  386. package/dist/internal/discovery/seed-files.js +21 -32
  387. package/dist/internal/discovery/services.js +74 -96
  388. package/dist/internal/discovery/skills.js +77 -94
  389. package/dist/internal/discovery/subagent.js +79 -95
  390. package/dist/internal/discovery/tools.js +12 -23
  391. package/dist/internal/distribution.js +2 -2
  392. package/dist/internal/docs-site.js +30 -45
  393. package/dist/internal/duration.js +1 -1
  394. package/dist/internal/env-file.js +48 -64
  395. package/dist/internal/eval-judge-model.js +17 -28
  396. package/dist/internal/eval-run-store.js +265 -254
  397. package/dist/internal/eval-runner.d.ts +8 -0
  398. package/dist/internal/eval-runner.d.ts.map +1 -1
  399. package/dist/internal/eval-runner.js +406 -408
  400. package/dist/internal/eval-transport.d.ts +24 -0
  401. package/dist/internal/eval-transport.d.ts.map +1 -0
  402. package/dist/internal/eval-transport.js +22 -0
  403. package/dist/internal/evals-client.js +242 -246
  404. package/dist/internal/event-log.js +72 -120
  405. package/dist/internal/event-mapper.js +30 -31
  406. package/dist/internal/factory-resource-channel.js +16 -30
  407. package/dist/internal/filesystem/errors.js +6 -6
  408. package/dist/internal/filesystem/format.js +10 -13
  409. package/dist/internal/filesystem/merge.js +52 -94
  410. package/dist/internal/filesystem/nearest.js +15 -27
  411. package/dist/internal/filesystem/scratch.js +65 -85
  412. package/dist/internal/filesystem/tools.js +221 -241
  413. package/dist/internal/filesystem/walk.js +76 -143
  414. package/dist/internal/framework-file-storage.js +118 -139
  415. package/dist/internal/framework-storage-selection.js +21 -13
  416. package/dist/internal/frontmatter.js +4 -6
  417. package/dist/internal/github-fanout.js +50 -64
  418. package/dist/internal/guest-network.js +96 -109
  419. package/dist/internal/handleAgentServeTrigger.js +121 -126
  420. package/dist/internal/host-files.js +73 -88
  421. package/dist/internal/host-kv.js +21 -36
  422. package/dist/internal/host-otel.js +22 -19
  423. package/dist/internal/host-platforms.js +49 -63
  424. package/dist/internal/hosted-catch-protocol.d.ts +1 -0
  425. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -1
  426. package/dist/internal/hosted-catch-protocol.js +1 -0
  427. package/dist/internal/hosted-catch.d.ts +5 -3
  428. package/dist/internal/hosted-catch.d.ts.map +1 -1
  429. package/dist/internal/hosted-catch.js +84 -93
  430. package/dist/internal/hosted-delivery-protocol.js +32 -8
  431. package/dist/internal/hosted-delivery.d.ts +13 -1
  432. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  433. package/dist/internal/hosted-delivery.js +614 -584
  434. package/dist/internal/hosted-eval-cases.d.ts +21 -0
  435. package/dist/internal/hosted-eval-cases.d.ts.map +1 -0
  436. package/dist/internal/hosted-eval-cases.js +162 -0
  437. package/dist/internal/hosted-execution-diag.js +38 -30
  438. package/dist/internal/hosted-execution-flush.js +75 -66
  439. package/dist/internal/hosted-execution-latency.js +16 -8
  440. package/dist/internal/hosted-managed-automation.js +2 -2
  441. package/dist/internal/hosting.js +2 -3
  442. package/dist/internal/http-channel-define.js +4 -1
  443. package/dist/internal/http-channel.js +101 -112
  444. package/dist/internal/http-control-plane-session.d.ts +18 -1
  445. package/dist/internal/http-control-plane-session.d.ts.map +1 -1
  446. package/dist/internal/http-control-plane-session.js +66 -32
  447. package/dist/internal/incoming-headers-to-fetch.js +1 -2
  448. package/dist/internal/init-interview.js +73 -93
  449. package/dist/internal/init-project.js +182 -214
  450. package/dist/internal/init-scaffold.js +10 -21
  451. package/dist/internal/inline-stdio-mcp.js +80 -86
  452. package/dist/internal/install-cursor-skills.js +231 -273
  453. package/dist/internal/legacy-command-guard.js +18 -31
  454. package/dist/internal/listen-port.js +34 -45
  455. package/dist/internal/local-control-plane.js +293 -307
  456. package/dist/internal/local-env.js +1 -1
  457. package/dist/internal/local-ingress.js +15 -9
  458. package/dist/internal/log-ring.js +1 -2
  459. package/dist/internal/logs-client.js +207 -227
  460. package/dist/internal/map-pool.js +24 -38
  461. package/dist/internal/mcp-endpoint.js +204 -180
  462. package/dist/internal/mcp-host.js +165 -168
  463. package/dist/internal/mcp-oauth-on-demand.js +170 -207
  464. package/dist/internal/mcp-oauth-persist.js +15 -29
  465. package/dist/internal/mcp-oauth.js +209 -266
  466. package/dist/internal/named-webhook-secret.d.ts +39 -0
  467. package/dist/internal/named-webhook-secret.d.ts.map +1 -0
  468. package/dist/internal/named-webhook-secret.js +47 -0
  469. package/dist/internal/open-browser.js +2 -3
  470. package/dist/internal/otel/collector.js +104 -68
  471. package/dist/internal/otel/config.js +24 -37
  472. package/dist/internal/otel/http.js +5 -7
  473. package/dist/internal/otel/mcp.js +3 -12
  474. package/dist/internal/otel/runtime.js +69 -83
  475. package/dist/internal/package-inline-stdio.js +57 -65
  476. package/dist/internal/peer-connections.js +9 -5
  477. package/dist/internal/platform-schedule-sync.js +39 -54
  478. package/dist/internal/platform-timers.js +176 -210
  479. package/dist/internal/playground/static.js +1 -2
  480. package/dist/internal/playground/toolchain.js +37 -53
  481. package/dist/internal/playground-proxy.js +230 -270
  482. package/dist/internal/process-memory-telemetry.js +33 -51
  483. package/dist/internal/prompt-context.js +3 -6
  484. package/dist/internal/reminder-control-plane-protocol.js +46 -13
  485. package/dist/internal/reminder-runner.js +770 -785
  486. package/dist/internal/reminder-schedule.js +1 -1
  487. package/dist/internal/reminder-store.js +57 -78
  488. package/dist/internal/request-error-status.js +1 -3
  489. package/dist/internal/request-headers.js +2 -2
  490. package/dist/internal/resolve-prod-target.js +119 -135
  491. package/dist/internal/resolved-connections.js +16 -6
  492. package/dist/internal/run-client.js +221 -229
  493. package/dist/internal/runtime-dispatch-runner.js +18 -43
  494. package/dist/internal/schedule-runner.js +49 -58
  495. package/dist/internal/scm/pr-url.js +7 -6
  496. package/dist/internal/sdk-runner.js +388 -363
  497. package/dist/internal/serve-restart.js +26 -39
  498. package/dist/internal/server.d.ts.map +1 -1
  499. package/dist/internal/server.js +1283 -1244
  500. package/dist/internal/session-cost.js +7 -9
  501. package/dist/internal/session-engine.d.ts +3 -1
  502. package/dist/internal/session-engine.d.ts.map +1 -1
  503. package/dist/internal/session-engine.js +2801 -2777
  504. package/dist/internal/session-links.js +12 -16
  505. package/dist/internal/session-run-log.js +134 -82
  506. package/dist/internal/session-store.js +133 -164
  507. package/dist/internal/sessions-client.js +97 -118
  508. package/dist/internal/skill-catalog.js +18 -23
  509. package/dist/internal/skills-sync.js +16 -30
  510. package/dist/internal/slack-provision-client.js +90 -116
  511. package/dist/internal/start-log-store.js +48 -67
  512. package/dist/internal/steering.js +1 -2
  513. package/dist/internal/storage-coordinator.js +160 -196
  514. package/dist/internal/store-mirror.js +16 -30
  515. package/dist/internal/stream-progress.js +6 -8
  516. package/dist/internal/terminal-style.js +3 -4
  517. package/dist/internal/testing/scm-continuation-fixtures.js +6 -2
  518. package/dist/internal/testing/slack-continuation-fixtures.d.ts +26 -0
  519. package/dist/internal/testing/slack-continuation-fixtures.d.ts.map +1 -0
  520. package/dist/internal/testing/slack-continuation-fixtures.js +136 -0
  521. package/dist/internal/tool-catalog.js +11 -5
  522. package/dist/internal/tool-result.js +1 -1
  523. package/dist/internal/trajectory.js +19 -22
  524. package/dist/internal/turn-cost.js +52 -62
  525. package/dist/internal/turn-governor.js +5 -8
  526. package/dist/internal/turn-lease-store.js +85 -105
  527. package/dist/internal/turn-outbox.js +28 -43
  528. package/dist/internal/update-check.js +231 -259
  529. package/dist/internal/v2-hosting.js +1 -2
  530. package/dist/internal/workspace-sync.js +25 -41
  531. package/dist/internal/workspace.js +111 -139
  532. package/dist/kv/memory-kv.js +27 -51
  533. package/dist/memory.js +106 -148
  534. package/dist/otel.js +5 -8
  535. package/dist/playground/assets/{index-Co4CUVTQ.js → index-Be0-1hw2.js} +45 -45
  536. package/dist/playground/assets/index-Clz6uHj9.css +1 -0
  537. package/dist/playground/index.html +2 -2
  538. package/dist/prompt.js +2 -4
  539. package/dist/storage-backends/cursor-hosted-v2.js +53 -83
  540. package/dist/storage-backends/cursor-hosted.js +105 -145
  541. package/dist/storage-backends/file-kv.js +100 -128
  542. package/dist/storage-protocol.js +3 -5
  543. package/dist/storage.js +17 -26
  544. package/dist/types.d.ts +68 -0
  545. package/dist/types.d.ts.map +1 -1
  546. package/dist/types.js +20 -18
  547. package/docs/building-with-agents.md +2 -0
  548. package/docs/deployment.md +7 -0
  549. package/docs/guides/bitbucket.md +9 -1
  550. package/docs/guides/github.md +20 -4
  551. package/docs/guides/gitlab.md +9 -1
  552. package/docs/guides/migrate.md +127 -0
  553. package/docs/reference/cli.md +39 -0
  554. package/docs/troubleshooting.md +1 -0
  555. package/package.json +1 -1
  556. package/skills/debug/SKILL.md +1 -0
  557. package/skills/github/SKILL.md +23 -0
  558. package/skills/migrate-v2/SKILL.md +51 -10
  559. package/dist/docs/assets/chunks/@localSearchIndexroot.BJ8UZggu.js +0 -1
  560. package/dist/docs/assets/chunks/channel.BTJ5J9FI.js +0 -1
  561. package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.D4BZ3cVV.js +0 -1
  562. package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.D4BZ3cVV.js +0 -1
  563. package/dist/docs/assets/chunks/clone.62tX-O-1.js +0 -1
  564. package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.DkTs1aEU.js +0 -1
  565. package/dist/docs/assets/reference_cli.md.GwugN3n-.lean.js +0 -1
  566. package/dist/docs/assets/troubleshooting.md.Bscj6ODe.js +0 -1
  567. package/dist/playground/assets/index-C1g_PTTZ.css +0 -1
  568. /package/dist/docs/assets/{building-with-agents.md.BPjPFxFg.lean.js → building-with-agents.md.Df87rAe1.lean.js} +0 -0
  569. /package/dist/docs/assets/{deployment.md.BdqTiGdc.lean.js → deployment.md.BYuEcDBv.lean.js} +0 -0
@@ -9,15 +9,6 @@
9
9
  * v2 agentsdk management API through `deploy-client.ts`, poll status, and
10
10
  * render.
11
11
  */
12
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
13
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
14
- return new (P || (P = Promise))(function (resolve, reject) {
15
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
16
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
17
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
18
- step((generator = generator.apply(thisArg, _arguments || [])).next());
19
- });
20
- };
21
12
  import { basename, resolve } from "node:path";
22
13
  import { catchAuthDeclaration, isPublicEndpointPolicy } from "../channels.js";
23
14
  import { isCursorAccountTransport, } from "../types.js";
@@ -26,6 +17,7 @@ import { cursorExternalApiUrl, resolveApiKey, SIGN_IN_HINT } from "./cursor/cred
26
17
  import { authorizeCursorAccountConnectors } from "./cursor-account-mcp-auth.js";
27
18
  import { readDeployTemplate } from "./cursor-agent-template.js";
28
19
  import { AgentServeDeployClient, DeployApiError, deploymentServiceAccountId, slugFromDirectoryName, TERMINAL_AGENTKIT_DEPLOY_STATUSES, TERMINAL_DEPLOY_STATUSES, validateDeploymentSlug, } from "./deploy-client.js";
20
+ import { channelCatchSecretNames, channelCredentialSecretNames } from "./deploy-manifest.js";
29
21
  import { inferDeployGitSource } from "./deploy-source.js";
30
22
  import { describeError } from "./describe-error.js";
31
23
  import { formatDiagnostics, hasErrorDiagnostics, isAgentProjectDir, listChildAgentDirs, loadAgentProject, } from "./discovery.js";
@@ -35,7 +27,7 @@ import { deploymentArchitecture, rejectV2ForLegacyCommand } from "./legacy-comma
35
27
  import { deployProgressLabel, sanitizeCustomerError } from "./logs-client.js";
36
28
  import { sleep } from "./sleep.js";
37
29
  import { stderrPalette } from "./terminal-style.js";
38
- const DEFAULT_POLL_INTERVAL_MS = 3000;
30
+ const DEFAULT_POLL_INTERVAL_MS = 3_000;
39
31
  const DEFAULT_DEPLOY_TIMEOUT_MS = 10 * 60 * 1000;
40
32
  /** `--multi-tenant` HTTP deploy is Anysphere-only (team id 1). */
41
33
  const MULTI_TENANT_HTTP_DEPLOY_TEAM_ID = 1;
@@ -44,328 +36,316 @@ const MULTI_TENANT_HTTP_DEPLOY_TEAM_ID = 1;
44
36
  * `--prod` AX routing. Returns an exit code (error already rendered) on
45
37
  * failure.
46
38
  */
47
- export function resolveDeployAuth(options) {
48
- return __awaiter(this, void 0, void 0, function* () {
49
- var _a;
50
- const err = (_a = options.err) !== null && _a !== void 0 ? _a : ((text) => void process.stderr.write(text));
51
- const resolved = yield resolveApiKey(options.apiKey === undefined ? undefined : { apiKey: options.apiKey });
52
- if (resolved === undefined) {
53
- err(`Not signed in to Cursor. ${SIGN_IN_HINT}\n`);
39
+ export async function resolveDeployAuth(options) {
40
+ const err = options.err ?? ((text) => void process.stderr.write(text));
41
+ const resolved = await resolveApiKey(options.apiKey === undefined ? undefined : { apiKey: options.apiKey });
42
+ if (resolved === undefined) {
43
+ err(`Not signed in to Cursor. ${SIGN_IN_HINT}\n`);
44
+ return 1;
45
+ }
46
+ // The deployment management routes live on the external API host
47
+ // (api.cursor.com), not the default backend (api2.cursor.sh) — see
48
+ // cursorExternalApiUrl. GetMe below stays on the resolved backend.
49
+ const client = new AgentServeDeployClient({
50
+ backendUrl: cursorExternalApiUrl(),
51
+ apiKey: resolved.apiKey,
52
+ fetchImpl: options.fetchImpl,
53
+ });
54
+ let teamId;
55
+ if (options.team !== undefined) {
56
+ teamId = Number.parseInt(options.team, 10);
57
+ if (Number.isNaN(teamId) || teamId <= 0) {
58
+ err(`Invalid --team: ${options.team} (expected a positive team id)\n`);
54
59
  return 1;
55
60
  }
56
- // The deployment management routes live on the external API host
57
- // (api.cursor.com), not the default backend (api2.cursor.sh) — see
58
- // cursorExternalApiUrl. GetMe below stays on the resolved backend.
59
- const client = new AgentServeDeployClient({
60
- backendUrl: cursorExternalApiUrl(),
61
+ }
62
+ else {
63
+ const account = new CursorBackendClient({
64
+ backendUrl: resolved.backendUrl,
61
65
  apiKey: resolved.apiKey,
62
66
  fetchImpl: options.fetchImpl,
63
67
  });
64
- let teamId;
65
- if (options.team !== undefined) {
66
- teamId = Number.parseInt(options.team, 10);
67
- if (Number.isNaN(teamId) || teamId <= 0) {
68
- err(`Invalid --team: ${options.team} (expected a positive team id)\n`);
69
- return 1;
70
- }
68
+ let identity;
69
+ try {
70
+ identity = await account.getMe();
71
71
  }
72
- else {
73
- const account = new CursorBackendClient({
74
- backendUrl: resolved.backendUrl,
75
- apiKey: resolved.apiKey,
76
- fetchImpl: options.fetchImpl,
77
- });
78
- let identity;
79
- try {
80
- identity = yield account.getMe();
81
- }
82
- catch (error) {
83
- err(`Could not resolve your team from the Cursor account: ${describeError(error)}\nPass --team <id> explicitly.\n`);
84
- return 1;
85
- }
86
- if (identity.teamId === undefined || identity.teamId <= 0) {
87
- err("This Cursor account has no default team; pass --team <id> (find it in the Cursor dashboard URL).\n");
88
- return 1;
89
- }
90
- teamId = identity.teamId;
91
- const dim = stderrPalette().dim;
92
- err(`${dim(`Using team ${teamId}${identity.teamName === undefined ? "" : ` (${identity.teamName})`}`)}\n${dim(" the account's team — pass --team to override.")}\n`);
72
+ catch (error) {
73
+ err(`Could not resolve your team from the Cursor account: ${describeError(error)}\nPass --team <id> explicitly.\n`);
74
+ return 1;
93
75
  }
94
- return {
95
- client,
96
- teamId,
97
- apiKey: resolved.apiKey,
98
- backendUrl: resolved.backendUrl,
99
- };
100
- });
76
+ if (identity.teamId === undefined || identity.teamId <= 0) {
77
+ err("This Cursor account has no default team; pass --team <id> (find it in the Cursor dashboard URL).\n");
78
+ return 1;
79
+ }
80
+ teamId = identity.teamId;
81
+ const dim = stderrPalette().dim;
82
+ err(`${dim(`Using team ${teamId}${identity.teamName === undefined ? "" : ` (${identity.teamName})`}`)}\n${dim(" the account's team — pass --team to override.")}\n`);
83
+ }
84
+ return {
85
+ client,
86
+ teamId,
87
+ apiKey: resolved.apiKey,
88
+ backendUrl: resolved.backendUrl,
89
+ };
101
90
  }
102
91
  /**
103
92
  * Shared preamble: credentials → client → team id. Returns an exit code
104
93
  * (with the error already rendered) when resolution fails.
105
94
  */
106
- export function prepare(options) {
107
- return __awaiter(this, void 0, void 0, function* () {
108
- var _a, _b, _c, _d;
109
- const out = (_a = options.out) !== null && _a !== void 0 ? _a : ((text) => void process.stdout.write(text));
110
- const err = (_b = options.err) !== null && _b !== void 0 ? _b : ((text) => void process.stderr.write(text));
111
- const auth = yield resolveDeployAuth({
112
- team: options.team,
113
- apiKey: options.apiKey,
114
- fetchImpl: options.fetchImpl,
115
- err,
116
- });
117
- if (typeof auth === "number") {
118
- return auth;
119
- }
120
- return {
121
- client: auth.client,
122
- teamId: auth.teamId,
123
- apiKey: auth.apiKey,
124
- backendUrl: auth.backendUrl,
125
- json: options.json === true,
126
- noWait: options.noWait === true,
127
- pollIntervalMs: (_c = options.pollIntervalMs) !== null && _c !== void 0 ? _c : DEFAULT_POLL_INTERVAL_MS,
128
- timeoutMs: (_d = options.timeoutMs) !== null && _d !== void 0 ? _d : DEFAULT_DEPLOY_TIMEOUT_MS,
129
- out,
130
- err,
131
- };
95
+ export async function prepare(options) {
96
+ const out = options.out ?? ((text) => void process.stdout.write(text));
97
+ const err = options.err ?? ((text) => void process.stderr.write(text));
98
+ const auth = await resolveDeployAuth({
99
+ team: options.team,
100
+ apiKey: options.apiKey,
101
+ fetchImpl: options.fetchImpl,
102
+ err,
132
103
  });
104
+ if (typeof auth === "number") {
105
+ return auth;
106
+ }
107
+ return {
108
+ client: auth.client,
109
+ teamId: auth.teamId,
110
+ apiKey: auth.apiKey,
111
+ backendUrl: auth.backendUrl,
112
+ json: options.json === true,
113
+ noWait: options.noWait === true,
114
+ pollIntervalMs: options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,
115
+ timeoutMs: options.timeoutMs ?? DEFAULT_DEPLOY_TIMEOUT_MS,
116
+ out,
117
+ err,
118
+ };
133
119
  }
134
120
  // ============================================================================
135
121
  // deploy
136
122
  // ============================================================================
137
- export function cmdDeploy(options) {
138
- return __awaiter(this, void 0, void 0, function* () {
139
- const ctx = yield prepare(options);
140
- if (typeof ctx === "number") {
141
- return ctx;
142
- }
143
- if (options.multiTenant === true && ctx.teamId !== MULTI_TENANT_HTTP_DEPLOY_TEAM_ID) {
144
- ctx.err("--multi-tenant is not available for this team.\n");
145
- return 1;
146
- }
147
- const targets = yield resolveDeployTargets(options, ctx);
148
- if (typeof targets === "number") {
149
- return targets;
150
- }
151
- if (targets.length === 1) {
152
- return deployOne(ctx, options, targets[0]);
153
- }
154
- // Multi-agent parent: when every child declares `architecture: "v2"`,
155
- // the v2 control plane models sibling agents as release components of
156
- // ONE application, so deploy them together (one app, one component per
157
- // child) instead of minting a separate application per child. Mixed and
158
- // v1 parents keep the per-child sequential deploys.
159
- const manifests = [];
160
- for (const target of targets) {
161
- manifests.push(yield readDeployManifest(target.dir));
162
- }
163
- if (manifests.every(manifest => manifest.architecture === "v2")) {
164
- return deployAgentsdkApplication(ctx, options, targets, {
165
- // `persistent` is per child agent, like `agentPath`: each release
166
- // component carries its own.
167
- componentPersistent: Object.fromEntries(targets.map((target, index) => { var _a; return [target.slug, ((_a = manifests[index]) === null || _a === void 0 ? void 0 : _a.persistent) === true]; })),
168
- componentImage: Object.fromEntries(targets.flatMap((target, index) => { var _a; return ((_a = manifests[index]) === null || _a === void 0 ? void 0 : _a.image) === undefined ? [] : [[target.slug, manifests[index].image]]; })),
169
- hasScmChannels: manifests.some(manifest => manifest.hasScmChannels),
170
- declaredSecretNames: [
171
- ...new Set(manifests.flatMap(manifest => { var _a; var _b; return (_b = (_a = manifest.hosting) === null || _a === void 0 ? void 0 : _a.secretNames) !== null && _b !== void 0 ? _b : []; })),
172
- ],
173
- hasDeploymentsChannels: manifests.some(manifest => manifest.hasDeploymentsChannels),
174
- });
175
- }
176
- if (!ctx.json && manifests.some(manifest => manifest.architecture === "v2")) {
177
- ctx.err(`warning: agents under this parent mix architectures; deploying each separately (v2 children become standalone single-component applications).\n`);
123
+ export async function cmdDeploy(options) {
124
+ const ctx = await prepare(options);
125
+ if (typeof ctx === "number") {
126
+ return ctx;
127
+ }
128
+ if (options.multiTenant === true && ctx.teamId !== MULTI_TENANT_HTTP_DEPLOY_TEAM_ID) {
129
+ ctx.err("--multi-tenant is not available for this team.\n");
130
+ return 1;
131
+ }
132
+ const targets = await resolveDeployTargets(options, ctx);
133
+ if (typeof targets === "number") {
134
+ return targets;
135
+ }
136
+ if (targets.length === 1) {
137
+ return deployOne(ctx, options, targets[0]);
138
+ }
139
+ // Multi-agent parent: when every child declares `architecture: "v2"`,
140
+ // the v2 control plane models sibling agents as release components of
141
+ // ONE application, so deploy them together (one app, one component per
142
+ // child) instead of minting a separate application per child. Mixed and
143
+ // v1 parents keep the per-child sequential deploys.
144
+ const manifests = [];
145
+ for (const target of targets) {
146
+ manifests.push(await readDeployManifest(target.dir));
147
+ }
148
+ if (manifests.every(manifest => manifest.architecture === "v2")) {
149
+ return deployAgentsdkApplication(ctx, options, targets, {
150
+ // `persistent` is per child agent, like `agentPath`: each release
151
+ // component carries its own.
152
+ componentPersistent: Object.fromEntries(targets.map((target, index) => [target.slug, manifests[index]?.persistent === true])),
153
+ componentImage: Object.fromEntries(targets.flatMap((target, index) => manifests[index]?.image === undefined ? [] : [[target.slug, manifests[index].image]])),
154
+ hasScmChannels: manifests.some(manifest => manifest.hasScmChannels),
155
+ declaredSecretNames: declaredSecretNames(manifests),
156
+ hasDeploymentsChannels: manifests.some(manifest => manifest.hasDeploymentsChannels),
157
+ });
158
+ }
159
+ if (!ctx.json && manifests.some(manifest => manifest.architecture === "v2")) {
160
+ ctx.err(`warning: agents under this parent mix architectures; deploying each separately (v2 children become standalone single-component applications).\n`);
161
+ }
162
+ // --path is per-agent (relative to the repo root). When deploying several
163
+ // agents, ignore a shared --path so each target can infer its own path.
164
+ let deployOptions = options;
165
+ if (options.path !== undefined) {
166
+ if (!ctx.json) {
167
+ ctx.err(`warning: ignoring --path ${JSON.stringify(options.path)} for a multi-agent deploy; each agent infers its own path from git.\n`);
178
168
  }
179
- // --path is per-agent (relative to the repo root). When deploying several
180
- // agents, ignore a shared --path so each target can infer its own path.
181
- let deployOptions = options;
182
- if (options.path !== undefined) {
183
- if (!ctx.json) {
184
- ctx.err(`warning: ignoring --path ${JSON.stringify(options.path)} for a multi-agent deploy; each agent infers its own path from git.\n`);
185
- }
186
- deployOptions = Object.assign(Object.assign({}, options), { path: undefined });
169
+ deployOptions = { ...options, path: undefined };
170
+ }
171
+ // Multi-agent batch: deploy sequentially; --json emits an array.
172
+ const jsonResults = [];
173
+ let failures = 0;
174
+ for (const [index, target] of targets.entries()) {
175
+ if (!ctx.json) {
176
+ ctx.err(`\n=== [${index + 1}/${targets.length}] Deploying ${target.slug} ===\n`);
187
177
  }
188
- // Multi-agent batch: deploy sequentially; --json emits an array.
189
- const jsonResults = [];
190
- let failures = 0;
191
- for (const [index, target] of targets.entries()) {
192
- if (!ctx.json) {
193
- ctx.err(`\n=== [${index + 1}/${targets.length}] Deploying ${target.slug} ===\n`);
194
- }
195
- const before = jsonResults.length;
196
- const code = yield deployOne(ctx, deployOptions, target, {
197
- jsonCollect: ctx.json ? jsonResults : undefined,
198
- });
199
- if (code !== 0) {
200
- failures += 1;
201
- if (ctx.json && jsonResults.length === before) {
202
- jsonResults.push({ slug: target.slug, error: "deploy failed" });
203
- }
178
+ const before = jsonResults.length;
179
+ const code = await deployOne(ctx, deployOptions, target, {
180
+ jsonCollect: ctx.json ? jsonResults : undefined,
181
+ });
182
+ if (code !== 0) {
183
+ failures += 1;
184
+ if (ctx.json && jsonResults.length === before) {
185
+ jsonResults.push({ slug: target.slug, error: "deploy failed" });
204
186
  }
205
187
  }
206
- if (ctx.json) {
207
- ctx.out(`${JSON.stringify(jsonResults, null, 2)}\n`);
208
- }
209
- else if (failures > 0) {
210
- ctx.err(`\n${failures} of ${targets.length} deploy(s) failed.\n`);
211
- }
212
- else {
213
- ctx.err(`\nDeployed ${targets.length} agents.\n`);
214
- }
215
- return failures === 0 ? 0 : 1;
216
- });
188
+ }
189
+ if (ctx.json) {
190
+ ctx.out(`${JSON.stringify(jsonResults, null, 2)}\n`);
191
+ }
192
+ else if (failures > 0) {
193
+ ctx.err(`\n${failures} of ${targets.length} deploy(s) failed.\n`);
194
+ }
195
+ else {
196
+ ctx.err(`\nDeployed ${targets.length} agents.\n`);
197
+ }
198
+ return failures === 0 ? 0 : 1;
217
199
  }
218
200
  /**
219
201
  * Resolve which agent directory(ies) to deploy from `--dir` / `--slug` /
220
202
  * `--all`, with an interactive picker when a multi-agent parent is on a TTY.
221
203
  */
222
- function resolveDeployTargets(options, ctx) {
223
- return __awaiter(this, void 0, void 0, function* () {
224
- var _a, _b;
225
- let dir = resolve((_a = options.dir) !== null && _a !== void 0 ? _a : ".");
226
- // A repo-root deploy commonly names the local agent through --path. Use
227
- // that project for manifest discovery unless --dir or --all chose a scope.
228
- if (options.dir === undefined && options.path !== undefined && options.all !== true) {
229
- const localSourceDir = resolve(options.path);
230
- if (yield isAgentProjectDir(localSourceDir)) {
231
- dir = localSourceDir;
232
- }
204
+ async function resolveDeployTargets(options, ctx) {
205
+ let dir = resolve(options.dir ?? ".");
206
+ // A repo-root deploy commonly names the local agent through --path. Use
207
+ // that project for manifest discovery unless --dir or --all chose a scope.
208
+ if (options.dir === undefined && options.path !== undefined && options.all !== true) {
209
+ const localSourceDir = resolve(options.path);
210
+ if (await isAgentProjectDir(localSourceDir)) {
211
+ dir = localSourceDir;
233
212
  }
234
- if (options.slug !== undefined) {
235
- const slugError = validateDeploymentSlug(options.slug);
236
- if (slugError !== undefined) {
237
- ctx.err(`${slugError}\n`);
238
- return 1;
239
- }
213
+ }
214
+ if (options.slug !== undefined) {
215
+ const slugError = validateDeploymentSlug(options.slug);
216
+ if (slugError !== undefined) {
217
+ ctx.err(`${slugError}\n`);
218
+ return 1;
240
219
  }
241
- if (options.all === true && options.slug !== undefined) {
242
- ctx.err("Pass either --slug or --all, not both.\n");
220
+ }
221
+ if (options.all === true && options.slug !== undefined) {
222
+ ctx.err("Pass either --slug or --all, not both.\n");
223
+ return 1;
224
+ }
225
+ if (await isAgentProjectDir(dir)) {
226
+ if (options.all === true) {
227
+ ctx.err(`--all requires a multi-agent parent directory (several child agents under --dir); ${dir} is a single agent project.\n`);
243
228
  return 1;
244
229
  }
245
- if (yield isAgentProjectDir(dir)) {
246
- if (options.all === true) {
247
- ctx.err(`--all requires a multi-agent parent directory (several child agents under --dir); ${dir} is a single agent project.\n`);
230
+ let slug;
231
+ if (options.slug !== undefined) {
232
+ slug = options.slug;
233
+ }
234
+ else {
235
+ const derived = slugFromDirectoryName(basename(dir));
236
+ if (derived === undefined) {
237
+ ctx.err(`Could not derive a deployment slug from the directory name ${JSON.stringify(basename(dir))}; pass --slug.\n`);
248
238
  return 1;
249
239
  }
250
- let slug;
251
- if (options.slug !== undefined) {
252
- slug = options.slug;
253
- }
254
- else {
255
- const derived = slugFromDirectoryName(basename(dir));
256
- if (derived === undefined) {
257
- ctx.err(`Could not derive a deployment slug from the directory name ${JSON.stringify(basename(dir))}; pass --slug.\n`);
258
- return 1;
259
- }
260
- slug = derived;
261
- if (!ctx.json) {
262
- ctx.err(`Deploying as "${slug}" (from the directory name).\n`);
263
- }
240
+ slug = derived;
241
+ if (!ctx.json) {
242
+ ctx.err(`Deploying as "${slug}" (from the directory name).\n`);
264
243
  }
265
- return [{ slug, dir }];
266
244
  }
267
- let children;
268
- try {
269
- children = yield listChildAgentDirs(dir);
245
+ return [{ slug, dir }];
246
+ }
247
+ let children;
248
+ try {
249
+ children = await listChildAgentDirs(dir);
250
+ }
251
+ catch (error) {
252
+ ctx.err(`${describeError(error)}\n`);
253
+ return 1;
254
+ }
255
+ // Deploy slugs are lowercase-only; normalize directory names the same way
256
+ // single-agent deploy does so MixedCase child dirs still deploy.
257
+ children = children.flatMap(child => {
258
+ const slug = slugFromDirectoryName(basename(child.dir));
259
+ if (slug === undefined) {
260
+ return [];
270
261
  }
271
- catch (error) {
272
- ctx.err(`${describeError(error)}\n`);
262
+ return [{ slug, dir: child.dir }];
263
+ });
264
+ if (children.length === 0) {
265
+ if (options.all === true) {
266
+ ctx.err(`--all requires child agent projects under --dir; none found in ${dir}.\n`);
273
267
  return 1;
274
268
  }
275
- // Deploy slugs are lowercase-only; normalize directory names the same way
276
- // single-agent deploy does so MixedCase child dirs still deploy.
277
- children = children.flatMap(child => {
278
- const slug = slugFromDirectoryName(basename(child.dir));
279
- if (slug === undefined) {
280
- return [];
281
- }
282
- return [{ slug, dir: child.dir }];
283
- });
284
- if (children.length === 0) {
285
- if (options.all === true) {
286
- ctx.err(`--all requires child agent projects under --dir; none found in ${dir}.\n`);
287
- return 1;
288
- }
289
- // Bare-slug deploy against a non-agent directory (still requires --repo).
290
- let slug;
291
- if (options.slug !== undefined) {
292
- slug = options.slug;
293
- }
294
- else {
295
- const derived = slugFromDirectoryName(basename(dir));
296
- if (derived === undefined) {
297
- ctx.err(`No agent projects under ${dir}, and could not derive a slug from ${JSON.stringify(basename(dir))}; pass --slug or --dir <agent>.\n`);
298
- return 1;
299
- }
300
- slug = derived;
301
- if (!ctx.json) {
302
- ctx.err(`Deploying as "${slug}" (no agent project at ${dir}).\n`);
303
- }
304
- }
305
- return [{ slug, dir }];
269
+ // Bare-slug deploy against a non-agent directory (still requires --repo).
270
+ let slug;
271
+ if (options.slug !== undefined) {
272
+ slug = options.slug;
306
273
  }
307
- if (children.length === 1) {
308
- const only = children[0];
309
- if (options.all === true) {
310
- // One child is fine for --all (degenerate multi-agent parent).
311
- }
312
- else if (options.slug !== undefined && options.slug.toLowerCase() !== only.slug) {
313
- ctx.err(`No agent "${options.slug}" under ${dir}; found "${only.slug}".\n`);
274
+ else {
275
+ const derived = slugFromDirectoryName(basename(dir));
276
+ if (derived === undefined) {
277
+ ctx.err(`No agent projects under ${dir}, and could not derive a slug from ${JSON.stringify(basename(dir))}; pass --slug or --dir <agent>.\n`);
314
278
  return 1;
315
279
  }
280
+ slug = derived;
316
281
  if (!ctx.json) {
317
- ctx.err(`Deploying "${only.slug}" (only agent under ${basename(dir)}).\n`);
282
+ ctx.err(`Deploying as "${slug}" (no agent project at ${dir}).\n`);
318
283
  }
319
- return [only];
320
284
  }
321
- // Multiple children.
285
+ return [{ slug, dir }];
286
+ }
287
+ if (children.length === 1) {
288
+ const only = children[0];
322
289
  if (options.all === true) {
323
- if (!ctx.json) {
324
- ctx.err(`Deploying all ${children.length} agents under ${basename(dir)}: ${children.map(c => c.slug).join(", ")}.\n`);
325
- }
326
- return [...children];
290
+ // One child is fine for --all (degenerate multi-agent parent).
327
291
  }
328
- if (options.slug !== undefined) {
329
- const wanted = options.slug.toLowerCase();
330
- const match = children.find(child => child.slug === wanted);
331
- if (match === undefined) {
332
- ctx.err(`No agent "${options.slug}" under ${dir}.\n` +
333
- formatAgentList(children) +
334
- `Pass --slug <name> or --all.\n`);
335
- return 1;
336
- }
337
- return [match];
292
+ else if (options.slug !== undefined && options.slug.toLowerCase() !== only.slug) {
293
+ ctx.err(`No agent "${options.slug}" under ${dir}; found "${only.slug}".\n`);
294
+ return 1;
338
295
  }
339
- // An all-v2 parent deploys as ONE application (siblings are components
340
- // of a single app on the v2 control plane), so "deploy the parent" is
341
- // unambiguous and needs no picker or --all. A child that is v1 — or
342
- // fails to load — keeps the interactive picker below.
343
- if (yield allChildrenAreV2(children)) {
344
- if (!ctx.json) {
345
- ctx.err(`Deploying all ${children.length} v2 agents under ${basename(dir)} as one application (pass --slug <name> to deploy a single agent standalone).\n`);
346
- }
347
- return [...children];
296
+ if (!ctx.json) {
297
+ ctx.err(`Deploying "${only.slug}" (only agent under ${basename(dir)}).\n`);
348
298
  }
349
- const chooser = (_b = options.chooseTargets) !== null && _b !== void 0 ? _b : (agents => { var _a, _b; return promptChooseDeployTargets(agents, {
350
- err: ctx.err,
351
- stdin: (_a = options.stdin) !== null && _a !== void 0 ? _a : process.stdin,
352
- interactive: ctx.json !== true &&
353
- ((_b = options.stdin) !== null && _b !== void 0 ? _b : process.stdin).isTTY === true &&
354
- process.stderr.isTTY === true,
355
- }); });
356
- const chosen = yield chooser(children);
357
- if (chosen === null) {
358
- ctx.err("Deploy cancelled.\n");
359
- return 1;
299
+ return [only];
300
+ }
301
+ // Multiple children.
302
+ if (options.all === true) {
303
+ if (!ctx.json) {
304
+ ctx.err(`Deploying all ${children.length} agents under ${basename(dir)}: ${children.map(c => c.slug).join(", ")}.\n`);
360
305
  }
361
- if (chosen.length === 0) {
362
- ctx.err(`Multiple agents under ${dir}:\n` +
306
+ return [...children];
307
+ }
308
+ if (options.slug !== undefined) {
309
+ const wanted = options.slug.toLowerCase();
310
+ const match = children.find(child => child.slug === wanted);
311
+ if (match === undefined) {
312
+ ctx.err(`No agent "${options.slug}" under ${dir}.\n` +
363
313
  formatAgentList(children) +
364
- `Pass --slug <name> or --all (or re-run on a TTY to pick interactively).\n`);
314
+ `Pass --slug <name> or --all.\n`);
365
315
  return 1;
366
316
  }
367
- return chosen;
368
- });
317
+ return [match];
318
+ }
319
+ // An all-v2 parent deploys as ONE application (siblings are components
320
+ // of a single app on the v2 control plane), so "deploy the parent" is
321
+ // unambiguous and needs no picker or --all. A child that is v1 — or
322
+ // fails to load — keeps the interactive picker below.
323
+ if (await allChildrenAreV2(children)) {
324
+ if (!ctx.json) {
325
+ ctx.err(`Deploying all ${children.length} v2 agents under ${basename(dir)} as one application (pass --slug <name> to deploy a single agent standalone).\n`);
326
+ }
327
+ return [...children];
328
+ }
329
+ const chooser = options.chooseTargets ??
330
+ (agents => promptChooseDeployTargets(agents, {
331
+ err: ctx.err,
332
+ stdin: options.stdin ?? process.stdin,
333
+ interactive: ctx.json !== true &&
334
+ (options.stdin ?? process.stdin).isTTY === true &&
335
+ process.stderr.isTTY === true,
336
+ }));
337
+ const chosen = await chooser(children);
338
+ if (chosen === null) {
339
+ ctx.err("Deploy cancelled.\n");
340
+ return 1;
341
+ }
342
+ if (chosen.length === 0) {
343
+ ctx.err(`Multiple agents under ${dir}:\n` +
344
+ formatAgentList(children) +
345
+ `Pass --slug <name> or --all (or re-run on a TTY to pick interactively).\n`);
346
+ return 1;
347
+ }
348
+ return chosen;
369
349
  }
370
350
  function formatAgentList(agents) {
371
351
  return agents.map((agent, i) => ` ${i + 1}) ${agent.slug}\n`).join("");
@@ -376,240 +356,246 @@ function formatAgentList(agents) {
376
356
  * resolution falls back to the picker instead of failing the whole deploy
377
357
  * on a child the user might not even select.
378
358
  */
379
- function allChildrenAreV2(children) {
380
- return __awaiter(this, void 0, void 0, function* () {
381
- for (const child of children) {
382
- try {
383
- if ((yield readDeployManifest(child.dir)).architecture !== "v2") {
384
- return false;
385
- }
386
- }
387
- catch (_a) {
359
+ async function allChildrenAreV2(children) {
360
+ for (const child of children) {
361
+ try {
362
+ if ((await readDeployManifest(child.dir)).architecture !== "v2") {
388
363
  return false;
389
364
  }
390
365
  }
391
- return true;
392
- });
366
+ catch {
367
+ return false;
368
+ }
369
+ }
370
+ return true;
393
371
  }
394
372
  /**
395
373
  * TTY picker for multi-agent parents. Non-interactive callers get `[]`
396
374
  * so {@link resolveDeployTargets} can print the --slug/--all hint.
397
375
  */
398
- export function promptChooseDeployTargets(agents, options) {
399
- return __awaiter(this, void 0, void 0, function* () {
400
- var _a, _b, _c;
401
- options.err(`Multiple agents (${agents.length}):\n` + formatAgentList(agents) + ` a) all\n`);
402
- if (!options.interactive) {
403
- return [];
404
- }
405
- options.err('Deploy which? Enter a number, slug, "all", or "q" to cancel: ');
406
- const readLine = createLineReader(options.stdin);
407
- // createLineReader pauses until data; ensure stdin is flowing on a TTY.
408
- (_b = (_a = options.stdin).resume) === null || _b === void 0 ? void 0 : _b.call(_a);
409
- const answer = (_c = (yield readLine())) === null || _c === void 0 ? void 0 : _c.trim().toLowerCase();
410
- if (answer === undefined || answer === "q" || answer === "quit") {
411
- return null;
412
- }
413
- if (answer === "a" || answer === "all" || answer === "*") {
414
- return [...agents];
415
- }
416
- const asIndex = Number.parseInt(answer, 10);
417
- if (!Number.isNaN(asIndex) &&
418
- String(asIndex) === answer &&
419
- asIndex >= 1 &&
420
- asIndex <= agents.length) {
421
- return [agents[asIndex - 1]];
422
- }
423
- const bySlug = agents.find(agent => agent.slug.toLowerCase() === answer);
424
- if (bySlug !== undefined) {
425
- return [bySlug];
426
- }
427
- options.err(`Unrecognized choice ${JSON.stringify(answer)} — expected 1–${agents.length}, a slug, "all", or "q". Aborting.\n`);
376
+ export async function promptChooseDeployTargets(agents, options) {
377
+ options.err(`Multiple agents (${agents.length}):\n` + formatAgentList(agents) + ` a) all\n`);
378
+ if (!options.interactive) {
379
+ return [];
380
+ }
381
+ options.err('Deploy which? Enter a number, slug, "all", or "q" to cancel: ');
382
+ const readLine = createLineReader(options.stdin);
383
+ // createLineReader pauses until data; ensure stdin is flowing on a TTY.
384
+ options.stdin.resume?.();
385
+ const answer = (await readLine())?.trim().toLowerCase();
386
+ if (answer === undefined || answer === "q" || answer === "quit") {
428
387
  return null;
429
- });
388
+ }
389
+ if (answer === "a" || answer === "all" || answer === "*") {
390
+ return [...agents];
391
+ }
392
+ const asIndex = Number.parseInt(answer, 10);
393
+ if (!Number.isNaN(asIndex) &&
394
+ String(asIndex) === answer &&
395
+ asIndex >= 1 &&
396
+ asIndex <= agents.length) {
397
+ return [agents[asIndex - 1]];
398
+ }
399
+ const bySlug = agents.find(agent => agent.slug.toLowerCase() === answer);
400
+ if (bySlug !== undefined) {
401
+ return [bySlug];
402
+ }
403
+ options.err(`Unrecognized choice ${JSON.stringify(answer)} — expected 1–${agents.length}, a slug, "all", or "q". Aborting.\n`);
404
+ return null;
430
405
  }
431
- function deployOne(ctx, options, target, extras) {
432
- return __awaiter(this, void 0, void 0, function* () {
433
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
434
- const { dir, slug } = target;
435
- // Fill --repo/--ref/--path from the local git checkout when omitted so
436
- // `agent-sdk deploy` inside an agent directory is enough. Only probe git
437
- // for real agent projects (avoids ambient monorepo remotes when someone
438
- // deploys a bare --slug). Explicit flags always win.
439
- const isAgent = yield isAgentProjectDir(dir);
440
- const needsGitInference = isAgent &&
441
- (options.repo === undefined || options.ref === undefined || options.path === undefined);
442
- const inferred = needsGitInference
443
- ? yield inferDeployGitSource(dir, Object.assign({}, (options.git === undefined ? {} : { git: options.git })))
444
- : {};
445
- const gitRepoUrl = (_a = options.repo) !== null && _a !== void 0 ? _a : inferred.gitRepoUrl;
446
- const gitRef = (_b = options.ref) !== null && _b !== void 0 ? _b : inferred.gitRef;
447
- const agentPath = (_c = options.path) !== null && _c !== void 0 ? _c : inferred.agentPath;
448
- if (gitRepoUrl !== undefined && !gitRepoUrl.startsWith("https://")) {
449
- ctx.err(`Invalid --repo: ${gitRepoUrl} (expected an https:// git repository URL)\n`);
406
+ async function deployOne(ctx, options, target, extras) {
407
+ const { dir, slug } = target;
408
+ // Fill --repo/--ref/--path from the local git checkout when omitted so
409
+ // `agent-sdk deploy` inside an agent directory is enough. Only probe git
410
+ // for real agent projects (avoids ambient monorepo remotes when someone
411
+ // deploys a bare --slug). Explicit flags always win.
412
+ const isAgent = await isAgentProjectDir(dir);
413
+ const needsGitInference = isAgent &&
414
+ (options.repo === undefined || options.ref === undefined || options.path === undefined);
415
+ const inferred = needsGitInference
416
+ ? await inferDeployGitSource(dir, {
417
+ ...(options.git === undefined ? {} : { git: options.git }),
418
+ })
419
+ : {};
420
+ const gitRepoUrl = options.repo ?? inferred.gitRepoUrl;
421
+ const gitRef = options.ref ?? inferred.gitRef;
422
+ const agentPath = options.path ?? inferred.agentPath;
423
+ if (gitRepoUrl !== undefined && !gitRepoUrl.startsWith("https://")) {
424
+ ctx.err(`Invalid --repo: ${gitRepoUrl} (expected an https:// git repository URL)\n`);
425
+ return 1;
426
+ }
427
+ if (gitRepoUrl === undefined) {
428
+ ctx.err(`Could not resolve an https:// git repository URL for this deploy.\n` +
429
+ ` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n`);
430
+ return 1;
431
+ }
432
+ for (const repo of options.cursorEventsRepos ?? []) {
433
+ if (!isValidCursorEventRepo(repo)) {
434
+ ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
450
435
  return 1;
451
436
  }
452
- if (gitRepoUrl === undefined) {
453
- ctx.err(`Could not resolve an https:// git repository URL for this deploy.\n` +
454
- ` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n`);
455
- return 1;
437
+ }
438
+ if (!ctx.json && gitRepoUrl !== undefined) {
439
+ const inferredBits = [];
440
+ if (options.repo === undefined && inferred.gitRepoUrl !== undefined) {
441
+ inferredBits.push("repo");
456
442
  }
457
- for (const repo of (_d = options.cursorEventsRepos) !== null && _d !== void 0 ? _d : []) {
458
- if (!isValidCursorEventRepo(repo)) {
459
- ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
460
- return 1;
461
- }
443
+ if (options.ref === undefined && inferred.gitRef !== undefined) {
444
+ inferredBits.push("ref");
462
445
  }
463
- if (!ctx.json && gitRepoUrl !== undefined) {
464
- const inferredBits = [];
465
- if (options.repo === undefined && inferred.gitRepoUrl !== undefined) {
466
- inferredBits.push("repo");
467
- }
468
- if (options.ref === undefined && inferred.gitRef !== undefined) {
469
- inferredBits.push("ref");
470
- }
471
- if (options.path === undefined && inferred.agentPath !== undefined) {
472
- inferredBits.push("path");
473
- }
474
- ctx.err(` source: ${gitRepoUrl}${gitRef === undefined ? "" : ` @ ${gitRef}`}\n` +
475
- (agentPath === undefined ? "" : ` path: ${agentPath}\n`) +
476
- (inferredBits.length === 0
477
- ? ""
478
- : ` (inferred ${inferredBits.join(", ")} from git; pass --repo/--ref/--path to override)\n`));
479
- }
480
- // The package manifest (`defineAgent({ hosting })`) is the source of
481
- // truth for egress domains and expected secret names; flags override or
482
- // augment it. Directories without an agent project have no manifest. The same load supplies the
483
- // cursorAccount connection refs for the post-deploy connector auth and
484
- // the channels declared public via `publicEndpoint()`.
485
- const manifest = isAgent ? yield readDeployManifest(dir) : undefined;
486
- const hosting = manifest === null || manifest === void 0 ? void 0 : manifest.hosting;
487
- const egressAllowedDomains = [
488
- ...new Set([...((_e = hosting === null || hosting === void 0 ? void 0 : hosting.egressDomains) !== null && _e !== void 0 ? _e : []), ...((_f = options.allowDomains) !== null && _f !== void 0 ? _f : [])]),
489
- ];
490
- const publicRoutePaths = ((_g = manifest === null || manifest === void 0 ? void 0 : manifest.publicChannelIds) !== null && _g !== void 0 ? _g : []).map(channelId => `/v1/channels/${channelId}`);
491
- if (!ctx.json && (manifest === null || manifest === void 0 ? void 0 : manifest.httpChannelPublicEndpoint) === true) {
492
- ctx.err(`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`);
493
- }
494
- if (!ctx.json && publicRoutePaths.length > 0 && (manifest === null || manifest === void 0 ? void 0 : manifest.architecture) !== "v2") {
495
- // Security-relevant surface change: say exactly what will be reachable
496
- // without the alias token before the deploy is accepted. v2 registers
497
- // these routes only after bake, so a relative path here would not be a
498
- // live webhook URL — the running status prints the absolute one.
499
- ctx.err(` public: ${publicRoutePaths.join(", ")} (served WITHOUT the alias token — these channels authenticate requests themselves)\n`);
500
- }
501
- const extensionEgress = (_h = manifest === null || manifest === void 0 ? void 0 : manifest.extensionEgress) !== null && _h !== void 0 ? _h : [];
502
- if (!ctx.json && extensionEgress.length > 0) {
503
- // Mounted packages widen the pod's egress without an agent.ts edit; name
504
- // each one before the deploy is accepted.
505
- ctx.err(` egress from extensions: ${extensionEgress
506
- .map(entry => `${entry.extension} (${entry.egressDomains.join(", ")})`)
507
- .join("; ")}\n`);
508
- }
509
- const deadSecretChannels = (_j = manifest === null || manifest === void 0 ? void 0 : manifest.publicChannelIdsWithDeadSecretPolicies) !== null && _j !== void 0 ? _j : [];
510
- if (!ctx.json && deadSecretChannels.length > 0) {
511
- ctx.err(`warning: ${deadSecretChannels
512
- .map(channelId => `/v1/channels/${channelId}`)
513
- .join(", ")}: 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`);
514
- }
515
- if ((manifest === null || manifest === void 0 ? void 0 : manifest.architecture) === "v2") {
516
- if (!ctx.json) {
517
- ctx.err(` architecture: v2${manifest.persistent ? " (persistent)" : ""}${manifest.image === undefined ? "" : `\n image: ${manifest.image}`}\n`);
518
- }
519
- return deployOneAgentsdk(ctx, extras, {
520
- persistent: manifest.persistent,
521
- image: manifest.image,
522
- slug,
523
- gitRepoUrl,
524
- gitRef,
525
- agentPath,
526
- repositories: options.cursorEventsRepos,
527
- hasScmChannels: manifest.hasScmChannels,
528
- declaredSecretNames: hosting === null || hosting === void 0 ? void 0 : hosting.secretNames,
529
- hasDeploymentsChannels: manifest.hasDeploymentsChannels,
530
- multiTenant: options.multiTenant === true,
531
- });
446
+ if (options.path === undefined && inferred.agentPath !== undefined) {
447
+ inferredBits.push("path");
532
448
  }
533
- if (options.multiTenant === true) {
534
- ctx.err("--multi-tenant is only valid for architecture: v2 deploys (Cursor-managed products).\n");
535
- return 1;
449
+ ctx.err(` source: ${gitRepoUrl}${gitRef === undefined ? "" : ` @ ${gitRef}`}\n` +
450
+ (agentPath === undefined ? "" : ` path: ${agentPath}\n`) +
451
+ (inferredBits.length === 0
452
+ ? ""
453
+ : ` (inferred ${inferredBits.join(", ")} from git; pass --repo/--ref/--path to override)\n`));
454
+ }
455
+ // The package manifest (`defineAgent({ hosting })`) is the source of
456
+ // truth for egress domains and expected secret names; flags override or
457
+ // augment it. Directories without an agent project have no manifest. The same load supplies the
458
+ // cursorAccount connection refs for the post-deploy connector auth and
459
+ // the channels declared public via `publicEndpoint()`.
460
+ const manifest = isAgent ? await readDeployManifest(dir) : undefined;
461
+ const hosting = manifest?.hosting;
462
+ const egressAllowedDomains = [
463
+ ...new Set([...(hosting?.egressDomains ?? []), ...(options.allowDomains ?? [])]),
464
+ ];
465
+ const publicRoutePaths = (manifest?.publicChannelIds ?? []).map(channelId => `/v1/channels/${channelId}`);
466
+ if (!ctx.json && manifest?.httpChannelPublicEndpoint === true) {
467
+ ctx.err(`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`);
468
+ }
469
+ if (!ctx.json && publicRoutePaths.length > 0 && manifest?.architecture !== "v2") {
470
+ // Security-relevant surface change: say exactly what will be reachable
471
+ // without the alias token before the deploy is accepted. v2 registers
472
+ // these routes only after bake, so a relative path here would not be a
473
+ // live webhook URL — the running status prints the absolute one.
474
+ ctx.err(` public: ${publicRoutePaths.join(", ")} (served WITHOUT the alias token — these channels authenticate requests themselves)\n`);
475
+ }
476
+ const extensionEgress = manifest?.extensionEgress ?? [];
477
+ if (!ctx.json && extensionEgress.length > 0) {
478
+ // Mounted packages widen the pod's egress without an agent.ts edit; name
479
+ // each one before the deploy is accepted.
480
+ ctx.err(` egress from extensions: ${extensionEgress
481
+ .map(entry => `${entry.extension} (${entry.egressDomains.join(", ")})`)
482
+ .join("; ")}\n`);
483
+ }
484
+ const deadSecretChannels = manifest?.publicChannelIdsWithDeadSecretPolicies ?? [];
485
+ if (!ctx.json && deadSecretChannels.length > 0) {
486
+ ctx.err(`warning: ${deadSecretChannels
487
+ .map(channelId => `/v1/channels/${channelId}`)
488
+ .join(", ")}: 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`);
489
+ }
490
+ if (manifest?.architecture === "v2") {
491
+ if (!ctx.json) {
492
+ ctx.err(` architecture: v2${manifest.persistent ? " (persistent)" : ""}${manifest.image === undefined ? "" : `\n image: ${manifest.image}`}\n`);
536
493
  }
537
- // Today's only source shape: the control plane builds from a git ref.
538
- // See DeploySource for the artifact seam.
539
- const source = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ kind: "git-ref", gitRepoUrl }, (gitRef === undefined ? {} : { gitRef })), (agentPath === undefined ? {} : { agentPath })), (options.cursorEventsRepos === undefined || options.cursorEventsRepos.length === 0
494
+ return deployOneAgentsdk(ctx, extras, {
495
+ persistent: manifest.persistent,
496
+ image: manifest.image,
497
+ slug,
498
+ gitRepoUrl,
499
+ gitRef,
500
+ agentPath,
501
+ repositories: options.cursorEventsRepos,
502
+ hasScmChannels: manifest.hasScmChannels,
503
+ declaredSecretNames: declaredSecretNames([manifest]),
504
+ hasDeploymentsChannels: manifest.hasDeploymentsChannels,
505
+ multiTenant: options.multiTenant === true,
506
+ });
507
+ }
508
+ if (options.multiTenant === true) {
509
+ ctx.err("--multi-tenant is only valid for architecture: v2 deploys (Cursor-managed products).\n");
510
+ return 1;
511
+ }
512
+ // Today's only source shape: the control plane builds from a git ref.
513
+ // See DeploySource for the artifact seam.
514
+ const source = {
515
+ kind: "git-ref",
516
+ gitRepoUrl,
517
+ ...(gitRef === undefined ? {} : { gitRef }),
518
+ ...(agentPath === undefined ? {} : { agentPath }),
519
+ ...(options.cursorEventsRepos === undefined || options.cursorEventsRepos.length === 0
540
520
  ? {}
541
- : { cursorEventRepos: options.cursorEventsRepos })), (egressAllowedDomains.length === 0 ? {} : { egressAllowedDomains })), { publicRoutePaths: publicRoutePaths.length === 0 ? undefined : publicRoutePaths });
542
- let accepted;
543
- try {
544
- accepted = yield ctx.client.deploy({
545
- teamId: ctx.teamId,
546
- slug,
547
- source,
548
- template: readDeployTemplate(dir),
549
- });
550
- }
551
- catch (error) {
552
- return renderApiError(error, ctx.err);
553
- }
554
- const aliasUrl = ctx.client.aliasUrl(accepted.engineAlias);
555
- if (!ctx.json && accepted.aliasToken !== undefined) {
556
- ctx.out(aliasTokenBlock(accepted.aliasToken));
557
- }
558
- if (ctx.noWait) {
559
- if ((extras === null || extras === void 0 ? void 0 : extras.jsonCollect) !== undefined) {
560
- extras.jsonCollect.push(accepted);
561
- }
562
- else if (ctx.json) {
563
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
564
- }
565
- else {
566
- ctx.out(`Deploy accepted: ${slug} (team ${ctx.teamId}, generation ${accepted.generation}, ${accepted.deploymentKind})\n` +
567
- ` alias: ${aliasUrl}\n` +
568
- `Check progress with \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.\n`);
569
- }
570
- return 0;
571
- }
572
- let detail;
573
- try {
574
- detail = yield pollUntil(ctx, slug, TERMINAL_DEPLOY_STATUSES, () => ctx.client.getDeployment({ teamId: ctx.teamId, slug }));
575
- }
576
- catch (error) {
577
- return renderApiError(error, ctx.err);
578
- }
579
- warnMissingSecrets(ctx, slug, hosting === null || hosting === void 0 ? void 0 : hosting.secretNames, detail.secretNames);
580
- const payload = accepted.aliasToken === undefined ? detail : Object.assign(Object.assign({}, detail), { aliasToken: accepted.aliasToken });
581
- if ((extras === null || extras === void 0 ? void 0 : extras.jsonCollect) !== undefined) {
582
- extras.jsonCollect.push(payload);
583
- return detail.status === "running" ? 0 : 1;
521
+ : { cursorEventRepos: options.cursorEventsRepos }),
522
+ ...(egressAllowedDomains.length === 0 ? {} : { egressAllowedDomains }),
523
+ publicRoutePaths: publicRoutePaths.length === 0 ? undefined : publicRoutePaths,
524
+ // Deliberately NO manifest here: the control plane captures it from the
525
+ // provisioned engine (`GET /v1/manifest` after the health probe), which
526
+ // is the single write path for deploy manifests. `july manifest` remains
527
+ // available for local visibility only.
528
+ };
529
+ let accepted;
530
+ try {
531
+ accepted = await ctx.client.deploy({
532
+ teamId: ctx.teamId,
533
+ slug,
534
+ source,
535
+ template: readDeployTemplate(dir),
536
+ });
537
+ }
538
+ catch (error) {
539
+ return renderApiError(error, ctx.err);
540
+ }
541
+ const aliasUrl = ctx.client.aliasUrl(accepted.engineAlias);
542
+ if (!ctx.json && accepted.aliasToken !== undefined) {
543
+ ctx.out(aliasTokenBlock(accepted.aliasToken));
544
+ }
545
+ if (ctx.noWait) {
546
+ if (extras?.jsonCollect !== undefined) {
547
+ extras.jsonCollect.push(accepted);
584
548
  }
585
- if (ctx.json) {
586
- ctx.out(`${JSON.stringify(payload, null, 2)}\n`);
587
- return detail.status === "running" ? 0 : 1;
549
+ else if (ctx.json) {
550
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
588
551
  }
589
- if (detail.status !== "running") {
590
- ctx.err(`Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`);
591
- return 1;
552
+ else {
553
+ ctx.out(`Deploy accepted: ${slug} (team ${ctx.teamId}, generation ${accepted.generation}, ${accepted.deploymentKind})\n` +
554
+ ` alias: ${aliasUrl}\n` +
555
+ `Check progress with \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.\n`);
592
556
  }
593
- const deployedPublicRoutes = (_k = detail.publicRoutePaths) !== null && _k !== void 0 ? _k : [];
594
- ctx.out(`Deployed ${slug} (team ${ctx.teamId})\n` +
595
- ` status: running\n` +
596
- ` generation: ${detail.generation}\n` +
597
- ` kind: ${detail.deploymentKind}\n` +
598
- ` alias: ${aliasUrl}\n` +
599
- ` playground: ${aliasUrl}/playground (sign in with the alias token)\n` +
600
- ` open: ${CLI} playground --prod --slug ${slug} --team ${ctx.teamId}\n` +
601
- // Paste-ready webhook URLs: these subtrees skip the alias token, so
602
- // the channel handler must verify deliveries (webhook signatures).
603
- deployedPublicRoutes
604
- .map(path => ` public: ${aliasUrl}${path} (no alias token)\n`)
605
- .join(""));
606
- yield runPostDeployConnectorAuth(ctx, options, {
607
- slug,
608
- connections: (_l = manifest === null || manifest === void 0 ? void 0 : manifest.cursorAccountConnections) !== null && _l !== void 0 ? _l : [],
609
- serviceAccountId: deploymentServiceAccountId(detail),
610
- });
611
557
  return 0;
558
+ }
559
+ let detail;
560
+ try {
561
+ detail = await pollUntil(ctx, slug, TERMINAL_DEPLOY_STATUSES, () => ctx.client.getDeployment({ teamId: ctx.teamId, slug }));
562
+ }
563
+ catch (error) {
564
+ return renderApiError(error, ctx.err);
565
+ }
566
+ warnMissingSecrets(ctx, slug, declaredSecretNames([manifest]), detail.secretNames);
567
+ const payload = accepted.aliasToken === undefined ? detail : { ...detail, aliasToken: accepted.aliasToken };
568
+ if (extras?.jsonCollect !== undefined) {
569
+ extras.jsonCollect.push(payload);
570
+ return detail.status === "running" ? 0 : 1;
571
+ }
572
+ if (ctx.json) {
573
+ ctx.out(`${JSON.stringify(payload, null, 2)}\n`);
574
+ return detail.status === "running" ? 0 : 1;
575
+ }
576
+ if (detail.status !== "running") {
577
+ ctx.err(`Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`);
578
+ return 1;
579
+ }
580
+ const deployedPublicRoutes = detail.publicRoutePaths ?? [];
581
+ ctx.out(`Deployed ${slug} (team ${ctx.teamId})\n` +
582
+ ` status: running\n` +
583
+ ` generation: ${detail.generation}\n` +
584
+ ` kind: ${detail.deploymentKind}\n` +
585
+ ` alias: ${aliasUrl}\n` +
586
+ ` playground: ${aliasUrl}/playground (sign in with the alias token)\n` +
587
+ ` open: ${CLI} playground --prod --slug ${slug} --team ${ctx.teamId}\n` +
588
+ // Paste-ready webhook URLs: these subtrees skip the alias token, so
589
+ // the channel handler must verify deliveries (webhook signatures).
590
+ deployedPublicRoutes
591
+ .map(path => ` public: ${aliasUrl}${path} (no alias token)\n`)
592
+ .join(""));
593
+ await runPostDeployConnectorAuth(ctx, options, {
594
+ slug,
595
+ connections: manifest?.cursorAccountConnections ?? [],
596
+ serviceAccountId: deploymentServiceAccountId(detail),
612
597
  });
598
+ return 0;
613
599
  }
614
600
  /**
615
601
  * Multi-agent parent whose children all declare `architecture: "v2"`:
@@ -618,158 +604,165 @@ function deployOne(ctx, options, target, extras) {
618
604
  * key is the child's slug and its path is the child directory relative to
619
605
  * the repo root (a shared --path names the parent's directory in the repo).
620
606
  */
621
- function deployAgentsdkApplication(ctx, options, targets, declarations) {
622
- return __awaiter(this, void 0, void 0, function* () {
623
- var _a, _b, _c, _d, _e;
624
- const parentDir = resolve((_a = options.dir) !== null && _a !== void 0 ? _a : ".");
625
- const slug = slugFromDirectoryName(basename(parentDir));
626
- if (slug === undefined) {
627
- ctx.err(`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`);
628
- return 1;
629
- }
630
- const needsGitInference = options.repo === undefined || options.ref === undefined || options.path === undefined;
631
- const inferred = needsGitInference
632
- ? yield inferDeployGitSource(parentDir, Object.assign({}, (options.git === undefined ? {} : { git: options.git })))
633
- : {};
634
- const gitRepoUrl = (_b = options.repo) !== null && _b !== void 0 ? _b : inferred.gitRepoUrl;
635
- const gitRef = (_c = options.ref) !== null && _c !== void 0 ? _c : inferred.gitRef;
636
- const parentPath = (_d = options.path) !== null && _d !== void 0 ? _d : inferred.agentPath;
637
- if (gitRepoUrl !== undefined && !gitRepoUrl.startsWith("https://")) {
638
- ctx.err(`Invalid --repo: ${gitRepoUrl} (expected an https:// git repository URL)\n`);
639
- return 1;
640
- }
641
- if (gitRepoUrl === undefined) {
642
- ctx.err(`Could not resolve an https:// git repository URL for this deploy.\n` +
643
- ` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n`);
607
+ async function deployAgentsdkApplication(ctx, options, targets, declarations) {
608
+ const parentDir = resolve(options.dir ?? ".");
609
+ const slug = slugFromDirectoryName(basename(parentDir));
610
+ if (slug === undefined) {
611
+ ctx.err(`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`);
612
+ return 1;
613
+ }
614
+ const needsGitInference = options.repo === undefined || options.ref === undefined || options.path === undefined;
615
+ const inferred = needsGitInference
616
+ ? await inferDeployGitSource(parentDir, {
617
+ ...(options.git === undefined ? {} : { git: options.git }),
618
+ })
619
+ : {};
620
+ const gitRepoUrl = options.repo ?? inferred.gitRepoUrl;
621
+ const gitRef = options.ref ?? inferred.gitRef;
622
+ const parentPath = options.path ?? inferred.agentPath;
623
+ if (gitRepoUrl !== undefined && !gitRepoUrl.startsWith("https://")) {
624
+ ctx.err(`Invalid --repo: ${gitRepoUrl} (expected an https:// git repository URL)\n`);
625
+ return 1;
626
+ }
627
+ if (gitRepoUrl === undefined) {
628
+ ctx.err(`Could not resolve an https:// git repository URL for this deploy.\n` +
629
+ ` Pass --repo https://github.com/<owner>/<repo> (inferred from origin when possible).\n`);
630
+ return 1;
631
+ }
632
+ for (const repo of options.cursorEventsRepos ?? []) {
633
+ if (!isValidCursorEventRepo(repo)) {
634
+ ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
644
635
  return 1;
645
636
  }
646
- for (const repo of (_e = options.cursorEventsRepos) !== null && _e !== void 0 ? _e : []) {
647
- if (!isValidCursorEventRepo(repo)) {
648
- ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
649
- return 1;
650
- }
651
- }
652
- const components = targets.map(target => ({
653
- componentKey: target.slug,
654
- agentPath: [parentPath, basename(target.dir)]
655
- .filter((part) => part !== undefined && part !== "")
656
- .join("/"),
657
- persistent: declarations.componentPersistent[target.slug] === true,
658
- image: declarations.componentImage[target.slug],
659
- }));
660
- if (!ctx.json) {
661
- ctx.err(`Deploying "${slug}" as one v2 application with ${targets.length} components (slug from the parent directory name).\n` +
662
- ` architecture: v2\n` +
663
- ` source: ${gitRepoUrl}${gitRef === undefined ? "" : ` @ ${gitRef}`}\n` +
664
- components
665
- .map(component => { var _a; return ` component: ${component.componentKey} (${(_a = component.agentPath) !== null && _a !== void 0 ? _a : "."})${component.persistent ? " persistent" : ""}${component.image === undefined ? "" : ` image ${component.image}`}\n`; })
666
- .join(""));
667
- }
668
- return deployOneAgentsdk(ctx, undefined, {
669
- // Multi-component: the flag travels on each component instead.
670
- persistent: false,
671
- slug,
672
- gitRepoUrl,
673
- gitRef,
674
- agentPath: undefined,
675
- components,
676
- repositories: options.cursorEventsRepos,
677
- hasScmChannels: declarations.hasScmChannels,
678
- declaredSecretNames: declarations.declaredSecretNames,
679
- hasDeploymentsChannels: declarations.hasDeploymentsChannels,
680
- multiTenant: options.multiTenant === true,
681
- });
637
+ }
638
+ const components = targets.map(target => ({
639
+ componentKey: target.slug,
640
+ agentPath: [parentPath, basename(target.dir)]
641
+ .filter((part) => part !== undefined && part !== "")
642
+ .join("/"),
643
+ persistent: declarations.componentPersistent[target.slug] === true,
644
+ image: declarations.componentImage[target.slug],
645
+ }));
646
+ if (!ctx.json) {
647
+ ctx.err(`Deploying "${slug}" as one v2 application with ${targets.length} components (slug from the parent directory name).\n` +
648
+ ` architecture: v2\n` +
649
+ ` source: ${gitRepoUrl}${gitRef === undefined ? "" : ` @ ${gitRef}`}\n` +
650
+ components
651
+ .map(component => ` component: ${component.componentKey} (${component.agentPath ?? "."})${component.persistent ? " persistent" : ""}${component.image === undefined ? "" : ` image ${component.image}`}\n`)
652
+ .join(""));
653
+ }
654
+ return deployOneAgentsdk(ctx, undefined, {
655
+ // Multi-component: the flag travels on each component instead.
656
+ persistent: false,
657
+ slug,
658
+ gitRepoUrl,
659
+ gitRef,
660
+ agentPath: undefined,
661
+ components,
662
+ repositories: options.cursorEventsRepos,
663
+ hasScmChannels: declarations.hasScmChannels,
664
+ declaredSecretNames: declarations.declaredSecretNames,
665
+ hasDeploymentsChannels: declarations.hasDeploymentsChannels,
666
+ multiTenant: options.multiTenant === true,
682
667
  });
683
668
  }
684
669
  /**
685
670
  * `architecture: "v2"` deploy: POST `/internal/agentsdk/deployments` and
686
671
  * poll the matching GET.
687
672
  */
688
- function deployOneAgentsdk(ctx, extras, args) {
689
- return __awaiter(this, void 0, void 0, function* () {
690
- var _a;
691
- const { slug } = args;
692
- const componentsLine = args.components === undefined
693
- ? ""
694
- : ` components: ${args.components.map(component => component.componentKey).join(", ")}\n`;
695
- if (args.multiTenant && !ctx.json) {
696
- ctx.err(" multi-tenant: existing product\n");
697
- }
698
- let accepted;
699
- try {
700
- accepted = yield ctx.client.deployAgentkit(Object.assign(Object.assign({ teamId: ctx.teamId, slug, gitRepoUrl: args.gitRepoUrl, gitRef: args.gitRef, agentPath: args.agentPath, components: args.components, repositories: args.repositories }, (args.multiTenant ? { multiTenant: true } : {})), { persistent: args.persistent, image: args.image }));
701
- }
702
- catch (error) {
703
- return renderApiError(error, ctx.err, {
704
- multiTenant: args.multiTenant,
705
- teamId: ctx.teamId,
706
- });
707
- }
708
- if (!ctx.json && accepted.aliasToken !== undefined) {
709
- ctx.out(aliasTokenBlock(accepted.aliasToken));
710
- }
711
- if (ctx.noWait) {
712
- if ((extras === null || extras === void 0 ? void 0 : extras.jsonCollect) !== undefined) {
713
- extras.jsonCollect.push(accepted);
714
- }
715
- else if (ctx.json) {
716
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
717
- }
718
- else {
719
- ctx.out(`Deploy accepted: ${slug} (team ${ctx.teamId}, v2)\n` +
720
- ` application: ${accepted.applicationId}\n` +
721
- ` release: ${accepted.releaseId}\n` +
722
- ` alias: ${ctx.client.aliasUrl(accepted.engineAlias)}\n` +
723
- componentsLine);
724
- }
725
- return 0;
726
- }
727
- let detail;
728
- try {
729
- detail = yield pollUntil(ctx, slug, TERMINAL_AGENTKIT_DEPLOY_STATUSES, () => ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug }));
730
- }
731
- catch (error) {
732
- return renderApiError(error, ctx.err);
733
- }
734
- const payload = Object.assign(Object.assign({}, detail), { aliasToken: accepted.aliasToken });
735
- if ((extras === null || extras === void 0 ? void 0 : extras.jsonCollect) !== undefined) {
736
- extras.jsonCollect.push(payload);
737
- return detail.status === "running" ? 0 : 1;
738
- }
739
- if (ctx.json) {
740
- ctx.out(`${JSON.stringify(payload, null, 2)}\n`);
741
- return detail.status === "running" ? 0 : 1;
673
+ async function deployOneAgentsdk(ctx, extras, args) {
674
+ const { slug } = args;
675
+ const componentsLine = args.components === undefined
676
+ ? ""
677
+ : ` components: ${args.components.map(component => component.componentKey).join(", ")}\n`;
678
+ if (args.multiTenant && !ctx.json) {
679
+ ctx.err(" multi-tenant: existing product\n");
680
+ }
681
+ let accepted;
682
+ try {
683
+ accepted = await ctx.client.deployAgentkit({
684
+ teamId: ctx.teamId,
685
+ slug,
686
+ gitRepoUrl: args.gitRepoUrl,
687
+ gitRef: args.gitRef,
688
+ agentPath: args.agentPath,
689
+ components: args.components,
690
+ repositories: args.repositories,
691
+ ...(args.multiTenant ? { multiTenant: true } : {}),
692
+ persistent: args.persistent,
693
+ image: args.image,
694
+ });
695
+ }
696
+ catch (error) {
697
+ return renderApiError(error, ctx.err, {
698
+ multiTenant: args.multiTenant,
699
+ teamId: ctx.teamId,
700
+ });
701
+ }
702
+ if (!ctx.json && accepted.aliasToken !== undefined) {
703
+ ctx.out(aliasTokenBlock(accepted.aliasToken));
704
+ }
705
+ if (ctx.noWait) {
706
+ if (extras?.jsonCollect !== undefined) {
707
+ extras.jsonCollect.push(accepted);
742
708
  }
743
- if (detail.status !== "running") {
744
- ctx.err(`Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`);
745
- return 1;
709
+ else if (ctx.json) {
710
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
746
711
  }
747
- warnMissingSecrets(ctx, slug, args.declaredSecretNames, detail.secretNames);
748
- const watchesRepositories = args.hasScmChannels || args.hasDeploymentsChannels === true;
749
- ctx.out(`Deployed ${slug} (team ${ctx.teamId})\n` +
750
- ` status: running\n` +
751
- ` architecture: v2\n` +
752
- ` application: ${detail.applicationId}\n` +
753
- ` release: ${detail.releaseId}\n` +
754
- ` alias: ${ctx.client.aliasUrl(accepted.engineAlias)}\n` +
755
- (args.components === undefined
756
- ? ""
757
- : ` components: ${args.components
758
- .map(component => component.componentKey)
759
- .join(", ")}\n`) +
760
- (detail.repositories === undefined || !watchesRepositories
761
- ? ""
762
- : ` watching: ${detail.repositories.length === 0 ? "(nothing)" : detail.repositories.join(", ")}\n`) +
763
- livePublicWebhookLines(ctx, detail));
764
- // An agent with GitHub/Origin/deployments channels bound to no repository
765
- // scope gets no deliveries at all (deployments channels receive the
766
- // watched repos' deployment events), which is otherwise invisible here.
767
- if (watchesRepositories && ((_a = detail.repositories) === null || _a === void 0 ? void 0 : _a.length) === 0) {
768
- ctx.err(`warning: ${slug} watches no repositories, so its GitHub/Origin/deployments channels receive no events.\n` +
769
- ` Redeploy with --cursor-events-repo <owner>/<name> to set the scope.\n`);
712
+ else {
713
+ ctx.out(`Deploy accepted: ${slug} (team ${ctx.teamId}, v2)\n` +
714
+ ` application: ${accepted.applicationId}\n` +
715
+ ` release: ${accepted.releaseId}\n` +
716
+ ` alias: ${ctx.client.aliasUrl(accepted.engineAlias)}\n` +
717
+ componentsLine);
770
718
  }
771
719
  return 0;
772
- });
720
+ }
721
+ let detail;
722
+ try {
723
+ detail = await pollUntil(ctx, slug, TERMINAL_AGENTKIT_DEPLOY_STATUSES, () => ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug }));
724
+ }
725
+ catch (error) {
726
+ return renderApiError(error, ctx.err);
727
+ }
728
+ const payload = { ...detail, aliasToken: accepted.aliasToken };
729
+ if (extras?.jsonCollect !== undefined) {
730
+ extras.jsonCollect.push(payload);
731
+ return detail.status === "running" ? 0 : 1;
732
+ }
733
+ if (ctx.json) {
734
+ ctx.out(`${JSON.stringify(payload, null, 2)}\n`);
735
+ return detail.status === "running" ? 0 : 1;
736
+ }
737
+ if (detail.status !== "running") {
738
+ ctx.err(`Deployment ${slug} ended ${detail.status}${deployFailureDetail(detail.lastError)}\n`);
739
+ return 1;
740
+ }
741
+ warnMissingSecrets(ctx, slug, args.declaredSecretNames, detail.secretNames);
742
+ const watchesRepositories = args.hasScmChannels || args.hasDeploymentsChannels === true;
743
+ ctx.out(`Deployed ${slug} (team ${ctx.teamId})\n` +
744
+ ` status: running\n` +
745
+ ` architecture: v2\n` +
746
+ ` application: ${detail.applicationId}\n` +
747
+ ` release: ${detail.releaseId}\n` +
748
+ ` alias: ${ctx.client.aliasUrl(accepted.engineAlias)}\n` +
749
+ (args.components === undefined
750
+ ? ""
751
+ : ` components: ${args.components
752
+ .map(component => component.componentKey)
753
+ .join(", ")}\n`) +
754
+ (detail.repositories === undefined || !watchesRepositories
755
+ ? ""
756
+ : ` watching: ${detail.repositories.length === 0 ? "(nothing)" : detail.repositories.join(", ")}\n`) +
757
+ livePublicWebhookLines(ctx, detail));
758
+ // An agent with GitHub/Origin/deployments channels bound to no repository
759
+ // scope gets no deliveries at all (deployments channels receive the
760
+ // watched repos' deployment events), which is otherwise invisible here.
761
+ if (watchesRepositories && detail.repositories?.length === 0) {
762
+ ctx.err(`warning: ${slug} watches no repositories, so its GitHub/Origin/deployments channels receive no events.\n` +
763
+ ` Redeploy with --cursor-events-repo <owner>/<name> to set the scope.\n`);
764
+ }
765
+ return 0;
773
766
  }
774
767
  /**
775
768
  * Post-deploy connector authorization for `cursorAccount` connections: the
@@ -779,113 +772,124 @@ function deployOneAgentsdk(ctx, extras, args) {
779
772
  * ones skipped); otherwise it reports status only. Never affects the deploy
780
773
  * outcome — anything left unauthorized just gets a playground-page pointer.
781
774
  */
782
- function runPostDeployConnectorAuth(ctx, options, args) {
783
- return __awaiter(this, void 0, void 0, function* () {
784
- if (args.connections.length === 0) {
785
- return;
786
- }
787
- const { serviceAccountId } = args;
788
- if (serviceAccountId === undefined) {
789
- ctx.err(`warning: this agent uses Cursor account connectors, but the deployment has no service account; redeploy to mint one.\n`);
790
- return;
791
- }
792
- const backendClient = new CursorBackendClient({
793
- backendUrl: ctx.backendUrl,
794
- apiKey: ctx.apiKey,
795
- fetchImpl: options.fetchImpl,
796
- });
797
- const interactive = options.openBrowserImpl !== undefined ||
798
- (process.stdout.isTTY === true && process.stdin.isTTY === true);
799
- let anyUnauthorized = false;
800
- for (const ref of args.connections) {
801
- ctx.out(`\nThis agent uses Cursor account connectors (connection "${ref.name}"${ref.servers === undefined || ref.servers.length === 0 ? "" : `: ${ref.servers.join(", ")}`}).\n`);
802
- try {
803
- const result = yield authorizeCursorAccountConnectors({
804
- backendClient,
805
- teamId: ctx.teamId,
806
- slug: args.slug,
807
- serviceAccountId,
808
- connectionName: ref.name,
809
- servers: ref.servers,
810
- interactive,
811
- out: ctx.out,
812
- err: ctx.err,
813
- openBrowserImpl: options.openBrowserImpl,
814
- sleep: options.sleepImpl,
815
- pollIntervalMs: options.connectorPollIntervalMs,
816
- pollTimeoutMs: options.connectorPollTimeoutMs,
817
- });
818
- if (result.pending.length > 0 || result.errored.length > 0) {
819
- anyUnauthorized = true;
820
- if (result.pending.length > 0) {
821
- ctx.out(`Connectors not authorized yet: ${result.pending.join(", ")}.\n`);
822
- }
823
- }
824
- }
825
- catch (error) {
775
+ async function runPostDeployConnectorAuth(ctx, options, args) {
776
+ if (args.connections.length === 0) {
777
+ return;
778
+ }
779
+ const { serviceAccountId } = args;
780
+ if (serviceAccountId === undefined) {
781
+ ctx.err(`warning: this agent uses Cursor account connectors, but the deployment has no service account; redeploy to mint one.\n`);
782
+ return;
783
+ }
784
+ const backendClient = new CursorBackendClient({
785
+ backendUrl: ctx.backendUrl,
786
+ apiKey: ctx.apiKey,
787
+ fetchImpl: options.fetchImpl,
788
+ });
789
+ const interactive = options.openBrowserImpl !== undefined ||
790
+ (process.stdout.isTTY === true && process.stdin.isTTY === true);
791
+ let anyUnauthorized = false;
792
+ for (const ref of args.connections) {
793
+ ctx.out(`\nThis agent uses Cursor account connectors (connection "${ref.name}"${ref.servers === undefined || ref.servers.length === 0 ? "" : `: ${ref.servers.join(", ")}`}).\n`);
794
+ try {
795
+ const result = await authorizeCursorAccountConnectors({
796
+ backendClient,
797
+ teamId: ctx.teamId,
798
+ slug: args.slug,
799
+ serviceAccountId,
800
+ connectionName: ref.name,
801
+ servers: ref.servers,
802
+ interactive,
803
+ out: ctx.out,
804
+ err: ctx.err,
805
+ openBrowserImpl: options.openBrowserImpl,
806
+ sleep: options.sleepImpl,
807
+ pollIntervalMs: options.connectorPollIntervalMs,
808
+ pollTimeoutMs: options.connectorPollTimeoutMs,
809
+ });
810
+ if (result.pending.length > 0 || result.errored.length > 0) {
826
811
  anyUnauthorized = true;
827
- ctx.err(`warning: could not check connector authorization for "${ref.name}": ${describeError(error)}\n`);
812
+ if (result.pending.length > 0) {
813
+ ctx.out(`Connectors not authorized yet: ${result.pending.join(", ")}.\n`);
814
+ }
828
815
  }
829
816
  }
830
- if (anyUnauthorized) {
831
- ctx.out(`You can authorize connectors at the playground page (cursor.com dashboard → Deployed Agents → ${args.slug}) or with \`${CLI} mcp oauth <connection>\`.\n`);
817
+ catch (error) {
818
+ anyUnauthorized = true;
819
+ ctx.err(`warning: could not check connector authorization for "${ref.name}": ${describeError(error)}\n`);
832
820
  }
833
- });
821
+ }
822
+ if (anyUnauthorized) {
823
+ ctx.out(`You can authorize connectors at the playground page (cursor.com dashboard → Deployed Agents → ${args.slug}) or with \`${CLI} mcp oauth <connection>\`.\n`);
824
+ }
834
825
  }
835
826
  /**
836
827
  * Read the deploy-relevant bits of the project manifest at `dir` in one
837
828
  * load: the `hosting` block, the agent's cursorAccount connections, and the
838
829
  * channels declared public via `publicEndpoint()`.
839
830
  */
840
- function readDeployManifest(dir) {
841
- return __awaiter(this, void 0, void 0, function* () {
842
- var _a;
843
- var _b, _c;
844
- const project = yield loadAgentProject(dir);
845
- // Fail here, before anything is dispatched: a project with error
846
- // diagnostics (e.g. agent/storage.ts on architecture v2) would only be
847
- // refused later by `serve` inside the hosted build, wasting a bake.
848
- if (hasErrorDiagnostics(project)) {
849
- throw new Error(`Refusing to deploy ${project.name} — it has errors:\n${formatDiagnostics(project.diagnostics.filter(d => d.severity === "error"))}`);
850
- }
851
- return {
852
- hosting: project.agent.hosting,
853
- architecture: project.agent.architecture,
854
- persistent: project.agent.persistent === true,
855
- image: (_a = project.agent.hosting) === null || _a === void 0 ? void 0 : _a.image,
856
- cursorAccountConnections: project.agent.connections.flatMap(connection => isCursorAccountTransport(connection.transport)
857
- ? [{ name: connection.name, servers: connection.transport.servers }]
858
- : []),
859
- publicChannelIds: project.channels
860
- .filter(channel => { var _a; return ((_a = channel.definition.auth) !== null && _a !== void 0 ? _a : []).some(isPublicEndpointPolicy); })
861
- .map(channel => channel.id),
862
- publicChannelIdsWithDeadSecretPolicies: project.channels
863
- .filter(channel => {
864
- var _a;
865
- const auth = (_a = channel.definition.auth) !== null && _a !== void 0 ? _a : [];
866
- return (auth.some(isPublicEndpointPolicy) &&
867
- auth.some(policy => {
868
- var _a;
869
- const kind = (_a = catchAuthDeclaration(policy)) === null || _a === void 0 ? void 0 : _a.kind;
870
- return kind !== undefined && kind !== "public";
871
- }));
872
- })
873
- .map(channel => channel.id),
874
- httpChannelPublicEndpoint: ((_b = project.httpChannel.auth) !== null && _b !== void 0 ? _b : []).some(isPublicEndpointPolicy),
875
- hasScmChannels: project.channels.some(channel => {
876
- var _a;
877
- const kind = (_a = channel.definition.meta) === null || _a === void 0 ? void 0 : _a.kind;
878
- return kind === "github" || kind === "origin";
879
- }),
880
- hasDeploymentsChannels: project.channels.some(channel => { var _a; return ((_a = channel.definition.meta) === null || _a === void 0 ? void 0 : _a.kind) === "deployments"; }),
881
- extensionEgress: ((_c = project.agent.extensions) !== null && _c !== void 0 ? _c : []).flatMap(extension => {
882
- var _a;
883
- var _b;
884
- const egressDomains = (_b = (_a = extension.hosting) === null || _a === void 0 ? void 0 : _a.egressDomains) !== null && _b !== void 0 ? _b : [];
885
- return egressDomains.length === 0 ? [] : [{ extension: extension.name, egressDomains }];
886
- }),
887
- };
888
- });
831
+ async function readDeployManifest(dir) {
832
+ const project = await loadAgentProject(dir);
833
+ // Fail here, before anything is dispatched: a project with error
834
+ // diagnostics (e.g. agent/storage.ts on architecture v2) would only be
835
+ // refused later by `serve` inside the hosted build, wasting a bake.
836
+ if (hasErrorDiagnostics(project)) {
837
+ throw new Error(`Refusing to deploy ${project.name} — it has errors:\n${formatDiagnostics(project.diagnostics.filter(d => d.severity === "error"))}`);
838
+ }
839
+ return {
840
+ hosting: project.agent.hosting,
841
+ architecture: project.agent.architecture,
842
+ persistent: project.agent.persistent === true,
843
+ image: project.agent.hosting?.image,
844
+ cursorAccountConnections: project.agent.connections.flatMap(connection => isCursorAccountTransport(connection.transport)
845
+ ? [{ name: connection.name, servers: connection.transport.servers }]
846
+ : []),
847
+ publicChannelIds: project.channels
848
+ .filter(channel => (channel.definition.auth ?? []).some(isPublicEndpointPolicy))
849
+ .map(channel => channel.id),
850
+ publicChannelIdsWithDeadSecretPolicies: project.channels
851
+ .filter(channel => {
852
+ const auth = channel.definition.auth ?? [];
853
+ return (auth.some(isPublicEndpointPolicy) &&
854
+ auth.some(policy => {
855
+ const kind = catchAuthDeclaration(policy)?.kind;
856
+ return kind !== undefined && kind !== "public";
857
+ }));
858
+ })
859
+ .map(channel => channel.id),
860
+ httpChannelPublicEndpoint: (project.httpChannel.auth ?? []).some(isPublicEndpointPolicy),
861
+ catchSecretNames: [
862
+ ...new Set(project.channels.flatMap(channel => channelCatchSecretNames(channel.definition))),
863
+ ],
864
+ credentialSecretNames: [
865
+ ...new Set(project.channels.flatMap(channel => channelCredentialSecretNames(channel.definition))),
866
+ ],
867
+ hasScmChannels: project.channels.some(channel => {
868
+ const kind = channel.definition.meta?.kind;
869
+ return kind === "github" || kind === "origin";
870
+ }),
871
+ hasDeploymentsChannels: project.channels.some(channel => channel.definition.meta?.kind === "deployments"),
872
+ extensionEgress: (project.agent.extensions ?? []).flatMap(extension => {
873
+ const egressDomains = extension.hosting?.egressDomains ?? [];
874
+ return egressDomains.length === 0 ? [] : [{ extension: extension.name, egressDomains }];
875
+ }),
876
+ };
877
+ }
878
+ /**
879
+ * Every secret name the deployment is expected to carry: the authored
880
+ * `hosting.secretNames` plus the names the control plane verifies caught
881
+ * requests with. Empty when the manifests declare none.
882
+ */
883
+ function declaredSecretNames(manifests) {
884
+ return [
885
+ ...new Set(manifests.flatMap(manifest => manifest === undefined
886
+ ? []
887
+ : [
888
+ ...(manifest.hosting?.secretNames ?? []),
889
+ ...manifest.catchSecretNames,
890
+ ...manifest.credentialSecretNames,
891
+ ])),
892
+ ];
889
893
  }
890
894
  /**
891
895
  * Friendly post-deploy nudge: the manifest declares secrets the agent
@@ -895,7 +899,7 @@ function warnMissingSecrets(ctx, slug, declared, set) {
895
899
  if (declared === undefined || declared.length === 0) {
896
900
  return;
897
901
  }
898
- const setNames = new Set(set !== null && set !== void 0 ? set : []);
902
+ const setNames = new Set(set ?? []);
899
903
  // Platform-managed names (CURSOR_*, hosted storage) are injected by the
900
904
  // control plane and never appear in secrets list — do not warn on them.
901
905
  const missing = declared.filter(name => !setNames.has(name) && !isReservedSecretName(name));
@@ -908,160 +912,155 @@ function warnMissingSecrets(ctx, slug, declared, set) {
908
912
  // ============================================================================
909
913
  // deployments (list)
910
914
  // ============================================================================
911
- export function cmdDeployments(options) {
912
- return __awaiter(this, void 0, void 0, function* () {
913
- const ctx = yield prepare(options);
914
- if (typeof ctx === "number") {
915
- return ctx;
916
- }
917
- let deployments;
918
- try {
919
- deployments = yield ctx.client.listDeployments({ teamId: ctx.teamId });
920
- }
921
- catch (error) {
915
+ export async function cmdDeployments(options) {
916
+ const ctx = await prepare(options);
917
+ if (typeof ctx === "number") {
918
+ return ctx;
919
+ }
920
+ let deployments;
921
+ try {
922
+ deployments = await ctx.client.listDeployments({ teamId: ctx.teamId });
923
+ }
924
+ catch (error) {
925
+ return renderApiError(error, ctx.err);
926
+ }
927
+ let applications = [];
928
+ try {
929
+ applications = await ctx.client.listAgentkitDeployments({
930
+ teamId: ctx.teamId,
931
+ });
932
+ }
933
+ catch (error) {
934
+ // Older control planes 404 this route; keep listing v1.
935
+ if (!(error instanceof DeployApiError && error.status === 404)) {
922
936
  return renderApiError(error, ctx.err);
923
937
  }
924
- let applications = [];
925
- try {
926
- applications = yield ctx.client.listAgentkitDeployments({
927
- teamId: ctx.teamId,
928
- });
929
- }
930
- catch (error) {
931
- // Older control planes 404 this route; keep listing v1.
932
- if (!(error instanceof DeployApiError && error.status === 404)) {
933
- return renderApiError(error, ctx.err);
934
- }
935
- }
936
- if (ctx.json) {
937
- // Empty v2 list keeps `{ deployments }` for v1-only parsers.
938
- ctx.out(`${JSON.stringify(applications.length === 0 ? { deployments } : { deployments, applications }, null, 2)}\n`);
939
- return 0;
940
- }
941
- if (deployments.length === 0 && applications.length === 0) {
942
- ctx.out(`No deployments on team ${ctx.teamId}. Create one with \`${CLI} deploy\`.\n`);
943
- return 0;
944
- }
945
- ctx.out(`${renderTable(["SLUG", "ARCH", "STATUS", "GEN", "KIND", "UPDATED"], [
946
- ...deployments.map(d => { var _a; return [
947
- d.slug,
948
- "v1",
949
- d.status,
950
- String(d.generation),
951
- d.deploymentKind,
952
- (_a = d.desiredUpdatedAt) !== null && _a !== void 0 ? _a : "",
953
- ]; }),
954
- ...applications.map(application => { var _a; return [
955
- application.slug,
956
- "v2",
957
- application.status,
958
- "-",
959
- "application",
960
- (_a = application.deployments
961
- .map(row => row.desiredUpdatedAt)
962
- .sort()
963
- .at(-1)) !== null && _a !== void 0 ? _a : "",
964
- ]; }),
965
- ])}\n`);
938
+ }
939
+ if (ctx.json) {
940
+ // Empty v2 list keeps `{ deployments }` for v1-only parsers.
941
+ ctx.out(`${JSON.stringify(applications.length === 0 ? { deployments } : { deployments, applications }, null, 2)}\n`);
966
942
  return 0;
967
- });
943
+ }
944
+ if (deployments.length === 0 && applications.length === 0) {
945
+ ctx.out(`No deployments on team ${ctx.teamId}. Create one with \`${CLI} deploy\`.\n`);
946
+ return 0;
947
+ }
948
+ ctx.out(`${renderTable(["SLUG", "ARCH", "STATUS", "GEN", "KIND", "UPDATED"], [
949
+ ...deployments.map(d => [
950
+ d.slug,
951
+ "v1",
952
+ d.status,
953
+ String(d.generation),
954
+ d.deploymentKind,
955
+ d.desiredUpdatedAt ?? "",
956
+ ]),
957
+ ...applications.map(application => [
958
+ application.slug,
959
+ "v2",
960
+ application.status,
961
+ "-",
962
+ "application",
963
+ application.deployments
964
+ .map(row => row.desiredUpdatedAt)
965
+ .sort()
966
+ .at(-1) ?? "",
967
+ ]),
968
+ ])}\n`);
969
+ return 0;
968
970
  }
969
971
  // ============================================================================
970
972
  // deployment <slug> (detail)
971
973
  // ============================================================================
972
- export function cmdDeploymentStatus(slug, options) {
973
- return __awaiter(this, void 0, void 0, function* () {
974
- var _a, _b;
975
- if (slug === undefined || slug === "") {
976
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} deployment <slug> [--team <id>] [--json]\n`);
977
- return 1;
978
- }
979
- const ctx = yield prepare(options);
980
- if (typeof ctx === "number") {
981
- return ctx;
982
- }
983
- // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
984
- // GET goes first. A v2 404 (missing slug, or an older backend) falls
985
- // through to the v1 agent-serve detail.
986
- try {
987
- const detail = yield ctx.client.getAgentkitDeploy({
988
- teamId: ctx.teamId,
989
- slug,
990
- });
991
- renderAgentkitDeploymentStatus(ctx, detail);
992
- return 0;
993
- }
994
- catch (error) {
995
- if (!(error instanceof DeployApiError) || error.status !== 404) {
996
- return renderApiError(error, ctx.err);
997
- }
998
- }
999
- let detail;
1000
- try {
1001
- detail = yield ctx.client.getDeployment({ teamId: ctx.teamId, slug });
1002
- }
1003
- catch (error) {
974
+ export async function cmdDeploymentStatus(slug, options) {
975
+ if (slug === undefined || slug === "") {
976
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} deployment <slug> [--team <id>] [--json]\n`);
977
+ return 1;
978
+ }
979
+ const ctx = await prepare(options);
980
+ if (typeof ctx === "number") {
981
+ return ctx;
982
+ }
983
+ // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
984
+ // GET goes first. A v2 404 (missing slug, or an older backend) falls
985
+ // through to the v1 agent-serve detail.
986
+ try {
987
+ const detail = await ctx.client.getAgentkitDeploy({
988
+ teamId: ctx.teamId,
989
+ slug,
990
+ });
991
+ renderAgentkitDeploymentStatus(ctx, detail);
992
+ return 0;
993
+ }
994
+ catch (error) {
995
+ if (!(error instanceof DeployApiError) || error.status !== 404) {
1004
996
  return renderApiError(error, ctx.err);
1005
997
  }
1006
- if (ctx.json) {
1007
- ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1008
- return 0;
1009
- }
1010
- const aliasUrl = ctx.client.aliasUrl(detail.engineAlias);
1011
- const lines = [`${detail.slug} (team ${detail.teamId})`, ` status: ${detail.status}`];
1012
- if (detail.progress !== undefined) {
1013
- lines.push(` progress: ${detail.progress}`);
1014
- }
1015
- if (detail.statusMessage !== null &&
1016
- detail.statusMessage !== undefined &&
1017
- detail.statusMessage.trim() !== "") {
1018
- lines.push(` step: ${detail.statusMessage}`);
1019
- }
1020
- lines.push(` generation: ${detail.generation}`, ` kind: ${detail.deploymentKind}`, ` alias: ${aliasUrl}`, ` playground: ${aliasUrl}/playground`);
1021
- if (detail.gitRepoUrl !== null && detail.gitRepoUrl !== undefined) {
1022
- lines.push(` repo: ${detail.gitRepoUrl} @ ${(_b = detail.gitRef) !== null && _b !== void 0 ? _b : ""}`);
1023
- }
1024
- if (detail.serviceAccountId !== undefined && detail.serviceAccountId !== null) {
1025
- lines.push(` service account: ${detail.serviceAccountId}`);
1026
- }
1027
- if (detail.agentStoreSourceId !== undefined) {
1028
- // The durable file store's address: GET /v0/agent-serve-files/<id> lists
1029
- // it, and the pod sees it as AGENT_SERVE_STORE_SOURCE_ID.
1030
- lines.push(` file store: ${detail.agentStoreSourceId}`);
1031
- }
1032
- if (detail.egressAllowedDomains !== undefined && detail.egressAllowedDomains.length > 0) {
1033
- lines.push(` egress: ${detail.egressAllowedDomains.join(", ")}`);
1034
- }
1035
- if (detail.publicRoutePaths !== undefined && detail.publicRoutePaths.length > 0) {
1036
- // Served through the alias WITHOUT X-Agent-Alias-Token (the channel
1037
- // authenticates deliveries itself).
1038
- for (const path of detail.publicRoutePaths) {
1039
- lines.push(` public: ${aliasUrl}${path} (no alias token)`);
1040
- }
1041
- }
1042
- if (detail.secretNames !== undefined && detail.secretNames.length > 0) {
1043
- lines.push(` secrets: ${detail.secretNames.join(", ")}`);
1044
- }
1045
- if (detail.podCredentialMaskedKey !== undefined && detail.podCredentialMaskedKey !== null) {
1046
- lines.push(` pod credential: ${detail.podCredentialMaskedKey}`);
1047
- }
1048
- if (detail.engineUrl !== null && detail.engineUrl !== undefined) {
1049
- lines.push(` engine: ${detail.engineUrl}`);
1050
- }
1051
- if (detail.engineAccess !== null &&
1052
- detail.engineAccess !== undefined &&
1053
- typeof detail.engineAccess === "object") {
1054
- lines.push(` engine access: ${detail.engineAccess.url} (expires ${detail.engineAccess.expiresAt})`);
1055
- }
1056
- if (detail.lastError !== null && detail.lastError !== undefined) {
1057
- lines.push(` last error: ${sanitizeCustomerError(detail.lastError)}`);
1058
- }
1059
- if (detail.desiredUpdatedAt !== undefined) {
1060
- lines.push(` updated: ${detail.desiredUpdatedAt}`);
1061
- }
1062
- ctx.out(`${lines.join("\n")}\n`);
998
+ }
999
+ let detail;
1000
+ try {
1001
+ detail = await ctx.client.getDeployment({ teamId: ctx.teamId, slug });
1002
+ }
1003
+ catch (error) {
1004
+ return renderApiError(error, ctx.err);
1005
+ }
1006
+ if (ctx.json) {
1007
+ ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1063
1008
  return 0;
1064
- });
1009
+ }
1010
+ const aliasUrl = ctx.client.aliasUrl(detail.engineAlias);
1011
+ const lines = [`${detail.slug} (team ${detail.teamId})`, ` status: ${detail.status}`];
1012
+ if (detail.progress !== undefined) {
1013
+ lines.push(` progress: ${detail.progress}`);
1014
+ }
1015
+ if (detail.statusMessage !== null &&
1016
+ detail.statusMessage !== undefined &&
1017
+ detail.statusMessage.trim() !== "") {
1018
+ lines.push(` step: ${detail.statusMessage}`);
1019
+ }
1020
+ lines.push(` generation: ${detail.generation}`, ` kind: ${detail.deploymentKind}`, ` alias: ${aliasUrl}`, ` playground: ${aliasUrl}/playground`);
1021
+ if (detail.gitRepoUrl !== null && detail.gitRepoUrl !== undefined) {
1022
+ lines.push(` repo: ${detail.gitRepoUrl} @ ${detail.gitRef ?? ""}`);
1023
+ }
1024
+ if (detail.serviceAccountId !== undefined && detail.serviceAccountId !== null) {
1025
+ lines.push(` service account: ${detail.serviceAccountId}`);
1026
+ }
1027
+ if (detail.agentStoreSourceId !== undefined) {
1028
+ // The durable file store's address: GET /v0/agent-serve-files/<id> lists
1029
+ // it, and the pod sees it as AGENT_SERVE_STORE_SOURCE_ID.
1030
+ lines.push(` file store: ${detail.agentStoreSourceId}`);
1031
+ }
1032
+ if (detail.egressAllowedDomains !== undefined && detail.egressAllowedDomains.length > 0) {
1033
+ lines.push(` egress: ${detail.egressAllowedDomains.join(", ")}`);
1034
+ }
1035
+ if (detail.publicRoutePaths !== undefined && detail.publicRoutePaths.length > 0) {
1036
+ // Served through the alias WITHOUT X-Agent-Alias-Token (the channel
1037
+ // authenticates deliveries itself).
1038
+ for (const path of detail.publicRoutePaths) {
1039
+ lines.push(` public: ${aliasUrl}${path} (no alias token)`);
1040
+ }
1041
+ }
1042
+ if (detail.secretNames !== undefined && detail.secretNames.length > 0) {
1043
+ lines.push(` secrets: ${detail.secretNames.join(", ")}`);
1044
+ }
1045
+ if (detail.podCredentialMaskedKey !== undefined && detail.podCredentialMaskedKey !== null) {
1046
+ lines.push(` pod credential: ${detail.podCredentialMaskedKey}`);
1047
+ }
1048
+ if (detail.engineUrl !== null && detail.engineUrl !== undefined) {
1049
+ lines.push(` engine: ${detail.engineUrl}`);
1050
+ }
1051
+ if (detail.engineAccess !== null &&
1052
+ detail.engineAccess !== undefined &&
1053
+ typeof detail.engineAccess === "object") {
1054
+ lines.push(` engine access: ${detail.engineAccess.url} (expires ${detail.engineAccess.expiresAt})`);
1055
+ }
1056
+ if (detail.lastError !== null && detail.lastError !== undefined) {
1057
+ lines.push(` last error: ${sanitizeCustomerError(detail.lastError)}`);
1058
+ }
1059
+ if (detail.desiredUpdatedAt !== undefined) {
1060
+ lines.push(` updated: ${detail.desiredUpdatedAt}`);
1061
+ }
1062
+ ctx.out(`${lines.join("\n")}\n`);
1063
+ return 0;
1065
1064
  }
1066
1065
  /**
1067
1066
  * Absolute webhook URLs for channels the running release actually admits
@@ -1071,12 +1070,11 @@ export function cmdDeploymentStatus(slug, options) {
1071
1070
  * the deployment URL is not this application's alias.
1072
1071
  */
1073
1072
  function livePublicWebhookLines(ctx, detail) {
1074
- var _a;
1075
1073
  const engineAlias = detail.engineAlias;
1076
1074
  if (detail.status !== "running" || engineAlias === undefined) {
1077
1075
  return "";
1078
1076
  }
1079
- return ((_a = detail.publicRoutePaths) !== null && _a !== void 0 ? _a : [])
1077
+ return (detail.publicRoutePaths ?? [])
1080
1078
  .map(path => ` public: ${ctx.client.aliasUrl(engineAlias)}${path} (no alias token)\n`)
1081
1079
  .join("");
1082
1080
  }
@@ -1114,84 +1112,81 @@ function renderAgentkitDeploymentStatus(ctx, detail) {
1114
1112
  // ============================================================================
1115
1113
  // stop <slug>
1116
1114
  // ============================================================================
1117
- export function cmdStop(slug, options) {
1118
- return __awaiter(this, void 0, void 0, function* () {
1119
- var _a;
1120
- if (slug === undefined || slug === "") {
1121
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} stop <slug> [--team <id>] [--json] [--no-wait]\n`);
1122
- return 1;
1123
- }
1124
- const ctx = yield prepare(options);
1125
- if (typeof ctx === "number") {
1126
- return ctx;
1127
- }
1128
- // Stop takes only a slug, so there is no manifest to dispatch on (unlike
1129
- // deploy). The v2 agentsdk control plane goes first: v1 endpoints refuse
1130
- // `architecture: "v2"` slugs with a 409 rather than a 404, so v1-first
1131
- // could not fall through. A v2 404 (including an older backend without
1132
- // the `/internal/agentsdk` mount) falls back to the v1 stop.
1133
- let architecture = "v2";
1134
- let accepted;
1135
- try {
1136
- accepted = yield ctx.client.stopAgentkit({
1137
- teamId: ctx.teamId,
1138
- slug,
1139
- cancelRuns: options.cancelRuns,
1140
- });
1141
- }
1142
- catch (error) {
1143
- if (!(error instanceof DeployApiError) || error.status !== 404) {
1144
- return renderApiError(error, ctx.err);
1145
- }
1146
- if (options.cancelRuns === true) {
1147
- ctx.err(`Canceling active runs while stopping is supported only for Agent SDK v2 deployments.\n`);
1148
- return 1;
1149
- }
1150
- try {
1151
- accepted = yield ctx.client.stopDeployment({ teamId: ctx.teamId, slug });
1152
- architecture = "v1";
1153
- }
1154
- catch (v1Error) {
1155
- return renderApiError(v1Error, ctx.err);
1156
- }
1115
+ export async function cmdStop(slug, options) {
1116
+ if (slug === undefined || slug === "") {
1117
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} stop <slug> [--team <id>] [--json] [--no-wait]\n`);
1118
+ return 1;
1119
+ }
1120
+ const ctx = await prepare(options);
1121
+ if (typeof ctx === "number") {
1122
+ return ctx;
1123
+ }
1124
+ // Stop takes only a slug, so there is no manifest to dispatch on (unlike
1125
+ // deploy). The v2 agentsdk control plane goes first: v1 endpoints refuse
1126
+ // `architecture: "v2"` slugs with a 409 rather than a 404, so v1-first
1127
+ // could not fall through. A v2 404 (including an older backend without
1128
+ // the `/internal/agentsdk` mount) falls back to the v1 stop.
1129
+ let architecture = "v2";
1130
+ let accepted;
1131
+ try {
1132
+ accepted = await ctx.client.stopAgentkit({
1133
+ teamId: ctx.teamId,
1134
+ slug,
1135
+ cancelRuns: options.cancelRuns,
1136
+ });
1137
+ }
1138
+ catch (error) {
1139
+ if (!(error instanceof DeployApiError) || error.status !== 404) {
1140
+ return renderApiError(error, ctx.err);
1157
1141
  }
1158
- const cancellation = "cancellation" in accepted ? accepted.cancellation : undefined;
1159
- const stoppedGlobally = "scope" in accepted && accepted.scope === "global";
1160
- if (ctx.noWait) {
1161
- if (ctx.json) {
1162
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1163
- }
1164
- else {
1165
- ctx.out(stoppedGlobally
1166
- ? `Stop accepted for ${slug} across all tenants (status: ${accepted.status}).\n`
1167
- : `Stop accepted for ${slug} (status: ${accepted.status}).\n`);
1168
- }
1169
- return (cancellation === null || cancellation === void 0 ? void 0 : cancellation.failed) === 0 || cancellation === undefined ? 0 : 1;
1142
+ if (options.cancelRuns === true) {
1143
+ ctx.err(`Canceling active runs while stopping is supported only for Agent SDK v2 deployments.\n`);
1144
+ return 1;
1170
1145
  }
1171
- let detail;
1172
1146
  try {
1173
- detail =
1174
- architecture === "v2"
1175
- ? yield pollUntil(ctx, slug, new Set(["stopped"]), () => ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug }))
1176
- : yield pollUntil(ctx, slug, new Set(["stopped"]), () => ctx.client.getDeployment({ teamId: ctx.teamId, slug }));
1147
+ accepted = await ctx.client.stopDeployment({ teamId: ctx.teamId, slug });
1148
+ architecture = "v1";
1177
1149
  }
1178
- catch (error) {
1179
- return renderApiError(error, ctx.err);
1150
+ catch (v1Error) {
1151
+ return renderApiError(v1Error, ctx.err);
1180
1152
  }
1153
+ }
1154
+ const cancellation = "cancellation" in accepted ? accepted.cancellation : undefined;
1155
+ const stoppedGlobally = "scope" in accepted && accepted.scope === "global";
1156
+ if (ctx.noWait) {
1181
1157
  if (ctx.json) {
1182
- ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1183
- }
1184
- else if (stoppedGlobally) {
1185
- ctx.out(`Stopped ${slug} across all tenants (team ${ctx.teamId}); resume with \`${CLI} start ${slug}\`.\n`);
1158
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1186
1159
  }
1187
1160
  else {
1188
- ctx.out(`Stopped ${slug} (team ${ctx.teamId}).\n`);
1161
+ ctx.out(stoppedGlobally
1162
+ ? `Stop accepted for ${slug} across all tenants (status: ${accepted.status}).\n`
1163
+ : `Stop accepted for ${slug} (status: ${accepted.status}).\n`);
1189
1164
  }
1190
- if (cancellation !== undefined) {
1191
- return writeCancellationStarted(ctx, cancellation, slug);
1192
- }
1193
- return 0;
1194
- });
1165
+ return cancellation?.failed === 0 || cancellation === undefined ? 0 : 1;
1166
+ }
1167
+ let detail;
1168
+ try {
1169
+ detail =
1170
+ architecture === "v2"
1171
+ ? await pollUntil(ctx, slug, new Set(["stopped"]), () => ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug }))
1172
+ : await pollUntil(ctx, slug, new Set(["stopped"]), () => ctx.client.getDeployment({ teamId: ctx.teamId, slug }));
1173
+ }
1174
+ catch (error) {
1175
+ return renderApiError(error, ctx.err);
1176
+ }
1177
+ if (ctx.json) {
1178
+ ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
1179
+ }
1180
+ else if (stoppedGlobally) {
1181
+ ctx.out(`Stopped ${slug} across all tenants (team ${ctx.teamId}); resume with \`${CLI} start ${slug}\`.\n`);
1182
+ }
1183
+ else {
1184
+ ctx.out(`Stopped ${slug} (team ${ctx.teamId}).\n`);
1185
+ }
1186
+ if (cancellation !== undefined) {
1187
+ return writeCancellationStarted(ctx, cancellation, slug);
1188
+ }
1189
+ return 0;
1195
1190
  }
1196
1191
  function writeCancellationStarted(ctx, cancellation, slug) {
1197
1192
  ctx.out(`Started cancellation across ${cancellation.batchesStarted} deployment batch(es).\n`);
@@ -1204,510 +1199,475 @@ function writeCancellationStarted(ctx, cancellation, slug) {
1204
1199
  }
1205
1200
  return 0;
1206
1201
  }
1207
- export function cmdStart(slug, options) {
1208
- return __awaiter(this, void 0, void 0, function* () {
1209
- var _a;
1210
- if (slug === undefined || slug === "") {
1211
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} start <slug> [--team <id>] [--json]\n`);
1212
- return 1;
1213
- }
1214
- const ctx = yield prepare(options);
1215
- if (typeof ctx === "number") {
1216
- return ctx;
1217
- }
1218
- try {
1219
- const accepted = yield ctx.client.startAgentkit({
1220
- teamId: ctx.teamId,
1221
- slug,
1222
- });
1223
- if (ctx.json) {
1224
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1225
- }
1226
- else {
1227
- ctx.out(`Started ${slug} (team ${ctx.teamId}).\n`);
1228
- }
1229
- return 0;
1230
- }
1231
- catch (error) {
1232
- return renderApiError(error, ctx.err);
1233
- }
1234
- });
1235
- }
1236
- export function cmdKill(slug, options) {
1237
- return __awaiter(this, void 0, void 0, function* () {
1238
- var _a;
1239
- if (slug === undefined || slug === "") {
1240
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} kill <slug> [--team <id>] [--json]\n`);
1241
- return 1;
1242
- }
1243
- const ctx = yield prepare(options);
1244
- if (typeof ctx === "number") {
1245
- return ctx;
1246
- }
1247
- let accepted;
1248
- try {
1249
- accepted = yield ctx.client.killAgentkit({ teamId: ctx.teamId, slug });
1250
- }
1251
- catch (error) {
1252
- return renderApiError(error, ctx.err);
1253
- }
1202
+ export async function cmdStart(slug, options) {
1203
+ if (slug === undefined || slug === "") {
1204
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} start <slug> [--team <id>] [--json]\n`);
1205
+ return 1;
1206
+ }
1207
+ const ctx = await prepare(options);
1208
+ if (typeof ctx === "number") {
1209
+ return ctx;
1210
+ }
1211
+ try {
1212
+ const accepted = await ctx.client.startAgentkit({
1213
+ teamId: ctx.teamId,
1214
+ slug,
1215
+ });
1254
1216
  if (ctx.json) {
1255
1217
  ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1256
1218
  }
1257
1219
  else {
1258
- ctx.out(accepted.scope === "global"
1259
- ? `Killed ${slug} across all tenants (team ${ctx.teamId}): deploys locked, admission stopped.\n`
1260
- : `Killed ${slug} (team ${ctx.teamId}): deploys locked, admission stopped.\n`);
1261
- ctx.out(`Resume traffic with \`${CLI} unlock-deploys ${slug}\` then \`${CLI} start ${slug}\`.\n`);
1262
- ctx.out(`Unlock deploys with \`${CLI} unlock-deploys ${slug}\`.\n`);
1263
- }
1264
- if (accepted.cancellation !== undefined) {
1265
- return writeCancellationStarted(ctx, accepted.cancellation, slug);
1220
+ ctx.out(`Started ${slug} (team ${ctx.teamId}).\n`);
1266
1221
  }
1267
1222
  return 0;
1268
- });
1223
+ }
1224
+ catch (error) {
1225
+ return renderApiError(error, ctx.err);
1226
+ }
1269
1227
  }
1270
- export function cmdUnlockDeploys(slug, options) {
1271
- return __awaiter(this, void 0, void 0, function* () {
1272
- var _a;
1273
- if (slug === undefined || slug === "") {
1274
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} unlock-deploys <slug> [--team <id>] [--json]\n`);
1275
- return 1;
1276
- }
1277
- const ctx = yield prepare(options);
1278
- if (typeof ctx === "number") {
1279
- return ctx;
1280
- }
1281
- try {
1282
- const accepted = yield ctx.client.unlockAgentkitDeploys({
1283
- teamId: ctx.teamId,
1284
- slug,
1285
- });
1286
- if (ctx.json) {
1287
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1288
- }
1289
- else {
1290
- ctx.out(`Unlocked deploys for ${slug} (team ${ctx.teamId}).\n`);
1291
- }
1292
- return 0;
1293
- }
1294
- catch (error) {
1295
- return renderApiError(error, ctx.err);
1296
- }
1297
- });
1228
+ export async function cmdKill(slug, options) {
1229
+ if (slug === undefined || slug === "") {
1230
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} kill <slug> [--team <id>] [--json]\n`);
1231
+ return 1;
1232
+ }
1233
+ const ctx = await prepare(options);
1234
+ if (typeof ctx === "number") {
1235
+ return ctx;
1236
+ }
1237
+ let accepted;
1238
+ try {
1239
+ accepted = await ctx.client.killAgentkit({ teamId: ctx.teamId, slug });
1240
+ }
1241
+ catch (error) {
1242
+ return renderApiError(error, ctx.err);
1243
+ }
1244
+ if (ctx.json) {
1245
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1246
+ }
1247
+ else {
1248
+ ctx.out(accepted.scope === "global"
1249
+ ? `Killed ${slug} across all tenants (team ${ctx.teamId}): deploys locked, admission stopped.\n`
1250
+ : `Killed ${slug} (team ${ctx.teamId}): deploys locked, admission stopped.\n`);
1251
+ ctx.out(`Resume traffic with \`${CLI} unlock-deploys ${slug}\` then \`${CLI} start ${slug}\`.\n`);
1252
+ ctx.out(`Unlock deploys with \`${CLI} unlock-deploys ${slug}\`.\n`);
1253
+ }
1254
+ if (accepted.cancellation !== undefined) {
1255
+ return writeCancellationStarted(ctx, accepted.cancellation, slug);
1256
+ }
1257
+ return 0;
1298
1258
  }
1299
- export function cmdCancelRuns(slug, options) {
1300
- return __awaiter(this, void 0, void 0, function* () {
1301
- var _a;
1302
- if (slug === undefined || slug === "") {
1303
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((text) => void process.stderr.write(text)))(`Usage: ${CLI} cancel-runs <slug> [--team <id>] [--json]\n`);
1304
- return 1;
1305
- }
1306
- const ctx = yield prepare(options);
1307
- if (typeof ctx === "number") {
1308
- return ctx;
1309
- }
1310
- let result;
1311
- try {
1312
- result = yield ctx.client.cancelAgentkitRuns({
1313
- teamId: ctx.teamId,
1314
- slug,
1315
- });
1316
- }
1317
- catch (error) {
1318
- return renderApiError(error, ctx.err);
1319
- }
1259
+ export async function cmdUnlockDeploys(slug, options) {
1260
+ if (slug === undefined || slug === "") {
1261
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} unlock-deploys <slug> [--team <id>] [--json]\n`);
1262
+ return 1;
1263
+ }
1264
+ const ctx = await prepare(options);
1265
+ if (typeof ctx === "number") {
1266
+ return ctx;
1267
+ }
1268
+ try {
1269
+ const accepted = await ctx.client.unlockAgentkitDeploys({
1270
+ teamId: ctx.teamId,
1271
+ slug,
1272
+ });
1320
1273
  if (ctx.json) {
1321
- ctx.out(`${JSON.stringify(result, null, 2)}\n`);
1274
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1322
1275
  }
1323
1276
  else {
1324
- ctx.out(`Started cancellation across ${result.batchesStarted} deployment batch(es).\n`);
1325
- if (result.sessionsMarkedFailed !== undefined) {
1326
- ctx.out(`Marked ${result.sessionsMarkedFailed} factory session(s) failed.\n`);
1327
- }
1328
- }
1329
- if (result.failed > 0) {
1330
- ctx.err(`Failed to start ${result.failed} cancellation batch(es).\n`);
1331
- return 1;
1277
+ ctx.out(`Unlocked deploys for ${slug} (team ${ctx.teamId}).\n`);
1332
1278
  }
1333
1279
  return 0;
1334
- });
1280
+ }
1281
+ catch (error) {
1282
+ return renderApiError(error, ctx.err);
1283
+ }
1284
+ }
1285
+ export async function cmdCancelRuns(slug, options) {
1286
+ if (slug === undefined || slug === "") {
1287
+ (options.err ?? ((text) => void process.stderr.write(text)))(`Usage: ${CLI} cancel-runs <slug> [--team <id>] [--json]\n`);
1288
+ return 1;
1289
+ }
1290
+ const ctx = await prepare(options);
1291
+ if (typeof ctx === "number") {
1292
+ return ctx;
1293
+ }
1294
+ let result;
1295
+ try {
1296
+ result = await ctx.client.cancelAgentkitRuns({
1297
+ teamId: ctx.teamId,
1298
+ slug,
1299
+ });
1300
+ }
1301
+ catch (error) {
1302
+ return renderApiError(error, ctx.err);
1303
+ }
1304
+ if (ctx.json) {
1305
+ ctx.out(`${JSON.stringify(result, null, 2)}\n`);
1306
+ }
1307
+ else {
1308
+ ctx.out(`Started cancellation across ${result.batchesStarted} deployment batch(es).\n`);
1309
+ if (result.sessionsMarkedFailed !== undefined) {
1310
+ ctx.out(`Marked ${result.sessionsMarkedFailed} factory session(s) failed.\n`);
1311
+ }
1312
+ }
1313
+ if (result.failed > 0) {
1314
+ ctx.err(`Failed to start ${result.failed} cancellation batch(es).\n`);
1315
+ return 1;
1316
+ }
1317
+ return 0;
1335
1318
  }
1336
1319
  // ============================================================================
1337
1320
  // event-repos <slug> --repo <owner/name>...
1338
1321
  // ============================================================================
1339
- export function cmdEventRepos(slug, repositories, options) {
1340
- return __awaiter(this, void 0, void 0, function* () {
1341
- var _a;
1342
- if (slug === undefined || slug === "") {
1343
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((text) => void process.stderr.write(text)))(`Usage: ${CLI} event-repos <slug> --repo <owner/name>... [--team <id>] [--json]\n`);
1344
- return 1;
1345
- }
1346
- const ctx = yield prepare(options);
1347
- if (typeof ctx === "number") {
1348
- return ctx;
1349
- }
1350
- let configured;
1351
- try {
1352
- configured = yield ctx.client.setAgentkitEventRepositories({
1353
- teamId: ctx.teamId,
1354
- slug,
1355
- repositories,
1356
- });
1357
- }
1358
- catch (error) {
1359
- return renderApiError(error, ctx.err);
1360
- }
1361
- if (ctx.json) {
1362
- ctx.out(`${JSON.stringify({ repositories: configured }, null, 2)}\n`);
1363
- }
1364
- else if (configured.length === 0) {
1365
- ctx.out(`${slug} now watches no repositories.\n`);
1366
- }
1367
- else {
1368
- ctx.out(`${slug} now watches ${configured.join(", ")}.\n`);
1369
- }
1370
- return 0;
1371
- });
1322
+ export async function cmdEventRepos(slug, repositories, options) {
1323
+ if (slug === undefined || slug === "") {
1324
+ (options.err ?? ((text) => void process.stderr.write(text)))(`Usage: ${CLI} event-repos <slug> --repo <owner/name>... [--team <id>] [--json]\n`);
1325
+ return 1;
1326
+ }
1327
+ const ctx = await prepare(options);
1328
+ if (typeof ctx === "number") {
1329
+ return ctx;
1330
+ }
1331
+ let configured;
1332
+ try {
1333
+ configured = await ctx.client.setAgentkitEventRepositories({
1334
+ teamId: ctx.teamId,
1335
+ slug,
1336
+ repositories,
1337
+ });
1338
+ }
1339
+ catch (error) {
1340
+ return renderApiError(error, ctx.err);
1341
+ }
1342
+ if (ctx.json) {
1343
+ ctx.out(`${JSON.stringify({ repositories: configured }, null, 2)}\n`);
1344
+ }
1345
+ else if (configured.length === 0) {
1346
+ ctx.out(`${slug} now watches no repositories.\n`);
1347
+ }
1348
+ else {
1349
+ ctx.out(`${slug} now watches ${configured.join(", ")}.\n`);
1350
+ }
1351
+ return 0;
1372
1352
  }
1373
1353
  // ============================================================================
1374
1354
  // upgrade <slug>
1375
1355
  // ============================================================================
1376
1356
  /** Release ids are uuids; anything else the user typed is a version. */
1377
1357
  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;
1378
- export function cmdUpgrade(args, options) {
1379
- return __awaiter(this, void 0, void 0, function* () {
1380
- return cmdPinRelease(args, options, {
1381
- usage: `Usage: ${CLI} upgrade <slug> [--release <id|version>] [--team <id>] [--json]\n`,
1382
- pin: (client, request) => client.upgradeAgentkitInstall(request),
1383
- success: (slug, releaseId) => `${slug} now runs release ${releaseId}.\n`,
1384
- });
1358
+ export async function cmdUpgrade(args, options) {
1359
+ return cmdPinRelease(args, options, {
1360
+ usage: `Usage: ${CLI} upgrade <slug> [--release <id|version>] [--team <id>] [--json]\n`,
1361
+ pin: (client, request) => client.upgradeAgentkitInstall(request),
1362
+ success: (slug, releaseId) => `${slug} now runs release ${releaseId}.\n`,
1385
1363
  });
1386
1364
  }
1387
- export function cmdRollback(args, options) {
1388
- return __awaiter(this, void 0, void 0, function* () {
1389
- return cmdPinRelease(args, options, {
1390
- usage: `Usage: ${CLI} rollback <slug> [--release <id|version>] [--team <id>] [--json]\n`,
1391
- pin: (client, request) => client.rollbackAgentkitInstall(request),
1392
- success: (slug, releaseId) => `${slug} rolled back to release ${releaseId}.\n`,
1393
- });
1365
+ export async function cmdRollback(args, options) {
1366
+ return cmdPinRelease(args, options, {
1367
+ usage: `Usage: ${CLI} rollback <slug> [--release <id|version>] [--team <id>] [--json]\n`,
1368
+ pin: (client, request) => client.rollbackAgentkitInstall(request),
1369
+ success: (slug, releaseId) => `${slug} rolled back to release ${releaseId}.\n`,
1394
1370
  });
1395
1371
  }
1396
- function cmdPinRelease(args, options, pin) {
1397
- return __awaiter(this, void 0, void 0, function* () {
1398
- var _a, _b;
1399
- const { slug, release } = args;
1400
- if (slug === undefined || slug === "") {
1401
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((text) => void process.stderr.write(text)))(pin.usage);
1402
- return 1;
1403
- }
1404
- const ctx = yield prepare(options);
1405
- if (typeof ctx === "number") {
1406
- return ctx;
1407
- }
1408
- const selector = (_b = release === null || release === void 0 ? void 0 : release.trim()) !== null && _b !== void 0 ? _b : "";
1409
- let releaseId;
1410
- try {
1411
- releaseId = yield pin.pin(ctx.client, Object.assign({ teamId: ctx.teamId, slug }, (selector === ""
1372
+ async function cmdPinRelease(args, options, pin) {
1373
+ const { slug, release } = args;
1374
+ if (slug === undefined || slug === "") {
1375
+ (options.err ?? ((text) => void process.stderr.write(text)))(pin.usage);
1376
+ return 1;
1377
+ }
1378
+ const ctx = await prepare(options);
1379
+ if (typeof ctx === "number") {
1380
+ return ctx;
1381
+ }
1382
+ const selector = release?.trim() ?? "";
1383
+ let releaseId;
1384
+ try {
1385
+ releaseId = await pin.pin(ctx.client, {
1386
+ teamId: ctx.teamId,
1387
+ slug,
1388
+ ...(selector === ""
1412
1389
  ? {}
1413
1390
  : RELEASE_ID_RE.test(selector)
1414
1391
  ? { releaseId: selector }
1415
- : { version: selector })));
1416
- }
1417
- catch (error) {
1418
- return renderApiError(error, ctx.err);
1419
- }
1420
- if (ctx.json) {
1421
- ctx.out(`${JSON.stringify({ releaseId }, null, 2)}\n`);
1422
- }
1423
- else {
1424
- ctx.out(pin.success(slug, releaseId));
1425
- }
1426
- return 0;
1427
- });
1392
+ : { version: selector }),
1393
+ });
1394
+ }
1395
+ catch (error) {
1396
+ return renderApiError(error, ctx.err);
1397
+ }
1398
+ if (ctx.json) {
1399
+ ctx.out(`${JSON.stringify({ releaseId }, null, 2)}\n`);
1400
+ }
1401
+ else {
1402
+ ctx.out(pin.success(slug, releaseId));
1403
+ }
1404
+ return 0;
1428
1405
  }
1429
1406
  // ============================================================================
1430
1407
  // delete <slug>
1431
1408
  // ============================================================================
1432
- export function cmdDelete(slug, options) {
1433
- return __awaiter(this, void 0, void 0, function* () {
1434
- var _a;
1435
- if (slug === undefined || slug === "") {
1436
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} delete <slug> [--team <id>] [--json] [--no-wait]\n`);
1437
- return 1;
1438
- }
1439
- const ctx = yield prepare(options);
1440
- if (typeof ctx === "number") {
1441
- return ctx;
1442
- }
1443
- // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
1444
- // DELETE goes first. A v2 404 (missing slug, or an older backend)
1445
- // falls through to the v1 agent-serve delete.
1446
- let architecture = "v2";
1447
- let accepted;
1448
- try {
1449
- accepted = yield ctx.client.deleteAgentkit({ teamId: ctx.teamId, slug });
1450
- }
1451
- catch (error) {
1452
- if (!(error instanceof DeployApiError) || error.status !== 404) {
1453
- return renderApiError(error, ctx.err);
1454
- }
1455
- try {
1456
- accepted = yield ctx.client.deleteDeployment({
1457
- teamId: ctx.teamId,
1458
- slug,
1459
- });
1460
- architecture = "v1";
1461
- }
1462
- catch (v1Error) {
1463
- return renderApiError(v1Error, ctx.err);
1464
- }
1465
- }
1466
- if (ctx.noWait) {
1467
- if (ctx.json) {
1468
- ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1469
- }
1470
- else {
1471
- ctx.out(`Delete accepted for ${slug} (status: ${accepted.status}).\n`);
1472
- }
1473
- return 0;
1474
- }
1475
- try {
1476
- yield pollUntilGone(ctx, slug, () => architecture === "v2"
1477
- ? ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug })
1478
- : ctx.client.getDeployment({ teamId: ctx.teamId, slug }));
1479
- }
1480
- catch (error) {
1409
+ export async function cmdDelete(slug, options) {
1410
+ if (slug === undefined || slug === "") {
1411
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} delete <slug> [--team <id>] [--json] [--no-wait]\n`);
1412
+ return 1;
1413
+ }
1414
+ const ctx = await prepare(options);
1415
+ if (typeof ctx === "number") {
1416
+ return ctx;
1417
+ }
1418
+ // Same dispatch as `stop`: v1 409s architecture-v2 slugs, so the v2
1419
+ // DELETE goes first. A v2 404 (missing slug, or an older backend)
1420
+ // falls through to the v1 agent-serve delete.
1421
+ let architecture = "v2";
1422
+ let accepted;
1423
+ try {
1424
+ accepted = await ctx.client.deleteAgentkit({ teamId: ctx.teamId, slug });
1425
+ }
1426
+ catch (error) {
1427
+ if (!(error instanceof DeployApiError) || error.status !== 404) {
1481
1428
  return renderApiError(error, ctx.err);
1482
1429
  }
1483
- if (ctx.json) {
1484
- ctx.out(`${JSON.stringify({ slug, status: "deleted" }, null, 2)}\n`);
1485
- }
1486
- else {
1487
- ctx.out(`Deleted ${slug} (team ${ctx.teamId}).\n`);
1488
- }
1489
- return 0;
1490
- });
1491
- }
1492
- // ============================================================================
1493
- // rotate-token <slug>
1494
- // ============================================================================
1495
- export function cmdRotateToken(slug, options) {
1496
- return __awaiter(this, void 0, void 0, function* () {
1497
- var _a;
1498
- if (slug === undefined || slug === "") {
1499
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} rotate-token <slug> [--team <id>]\n`);
1500
- return 1;
1501
- }
1502
- const ctx = yield prepare(options);
1503
- if (typeof ctx === "number") {
1504
- return ctx;
1505
- }
1506
- let aliasToken;
1507
1430
  try {
1508
- const architecture = yield deploymentArchitecture({
1509
- client: ctx.client,
1431
+ accepted = await ctx.client.deleteDeployment({
1510
1432
  teamId: ctx.teamId,
1511
1433
  slug,
1512
1434
  });
1513
- aliasToken =
1514
- architecture === "v2"
1515
- ? yield ctx.client.rotateAgentsdkAliasToken({
1516
- teamId: ctx.teamId,
1517
- slug,
1518
- })
1519
- : yield ctx.client.rotateAliasToken({
1520
- teamId: ctx.teamId,
1521
- slug,
1522
- });
1435
+ architecture = "v1";
1523
1436
  }
1524
- catch (error) {
1525
- return renderApiError(error, ctx.err);
1437
+ catch (v1Error) {
1438
+ return renderApiError(v1Error, ctx.err);
1526
1439
  }
1440
+ }
1441
+ if (ctx.noWait) {
1527
1442
  if (ctx.json) {
1528
- ctx.out(`${JSON.stringify({ aliasToken }, null, 2)}\n`);
1529
- return 0;
1443
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1444
+ }
1445
+ else {
1446
+ ctx.out(`Delete accepted for ${slug} (status: ${accepted.status}).\n`);
1530
1447
  }
1531
- ctx.out(`Rotated the alias token for ${slug}. The old token stopped working immediately.\n${aliasTokenBlock(aliasToken)}`);
1532
1448
  return 0;
1533
- });
1449
+ }
1450
+ try {
1451
+ await pollUntilGone(ctx, slug, () => architecture === "v2"
1452
+ ? ctx.client.getAgentkitDeploy({ teamId: ctx.teamId, slug })
1453
+ : ctx.client.getDeployment({ teamId: ctx.teamId, slug }));
1454
+ }
1455
+ catch (error) {
1456
+ return renderApiError(error, ctx.err);
1457
+ }
1458
+ if (ctx.json) {
1459
+ ctx.out(`${JSON.stringify({ slug, status: "deleted" }, null, 2)}\n`);
1460
+ }
1461
+ else {
1462
+ ctx.out(`Deleted ${slug} (team ${ctx.teamId}).\n`);
1463
+ }
1464
+ return 0;
1534
1465
  }
1535
1466
  // ============================================================================
1536
- // secrets set|list|unset
1467
+ // rotate-token <slug>
1537
1468
  // ============================================================================
1538
- function secretDeploymentArchitecture(ctx, slug) {
1539
- return __awaiter(this, void 0, void 0, function* () {
1540
- return deploymentArchitecture({
1469
+ export async function cmdRotateToken(slug, options) {
1470
+ if (slug === undefined || slug === "") {
1471
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} rotate-token <slug> [--team <id>]\n`);
1472
+ return 1;
1473
+ }
1474
+ const ctx = await prepare(options);
1475
+ if (typeof ctx === "number") {
1476
+ return ctx;
1477
+ }
1478
+ let aliasToken;
1479
+ try {
1480
+ const architecture = await deploymentArchitecture({
1541
1481
  client: ctx.client,
1542
1482
  teamId: ctx.teamId,
1543
1483
  slug,
1544
1484
  });
1485
+ aliasToken =
1486
+ architecture === "v2"
1487
+ ? await ctx.client.rotateAgentsdkAliasToken({
1488
+ teamId: ctx.teamId,
1489
+ slug,
1490
+ })
1491
+ : await ctx.client.rotateAliasToken({
1492
+ teamId: ctx.teamId,
1493
+ slug,
1494
+ });
1495
+ }
1496
+ catch (error) {
1497
+ return renderApiError(error, ctx.err);
1498
+ }
1499
+ if (ctx.json) {
1500
+ ctx.out(`${JSON.stringify({ aliasToken }, null, 2)}\n`);
1501
+ return 0;
1502
+ }
1503
+ ctx.out(`Rotated the alias token for ${slug}. The old token stopped working immediately.\n${aliasTokenBlock(aliasToken)}`);
1504
+ return 0;
1505
+ }
1506
+ // ============================================================================
1507
+ // secrets set|list|unset
1508
+ // ============================================================================
1509
+ async function secretDeploymentArchitecture(ctx, slug) {
1510
+ return deploymentArchitecture({
1511
+ client: ctx.client,
1512
+ teamId: ctx.teamId,
1513
+ slug,
1545
1514
  });
1546
1515
  }
1547
- export function cmdSecretsSet(slug, specs, options) {
1548
- return __awaiter(this, void 0, void 0, function* () {
1549
- var _a, _b, _c;
1550
- const usageErr = (_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t));
1551
- if (slug === undefined || slug === "" || specs.length === 0) {
1552
- usageErr(`Usage: ${CLI} secrets set <slug> NAME [NAME2 ...] [--team <id>] [--json]\n` +
1553
- ` Hidden prompt on a TTY. One NAME reads all of stdin (redirect a PEM).\n` +
1554
- ` Several NAMEs: one stdin line each.\n` +
1555
- ` Opt-in (leaks into argv / agent terminals): NAME=VALUE … --from-argv\n`);
1556
- return 1;
1557
- }
1558
- // Parse and validate every name before prompting for any value, so a
1559
- // typo in the last name cannot waste typed-in secrets.
1560
- const parsed = [];
1561
- for (const spec of specs) {
1562
- const eq = spec.indexOf("=");
1563
- const name = eq === -1 ? spec : spec.slice(0, eq);
1564
- const nameError = validateSettableSecretName(name);
1565
- if (nameError !== undefined) {
1566
- usageErr(`${nameError}\n`);
1567
- return 1;
1568
- }
1569
- parsed.push(eq === -1 ? { name } : { name, value: spec.slice(eq + 1) });
1570
- }
1571
- const hasArgvValues = parsed.some(entry => entry.value !== undefined);
1572
- if (hasArgvValues && options.fromArgv !== true) {
1573
- usageErr(`Refusing NAME=VALUE on argv (shows up in shell history and agent-captured terminals).\n` +
1574
- `Pass names only:\n` +
1575
- ` ${CLI} secrets set ${slug} NAME\n` +
1576
- `Hidden prompt on a TTY. One NAME reads all of stdin, including newlines:\n` +
1577
- ` ${CLI} secrets set ${slug} NAME < ./secret.pem\n` +
1578
- `Several NAMEs take one stdin line each.\n`);
1516
+ export async function cmdSecretsSet(slug, specs, options) {
1517
+ const usageErr = options.err ?? ((t) => void process.stderr.write(t));
1518
+ if (slug === undefined || slug === "" || specs.length === 0) {
1519
+ usageErr(`Usage: ${CLI} secrets set <slug> NAME [NAME2 ...] [--team <id>] [--json]\n` +
1520
+ ` Hidden prompt on a TTY. One NAME reads all of stdin (redirect a PEM).\n` +
1521
+ ` Several NAMEs: one stdin line each.\n` +
1522
+ ` Opt-in (leaks into argv / agent terminals): NAME=VALUE … --from-argv\n`);
1523
+ return 1;
1524
+ }
1525
+ // Parse and validate every name before prompting for any value, so a
1526
+ // typo in the last name cannot waste typed-in secrets.
1527
+ const parsed = [];
1528
+ for (const spec of specs) {
1529
+ const eq = spec.indexOf("=");
1530
+ const name = eq === -1 ? spec : spec.slice(0, eq);
1531
+ const nameError = validateSettableSecretName(name);
1532
+ if (nameError !== undefined) {
1533
+ usageErr(`${nameError}\n`);
1579
1534
  return 1;
1580
1535
  }
1581
- if (hasArgvValues) {
1582
- usageErr(`warning: --from-argv puts secret values in argv (shell history and agent-captured terminals).\n`);
1583
- }
1584
- const ctx = yield prepare(options);
1585
- if (typeof ctx === "number") {
1586
- return ctx;
1536
+ parsed.push(eq === -1 ? { name } : { name, value: spec.slice(eq + 1) });
1537
+ }
1538
+ const hasArgvValues = parsed.some(entry => entry.value !== undefined);
1539
+ if (hasArgvValues && options.fromArgv !== true) {
1540
+ usageErr(`Refusing NAME=VALUE on argv (shows up in shell history and agent-captured terminals).\n` +
1541
+ `Pass names only:\n` +
1542
+ ` ${CLI} secrets set ${slug} NAME\n` +
1543
+ `Hidden prompt on a TTY. One NAME reads all of stdin, including newlines:\n` +
1544
+ ` ${CLI} secrets set ${slug} NAME < ./secret.pem\n` +
1545
+ `Several NAMEs take one stdin line each.\n`);
1546
+ return 1;
1547
+ }
1548
+ if (hasArgvValues) {
1549
+ usageErr(`warning: --from-argv puts secret values in argv (shell history and agent-captured terminals).\n`);
1550
+ }
1551
+ const ctx = await prepare(options);
1552
+ if (typeof ctx === "number") {
1553
+ return ctx;
1554
+ }
1555
+ const stdin = options.stdin ?? process.stdin;
1556
+ const secrets = [];
1557
+ let secretNames;
1558
+ let architecture;
1559
+ try {
1560
+ const only = parsed.length === 1 ? parsed[0] : undefined;
1561
+ if (only !== undefined && only.value === undefined && stdin.isTTY !== true) {
1562
+ secrets.push({
1563
+ name: only.name,
1564
+ value: await readWholeStdinValue(stdin, only.name),
1565
+ });
1587
1566
  }
1588
- const stdin = (_b = options.stdin) !== null && _b !== void 0 ? _b : process.stdin;
1589
- const secrets = [];
1590
- let secretNames;
1591
- let architecture;
1592
- try {
1593
- const only = parsed.length === 1 ? parsed[0] : undefined;
1594
- if (only !== undefined && only.value === undefined && stdin.isTTY !== true) {
1567
+ else {
1568
+ const readValue = createSecretValueReader(stdin, ctx.err);
1569
+ for (const entry of parsed) {
1595
1570
  secrets.push({
1596
- name: only.name,
1597
- value: yield readWholeStdinValue(stdin, only.name),
1571
+ name: entry.name,
1572
+ value: entry.value ?? (await readValue(entry.name)),
1598
1573
  });
1599
1574
  }
1600
- else {
1601
- const readValue = createSecretValueReader(stdin, ctx.err);
1602
- for (const entry of parsed) {
1603
- secrets.push({
1604
- name: entry.name,
1605
- value: (_c = entry.value) !== null && _c !== void 0 ? _c : (yield readValue(entry.name)),
1606
- });
1607
- }
1608
- }
1609
- architecture = yield secretDeploymentArchitecture(ctx, slug);
1610
- secretNames =
1611
- architecture === "v2"
1612
- ? yield ctx.client.setAgentkitSecrets({
1613
- teamId: ctx.teamId,
1614
- slug,
1615
- secrets,
1616
- })
1617
- : yield ctx.client.setSecrets({
1618
- teamId: ctx.teamId,
1619
- slug,
1620
- secrets,
1621
- });
1622
- }
1623
- catch (error) {
1624
- return renderApiError(error, ctx.err);
1625
1575
  }
1626
- if (ctx.json) {
1627
- ctx.out(`${JSON.stringify({ secretNames }, null, 2)}\n`);
1628
- return 0;
1629
- }
1630
- ctx.out(`Set ${secrets.length} secret${secrets.length === 1 ? "" : "s"} on ${slug}.\n` +
1631
- `Secrets now set: ${secretNames.join(", ")}\n` +
1632
- (architecture === "v2"
1633
- ? `The next task picks them up; no redeploy is required.\n`
1634
- : `The engine picks them up on its next deploy.\n`));
1576
+ architecture = await secretDeploymentArchitecture(ctx, slug);
1577
+ secretNames =
1578
+ architecture === "v2"
1579
+ ? await ctx.client.setAgentkitSecrets({
1580
+ teamId: ctx.teamId,
1581
+ slug,
1582
+ secrets,
1583
+ })
1584
+ : await ctx.client.setSecrets({
1585
+ teamId: ctx.teamId,
1586
+ slug,
1587
+ secrets,
1588
+ });
1589
+ }
1590
+ catch (error) {
1591
+ return renderApiError(error, ctx.err);
1592
+ }
1593
+ if (ctx.json) {
1594
+ ctx.out(`${JSON.stringify({ secretNames }, null, 2)}\n`);
1635
1595
  return 0;
1636
- });
1596
+ }
1597
+ ctx.out(`Set ${secrets.length} secret${secrets.length === 1 ? "" : "s"} on ${slug}.\n` +
1598
+ `Secrets now set: ${secretNames.join(", ")}\n` +
1599
+ (architecture === "v2"
1600
+ ? `The next task picks them up; no redeploy is required.\n`
1601
+ : `The engine picks them up on its next deploy.\n`));
1602
+ return 0;
1637
1603
  }
1638
- export function cmdSecretsList(slug, options) {
1639
- return __awaiter(this, void 0, void 0, function* () {
1640
- var _a;
1641
- if (slug === undefined || slug === "") {
1642
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} secrets list <slug> [--team <id>] [--json]\n`);
1643
- return 1;
1644
- }
1645
- const ctx = yield prepare(options);
1646
- if (typeof ctx === "number") {
1647
- return ctx;
1648
- }
1649
- let secrets;
1650
- try {
1651
- const architecture = yield secretDeploymentArchitecture(ctx, slug);
1652
- secrets =
1653
- architecture === "v2"
1654
- ? yield ctx.client.listAgentkitSecrets({ teamId: ctx.teamId, slug })
1655
- : yield ctx.client.listSecrets({ teamId: ctx.teamId, slug });
1656
- }
1657
- catch (error) {
1658
- return renderApiError(error, ctx.err);
1659
- }
1660
- if (ctx.json) {
1661
- ctx.out(`${JSON.stringify({ secrets }, null, 2)}\n`);
1662
- return 0;
1663
- }
1664
- if (secrets.length === 0) {
1665
- ctx.out(`No secrets set on ${slug}. Add one with \`${CLI} secrets set ${slug} NAME\`.\n`);
1666
- return 0;
1667
- }
1668
- ctx.out(`${renderTable(["NAME", "CREATED"], secrets.map(secret => [secret.name, secret.createdAt]))}\n`);
1604
+ export async function cmdSecretsList(slug, options) {
1605
+ if (slug === undefined || slug === "") {
1606
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} secrets list <slug> [--team <id>] [--json]\n`);
1607
+ return 1;
1608
+ }
1609
+ const ctx = await prepare(options);
1610
+ if (typeof ctx === "number") {
1611
+ return ctx;
1612
+ }
1613
+ let secrets;
1614
+ try {
1615
+ const architecture = await secretDeploymentArchitecture(ctx, slug);
1616
+ secrets =
1617
+ architecture === "v2"
1618
+ ? await ctx.client.listAgentkitSecrets({ teamId: ctx.teamId, slug })
1619
+ : await ctx.client.listSecrets({ teamId: ctx.teamId, slug });
1620
+ }
1621
+ catch (error) {
1622
+ return renderApiError(error, ctx.err);
1623
+ }
1624
+ if (ctx.json) {
1625
+ ctx.out(`${JSON.stringify({ secrets }, null, 2)}\n`);
1669
1626
  return 0;
1670
- });
1627
+ }
1628
+ if (secrets.length === 0) {
1629
+ ctx.out(`No secrets set on ${slug}. Add one with \`${CLI} secrets set ${slug} NAME\`.\n`);
1630
+ return 0;
1631
+ }
1632
+ ctx.out(`${renderTable(["NAME", "CREATED"], secrets.map(secret => [secret.name, secret.createdAt]))}\n`);
1633
+ return 0;
1671
1634
  }
1672
- export function cmdSecretsUnset(slug, name, options) {
1673
- return __awaiter(this, void 0, void 0, function* () {
1674
- var _a;
1675
- if (slug === undefined || slug === "" || name === undefined || name === "") {
1676
- ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} secrets unset <slug> NAME [--team <id>]\n`);
1677
- return 1;
1678
- }
1679
- const ctx = yield prepare(options);
1680
- if (typeof ctx === "number") {
1681
- return ctx;
1682
- }
1683
- try {
1684
- const architecture = yield secretDeploymentArchitecture(ctx, slug);
1685
- if (architecture === "v2") {
1686
- yield ctx.client.deleteAgentkitSecret({
1687
- teamId: ctx.teamId,
1688
- slug,
1689
- name,
1690
- });
1691
- }
1692
- else {
1693
- yield ctx.client.deleteSecret({ teamId: ctx.teamId, slug, name });
1694
- }
1695
- }
1696
- catch (error) {
1697
- if (error instanceof DeployApiError && error.status === 404) {
1698
- ctx.err(`No secret named ${name} on deployment ${slug} — check \`${CLI} secrets list ${slug}\` (and the slug / --team).\n`);
1699
- return 1;
1700
- }
1701
- return renderApiError(error, ctx.err);
1702
- }
1703
- if (ctx.json) {
1704
- ctx.out(`${JSON.stringify({ removed: name }, null, 2)}\n`);
1635
+ export async function cmdSecretsUnset(slug, name, options) {
1636
+ if (slug === undefined || slug === "" || name === undefined || name === "") {
1637
+ (options.err ?? ((t) => void process.stderr.write(t)))(`Usage: ${CLI} secrets unset <slug> NAME [--team <id>]\n`);
1638
+ return 1;
1639
+ }
1640
+ const ctx = await prepare(options);
1641
+ if (typeof ctx === "number") {
1642
+ return ctx;
1643
+ }
1644
+ try {
1645
+ const architecture = await secretDeploymentArchitecture(ctx, slug);
1646
+ if (architecture === "v2") {
1647
+ await ctx.client.deleteAgentkitSecret({
1648
+ teamId: ctx.teamId,
1649
+ slug,
1650
+ name,
1651
+ });
1705
1652
  }
1706
1653
  else {
1707
- ctx.out(`Removed secret ${name} from ${slug}.\n`);
1654
+ await ctx.client.deleteSecret({ teamId: ctx.teamId, slug, name });
1708
1655
  }
1709
- return 0;
1710
- });
1656
+ }
1657
+ catch (error) {
1658
+ if (error instanceof DeployApiError && error.status === 404) {
1659
+ ctx.err(`No secret named ${name} on deployment ${slug} — check \`${CLI} secrets list ${slug}\` (and the slug / --team).\n`);
1660
+ return 1;
1661
+ }
1662
+ return renderApiError(error, ctx.err);
1663
+ }
1664
+ if (ctx.json) {
1665
+ ctx.out(`${JSON.stringify({ removed: name }, null, 2)}\n`);
1666
+ }
1667
+ else {
1668
+ ctx.out(`Removed secret ${name} from ${slug}.\n`);
1669
+ }
1670
+ return 0;
1711
1671
  }
1712
1672
  /**
1713
1673
  * Returns a reader for interactive secret values: hidden (no-echo) prompt
@@ -1721,13 +1681,13 @@ function createSecretValueReader(stdin, err) {
1721
1681
  return name => promptHidden(stdin, err, `Value for ${name}: `);
1722
1682
  }
1723
1683
  const readLine = createLineReader(stdin);
1724
- return (name) => __awaiter(this, void 0, void 0, function* () {
1725
- const line = yield readLine();
1684
+ return async (name) => {
1685
+ const line = await readLine();
1726
1686
  if (line === undefined) {
1727
1687
  throw new DeployApiError(`stdin ended before a value for ${name} was provided (pipe one line per secret).`, 0);
1728
1688
  }
1729
1689
  return line;
1730
- });
1690
+ };
1731
1691
  }
1732
1692
  /** Longest mask run drawn while typing a secret; the count carries the rest. */
1733
1693
  const SECRET_MASK_MAX_WIDTH = 24;
@@ -1738,9 +1698,8 @@ const SECRET_MASK_MAX_WIDTH = 24;
1738
1698
  * mask is clamped to the terminal width so the redraw stays on one line.
1739
1699
  */
1740
1700
  function renderSecretPromptLine(prompt, length, dim) {
1741
- var _a;
1742
1701
  const count = `${length} char${length === 1 ? "" : "s"}`;
1743
- const room = ((_a = process.stderr.columns) !== null && _a !== void 0 ? _a : 80) - prompt.length - count.length - 2;
1702
+ const room = (process.stderr.columns ?? 80) - prompt.length - count.length - 2;
1744
1703
  const maskWidth = Math.max(0, Math.min(length, SECRET_MASK_MAX_WIDTH, room));
1745
1704
  // `·` over `•`: the rest of the CLI's progress output already uses it, and
1746
1705
  // fonts that ship no bullet glyph draw a tofu box in its place.
@@ -1754,19 +1713,17 @@ function renderSecretPromptLine(prompt, length, dim) {
1754
1713
  */
1755
1714
  function promptHidden(stdin, err, prompt) {
1756
1715
  return new Promise((resolvePromise, reject) => {
1757
- var _a;
1758
1716
  const { dim } = stderrPalette();
1759
1717
  let value = "";
1760
1718
  const draw = () => {
1761
1719
  err(renderSecretPromptLine(prompt, value.length, dim));
1762
1720
  };
1763
1721
  draw();
1764
- (_a = stdin.setRawMode) === null || _a === void 0 ? void 0 : _a.call(stdin, true);
1722
+ stdin.setRawMode?.(true);
1765
1723
  stdin.resume();
1766
1724
  const cleanup = () => {
1767
- var _a;
1768
1725
  stdin.off("data", onData);
1769
- (_a = stdin.setRawMode) === null || _a === void 0 ? void 0 : _a.call(stdin, false);
1726
+ stdin.setRawMode?.(false);
1770
1727
  stdin.pause();
1771
1728
  draw();
1772
1729
  err("\n");
@@ -1801,14 +1758,12 @@ function promptHidden(stdin, err, prompt) {
1801
1758
  * `echo value | secrets set slug NAME` still stores `value`. Internal
1802
1759
  * newlines stay, which is what a redirected PEM needs.
1803
1760
  */
1804
- function readWholeStdinValue(stdin, name) {
1805
- return __awaiter(this, void 0, void 0, function* () {
1806
- const raw = yield readStreamText(stdin);
1807
- if (raw === "") {
1808
- throw new DeployApiError(`stdin ended before a value for ${name} was provided.`, 0);
1809
- }
1810
- return stripOneTrailingNewline(raw);
1811
- });
1761
+ async function readWholeStdinValue(stdin, name) {
1762
+ const raw = await readStreamText(stdin);
1763
+ if (raw === "") {
1764
+ throw new DeployApiError(`stdin ended before a value for ${name} was provided.`, 0);
1765
+ }
1766
+ return stripOneTrailingNewline(raw);
1812
1767
  }
1813
1768
  function stripOneTrailingNewline(value) {
1814
1769
  if (value.endsWith("\r\n")) {
@@ -1850,13 +1805,12 @@ export function createLineReader(stream) {
1850
1805
  let ended = false;
1851
1806
  const waiters = [];
1852
1807
  const drain = () => {
1853
- var _a, _b;
1854
1808
  while (waiters.length > 0) {
1855
1809
  const newline = buffer.indexOf("\n");
1856
1810
  if (newline !== -1) {
1857
1811
  const line = buffer.slice(0, newline).replace(/\r$/, "");
1858
1812
  buffer = buffer.slice(newline + 1);
1859
- (_a = waiters.shift()) === null || _a === void 0 ? void 0 : _a(line);
1813
+ waiters.shift()?.(line);
1860
1814
  continue;
1861
1815
  }
1862
1816
  if (!ended) {
@@ -1865,7 +1819,7 @@ export function createLineReader(stream) {
1865
1819
  // Stream ended: a trailing unterminated line still counts once.
1866
1820
  const rest = buffer;
1867
1821
  buffer = "";
1868
- (_b = waiters.shift()) === null || _b === void 0 ? void 0 : _b(rest === "" ? undefined : rest.replace(/\r$/, ""));
1822
+ waiters.shift()?.(rest === "" ? undefined : rest.replace(/\r$/, ""));
1869
1823
  }
1870
1824
  };
1871
1825
  stream.on("data", (chunk) => {
@@ -1892,74 +1846,72 @@ export function createLineReader(stream) {
1892
1846
  * status so create → checkout → start is visible. Throws DeployApiError
1893
1847
  * on request failures or timeout.
1894
1848
  */
1895
- function pollUntil(ctx, slug, terminal, fetchDetail) {
1896
- return __awaiter(this, void 0, void 0, function* () {
1897
- const startedAt = Date.now();
1898
- const tty = process.stderr.isTTY === true;
1899
- let lastLabel;
1900
- let sawProgress = false;
1901
- const report = (detail) => {
1902
- if (ctx.json) {
1903
- return;
1904
- }
1905
- const label = deployProgressLabel(detail);
1906
- const elapsed = Math.round((Date.now() - startedAt) / 1000);
1907
- if (tty) {
1908
- ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1909
- sawProgress = true;
1910
- }
1911
- else if (label !== lastLabel) {
1912
- ctx.err(`${slug}: ${label}\n`);
1913
- }
1914
- lastLabel = label;
1915
- };
1916
- const finishProgressLine = () => {
1917
- if (tty && sawProgress) {
1918
- ctx.err("\n");
1919
- }
1920
- };
1921
- for (;;) {
1922
- let detail;
1923
- try {
1924
- detail = yield fetchDetail();
1925
- }
1926
- catch (error) {
1927
- // Capacity / rate-limit on GET is not a bake failure. The v2 accept
1928
- // already started freeze; keep polling until the wait budget expires.
1929
- if (isTransientDeployStatusError(error) && Date.now() - startedAt < ctx.timeoutMs) {
1930
- if (!ctx.json) {
1931
- const elapsed = Math.round((Date.now() - startedAt) / 1000);
1932
- const label = "Waiting for status (server busy)";
1933
- if (tty) {
1934
- ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1935
- sawProgress = true;
1936
- }
1937
- else if (label !== lastLabel) {
1938
- ctx.err(`${slug}: ${label}\n`);
1939
- }
1940
- lastLabel = label;
1849
+ async function pollUntil(ctx, slug, terminal, fetchDetail) {
1850
+ const startedAt = Date.now();
1851
+ const tty = process.stderr.isTTY === true;
1852
+ let lastLabel;
1853
+ let sawProgress = false;
1854
+ const report = (detail) => {
1855
+ if (ctx.json) {
1856
+ return;
1857
+ }
1858
+ const label = deployProgressLabel(detail);
1859
+ const elapsed = Math.round((Date.now() - startedAt) / 1000);
1860
+ if (tty) {
1861
+ ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1862
+ sawProgress = true;
1863
+ }
1864
+ else if (label !== lastLabel) {
1865
+ ctx.err(`${slug}: ${label}\n`);
1866
+ }
1867
+ lastLabel = label;
1868
+ };
1869
+ const finishProgressLine = () => {
1870
+ if (tty && sawProgress) {
1871
+ ctx.err("\n");
1872
+ }
1873
+ };
1874
+ for (;;) {
1875
+ let detail;
1876
+ try {
1877
+ detail = await fetchDetail();
1878
+ }
1879
+ catch (error) {
1880
+ // Capacity / rate-limit on GET is not a bake failure. The v2 accept
1881
+ // already started freeze; keep polling until the wait budget expires.
1882
+ if (isTransientDeployStatusError(error) && Date.now() - startedAt < ctx.timeoutMs) {
1883
+ if (!ctx.json) {
1884
+ const elapsed = Math.round((Date.now() - startedAt) / 1000);
1885
+ const label = "Waiting for status (server busy)";
1886
+ if (tty) {
1887
+ ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1888
+ sawProgress = true;
1941
1889
  }
1942
- const waitMs = transientDeployStatusWaitMs(error, ctx.pollIntervalMs);
1943
- const remaining = ctx.timeoutMs - (Date.now() - startedAt);
1944
- yield sleep(Math.max(0, Math.min(waitMs, remaining)));
1945
- continue;
1890
+ else if (label !== lastLabel) {
1891
+ ctx.err(`${slug}: ${label}\n`);
1892
+ }
1893
+ lastLabel = label;
1946
1894
  }
1947
- finishProgressLine();
1948
- throw error;
1949
- }
1950
- report(detail);
1951
- if (terminal.has(detail.status)) {
1952
- finishProgressLine();
1953
- return detail;
1954
- }
1955
- if (Date.now() - startedAt >= ctx.timeoutMs) {
1956
- finishProgressLine();
1957
- const last = deployProgressLabel(detail);
1958
- throw new DeployApiError(`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}\`.`, 0);
1895
+ const waitMs = transientDeployStatusWaitMs(error, ctx.pollIntervalMs);
1896
+ const remaining = ctx.timeoutMs - (Date.now() - startedAt);
1897
+ await sleep(Math.max(0, Math.min(waitMs, remaining)));
1898
+ continue;
1959
1899
  }
1960
- yield sleep(ctx.pollIntervalMs);
1900
+ finishProgressLine();
1901
+ throw error;
1961
1902
  }
1962
- });
1903
+ report(detail);
1904
+ if (terminal.has(detail.status)) {
1905
+ finishProgressLine();
1906
+ return detail;
1907
+ }
1908
+ if (Date.now() - startedAt >= ctx.timeoutMs) {
1909
+ finishProgressLine();
1910
+ const last = deployProgressLabel(detail);
1911
+ throw new DeployApiError(`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}\`.`, 0);
1912
+ }
1913
+ await sleep(ctx.pollIntervalMs);
1914
+ }
1963
1915
  }
1964
1916
  /** Load-shed / rate-limit on status GET — the deploy itself may still be baking. */
1965
1917
  function isTransientDeployStatusError(error) {
@@ -1977,46 +1929,44 @@ function transientDeployStatusWaitMs(error, pollIntervalMs) {
1977
1929
  * Wait until GET 404s (the delete reconciler purged the record). Treats
1978
1930
  * other errors as failures. Throws DeployApiError on timeout.
1979
1931
  */
1980
- function pollUntilGone(ctx, slug, getDetail) {
1981
- return __awaiter(this, void 0, void 0, function* () {
1982
- const startedAt = Date.now();
1983
- const tty = process.stderr.isTTY === true;
1984
- let sawProgress = false;
1985
- const report = (label) => {
1986
- if (ctx.json) {
1987
- return;
1988
- }
1989
- const elapsed = Math.round((Date.now() - startedAt) / 1000);
1990
- if (tty) {
1991
- ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1992
- sawProgress = true;
1993
- }
1994
- };
1995
- const finishProgressLine = () => {
1996
- if (tty && sawProgress) {
1997
- ctx.err("\n");
1998
- }
1999
- };
2000
- for (;;) {
2001
- try {
2002
- const detail = yield getDetail();
2003
- report(deployProgressLabel(detail));
2004
- }
2005
- catch (error) {
2006
- if (error instanceof DeployApiError && error.status === 404) {
2007
- finishProgressLine();
2008
- return;
2009
- }
2010
- finishProgressLine();
2011
- throw error;
2012
- }
2013
- if (Date.now() - startedAt >= ctx.timeoutMs) {
1932
+ async function pollUntilGone(ctx, slug, getDetail) {
1933
+ const startedAt = Date.now();
1934
+ const tty = process.stderr.isTTY === true;
1935
+ let sawProgress = false;
1936
+ const report = (label) => {
1937
+ if (ctx.json) {
1938
+ return;
1939
+ }
1940
+ const elapsed = Math.round((Date.now() - startedAt) / 1000);
1941
+ if (tty) {
1942
+ ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1943
+ sawProgress = true;
1944
+ }
1945
+ };
1946
+ const finishProgressLine = () => {
1947
+ if (tty && sawProgress) {
1948
+ ctx.err("\n");
1949
+ }
1950
+ };
1951
+ for (;;) {
1952
+ try {
1953
+ const detail = await getDetail();
1954
+ report(deployProgressLabel(detail));
1955
+ }
1956
+ catch (error) {
1957
+ if (error instanceof DeployApiError && error.status === 404) {
2014
1958
  finishProgressLine();
2015
- throw new DeployApiError(`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}\`.`, 0);
1959
+ return;
2016
1960
  }
2017
- yield sleep(ctx.pollIntervalMs);
1961
+ finishProgressLine();
1962
+ throw error;
2018
1963
  }
2019
- });
1964
+ if (Date.now() - startedAt >= ctx.timeoutMs) {
1965
+ finishProgressLine();
1966
+ throw new DeployApiError(`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}\`.`, 0);
1967
+ }
1968
+ await sleep(ctx.pollIntervalMs);
1969
+ }
2020
1970
  }
2021
1971
  function aliasTokenBlock(aliasToken) {
2022
1972
  return (`\n Alias token (shown ONCE — save it now, it cannot be retrieved again):\n\n` +
@@ -2038,10 +1988,10 @@ export function renderApiError(error, err, context) {
2038
1988
  if (error instanceof DeployApiError) {
2039
1989
  err(`${error.message}\n`);
2040
1990
  if (error.status === 409 && error.message.includes("application multiTenant does not match")) {
2041
- if ((context === null || context === void 0 ? void 0 : context.multiTenant) === true) {
1991
+ if (context?.multiTenant === true) {
2042
1992
  err("This slug is a single-tenant application. Redeploy it without --multi-tenant.\n");
2043
1993
  }
2044
- else if ((context === null || context === void 0 ? void 0 : context.teamId) === MULTI_TENANT_HTTP_DEPLOY_TEAM_ID) {
1994
+ else if (context?.teamId === MULTI_TENANT_HTTP_DEPLOY_TEAM_ID) {
2045
1995
  err("This slug is a Cursor-managed (multi-tenant) product. Redeploy it with --multi-tenant.\n");
2046
1996
  }
2047
1997
  }
@@ -2050,9 +2000,9 @@ export function renderApiError(error, err, context) {
2050
2000
  throw error;
2051
2001
  }
2052
2002
  export function renderTable(header, rows) {
2053
- const widths = header.map((h, i) => Math.max(h.length, ...rows.map(row => { var _a; return ((_a = row[i]) !== null && _a !== void 0 ? _a : "").length; })));
2003
+ const widths = header.map((h, i) => Math.max(h.length, ...rows.map(row => (row[i] ?? "").length)));
2054
2004
  const renderRow = (row) => row
2055
- .map((cell, i) => { var _a; return cell.padEnd((_a = widths[i]) !== null && _a !== void 0 ? _a : 0); })
2005
+ .map((cell, i) => cell.padEnd(widths[i] ?? 0))
2056
2006
  .join(" ")
2057
2007
  .trimEnd();
2058
2008
  return [renderRow(header), ...rows.map(renderRow)].join("\n");