@cursor/july 0.1.1 → 0.1.2

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 (199) hide show
  1. package/AGENTS.md +24 -2
  2. package/README.md +25 -15
  3. package/dist/bin/agent-serve.js +101 -12
  4. package/dist/channels/github/api.d.ts.map +1 -1
  5. package/dist/channels/github/api.js +31 -14
  6. package/dist/channels/github/cursor-account.d.ts +43 -0
  7. package/dist/channels/github/cursor-account.d.ts.map +1 -0
  8. package/dist/channels/github/cursor-account.js +95 -0
  9. package/dist/channels/github/github-channel.d.ts.map +1 -1
  10. package/dist/channels/github/github-channel.js +46 -9
  11. package/dist/channels/github/index.d.ts +2 -2
  12. package/dist/channels/github/index.js +2 -2
  13. package/dist/channels/github/types.d.ts +17 -0
  14. package/dist/channels/github/types.d.ts.map +1 -1
  15. package/dist/channels/slack/slack-channel.d.ts +8 -2
  16. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  17. package/dist/channels/slack/slack-channel.js +8 -0
  18. package/dist/channels/slack/types.d.ts +24 -3
  19. package/dist/channels/slack/types.d.ts.map +1 -1
  20. package/dist/channels/slack/types.js +15 -1
  21. package/dist/docs/404.html +2 -2
  22. package/dist/docs/ab.html +8 -8
  23. package/dist/docs/assets/{ab.md.COdXkces.js → ab.md.BMCZ6Hd7.js} +3 -3
  24. package/dist/docs/assets/{ab.md.COdXkces.lean.js → ab.md.BMCZ6Hd7.lean.js} +1 -1
  25. package/dist/docs/assets/{app.DqfFEmJd.js → app.Oje4vhlk.js} +1 -1
  26. package/dist/docs/assets/chunks/@localSearchIndexroot.zwQ9RCQ7.js +1 -0
  27. package/dist/docs/assets/chunks/{VPLocalSearchBox.BaLEdS15.js → VPLocalSearchBox.H5XZ2zCB.js} +1 -1
  28. package/dist/docs/assets/chunks/{theme.CZRvu_0q.js → theme.CTR_TuaE.js} +2 -2
  29. package/dist/docs/assets/{deployment.md.Dx1TYNk5.js → deployment.md.DTKwE15Z.js} +3 -3
  30. package/dist/docs/assets/{deployment.md.Dx1TYNk5.lean.js → deployment.md.DTKwE15Z.lean.js} +1 -1
  31. package/dist/docs/assets/{evals.md.DPZ_MAnI.js → evals.md.DAgEc_hL.js} +3 -3
  32. package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.js → guides_agent-to-agent.md.Bpzgq2Pq.js} +1 -1
  33. package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.js → guides_cloud-runtime.md.gVzabdQL.js} +1 -1
  34. package/dist/docs/assets/{guides_github.md.DwbKhCeS.js → guides_github.md.DOOCpqsW.js} +11 -4
  35. package/dist/docs/assets/{guides_github.md.DwbKhCeS.lean.js → guides_github.md.DOOCpqsW.lean.js} +1 -1
  36. package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.js → guides_human-in-the-loop.md.DlUqsp1S.js} +2 -2
  37. package/dist/docs/assets/{guides_slack.md.bv41fHfW.js → guides_slack.md.CCwqHvSV.js} +4 -4
  38. package/dist/docs/assets/{guides_slack.md.bv41fHfW.lean.js → guides_slack.md.CCwqHvSV.lean.js} +1 -1
  39. package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.js → guides_webhooks.md.B1EswtUu.js} +2 -2
  40. package/dist/docs/assets/index.md.m81y7TY7.js +20 -0
  41. package/dist/docs/assets/{index.md.BPKcj5AI.lean.js → index.md.m81y7TY7.lean.js} +1 -1
  42. package/dist/docs/assets/quickstart.md.CfU8_uTC.js +192 -0
  43. package/dist/docs/assets/quickstart.md.CfU8_uTC.lean.js +1 -0
  44. package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.js → reference_agent-config.md.DrW2JUM8.js} +4 -4
  45. package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.lean.js → reference_agent-config.md.DrW2JUM8.lean.js} +1 -1
  46. package/dist/docs/assets/{reference_channels.md.D7JTR03W.js → reference_channels.md.DdmiKgqf.js} +4 -4
  47. package/dist/docs/assets/{reference_channels.md.D7JTR03W.lean.js → reference_channels.md.DdmiKgqf.lean.js} +1 -1
  48. package/dist/docs/assets/{reference_connections.md.C3vNH_DE.js → reference_connections.md.zaEYCLHT.js} +1 -1
  49. package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.js → reference_hooks.md.DyLVfE1O.js} +1 -1
  50. package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.lean.js → reference_hooks.md.DyLVfE1O.lean.js} +1 -1
  51. package/dist/docs/assets/{reference_http-api.md.DBAahtdz.js → reference_http-api.md.Dx_nmDG6.js} +1 -1
  52. package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.js → reference_instructions.md.CgoV-YEb.js} +9 -7
  53. package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.lean.js → reference_instructions.md.CgoV-YEb.lean.js} +1 -1
  54. package/dist/docs/assets/{reference_schedules.md.D7qijxLk.js → reference_schedules.md.w_F2mXB6.js} +2 -2
  55. package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.js → reference_skills.md.B_jHN7JL.js} +3 -3
  56. package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.lean.js → reference_skills.md.B_jHN7JL.lean.js} +1 -1
  57. package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.js → reference_subagents.md.zWAMNfi1.js} +1 -1
  58. package/dist/docs/assets/{reference_tools.md.DF5kwlt0.js → reference_tools.md.CqgJroI0.js} +2 -2
  59. package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.js +1 -0
  60. package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.lean.js +1 -0
  61. package/dist/docs/assets/storage.md.CVnInNiN.js +17 -0
  62. package/dist/docs/assets/storage.md.CVnInNiN.lean.js +1 -0
  63. package/dist/docs/building-with-agents.html +4 -4
  64. package/dist/docs/concepts.html +4 -4
  65. package/dist/docs/deployment.html +7 -7
  66. package/dist/docs/evals.html +7 -7
  67. package/dist/docs/guides/agent-to-agent.html +6 -6
  68. package/dist/docs/guides/cloud-runtime.html +5 -5
  69. package/dist/docs/guides/github.html +14 -7
  70. package/dist/docs/guides/human-in-the-loop.html +6 -6
  71. package/dist/docs/guides/slack.html +8 -8
  72. package/dist/docs/guides/webhooks.html +6 -6
  73. package/dist/docs/hashmap.json +1 -1
  74. package/dist/docs/hillclimbing.html +5 -5
  75. package/dist/docs/index.html +7 -7
  76. package/dist/docs/quickstart.html +180 -23
  77. package/dist/docs/reference/agent-config.html +7 -7
  78. package/dist/docs/reference/channels.html +8 -8
  79. package/dist/docs/reference/cli.html +4 -4
  80. package/dist/docs/reference/connections.html +5 -5
  81. package/dist/docs/reference/hooks.html +5 -5
  82. package/dist/docs/reference/http-api.html +6 -6
  83. package/dist/docs/reference/instructions.html +13 -11
  84. package/dist/docs/reference/playground.html +4 -4
  85. package/dist/docs/reference/project-layout.html +4 -4
  86. package/dist/docs/reference/schedules.html +7 -7
  87. package/dist/docs/reference/sessions.html +4 -4
  88. package/dist/docs/reference/skills.html +6 -6
  89. package/dist/docs/reference/subagents.html +6 -6
  90. package/dist/docs/reference/tools.html +7 -7
  91. package/dist/docs/scaffolding-agents.html +5 -5
  92. package/dist/docs/storage.html +41 -0
  93. package/dist/docs/troubleshooting.html +4 -4
  94. package/dist/index.d.ts +2 -0
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +1 -0
  97. package/dist/internal/cli-deploy.d.ts +52 -0
  98. package/dist/internal/cli-deploy.d.ts.map +1 -0
  99. package/dist/internal/cli-deploy.js +731 -0
  100. package/dist/internal/cursor/backend-client.d.ts +10 -1
  101. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  102. package/dist/internal/cursor/backend-client.js +79 -1
  103. package/dist/internal/cursor/github-credentials.d.ts +44 -0
  104. package/dist/internal/cursor/github-credentials.d.ts.map +1 -0
  105. package/dist/internal/cursor/github-credentials.js +195 -0
  106. package/dist/internal/deploy-client.d.ts +176 -0
  107. package/dist/internal/deploy-client.d.ts.map +1 -0
  108. package/dist/internal/deploy-client.js +375 -0
  109. package/dist/internal/discovery.d.ts.map +1 -1
  110. package/dist/internal/discovery.js +73 -5
  111. package/dist/internal/distribution.d.ts.map +1 -1
  112. package/dist/internal/distribution.js +1 -0
  113. package/dist/internal/eval-run-store.d.ts +22 -3
  114. package/dist/internal/eval-run-store.d.ts.map +1 -1
  115. package/dist/internal/eval-run-store.js +37 -19
  116. package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
  117. package/dist/internal/handleAgentServeTrigger.js +10 -12
  118. package/dist/internal/host-platforms.d.ts +7 -2
  119. package/dist/internal/host-platforms.d.ts.map +1 -1
  120. package/dist/internal/host-platforms.js +15 -10
  121. package/dist/internal/hosting.d.ts +37 -0
  122. package/dist/internal/hosting.d.ts.map +1 -0
  123. package/dist/internal/hosting.js +67 -0
  124. package/dist/internal/reminder-runner.d.ts +7 -0
  125. package/dist/internal/reminder-runner.d.ts.map +1 -1
  126. package/dist/internal/reminder-runner.js +50 -6
  127. package/dist/internal/reminder-store.d.ts +2 -0
  128. package/dist/internal/reminder-store.d.ts.map +1 -1
  129. package/dist/internal/reminder-store.js +18 -0
  130. package/dist/internal/server.d.ts.map +1 -1
  131. package/dist/internal/server.js +173 -42
  132. package/dist/internal/session-engine.d.ts +49 -0
  133. package/dist/internal/session-engine.d.ts.map +1 -1
  134. package/dist/internal/session-engine.js +246 -17
  135. package/dist/internal/storage-coordinator.d.ts +139 -0
  136. package/dist/internal/storage-coordinator.d.ts.map +1 -0
  137. package/dist/internal/storage-coordinator.js +499 -0
  138. package/dist/playground/assets/cursor-icons-outline-BxTT_FVJ.woff2 +0 -0
  139. package/dist/playground/assets/index-B1Qc9h2u.css +1 -0
  140. package/dist/playground/assets/{index-FlWjhg3x.js → index-CpDYCj8W.js} +42 -42
  141. package/dist/playground/index.html +2 -2
  142. package/dist/storage.d.ts +204 -0
  143. package/dist/storage.d.ts.map +1 -0
  144. package/dist/storage.js +153 -0
  145. package/dist/types.d.ts +44 -3
  146. package/dist/types.d.ts.map +1 -1
  147. package/docs/README.md +3 -2
  148. package/docs/guides/github.md +43 -8
  149. package/docs/guides/slack.md +1 -1
  150. package/docs/quickstart.md +329 -51
  151. package/docs/reference/instructions.md +8 -6
  152. package/docs/scaffolding-agents.md +1 -1
  153. package/docs/storage.md +98 -0
  154. package/package.json +8 -1
  155. package/skills/github/SKILL.md +9 -1
  156. package/src/bin/agent-serve.ts +139 -0
  157. package/src/channels/github/api.ts +42 -23
  158. package/src/channels/github/cursor-account.ts +165 -0
  159. package/src/channels/github/github-channel.ts +66 -6
  160. package/src/channels/github/index.ts +2 -2
  161. package/src/channels/github/types.ts +19 -0
  162. package/src/channels/slack/slack-channel.ts +17 -3
  163. package/src/channels/slack/types.ts +44 -3
  164. package/src/index.ts +13 -0
  165. package/src/internal/cli-deploy.ts +940 -0
  166. package/src/internal/cursor/backend-client.ts +103 -1
  167. package/src/internal/cursor/github-credentials.ts +248 -0
  168. package/src/internal/deploy-client.ts +591 -0
  169. package/src/internal/discovery.ts +88 -1
  170. package/src/internal/distribution.ts +1 -0
  171. package/src/internal/eval-run-store.ts +48 -19
  172. package/src/internal/handleAgentServeTrigger.ts +10 -12
  173. package/src/internal/host-platforms.ts +28 -11
  174. package/src/internal/hosting.ts +77 -0
  175. package/src/internal/reminder-runner.ts +50 -6
  176. package/src/internal/reminder-store.ts +21 -0
  177. package/src/internal/server.ts +213 -27
  178. package/src/internal/session-engine.ts +285 -7
  179. package/src/internal/storage-coordinator.ts +615 -0
  180. package/src/storage.ts +325 -0
  181. package/src/types.ts +40 -2
  182. package/dist/docs/assets/chunks/@localSearchIndexroot.CcVk1uKq.js +0 -1
  183. package/dist/docs/assets/index.md.BPKcj5AI.js +0 -20
  184. package/dist/docs/assets/quickstart.md.tVPiGK_L.js +0 -35
  185. package/dist/docs/assets/quickstart.md.tVPiGK_L.lean.js +0 -1
  186. package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.js +0 -1
  187. package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.lean.js +0 -1
  188. package/dist/playground/assets/cursor-icons-outline-oY2V_mvK.woff2 +0 -0
  189. package/dist/playground/assets/index-1K-hG-7p.css +0 -1
  190. /package/dist/docs/assets/{evals.md.DPZ_MAnI.lean.js → evals.md.DAgEc_hL.lean.js} +0 -0
  191. /package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.lean.js → guides_agent-to-agent.md.Bpzgq2Pq.lean.js} +0 -0
  192. /package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.lean.js → guides_cloud-runtime.md.gVzabdQL.lean.js} +0 -0
  193. /package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.lean.js → guides_human-in-the-loop.md.DlUqsp1S.lean.js} +0 -0
  194. /package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.lean.js → guides_webhooks.md.B1EswtUu.lean.js} +0 -0
  195. /package/dist/docs/assets/{reference_connections.md.C3vNH_DE.lean.js → reference_connections.md.zaEYCLHT.lean.js} +0 -0
  196. /package/dist/docs/assets/{reference_http-api.md.DBAahtdz.lean.js → reference_http-api.md.Dx_nmDG6.lean.js} +0 -0
  197. /package/dist/docs/assets/{reference_schedules.md.D7qijxLk.lean.js → reference_schedules.md.w_F2mXB6.lean.js} +0 -0
  198. /package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.lean.js → reference_subagents.md.zWAMNfi1.lean.js} +0 -0
  199. /package/dist/docs/assets/{reference_tools.md.DF5kwlt0.lean.js → reference_tools.md.CqgJroI0.lean.js} +0 -0
