@cursor/july 0.1.47 → 0.1.49

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 (127) hide show
  1. package/dist/bin/agent-serve.js +30 -35
  2. package/dist/docs/404.html +2 -2
  3. package/dist/docs/ab.html +5 -5
  4. package/dist/docs/assets/{ab.md.hdxsvX5M.js → ab.md.DYjwREAP.js} +2 -2
  5. package/dist/docs/assets/{ab.md.hdxsvX5M.lean.js → ab.md.DYjwREAP.lean.js} +1 -1
  6. package/dist/docs/assets/{app.IEXEim5m.js → app.BpWAgjaR.js} +1 -1
  7. package/dist/docs/assets/chunks/@localSearchIndexroot.D00d772K.js +1 -0
  8. package/dist/docs/assets/chunks/{VPLocalSearchBox.78s6nqsH.js → VPLocalSearchBox.CnAktZtG.js} +1 -1
  9. package/dist/docs/assets/chunks/{theme.DroGdz_Q.js → theme.B5IvUxOB.js} +2 -2
  10. package/dist/docs/assets/{evals.md.qeoGgPw0.js → evals.md.CVe_O75-.js} +3 -3
  11. package/dist/docs/assets/{evals.md.qeoGgPw0.lean.js → evals.md.CVe_O75-.lean.js} +1 -1
  12. package/dist/docs/assets/{reference_http-api.md.DGrw_wOu.js → reference_http-api.md.DMbdFGVQ.js} +1 -1
  13. package/dist/docs/assets/{storage.md.CJYd5YmN.js → storage.md.D8NQ389l.js} +3 -3
  14. package/dist/docs/assets/storage.md.D8NQ389l.lean.js +1 -0
  15. package/dist/docs/building-with-agents.html +3 -3
  16. package/dist/docs/concepts.html +3 -3
  17. package/dist/docs/deployment.html +3 -3
  18. package/dist/docs/evals.html +6 -6
  19. package/dist/docs/example-agents/approval-buddy.html +3 -3
  20. package/dist/docs/example-agents/benny.html +3 -3
  21. package/dist/docs/example-agents/bugbot.html +3 -3
  22. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  23. package/dist/docs/example-agents/codeowners-review.html +3 -3
  24. package/dist/docs/example-agents/concierge.html +3 -3
  25. package/dist/docs/example-agents/fsd.html +3 -3
  26. package/dist/docs/example-agents/index.html +3 -3
  27. package/dist/docs/example-agents/knowledge-base.html +3 -3
  28. package/dist/docs/example-agents/oncall.html +3 -3
  29. package/dist/docs/example-agents/security-reviewer.html +3 -3
  30. package/dist/docs/example-agents/slack-agent.html +3 -3
  31. package/dist/docs/example-agents/weather-agent.html +3 -3
  32. package/dist/docs/guides/agent-to-agent.html +3 -3
  33. package/dist/docs/guides/cloud-runtime.html +3 -3
  34. package/dist/docs/guides/github.html +3 -3
  35. package/dist/docs/guides/human-in-the-loop.html +3 -3
  36. package/dist/docs/guides/mcp-oauth.html +3 -3
  37. package/dist/docs/guides/opentelemetry.html +3 -3
  38. package/dist/docs/guides/slack.html +3 -3
  39. package/dist/docs/guides/webhooks.html +3 -3
  40. package/dist/docs/hashmap.json +1 -1
  41. package/dist/docs/hillclimbing.html +3 -3
  42. package/dist/docs/index.html +3 -3
  43. package/dist/docs/quickstart.html +3 -3
  44. package/dist/docs/reference/agent-config.html +3 -3
  45. package/dist/docs/reference/artifacts.html +3 -3
  46. package/dist/docs/reference/channels.html +3 -3
  47. package/dist/docs/reference/cli.html +3 -3
  48. package/dist/docs/reference/connections.html +3 -3
  49. package/dist/docs/reference/hooks.html +3 -3
  50. package/dist/docs/reference/http-api.html +5 -5
  51. package/dist/docs/reference/instructions.html +3 -3
  52. package/dist/docs/reference/playground.html +3 -3
  53. package/dist/docs/reference/project-layout.html +3 -3
  54. package/dist/docs/reference/prompt.html +3 -3
  55. package/dist/docs/reference/schedules.html +3 -3
  56. package/dist/docs/reference/sessions.html +3 -3
  57. package/dist/docs/reference/skills.html +3 -3
  58. package/dist/docs/reference/subagents.html +3 -3
  59. package/dist/docs/reference/tools.html +3 -3
  60. package/dist/docs/scaffolding-agents.html +3 -3
  61. package/dist/docs/storage.html +5 -5
  62. package/dist/docs/templates/triage.html +3 -3
  63. package/dist/docs/troubleshooting.html +3 -3
  64. package/dist/internal/authored-loaders.d.ts +19 -0
  65. package/dist/internal/authored-loaders.d.ts.map +1 -1
  66. package/dist/internal/authored-loaders.js +39 -0
  67. package/dist/internal/cli-deploy.d.ts +2 -1
  68. package/dist/internal/cli-deploy.d.ts.map +1 -1
  69. package/dist/internal/cli-deploy.js +97 -1
  70. package/dist/internal/cli-slack.js +0 -3
  71. package/dist/internal/deploy-client.d.ts +7 -2
  72. package/dist/internal/deploy-client.d.ts.map +1 -1
  73. package/dist/internal/deploy-client.js +12 -0
  74. package/dist/internal/discovery.d.ts.map +1 -1
  75. package/dist/internal/discovery.js +2 -8
  76. package/dist/internal/eval-runner.d.ts.map +1 -1
  77. package/dist/internal/eval-runner.js +3 -8
  78. package/dist/internal/event-log.d.ts +17 -0
  79. package/dist/internal/event-log.d.ts.map +1 -1
  80. package/dist/internal/event-log.js +32 -2
  81. package/dist/internal/logs-client.d.ts +1 -1
  82. package/dist/internal/logs-client.d.ts.map +1 -1
  83. package/dist/internal/logs-client.js +3 -0
  84. package/dist/internal/process-memory-telemetry.d.ts +90 -0
  85. package/dist/internal/process-memory-telemetry.d.ts.map +1 -0
  86. package/dist/internal/process-memory-telemetry.js +259 -0
  87. package/dist/internal/serve-restart.d.ts +42 -0
  88. package/dist/internal/serve-restart.d.ts.map +1 -0
  89. package/dist/internal/serve-restart.js +85 -0
  90. package/dist/internal/server.d.ts.map +1 -1
  91. package/dist/internal/server.js +9 -10
  92. package/dist/internal/session-engine.d.ts +4 -0
  93. package/dist/internal/session-engine.d.ts.map +1 -1
  94. package/dist/internal/session-engine.js +19 -5
  95. package/dist/internal/slack-provision-client.d.ts +4 -4
  96. package/dist/internal/slack-provision-client.js +7 -7
  97. package/dist/playground/assets/index-Dox74yWJ.css +1 -0
  98. package/dist/playground/assets/{index-BgUHfe3L.js → index-Dq_HqyU-.js} +46 -46
  99. package/dist/playground/index.html +2 -2
  100. package/dist/storage.d.ts +36 -10
  101. package/dist/storage.d.ts.map +1 -1
  102. package/dist/storage.js +82 -6
  103. package/docs/ab.md +4 -3
  104. package/docs/evals.md +10 -7
  105. package/docs/reference/http-api.md +4 -3
  106. package/docs/storage.md +38 -22
  107. package/package.json +1 -1
  108. package/skills/setup-slack/SKILL.md +1 -1
  109. package/src/bin/agent-serve.ts +39 -38
  110. package/src/internal/authored-loaders.ts +45 -0
  111. package/src/internal/cli-deploy.ts +103 -1
  112. package/src/internal/cli-slack.ts +0 -5
  113. package/src/internal/deploy-client.ts +19 -1
  114. package/src/internal/discovery.ts +5 -12
  115. package/src/internal/eval-runner.ts +3 -12
  116. package/src/internal/event-log.ts +45 -7
  117. package/src/internal/logs-client.ts +4 -0
  118. package/src/internal/process-memory-telemetry.ts +373 -0
  119. package/src/internal/serve-restart.ts +120 -0
  120. package/src/internal/server.ts +13 -0
  121. package/src/internal/session-engine.ts +20 -1
  122. package/src/internal/slack-provision-client.ts +7 -7
  123. package/src/storage.ts +130 -11
  124. package/dist/docs/assets/chunks/@localSearchIndexroot.D7w61u6Y.js +0 -1
  125. package/dist/docs/assets/storage.md.CJYd5YmN.lean.js +0 -1
  126. package/dist/playground/assets/index-uFaeqVZS.css +0 -1
  127. /package/dist/docs/assets/{reference_http-api.md.DGrw_wOu.lean.js → reference_http-api.md.DMbdFGVQ.lean.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `agent-sdk deploy | deployments | deployment | stop | rotate-token |
2
+ * `agent-sdk deploy | deployments | deployment | stop | delete | rotate-token |
3
3
  * rotate-pod-credential | secrets set|list|unset` — Heroku-style deploys
4
4
  * onto Cursor's managed agent-serve hosting.
5
5
  *
@@ -24,6 +24,7 @@ import {
24
24
  import { authorizeCursorAccountConnectors } from "./cursor-account-mcp-auth.js";
25
25
  import {
26
26
  AgentServeDeployClient,
27
+ type DeleteAccepted,
27
28
  type DeployAccepted,
28
29
  DeployApiError,
29
30
  type Deployment,
@@ -1117,6 +1118,54 @@ export async function cmdStop(
1117
1118
  return 0;
1118
1119
  }
1119
1120
 
1121
+ // ============================================================================
1122
+ // delete <slug>
1123
+ // ============================================================================
1124
+
1125
+ export async function cmdDelete(
1126
+ slug: string | undefined,
1127
+ options: DeployCliOptions
1128
+ ): Promise<number> {
1129
+ if (slug === undefined || slug === "") {
1130
+ (options.err ?? ((t: string) => void process.stderr.write(t)))(
1131
+ `Usage: ${CLI} delete <slug> [--team <id>] [--json] [--no-wait]\n`
1132
+ );
1133
+ return 1;
1134
+ }
1135
+ const ctx = await prepare(options);
1136
+ if (typeof ctx === "number") {
1137
+ return ctx;
1138
+ }
1139
+ let accepted: DeleteAccepted;
1140
+ try {
1141
+ accepted = await ctx.client.deleteDeployment({
1142
+ teamId: ctx.teamId,
1143
+ slug,
1144
+ });
1145
+ } catch (error) {
1146
+ return renderApiError(error, ctx.err);
1147
+ }
1148
+ if (ctx.noWait) {
1149
+ if (ctx.json) {
1150
+ ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
1151
+ } else {
1152
+ ctx.out(`Delete accepted for ${slug} (status: ${accepted.status}).\n`);
1153
+ }
1154
+ return 0;
1155
+ }
1156
+ try {
1157
+ await pollUntilGone(ctx, slug);
1158
+ } catch (error) {
1159
+ return renderApiError(error, ctx.err);
1160
+ }
1161
+ if (ctx.json) {
1162
+ ctx.out(`${JSON.stringify({ slug, status: "deleted" }, null, 2)}\n`);
1163
+ } else {
1164
+ ctx.out(`Deleted ${slug} (team ${ctx.teamId}).\n`);
1165
+ }
1166
+ return 0;
1167
+ }
1168
+
1120
1169
  // ============================================================================
1121
1170
  // rotate-token <slug>
1122
1171
  // ============================================================================
@@ -1526,6 +1575,59 @@ async function pollUntil(
1526
1575
  }
1527
1576
  }
1528
1577
 
1578
+ /**
1579
+ * Wait until GET 404s (the delete reconciler purged the record). Treats
1580
+ * other errors as failures. Throws DeployApiError on timeout.
1581
+ */
1582
+ async function pollUntilGone(
1583
+ ctx: DeployCliContext,
1584
+ slug: string
1585
+ ): Promise<void> {
1586
+ const startedAt = Date.now();
1587
+ const tty = process.stderr.isTTY === true;
1588
+ let sawProgress = false;
1589
+ const report = (label: string): void => {
1590
+ if (ctx.json) {
1591
+ return;
1592
+ }
1593
+ const elapsed = Math.round((Date.now() - startedAt) / 1000);
1594
+ if (tty) {
1595
+ ctx.err(`\r\x1b[2K${slug}: ${label} (${elapsed}s)`);
1596
+ sawProgress = true;
1597
+ }
1598
+ };
1599
+ const finishProgressLine = (): void => {
1600
+ if (tty && sawProgress) {
1601
+ ctx.err("\n");
1602
+ }
1603
+ };
1604
+
1605
+ for (;;) {
1606
+ try {
1607
+ const detail = await ctx.client.getDeployment({
1608
+ teamId: ctx.teamId,
1609
+ slug,
1610
+ });
1611
+ report(deployProgressLabel(detail));
1612
+ } catch (error: unknown) {
1613
+ if (error instanceof DeployApiError && error.status === 404) {
1614
+ finishProgressLine();
1615
+ return;
1616
+ }
1617
+ finishProgressLine();
1618
+ throw error;
1619
+ }
1620
+ if (Date.now() - startedAt >= ctx.timeoutMs) {
1621
+ finishProgressLine();
1622
+ throw new DeployApiError(
1623
+ `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}\`.`,
1624
+ 0
1625
+ );
1626
+ }
1627
+ await sleep(ctx.pollIntervalMs);
1628
+ }
1629
+ }
1630
+
1529
1631
  function aliasTokenBlock(aliasToken: string): string {
1530
1632
  return (
1531
1633
  `\n Alias token (shown ONCE — save it now, it cannot be retrieved again):\n\n` +
@@ -1126,11 +1126,6 @@ function renderCreateProvisionError(
1126
1126
  `${error.message}\nA concurrent \`${CLI} slack create\` for this agent won the race; re-run create to pick up that app.\n`
1127
1127
  );
1128
1128
  return 1;
1129
- case "app_cap_reached":
1130
- err(
1131
- `${error.message}\nDelete unused apps with \`${CLI} slack destroy\`, then re-run create.\n`
1132
- );
1133
- return 1;
1134
1129
  case "ratelimited":
1135
1130
  err(`${error.message}\nRe-run \`${CLI} slack create\` after the wait.\n`);
1136
1131
  return 1;
@@ -25,7 +25,8 @@ export type DeploymentStatus =
25
25
  | "degraded"
26
26
  | "failed"
27
27
  | "stopping"
28
- | "stopped";
28
+ | "stopped"
29
+ | "deleting";
29
30
 
30
31
  /** Customer-safe deploy progress (no hosting phase / infra names). */
31
32
  export type DeploymentProgress =
@@ -39,6 +40,7 @@ export type DeploymentProgress =
39
40
  | "failed"
40
41
  | "stopping"
41
42
  | "stopped"
43
+ | "deleting"
42
44
  | "degraded";
43
45
 
44
46
  export const TERMINAL_DEPLOY_STATUSES: ReadonlySet<DeploymentStatus> = new Set([
@@ -211,6 +213,8 @@ export interface StopAccepted {
211
213
  status: string;
212
214
  }
213
215
 
216
+ export type DeleteAccepted = StopAccepted;
217
+
214
218
  /** One secret's metadata from the list endpoint — names only, never values. */
215
219
  export interface SecretInfo {
216
220
  name: string;
@@ -276,6 +280,7 @@ const deploymentSchema = z.object({
276
280
  "failed",
277
281
  "stopping",
278
282
  "stopped",
283
+ "deleting",
279
284
  ]),
280
285
  progress: z
281
286
  .enum([
@@ -289,6 +294,7 @@ const deploymentSchema = z.object({
289
294
  "failed",
290
295
  "stopping",
291
296
  "stopped",
297
+ "deleting",
292
298
  "degraded",
293
299
  ])
294
300
  .optional(),
@@ -495,6 +501,18 @@ export class AgentServeDeployClient {
495
501
  return stopAcceptedSchema.parse(raw);
496
502
  }
497
503
 
504
+ async deleteDeployment(args: {
505
+ teamId: number;
506
+ slug: string;
507
+ }): Promise<DeleteAccepted> {
508
+ const raw = await this.request({
509
+ method: "DELETE",
510
+ path: `/internal/agent-serve/deployments/${encodeURIComponent(args.slug)}?teamId=${args.teamId}`,
511
+ context: { verb: "delete", slug: args.slug },
512
+ });
513
+ return stopAcceptedSchema.parse(raw);
514
+ }
515
+
498
516
  /** Returns the new alias token exactly once; the old one dies now. */
499
517
  async rotateAliasToken(args: {
500
518
  teamId: number;
@@ -16,7 +16,6 @@ import {
16
16
  relative,
17
17
  resolve,
18
18
  } from "node:path";
19
- import { pathToFileURL } from "node:url";
20
19
  import { type ABConfigFile, resolveABMaxPlaygroundSessions } from "../ab.js";
21
20
  import { resolveArtifactsMax } from "../artifacts.js";
22
21
  import { httpChannel } from "../channels.js";
@@ -61,7 +60,10 @@ import {
61
60
  type ToolDefinition,
62
61
  toPublicCloudInfo,
63
62
  } from "../types.js";
64
- import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
63
+ import {
64
+ importAuthoredModule,
65
+ registerAuthoredModuleLoaders,
66
+ } from "./authored-loaders.js";
65
67
  import { normalizePositiveInt } from "./bounded-int.js";
66
68
  import { getDefinitionKind } from "./brand.js";
67
69
  import {
@@ -94,15 +96,6 @@ export interface LoadAgentProjectOptions {
94
96
 
95
97
  type ImportModule = (absolutePath: string) => Promise<Record<string, unknown>>;
96
98
 
97
- async function defaultImportModule(
98
- absolutePath: string
99
- ): Promise<Record<string, unknown>> {
100
- return (await import(pathToFileURL(absolutePath).href)) as Record<
101
- string,
102
- unknown
103
- >;
104
- }
105
-
106
99
  interface DiscoveryContext {
107
100
  rootDir: string;
108
101
  diagnostics: Diagnostic[];
@@ -282,7 +275,7 @@ export async function loadAgentProject(
282
275
  const ctx: DiscoveryContext = {
283
276
  rootDir,
284
277
  diagnostics,
285
- importModule: options.importModule ?? defaultImportModule,
278
+ importModule: options.importModule ?? importAuthoredModule,
286
279
  };
287
280
 
288
281
  const name = (await readPackageName(rootDir)) ?? basename(rootDir);
@@ -11,7 +11,6 @@
11
11
  import type { Dirent } from "node:fs";
12
12
  import { readdir } from "node:fs/promises";
13
13
  import { join, relative, resolve } from "node:path";
14
- import { pathToFileURL } from "node:url";
15
14
  import type {
16
15
  EvalAssertionHandle,
17
16
  EvalAssertions,
@@ -62,6 +61,7 @@ import {
62
61
  normalizeEvalMaxConcurrency,
63
62
  } from "../evals.js";
64
63
  import type { ModelSetting, SessionEvent } from "../types.js";
64
+ import { importAuthoredModule } from "./authored-loaders.js";
65
65
  import { isDefinitionOfKind } from "./brand.js";
66
66
  import {
67
67
  callJudgeModel,
@@ -131,15 +131,6 @@ export interface RunEvalsOptions extends EvalSelectionOptions {
131
131
  signal?: AbortSignal;
132
132
  }
133
133
 
134
- async function defaultImport(
135
- absolutePath: string
136
- ): Promise<Record<string, unknown>> {
137
- return (await import(pathToFileURL(absolutePath).href)) as Record<
138
- string,
139
- unknown
140
- >;
141
- }
142
-
143
134
  async function listEvalFiles(dir: string): Promise<string[]> {
144
135
  const out: string[] = [];
145
136
  async function walk(current: string): Promise<void> {
@@ -172,7 +163,7 @@ export async function discoverEvals(
172
163
  projectRoot: string,
173
164
  importModule: (
174
165
  absolutePath: string
175
- ) => Promise<Record<string, unknown>> = defaultImport
166
+ ) => Promise<Record<string, unknown>> = importAuthoredModule
176
167
  ): Promise<{
177
168
  evals: DiscoveredEval[];
178
169
  config: Partial<EvalConfigFile>;
@@ -291,7 +282,7 @@ export async function runDiscoveredEvals(
291
282
  selected = options.discovered.evals;
292
283
  config = options.discovered.config;
293
284
  } else {
294
- const importModule = options.importModule ?? defaultImport;
285
+ const importModule = options.importModule ?? importAuthoredModule;
295
286
  const discovered = await discoverEvals(options.projectRoot, importModule);
296
287
  config = discovered.config;
297
288
  selected = filterDiscoveredEvals(discovered.evals, {
@@ -59,6 +59,17 @@ export class SessionEventLog {
59
59
  return this.events.length;
60
60
  }
61
61
 
62
+ /**
63
+ * In-process residency vs recorded length. Today those are the same
64
+ * (`events` is the cache). A later change can drop the cache and keep
65
+ * `eventsTotal` as the durable count while `eventsRetained` shrinks to
66
+ * the unflushed tail.
67
+ */
68
+ memoryStats(): { eventsRetained: number; eventsTotal: number } {
69
+ const n = this.events.length;
70
+ return { eventsRetained: n, eventsTotal: n };
71
+ }
72
+
62
73
  /**
63
74
  * Assign the next index, record the event, and fan out to live
64
75
  * subscribers. Ordering is synchronous; file persistence is chained in
@@ -154,9 +165,16 @@ export class SessionEventLog {
154
165
  }
155
166
  }
156
167
 
168
+ export type EventLogMemoryStats = {
169
+ residentSessions: number;
170
+ eventsRetained: number;
171
+ eventsTotal: number;
172
+ };
173
+
157
174
  /** Lazily opens one {@link SessionEventLog} per session. */
158
175
  export class EventLogStore {
159
176
  private readonly logs = new Map<string, Promise<SessionEventLog>>();
177
+ private readonly opened = new Map<string, SessionEventLog>();
160
178
 
161
179
  constructor(
162
180
  private readonly eventFilePathFor: (sessionId: string) => string,
@@ -170,18 +188,38 @@ export class EventLogStore {
170
188
  let log = this.logs.get(sessionId);
171
189
  if (log === undefined) {
172
190
  const filePath = this.eventFilePathFor(sessionId);
173
- log = mkdir(dirname(filePath), { recursive: true }).then(() =>
174
- SessionEventLog.open({
175
- sessionId,
176
- filePath,
177
- onPersistError: (error) => this.onPersistError(sessionId, error),
178
- })
179
- );
191
+ log = mkdir(dirname(filePath), { recursive: true })
192
+ .then(() =>
193
+ SessionEventLog.open({
194
+ sessionId,
195
+ filePath,
196
+ onPersistError: (error) => this.onPersistError(sessionId, error),
197
+ })
198
+ )
199
+ .then((opened) => {
200
+ this.opened.set(sessionId, opened);
201
+ return opened;
202
+ });
180
203
  this.logs.set(sessionId, log);
181
204
  }
182
205
  return log;
183
206
  }
184
207
 
208
+ memoryStats(): EventLogMemoryStats {
209
+ let eventsRetained = 0;
210
+ let eventsTotal = 0;
211
+ for (const log of this.opened.values()) {
212
+ const stats = log.memoryStats();
213
+ eventsRetained += stats.eventsRetained;
214
+ eventsTotal += stats.eventsTotal;
215
+ }
216
+ return {
217
+ residentSessions: this.logs.size,
218
+ eventsRetained,
219
+ eventsTotal,
220
+ };
221
+ }
222
+
185
223
  async flushAll(): Promise<void> {
186
224
  await Promise.all(
187
225
  [...this.logs.values()].map((logPromise) =>
@@ -43,6 +43,7 @@ export type LogsProgress =
43
43
  | "failed"
44
44
  | "stopping"
45
45
  | "stopped"
46
+ | "deleting"
46
47
  | "degraded";
47
48
 
48
49
  const PROGRESS_MESSAGES: Readonly<Record<LogsProgress, string>> = {
@@ -56,6 +57,7 @@ const PROGRESS_MESSAGES: Readonly<Record<LogsProgress, string>> = {
56
57
  failed: "Deploy failed",
57
58
  stopping: "Stopping deployment…",
58
59
  stopped: "Deployment stopped",
60
+ deleting: "Deleting deployment…",
59
61
  degraded: "Deployment degraded",
60
62
  };
61
63
 
@@ -385,6 +387,8 @@ function resolveProgress(detail: DeploymentDetail): LogsProgress {
385
387
  return "stopping";
386
388
  case "stopped":
387
389
  return "stopped";
390
+ case "deleting":
391
+ return "deleting";
388
392
  default:
389
393
  return "queued";
390
394
  }