@@ -0,0 +1,731 @@
1
+ /**
2
+ * `agentkit deploy | deployments | deployment | stop | rotate-token |
3
+ * rotate-pod-credential | secrets set|list|unset` — Heroku-style deploys
4
+ * onto Cursor's managed agent-serve hosting.
5
+ *
6
+ * All intelligence is server-side (backend/server/src/agentServe/); these
7
+ * handlers resolve parameters (credentials, team, slug, the project's
8
+ * `hosting` manifest block), call the management API through
9
+ * `deploy-client.ts`, poll status, and render.
10
+ */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ import { basename, resolve } from "node:path";
21
+ import { CursorBackendClient } from "./cursor/backend-client.js";
22
+ import { cursorBackendUrl, resolveApiKey, SIGN_IN_HINT, } from "./cursor/credentials.js";
23
+ import { AgentServeDeployClient, DeployApiError, slugFromDirectoryName, TERMINAL_DEPLOY_STATUSES, validateDeploymentSlug, } from "./deploy-client.js";
24
+ import { isAgentProjectDir, loadAgentProject } from "./discovery.js";
25
+ import { CLI_COMMAND_NAME as CLI } from "./distribution.js";
26
+ import { isValidCursorEventRepo, validateSettableSecretName, } from "./hosting.js";
27
+ const DEFAULT_POLL_INTERVAL_MS = 3000;
28
+ const DEFAULT_DEPLOY_TIMEOUT_MS = 10 * 60 * 1000;
29
+ /**
30
+ * Shared preamble: credentials → client → team id. Returns an exit code
31
+ * (with the error already rendered) when resolution fails.
32
+ */
33
+ function prepare(options) {
34
+ return __awaiter(this, void 0, void 0, function* () {
35
+ var _a, _b, _c, _d;
36
+ const out = (_a = options.out) !== null && _a !== void 0 ? _a : ((text) => void process.stdout.write(text));
37
+ const err = (_b = options.err) !== null && _b !== void 0 ? _b : ((text) => void process.stderr.write(text));
38
+ const resolved = yield resolveApiKey(options.apiKey === undefined ? undefined : { apiKey: options.apiKey });
39
+ if (resolved === undefined) {
40
+ err(`Not signed in to Cursor. ${SIGN_IN_HINT}\n`);
41
+ return 1;
42
+ }
43
+ const client = new AgentServeDeployClient(Object.assign({ backendUrl: resolved.backendUrl, apiKey: resolved.apiKey }, (options.fetchImpl === undefined
44
+ ? {}
45
+ : { fetchImpl: options.fetchImpl })));
46
+ let teamId;
47
+ if (options.team !== undefined) {
48
+ teamId = Number.parseInt(options.team, 10);
49
+ if (Number.isNaN(teamId) || teamId <= 0) {
50
+ err(`Invalid --team: ${options.team} (expected a positive team id)\n`);
51
+ return 1;
52
+ }
53
+ }
54
+ else {
55
+ const account = new CursorBackendClient(Object.assign({ backendUrl: resolved.backendUrl, apiKey: resolved.apiKey }, (options.fetchImpl === undefined
56
+ ? {}
57
+ : { fetchImpl: options.fetchImpl })));
58
+ let identity;
59
+ try {
60
+ identity = yield account.getMe();
61
+ }
62
+ catch (error) {
63
+ err(`Could not resolve your team from the Cursor account: ${describeError(error)}\nPass --team <id> explicitly.\n`);
64
+ return 1;
65
+ }
66
+ if (identity.teamId === undefined || identity.teamId <= 0) {
67
+ err("This Cursor account has no default team; pass --team <id> (find it in the Cursor dashboard URL).\n");
68
+ return 1;
69
+ }
70
+ teamId = identity.teamId;
71
+ err(`Using team ${teamId}${identity.teamName === undefined ? "" : ` (${identity.teamName})`} — the account's team; pass --team to override.\n`);
72
+ }
73
+ return {
74
+ client,
75
+ teamId,
76
+ json: options.json === true,
77
+ noWait: options.noWait === true,
78
+ pollIntervalMs: (_c = options.pollIntervalMs) !== null && _c !== void 0 ? _c : DEFAULT_POLL_INTERVAL_MS,
79
+ timeoutMs: (_d = options.timeoutMs) !== null && _d !== void 0 ? _d : DEFAULT_DEPLOY_TIMEOUT_MS,
80
+ out,
81
+ err,
82
+ };
83
+ });
84
+ }
85
+ // ============================================================================
86
+ // deploy
87
+ // ============================================================================
88
+ export function cmdDeploy(options) {
89
+ return __awaiter(this, void 0, void 0, function* () {
90
+ var _a, _b, _c, _d;
91
+ const ctx = yield prepare(options);
92
+ if (typeof ctx === "number") {
93
+ return ctx;
94
+ }
95
+ const dir = resolve((_a = options.dir) !== null && _a !== void 0 ? _a : ".");
96
+ let slug;
97
+ if (options.slug !== undefined) {
98
+ const slugError = validateDeploymentSlug(options.slug);
99
+ if (slugError !== undefined) {
100
+ ctx.err(`${slugError}\n`);
101
+ return 1;
102
+ }
103
+ slug = options.slug;
104
+ }
105
+ else {
106
+ const derived = slugFromDirectoryName(basename(dir));
107
+ if (derived === undefined) {
108
+ ctx.err(`Could not derive a deployment slug from the directory name ${JSON.stringify(basename(dir))}; pass --slug.\n`);
109
+ return 1;
110
+ }
111
+ slug = derived;
112
+ ctx.err(`Deploying as "${slug}" (from the directory name).\n`);
113
+ }
114
+ if (options.repo !== undefined && !options.repo.startsWith("https://")) {
115
+ ctx.err(`Invalid --repo: ${options.repo} (expected an https:// git repository URL)\n`);
116
+ return 1;
117
+ }
118
+ for (const repo of (_b = options.cursorEventsRepos) !== null && _b !== void 0 ? _b : []) {
119
+ if (!isValidCursorEventRepo(repo)) {
120
+ ctx.err(`Invalid --cursor-events-repo: ${repo} (expected owner/name)\n`);
121
+ return 1;
122
+ }
123
+ }
124
+ // The package manifest (`defineAgent({ hosting })`) is the source of
125
+ // truth for egress domains and expected secret names; flags override or
126
+ // augment it. Directories without an agent project (static placeholder
127
+ // deploys) simply have no manifest.
128
+ const hosting = yield readHostingManifest(dir);
129
+ const egressAllowedDomains = [
130
+ ...new Set([
131
+ ...((_c = hosting === null || hosting === void 0 ? void 0 : hosting.egressDomains) !== null && _c !== void 0 ? _c : []),
132
+ ...((_d = options.allowDomains) !== null && _d !== void 0 ? _d : []),
133
+ ]),
134
+ ];
135
+ // Today's only source shape: the control plane builds from a git ref (or
136
+ // serves the static placeholder). See DeploySource for the artifact seam.
137
+ const source = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ kind: "git-ref" }, (options.repo === undefined ? {} : { gitRepoUrl: options.repo })), (options.ref === undefined ? {} : { gitRef: options.ref })), (options.path === undefined ? {} : { agentPath: options.path })), (options.cursorEventsRepos === undefined ||
138
+ options.cursorEventsRepos.length === 0
139
+ ? {}
140
+ : { cursorEventRepos: options.cursorEventsRepos })), (egressAllowedDomains.length === 0 ? {} : { egressAllowedDomains }));
141
+ let accepted;
142
+ try {
143
+ accepted = yield ctx.client.deploy({ teamId: ctx.teamId, slug, source });
144
+ }
145
+ catch (error) {
146
+ return renderApiError(error, ctx.err);
147
+ }
148
+ const aliasUrl = ctx.client.aliasUrl(accepted.engineAlias);
149
+ if (!ctx.json && accepted.aliasToken !== undefined) {
150
+ ctx.out(aliasTokenBlock(accepted.aliasToken));
151
+ }
152
+ if (ctx.noWait) {
153
+ if (ctx.json) {
154
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
155
+ }
156
+ else {
157
+ ctx.out(`Deploy accepted: ${slug} (team ${ctx.teamId}, generation ${accepted.generation}, ${accepted.deploymentKind})\n` +
158
+ ` alias: ${aliasUrl}\n` +
159
+ `Check progress with \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.\n`);
160
+ }
161
+ return 0;
162
+ }
163
+ let detail;
164
+ try {
165
+ detail = yield pollUntil(ctx, slug, TERMINAL_DEPLOY_STATUSES);
166
+ }
167
+ catch (error) {
168
+ return renderApiError(error, ctx.err);
169
+ }
170
+ warnMissingSecrets(ctx, slug, hosting === null || hosting === void 0 ? void 0 : hosting.secretNames, detail.secretNames);
171
+ if (ctx.json) {
172
+ ctx.out(`${JSON.stringify(accepted.aliasToken === undefined
173
+ ? detail
174
+ : Object.assign(Object.assign({}, detail), { aliasToken: accepted.aliasToken }), null, 2)}\n`);
175
+ return detail.status === "running" ? 0 : 1;
176
+ }
177
+ if (detail.status !== "running") {
178
+ ctx.err(`Deployment ${slug} ended ${detail.status}${detail.lastError === null || detail.lastError === undefined
179
+ ? ""
180
+ : `: ${detail.lastError}`}\n`);
181
+ return 1;
182
+ }
183
+ ctx.out(`Deployed ${slug} (team ${ctx.teamId})\n` +
184
+ ` status: running\n` +
185
+ ` generation: ${detail.generation}\n` +
186
+ ` kind: ${detail.deploymentKind}\n` +
187
+ ` alias: ${aliasUrl}\n` +
188
+ ` playground: ${aliasUrl}/playground (send X-Agent-Alias-Token)\n`);
189
+ return 0;
190
+ });
191
+ }
192
+ /**
193
+ * Read the `hosting` block from the project manifest at `dir`, or
194
+ * undefined when the directory is not an agent project (static deploys
195
+ * have nothing to discover).
196
+ */
197
+ function readHostingManifest(dir) {
198
+ return __awaiter(this, void 0, void 0, function* () {
199
+ if (!(yield isAgentProjectDir(dir))) {
200
+ return undefined;
201
+ }
202
+ const project = yield loadAgentProject(dir);
203
+ return project.agent.hosting;
204
+ });
205
+ }
206
+ /**
207
+ * Friendly post-deploy nudge: the manifest declares secrets the agent
208
+ * expects, but the deployment does not have them all set yet.
209
+ */
210
+ function warnMissingSecrets(ctx, slug, declared, set) {
211
+ if (declared === undefined || declared.length === 0) {
212
+ return;
213
+ }
214
+ const setNames = new Set(set !== null && set !== void 0 ? set : []);
215
+ const missing = declared.filter((name) => !setNames.has(name));
216
+ if (missing.length === 0) {
217
+ return;
218
+ }
219
+ ctx.err(`warning: secrets declared in the agent manifest but not set on ${slug}: ${missing.join(", ")}\n` +
220
+ ` set them with \`${CLI} secrets set ${slug} ${missing.join(" ")}\`\n`);
221
+ }
222
+ // ============================================================================
223
+ // deployments (list)
224
+ // ============================================================================
225
+ export function cmdDeployments(options) {
226
+ return __awaiter(this, void 0, void 0, function* () {
227
+ const ctx = yield prepare(options);
228
+ if (typeof ctx === "number") {
229
+ return ctx;
230
+ }
231
+ let deployments;
232
+ try {
233
+ deployments = yield ctx.client.listDeployments({ teamId: ctx.teamId });
234
+ }
235
+ catch (error) {
236
+ return renderApiError(error, ctx.err);
237
+ }
238
+ if (ctx.json) {
239
+ ctx.out(`${JSON.stringify({ deployments }, null, 2)}\n`);
240
+ return 0;
241
+ }
242
+ if (deployments.length === 0) {
243
+ ctx.out(`No deployments on team ${ctx.teamId}. Create one with \`${CLI} deploy\`.\n`);
244
+ return 0;
245
+ }
246
+ ctx.out(`${renderTable(["SLUG", "STATUS", "GEN", "KIND", "UPDATED"], deployments.map((d) => { var _a; return [
247
+ d.slug,
248
+ d.status,
249
+ String(d.generation),
250
+ d.deploymentKind,
251
+ (_a = d.desiredUpdatedAt) !== null && _a !== void 0 ? _a : "",
252
+ ]; }))}\n`);
253
+ return 0;
254
+ });
255
+ }
256
+ // ============================================================================
257
+ // deployment <slug> (detail)
258
+ // ============================================================================
259
+ export function cmdDeploymentStatus(slug, options) {
260
+ return __awaiter(this, void 0, void 0, function* () {
261
+ var _a, _b;
262
+ if (slug === undefined || slug === "") {
263
+ ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} deployment <slug> [--team <id>] [--json]\n`);
264
+ return 1;
265
+ }
266
+ const ctx = yield prepare(options);
267
+ if (typeof ctx === "number") {
268
+ return ctx;
269
+ }
270
+ let detail;
271
+ try {
272
+ detail = yield ctx.client.getDeployment({ teamId: ctx.teamId, slug });
273
+ }
274
+ catch (error) {
275
+ return renderApiError(error, ctx.err);
276
+ }
277
+ if (ctx.json) {
278
+ ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
279
+ return 0;
280
+ }
281
+ const aliasUrl = ctx.client.aliasUrl(detail.engineAlias);
282
+ const lines = [
283
+ `${detail.slug} (team ${detail.teamId})`,
284
+ ` status: ${detail.status}`,
285
+ ` generation: ${detail.generation}`,
286
+ ` kind: ${detail.deploymentKind}`,
287
+ ` alias: ${aliasUrl}`,
288
+ ];
289
+ if (detail.gitRepoUrl !== null && detail.gitRepoUrl !== undefined) {
290
+ lines.push(` repo: ${detail.gitRepoUrl} @ ${(_b = detail.gitRef) !== null && _b !== void 0 ? _b : ""}`);
291
+ }
292
+ if (detail.serviceAccountId !== undefined &&
293
+ detail.serviceAccountId !== null) {
294
+ lines.push(` service account: ${detail.serviceAccountId}`);
295
+ }
296
+ if (detail.egressAllowedDomains !== undefined &&
297
+ detail.egressAllowedDomains.length > 0) {
298
+ lines.push(` egress: ${detail.egressAllowedDomains.join(", ")}`);
299
+ }
300
+ if (detail.secretNames !== undefined && detail.secretNames.length > 0) {
301
+ lines.push(` secrets: ${detail.secretNames.join(", ")}`);
302
+ }
303
+ if (detail.podCredentialMaskedKey !== undefined &&
304
+ detail.podCredentialMaskedKey !== null) {
305
+ lines.push(` pod credential: ${detail.podCredentialMaskedKey}`);
306
+ }
307
+ if (detail.engineUrl !== null && detail.engineUrl !== undefined) {
308
+ lines.push(` engine: ${detail.engineUrl}`);
309
+ }
310
+ if (detail.engineAccess !== null &&
311
+ detail.engineAccess !== undefined &&
312
+ typeof detail.engineAccess === "object") {
313
+ lines.push(` engine access: ${detail.engineAccess.url} (expires ${detail.engineAccess.expiresAt})`);
314
+ }
315
+ if (detail.lastError !== null && detail.lastError !== undefined) {
316
+ lines.push(` last error: ${detail.lastError}`);
317
+ }
318
+ if (detail.desiredUpdatedAt !== undefined) {
319
+ lines.push(` updated: ${detail.desiredUpdatedAt}`);
320
+ }
321
+ ctx.out(`${lines.join("\n")}\n`);
322
+ return 0;
323
+ });
324
+ }
325
+ // ============================================================================
326
+ // stop <slug>
327
+ // ============================================================================
328
+ export function cmdStop(slug, options) {
329
+ return __awaiter(this, void 0, void 0, function* () {
330
+ var _a;
331
+ if (slug === undefined || slug === "") {
332
+ ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} stop <slug> [--team <id>] [--json] [--no-wait]\n`);
333
+ return 1;
334
+ }
335
+ const ctx = yield prepare(options);
336
+ if (typeof ctx === "number") {
337
+ return ctx;
338
+ }
339
+ let accepted;
340
+ try {
341
+ accepted = yield ctx.client.stopDeployment({ teamId: ctx.teamId, slug });
342
+ }
343
+ catch (error) {
344
+ return renderApiError(error, ctx.err);
345
+ }
346
+ if (ctx.noWait) {
347
+ if (ctx.json) {
348
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
349
+ }
350
+ else {
351
+ ctx.out(`Stop accepted for ${slug} (status: ${accepted.status}).\n`);
352
+ }
353
+ return 0;
354
+ }
355
+ let detail;
356
+ try {
357
+ detail = yield pollUntil(ctx, slug, new Set(["stopped"]));
358
+ }
359
+ catch (error) {
360
+ return renderApiError(error, ctx.err);
361
+ }
362
+ if (ctx.json) {
363
+ ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
364
+ }
365
+ else {
366
+ ctx.out(`Stopped ${slug} (team ${ctx.teamId}).\n`);
367
+ }
368
+ return 0;
369
+ });
370
+ }
371
+ // ============================================================================
372
+ // rotate-token <slug>
373
+ // ============================================================================
374
+ export function cmdRotateToken(slug, options) {
375
+ return __awaiter(this, void 0, void 0, function* () {
376
+ var _a;
377
+ if (slug === undefined || slug === "") {
378
+ ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} rotate-token <slug> [--team <id>]\n`);
379
+ return 1;
380
+ }
381
+ const ctx = yield prepare(options);
382
+ if (typeof ctx === "number") {
383
+ return ctx;
384
+ }
385
+ let aliasToken;
386
+ try {
387
+ aliasToken = yield ctx.client.rotateAliasToken({
388
+ teamId: ctx.teamId,
389
+ slug,
390
+ });
391
+ }
392
+ catch (error) {
393
+ return renderApiError(error, ctx.err);
394
+ }
395
+ if (ctx.json) {
396
+ ctx.out(`${JSON.stringify({ aliasToken }, null, 2)}\n`);
397
+ return 0;
398
+ }
399
+ ctx.out(`Rotated the alias token for ${slug}. The old token stopped working immediately.\n${aliasTokenBlock(aliasToken)}`);
400
+ return 0;
401
+ });
402
+ }
403
+ // ============================================================================
404
+ // rotate-pod-credential <slug>
405
+ // ============================================================================
406
+ export function cmdRotatePodCredential(slug, options) {
407
+ return __awaiter(this, void 0, void 0, function* () {
408
+ var _a;
409
+ if (slug === undefined || slug === "") {
410
+ ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} rotate-pod-credential <slug> [--team <id>]\n`);
411
+ return 1;
412
+ }
413
+ const ctx = yield prepare(options);
414
+ if (typeof ctx === "number") {
415
+ return ctx;
416
+ }
417
+ let podCredentialMaskedKey;
418
+ try {
419
+ podCredentialMaskedKey = yield ctx.client.rotatePodCredential({
420
+ teamId: ctx.teamId,
421
+ slug,
422
+ });
423
+ }
424
+ catch (error) {
425
+ return renderApiError(error, ctx.err);
426
+ }
427
+ if (ctx.json) {
428
+ ctx.out(`${JSON.stringify({ podCredentialMaskedKey }, null, 2)}\n`);
429
+ return 0;
430
+ }
431
+ ctx.out(`Rotated the pod credential for ${slug}: ${podCredentialMaskedKey}\n` +
432
+ `The running pod keeps the old credential until the next deploy — run \`${CLI} deploy --slug ${slug}\` to apply it.\n`);
433
+ return 0;
434
+ });
435
+ }
436
+ // ============================================================================
437
+ // secrets set|list|unset
438
+ // ============================================================================
439
+ export function cmdSecretsSet(slug, specs, options) {
440
+ return __awaiter(this, void 0, void 0, function* () {
441
+ var _a, _b, _c;
442
+ const usageErr = (_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t));
443
+ if (slug === undefined || slug === "" || specs.length === 0) {
444
+ usageErr(`Usage: ${CLI} secrets set <slug> NAME[=VALUE] [NAME2[=VALUE2] ...] [--team <id>] [--json]\n` +
445
+ `NAMEs without =VALUE are prompted for (hidden input; reads stdin when piped).\n`);
446
+ return 1;
447
+ }
448
+ // Parse and validate every name before prompting for any value, so a
449
+ // typo in the last name cannot waste typed-in secrets.
450
+ const parsed = [];
451
+ for (const spec of specs) {
452
+ const eq = spec.indexOf("=");
453
+ const name = eq === -1 ? spec : spec.slice(0, eq);
454
+ const nameError = validateSettableSecretName(name);
455
+ if (nameError !== undefined) {
456
+ usageErr(`${nameError}\n`);
457
+ return 1;
458
+ }
459
+ parsed.push(eq === -1 ? { name } : { name, value: spec.slice(eq + 1) });
460
+ }
461
+ if (parsed.some((entry) => entry.value !== undefined)) {
462
+ usageErr(`warning: secret values passed as arguments can end up in shell history; prefer \`${CLI} secrets set ${slug} NAME\` and enter the value at the hidden prompt.\n`);
463
+ }
464
+ const ctx = yield prepare(options);
465
+ if (typeof ctx === "number") {
466
+ return ctx;
467
+ }
468
+ const stdin = (_b = options.stdin) !== null && _b !== void 0 ? _b : process.stdin;
469
+ const readValue = createSecretValueReader(stdin, ctx.err);
470
+ const secrets = [];
471
+ for (const entry of parsed) {
472
+ secrets.push({
473
+ name: entry.name,
474
+ value: (_c = entry.value) !== null && _c !== void 0 ? _c : (yield readValue(entry.name)),
475
+ });
476
+ }
477
+ let secretNames;
478
+ try {
479
+ secretNames = yield ctx.client.setSecrets({
480
+ teamId: ctx.teamId,
481
+ slug,
482
+ secrets,
483
+ });
484
+ }
485
+ catch (error) {
486
+ return renderApiError(error, ctx.err);
487
+ }
488
+ if (ctx.json) {
489
+ ctx.out(`${JSON.stringify({ secretNames }, null, 2)}\n`);
490
+ return 0;
491
+ }
492
+ ctx.out(`Set ${secrets.length} secret${secrets.length === 1 ? "" : "s"} on ${slug}.\n` +
493
+ `Secrets now set: ${secretNames.join(", ")}\n` +
494
+ `The engine picks them up on its next deploy.\n`);
495
+ return 0;
496
+ });
497
+ }
498
+ export function cmdSecretsList(slug, options) {
499
+ return __awaiter(this, void 0, void 0, function* () {
500
+ var _a;
501
+ if (slug === undefined || slug === "") {
502
+ ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} secrets list <slug> [--team <id>] [--json]\n`);
503
+ return 1;
504
+ }
505
+ const ctx = yield prepare(options);
506
+ if (typeof ctx === "number") {
507
+ return ctx;
508
+ }
509
+ let secrets;
510
+ try {
511
+ secrets = yield ctx.client.listSecrets({ teamId: ctx.teamId, slug });
512
+ }
513
+ catch (error) {
514
+ return renderApiError(error, ctx.err);
515
+ }
516
+ if (ctx.json) {
517
+ ctx.out(`${JSON.stringify({ secrets }, null, 2)}\n`);
518
+ return 0;
519
+ }
520
+ if (secrets.length === 0) {
521
+ ctx.out(`No secrets set on ${slug}. Add one with \`${CLI} secrets set ${slug} NAME\`.\n`);
522
+ return 0;
523
+ }
524
+ ctx.out(`${renderTable(["NAME", "CREATED"], secrets.map((secret) => [secret.name, secret.createdAt]))}\n`);
525
+ return 0;
526
+ });
527
+ }
528
+ export function cmdSecretsUnset(slug, name, options) {
529
+ return __awaiter(this, void 0, void 0, function* () {
530
+ var _a;
531
+ if (slug === undefined || slug === "" || name === undefined || name === "") {
532
+ ((_a = options.err) !== null && _a !== void 0 ? _a : ((t) => void process.stderr.write(t)))(`Usage: ${CLI} secrets unset <slug> NAME [--team <id>]\n`);
533
+ return 1;
534
+ }
535
+ const ctx = yield prepare(options);
536
+ if (typeof ctx === "number") {
537
+ return ctx;
538
+ }
539
+ try {
540
+ yield ctx.client.deleteSecret({ teamId: ctx.teamId, slug, name });
541
+ }
542
+ catch (error) {
543
+ if (error instanceof DeployApiError && error.status === 404) {
544
+ ctx.err(`No secret named ${name} on deployment ${slug} — check \`${CLI} secrets list ${slug}\` (and the slug / --team).\n`);
545
+ return 1;
546
+ }
547
+ return renderApiError(error, ctx.err);
548
+ }
549
+ if (ctx.json) {
550
+ ctx.out(`${JSON.stringify({ removed: name }, null, 2)}\n`);
551
+ }
552
+ else {
553
+ ctx.out(`Removed secret ${name} from ${slug}.\n`);
554
+ }
555
+ return 0;
556
+ });
557
+ }
558
+ /**
559
+ * Returns a reader for interactive secret values: hidden (no-echo) prompt
560
+ * when `stdin` is a TTY, otherwise one line per secret from the piped
561
+ * stream. One reader per command so piped lines are consumed in order.
562
+ */
563
+ function createSecretValueReader(stdin, err) {
564
+ if (stdin.isTTY === true) {
565
+ return (name) => promptHidden(stdin, err, `Value for ${name}: `);
566
+ }
567
+ const readLine = createLineReader(stdin);
568
+ return (name) => __awaiter(this, void 0, void 0, function* () {
569
+ const line = yield readLine();
570
+ if (line === undefined) {
571
+ throw new DeployApiError(`stdin ended before a value for ${name} was provided (pipe one line per secret).`, 0);
572
+ }
573
+ return line;
574
+ });
575
+ }
576
+ /** Raw-mode hidden prompt: echoes nothing, supports backspace and Ctrl-C. */
577
+ function promptHidden(stdin, err, prompt) {
578
+ return new Promise((resolvePromise, reject) => {
579
+ var _a;
580
+ err(prompt);
581
+ (_a = stdin.setRawMode) === null || _a === void 0 ? void 0 : _a.call(stdin, true);
582
+ stdin.resume();
583
+ let value = "";
584
+ const cleanup = () => {
585
+ var _a;
586
+ stdin.off("data", onData);
587
+ (_a = stdin.setRawMode) === null || _a === void 0 ? void 0 : _a.call(stdin, false);
588
+ stdin.pause();
589
+ err("\n");
590
+ };
591
+ const onData = (chunk) => {
592
+ const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
593
+ for (const ch of text) {
594
+ if (ch === "\r" || ch === "\n") {
595
+ cleanup();
596
+ resolvePromise(value);
597
+ return;
598
+ }
599
+ if (ch === "\u0003") {
600
+ cleanup();
601
+ reject(new DeployApiError("Aborted.", 0));
602
+ return;
603
+ }
604
+ if (ch === "\u007f" || ch === "\b") {
605
+ value = value.slice(0, -1);
606
+ continue;
607
+ }
608
+ value += ch;
609
+ }
610
+ };
611
+ stdin.on("data", onData);
612
+ });
613
+ }
614
+ /** Buffered line reader over a piped stream; undefined once it ends. */
615
+ function createLineReader(stream) {
616
+ let buffer = "";
617
+ let ended = false;
618
+ const waiters = [];
619
+ const drain = () => {
620
+ var _a, _b;
621
+ while (waiters.length > 0) {
622
+ const newline = buffer.indexOf("\n");
623
+ if (newline !== -1) {
624
+ const line = buffer.slice(0, newline).replace(/\r$/, "");
625
+ buffer = buffer.slice(newline + 1);
626
+ (_a = waiters.shift()) === null || _a === void 0 ? void 0 : _a(line);
627
+ continue;
628
+ }
629
+ if (!ended) {
630
+ return;
631
+ }
632
+ // Stream ended: a trailing unterminated line still counts once.
633
+ const rest = buffer;
634
+ buffer = "";
635
+ (_b = waiters.shift()) === null || _b === void 0 ? void 0 : _b(rest === "" ? undefined : rest.replace(/\r$/, ""));
636
+ }
637
+ };
638
+ stream.on("data", (chunk) => {
639
+ buffer += typeof chunk === "string" ? chunk : chunk.toString("utf8");
640
+ drain();
641
+ });
642
+ stream.on("end", () => {
643
+ ended = true;
644
+ drain();
645
+ });
646
+ stream.resume();
647
+ return () => new Promise((resolvePromise) => {
648
+ waiters.push(resolvePromise);
649
+ drain();
650
+ });
651
+ }
652
+ // ============================================================================
653
+ // Polling + rendering helpers
654
+ // ============================================================================
655
+ /**
656
+ * Poll deployment status every `pollIntervalMs` until it lands in
657
+ * `terminal` (single-line progress on a TTY, one line per transition
658
+ * otherwise). Throws DeployApiError on request failures or timeout.
659
+ */
660
+ function pollUntil(ctx, slug, terminal) {
661
+ return __awaiter(this, void 0, void 0, function* () {
662
+ const startedAt = Date.now();
663
+ const tty = process.stderr.isTTY === true;
664
+ let lastStatus;
665
+ let sawProgress = false;
666
+ const report = (status) => {
667
+ if (ctx.json) {
668
+ return;
669
+ }
670
+ const elapsed = Math.round((Date.now() - startedAt) / 1000);
671
+ if (tty) {
672
+ ctx.err(`\r\x1b[2K${slug}: ${status} (${elapsed}s)`);
673
+ sawProgress = true;
674
+ }
675
+ else if (status !== lastStatus) {
676
+ ctx.err(`${slug}: ${status}\n`);
677
+ }
678
+ lastStatus = status;
679
+ };
680
+ const finishProgressLine = () => {
681
+ if (tty && sawProgress) {
682
+ ctx.err("\n");
683
+ }
684
+ };
685
+ for (;;) {
686
+ const detail = yield ctx.client
687
+ .getDeployment({ teamId: ctx.teamId, slug })
688
+ .catch((error) => {
689
+ finishProgressLine();
690
+ throw error;
691
+ });
692
+ report(detail.status);
693
+ if (terminal.has(detail.status)) {
694
+ finishProgressLine();
695
+ return detail;
696
+ }
697
+ if (Date.now() - startedAt >= ctx.timeoutMs) {
698
+ finishProgressLine();
699
+ throw new DeployApiError(`Timed out after ${Math.round(ctx.timeoutMs / 1000)}s waiting for ${slug} (last status: ${detail.status}). It may still converge — check \`${CLI} deployment ${slug} --team ${ctx.teamId}\`.`, 0);
700
+ }
701
+ yield sleep(ctx.pollIntervalMs);
702
+ }
703
+ });
704
+ }
705
+ function aliasTokenBlock(aliasToken) {
706
+ return (`\n Alias token (shown ONCE — save it now, it cannot be retrieved again):\n\n` +
707
+ ` ${aliasToken}\n\n` +
708
+ ` Send it as the X-Agent-Alias-Token header on requests to the alias URL.\n` +
709
+ ` Lost tokens: \`${CLI} rotate-token <slug>\` mints a replacement.\n\n`);
710
+ }
711
+ function renderApiError(error, err) {
712
+ if (error instanceof DeployApiError) {
713
+ err(`${error.message}\n`);
714
+ return 1;
715
+ }
716
+ throw error;
717
+ }
718
+ function renderTable(header, rows) {
719
+ 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; })));
720
+ const renderRow = (row) => row
721
+ .map((cell, i) => { var _a; return cell.padEnd((_a = widths[i]) !== null && _a !== void 0 ? _a : 0); })
722
+ .join(" ")
723
+ .trimEnd();
724
+ return [renderRow(header), ...rows.map(renderRow)].join("\n");
725
+ }
726
+ function describeError(error) {
727
+ return error instanceof Error ? error.message : String(error);
728
+ }
729
+ function sleep(ms) {
730
+ return new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
731
+ }