withruntime 0.33.3 → 0.35.0

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 (49) hide show
  1. package/E2B.md +7 -0
  2. package/dist/agents-cli.d.ts +1 -1
  3. package/dist/agents-cli.js +171 -7
  4. package/dist/agents-deploy.d.ts +13 -3
  5. package/dist/agents-deploy.js +68 -9
  6. package/dist/apps-cli.d.ts +1 -1
  7. package/dist/apps-cli.js +41 -9
  8. package/dist/browsers/index.d.ts +9 -0
  9. package/dist/browsers/index.js +10 -0
  10. package/dist/browsers-cli.d.ts +13 -0
  11. package/dist/browsers-cli.js +160 -0
  12. package/dist/ci-cli.d.ts +1 -1
  13. package/dist/ci-cli.js +16 -3
  14. package/dist/cli-words.js +1 -0
  15. package/dist/cli.d.ts +4 -0
  16. package/dist/cli.js +103 -12
  17. package/dist/desktops/index.d.ts +9 -0
  18. package/dist/desktops/index.js +10 -0
  19. package/dist/e2b/code-interpreter.d.ts +3 -12
  20. package/dist/e2b/code-interpreter.js +3 -6
  21. package/dist/e2b/index.d.ts +7 -1
  22. package/dist/e2b/index.js +9 -2
  23. package/dist/functions/index.d.ts +10 -0
  24. package/dist/functions/index.js +11 -0
  25. package/dist/index.d.ts +5 -3
  26. package/dist/products/agents.d.ts +162 -8
  27. package/dist/products/agents.js +108 -3
  28. package/dist/products/apps.d.ts +46 -5
  29. package/dist/products/browsers.d.ts +26 -0
  30. package/dist/products/browsers.js +11 -0
  31. package/dist/products/ci.d.ts +10 -4
  32. package/dist/products/ci.js +8 -0
  33. package/dist/products/desktops.d.ts +71 -0
  34. package/dist/products/desktops.js +27 -0
  35. package/dist/products/functions.d.ts +2 -0
  36. package/dist/products/functions.js +5 -0
  37. package/dist/products/index.d.ts +6 -0
  38. package/dist/products/index.js +8 -0
  39. package/dist/products/network.d.ts +4 -2
  40. package/dist/products/secrets.d.ts +10 -2
  41. package/dist/products/secrets.js +27 -7
  42. package/dist/products/uptime.d.ts +97 -0
  43. package/dist/products/uptime.js +42 -0
  44. package/dist/products/volumes.d.ts +41 -9
  45. package/dist/products/volumes.js +5 -2
  46. package/dist/transport.d.ts +4 -1
  47. package/dist/transport.js +2 -2
  48. package/dist/types.d.ts +15 -3
  49. package/package.json +17 -1
@@ -51,6 +51,11 @@ export type AgentDefinition = {
51
51
  * GEMINI_API_KEY, OPENROUTER_API_KEY, or an OpenAI-compatible endpoint's
52
52
  * key with env.OPENAI_BASE_URL). */
53
53
  secrets?: string[];
54
+ /** Claude accounts, 1 to 16 egress secrets' names: subscription tokens,
55
+ * or API keys for a name holding API_KEY. Each session takes the one with
56
+ * the most usage left; the review template moves to the next when one is
57
+ * out of usage, and waits for the soonest reset when all are. */
58
+ pool?: string[];
54
59
  /** MCP servers the harness may reach. */
55
60
  mcp?: {
56
61
  name: string;
@@ -130,12 +135,90 @@ export type AgentEvent = {
130
135
  } & Record<string, unknown>;
131
136
  createdAt: string;
132
137
  };
138
+ export type AgentAskState = "open" | "answered" | "expired" | "withdrawn" | "closed";
139
+ /** One row of the account's inbox: a question a session's harness needs
140
+ * answered to go on. Asks of one agent's sessions sharing a memory, with the same `step` are
141
+ * one row while it is open, and one answer reaches every session asking. */
142
+ export type AgentAsk = {
143
+ id: string;
144
+ /** The agent of the session that asked first. */
145
+ agentId: string;
146
+ /** What it waits on, in the asker's words. */
147
+ step: string | null;
148
+ question: string;
149
+ /** Why it matters. */
150
+ why: string | null;
151
+ options: {
152
+ label: string;
153
+ detail?: string;
154
+ }[];
155
+ /** The recommended option's label; taken as the answer when it expires. */
156
+ pick: string | null;
157
+ /** Who sees it: its agent's labels with the ask's own over them. */
158
+ labels: Record<string, string>;
159
+ state: AgentAskState;
160
+ /** An option's label and/or words; `expired` when the pick was taken at
161
+ * expiry. */
162
+ answer: {
163
+ option?: string;
164
+ text?: string;
165
+ expired?: boolean;
166
+ } | null;
167
+ /** A key's principal id, or `runtime` for a pick taken at expiry. */
168
+ answeredBy: string | null;
169
+ /** The sessions asking it, each with its ask event's seq and the answer
170
+ * event that woke it. */
171
+ sessions: {
172
+ sessionId: string;
173
+ state: "asking" | "answered" | "expired" | "withdrawn" | "ended";
174
+ seq: number;
175
+ answerSeq: number | null;
176
+ }[];
177
+ expiresAt: string | null;
178
+ createdAt: string;
179
+ updatedAt: string;
180
+ closedAt: string | null;
181
+ };
182
+ export type ListAgentAsks = {
183
+ /** Open by default. */
184
+ state?: AgentAskState[];
185
+ agent?: string;
186
+ /** Asks carrying every one of these labels: who sees an ask. */
187
+ labels?: Record<string, string>;
188
+ cursor?: string;
189
+ limit?: number;
190
+ };
191
+ /** An option's label, words, or both. */
192
+ export type AnswerAgentAsk = {
193
+ option?: string;
194
+ text?: string;
195
+ };
133
196
  export type AgentTriggerKind = "slack" | "github" | "schedule" | "webhook";
197
+ /** A trigger's rules, each optional. */
198
+ export type AgentTriggerRules = {
199
+ /** Queue order of its sessions when the agent's maxConcurrent is full:
200
+ * -100 to 100, higher first, then oldest. Default 0. */
201
+ priority?: number;
202
+ /** Sessions it may start in an hour; a call past it is held for you.
203
+ * Joining an open session is never capped. Default none. */
204
+ maxStartsPerHour?: number;
205
+ /** A call whose key's last session has ended: "start" a new one (the
206
+ * default), "note" it in the ended session's log and run nothing, or
207
+ * "ask" you (the call is held until you start it). */
208
+ onEnded?: "start" | "note" | "ask";
209
+ /** Where a held call is told: "email" to who added the trigger (the
210
+ * default), or "webhook", the account's webhooks' agent.call.held alone. */
211
+ notify?: "email" | "webhook";
212
+ /** A webhook's only: the key of a call that sends none, from its JSON's
213
+ * fields: "{cause}", "{alert.host}:{check}". */
214
+ key?: string;
215
+ };
134
216
  export type AgentTrigger = {
135
217
  id: string;
136
218
  agentId: string;
137
219
  kind: AgentTriggerKind;
138
220
  config: Record<string, unknown>;
221
+ rules: AgentTriggerRules;
139
222
  pausedAt: string | null;
140
223
  pausedWhy: string | null;
141
224
  createdAt: string;
@@ -157,7 +240,7 @@ export type StartAgentSession = {
157
240
  key?: string;
158
241
  labels?: Record<string, string>;
159
242
  };
160
- export type CreateAgentTrigger = {
243
+ export type CreateAgentTrigger = ({
161
244
  kind: "slack";
162
245
  config: {
163
246
  team: string;
@@ -180,9 +263,48 @@ export type CreateAgentTrigger = {
180
263
  } | {
181
264
  kind: "webhook";
182
265
  config: Record<string, never>;
266
+ }) & {
267
+ rules?: AgentTriggerRules;
268
+ };
269
+ /** One call to a webhook trigger: its words, and the key and labels of the
270
+ * session it starts or joins. */
271
+ export type AgentTriggerCall = {
272
+ text: string;
273
+ key?: string;
274
+ labels?: Record<string, string>;
275
+ };
276
+ /** What a call did: started a session, joined its key's open one, was
277
+ * noted in its key's ended one, or was held for you (`why`). */
278
+ export type AgentTriggerCallOutcome = {
279
+ outcome: "started" | "joined" | "noted" | "held";
280
+ sessionId: string | null;
281
+ seq: number | null;
282
+ callId: string | null;
283
+ why: AgentHeldCall["why"] | null;
284
+ replayed: boolean;
285
+ };
286
+ /** A call a trigger held for you because no session could take it. None is
287
+ * ever dropped. */
288
+ export type AgentHeldCall = {
289
+ id: string;
290
+ triggerId: string;
291
+ agentId: string;
292
+ key: string | null;
293
+ text: string;
294
+ labels: Record<string, string>;
295
+ /** The trigger was paused; it had started maxStartsPerHour sessions this
296
+ * hour; its key's session had ended and onEnded is "ask"; the agent's day
297
+ * budget was spent; the account's sessions were at their limit; Agents
298
+ * was closed to the account. */
299
+ why: "paused" | "rate" | "ended" | "budget" | "quota" | "closed";
300
+ state: "held" | "started" | "dismissed";
301
+ sessionId: string | null;
302
+ notify: "email" | "webhook";
303
+ createdAt: string;
304
+ resolvedAt: string | null;
183
305
  };
184
- /** The five harnesses' names, so `templates["claude-code"]` is known to be there. */
185
- export type AgentTemplateKey = "claude-code" | "codex" | "gemini-cli" | "claude-agent-sdk" | "openai-agents-sdk";
306
+ /** The harnesses' names, so `templates["claude-code"]` is known to be there. */
307
+ export type AgentTemplateKey = "claude-code" | "codex" | "gemini-cli" | "claude-agent-sdk" | "openai-agents-sdk" | "review" | "judge";
186
308
  /** A file of an agent's memory (`memory.list`). `scope` is whose: empty for
187
309
  * the shared memory, which every session reads (one keeping memory per key
188
310
  * reads what you wrote there, and never changes it), or a session key
@@ -240,9 +362,8 @@ export type AgentTemplate = {
240
362
  /** How your own subscription logs it in, for your own team's agents, or
241
363
  * null when it takes an API key alone. */
242
364
  subscription: string | null;
243
- definition: {
365
+ definition: Pick<AgentDefinition, "secrets" | "pool" | "vcpu" | "memoryMiB" | "maxSessionSeconds"> & {
244
366
  command: string;
245
- secrets: string[];
246
367
  };
247
368
  };
248
369
  /** A use: what an agent is for, merged into a template's definition. */
@@ -257,7 +378,7 @@ export type AgentUse = {
257
378
  template: "support" | "team";
258
379
  };
259
380
  };
260
- /** The five harnesses (agents-contract.md); tests/agents.test.ts holds them
381
+ /** The harnesses (agents-contract.md); tests/agents.test.ts holds them
261
382
  * to packages/cloud-guide/agent-templates.json. */
262
383
  export declare const AGENT_TEMPLATES: Readonly<Record<AgentTemplateKey, AgentTemplate>>;
263
384
  /** A harness by a key read from a file or a flag, or undefined. */
@@ -321,13 +442,45 @@ export declare function agents(t: Transport): {
321
442
  * (`session_open`): stop it first. */
322
443
  delete: (id: string, options?: RequestOptions) => Promise<void>;
323
444
  };
445
+ /** The account's inbox: the questions its agents' sessions need answered
446
+ * to go on, one row per step however many sessions ask it. */
447
+ asks: {
448
+ /** Newest first; open ones unless `state` says otherwise. */
449
+ list: (query?: ListAgentAsks, options?: RequestOptions) => Promise<Page<AgentAsk>>;
450
+ get: (id: string, options?: RequestOptions) => Promise<AgentAsk>;
451
+ /** Every session asking it reads the answer next, and wakes. An ask no
452
+ * longer open is refused with `ask_closed`. */
453
+ answer: (id: string, answer: AnswerAgentAsk, options?: RequestOptions) => Promise<AgentAsk>;
454
+ };
324
455
  triggers: {
325
456
  create: (agent: string, input: CreateAgentTrigger, options?: RequestOptions) => Promise<AgentTrigger>;
326
457
  list: (agent: string, options?: RequestOptions) => Promise<AgentTrigger[]>;
327
- /** Its events are refused, saying `why`; nothing else is held. */
458
+ /** Held: a webhook's calls are kept for you (see `held`), saying
459
+ * `why`; nothing else is held. */
328
460
  pause: (id: string, why: string, options?: RequestOptions) => Promise<AgentTrigger>;
329
461
  resume: (id: string, options?: RequestOptions) => Promise<AgentTrigger>;
330
462
  delete: (id: string, options?: RequestOptions) => Promise<void>;
463
+ /** Its rules, whole, in place: its secret stays. `{}` is every default. */
464
+ setRules: (id: string, rules: AgentTriggerRules, options?: RequestOptions) => Promise<AgentTrigger>;
465
+ /** A webhook trigger's call, as its sender makes it: by the trigger's
466
+ * secret, never your key. A call with the key of an open session joins
467
+ * it. Pass `idempotencyKey` to make a retry the same call. */
468
+ call: (id: string, secret: string, call: AgentTriggerCall, options?: RequestOptions) => Promise<AgentTriggerCallOutcome>;
469
+ /** Calls it held for you, newest first. */
470
+ held: (trigger: string, query?: {
471
+ state?: AgentHeldCall["state"][];
472
+ cursor?: string;
473
+ limit?: number;
474
+ }, options?: RequestOptions) => Promise<Page<AgentHeldCall>>;
475
+ /** Start a held call: one session with it and every call held for its
476
+ * key since, oldest first. */
477
+ startHeld: (id: string, call: string, options?: RequestOptions) => Promise<{
478
+ session: AgentSession;
479
+ joined: boolean;
480
+ calls: number;
481
+ }>;
482
+ /** Dismiss a held call: nothing runs. */
483
+ dismissHeld: (id: string, call: string, options?: RequestOptions) => Promise<AgentHeldCall>;
331
484
  };
332
485
  /** Its built-in memory: text files kept across sessions, which the
333
486
  * agent reads, writes and searches from inside its sessions. A scope is
@@ -363,7 +516,8 @@ export declare function agents(t: Transport): {
363
516
  }, options?: RequestOptions) => Promise<boolean>;
364
517
  };
365
518
  /** The harnesses, as data: claude-code, codex, gemini-cli,
366
- * claude-agent-sdk, openai-agents-sdk. */
519
+ * claude-agent-sdk, openai-agents-sdk, review (a CI/CD agent step's
520
+ * reviewer) and judge (an agent step held to your instructions alone). */
367
521
  templates: Readonly<Record<AgentTemplateKey, AgentTemplate>>;
368
522
  /** The uses, as data: support (your customers) and team (your team). */
369
523
  uses: Readonly<Record<"team" | "support", AgentUse>>;
@@ -22,7 +22,9 @@ import { Page } from "../page.js";
22
22
  const START = 'npx -y @anthropic-ai/claude-code --dangerously-skip-permissions --mcp-config ~/.runtime-agent/mcp.json -p "$(cat ~/.runtime-agent/start.md)"';
23
23
  const CODEX = 'npx -y @openai/codex exec --dangerously-bypass-approvals-and-sandbox "$(cat ~/.runtime-agent/start.md)"';
24
24
  const GEMINI = 'npx -y @google/gemini-cli --yolo -p "$(cat ~/.runtime-agent/start.md)"';
25
- /** The five harnesses (agents-contract.md); tests/agents.test.ts holds them
25
+ const REVIEW = "python3 ~/.runtime-agent/runtime-agent review";
26
+ const JUDGE = "python3 ~/.runtime-agent/runtime-agent judge";
27
+ /** The harnesses (agents-contract.md); tests/agents.test.ts holds them
26
28
  * to packages/cloud-guide/agent-templates.json. */
27
29
  export const AGENT_TEMPLATES = {
28
30
  "claude-code": {
@@ -70,6 +72,36 @@ export const AGENT_TEMPLATES = {
70
72
  subscription: null,
71
73
  definition: { command: "python3 ~/agent.py", secrets: ["OPENAI_API_KEY"] },
72
74
  },
75
+ review: {
76
+ key: "review",
77
+ title: "Code review",
78
+ command: REVIEW,
79
+ apiKeySecret: "ANTHROPIC_API_KEY",
80
+ apiKeyHost: "api.anthropic.com",
81
+ subscription: "a token per account: run `claude setup-token` on your own computer (Pro/Max) for each, store each with `runtime secrets set CLAUDE_1` scoped to api.anthropic.com, then name them all in pool (--pool CLAUDE_1 --pool CLAUDE_2)",
82
+ definition: {
83
+ command: REVIEW,
84
+ pool: ["ANTHROPIC_API_KEY"],
85
+ vcpu: 2,
86
+ memoryMiB: 2048,
87
+ maxSessionSeconds: 1800,
88
+ },
89
+ },
90
+ judge: {
91
+ key: "judge",
92
+ title: "Your rules",
93
+ command: JUDGE,
94
+ apiKeySecret: "ANTHROPIC_API_KEY",
95
+ apiKeyHost: "api.anthropic.com",
96
+ subscription: "a token per account, as for review: `runtime secrets set CLAUDE_1` scoped to api.anthropic.com for each, then name them all in pool; its instructions are the rules that block",
97
+ definition: {
98
+ command: JUDGE,
99
+ pool: ["ANTHROPIC_API_KEY"],
100
+ vcpu: 2,
101
+ memoryMiB: 2048,
102
+ maxSessionSeconds: 1800,
103
+ },
104
+ },
73
105
  };
74
106
  /** A harness by a key read from a file or a flag, or undefined. */
75
107
  export function agentTemplate(key) {
@@ -166,6 +198,28 @@ export function agents(t) {
166
198
  });
167
199
  return new Page(page.data, page.nextCursor, (cursor) => listSessions({ ...query, cursor }, options));
168
200
  };
201
+ const listAsks = async (query = {}, options) => {
202
+ const { labels, ...rest } = query;
203
+ const page = await t.json({
204
+ method: "GET",
205
+ path: "/v1/agents/asks",
206
+ query: {
207
+ ...rest,
208
+ ...(labels ? { label: Object.entries(labels).map(([k, v]) => `${k}:${v}`) } : {}),
209
+ },
210
+ ...options,
211
+ });
212
+ return new Page(page.data, page.nextCursor, (cursor) => listAsks({ ...query, cursor }, options));
213
+ };
214
+ const listHeld = async (trigger, query = {}, options) => {
215
+ const page = await t.json({
216
+ method: "GET",
217
+ path: `/v1/agents/triggers/${enc(trigger)}/held`,
218
+ query,
219
+ ...options,
220
+ });
221
+ return new Page(page.data, page.nextCursor, (cursor) => listHeld(trigger, { ...query, cursor }, options));
222
+ };
169
223
  const listMemory = async (agent, query = {}, options) => {
170
224
  const page = await t.json({
171
225
  method: "GET",
@@ -227,6 +281,21 @@ export function agents(t) {
227
281
  });
228
282
  },
229
283
  },
284
+ /** The account's inbox: the questions its agents' sessions need answered
285
+ * to go on, one row per step however many sessions ask it. */
286
+ asks: {
287
+ /** Newest first; open ones unless `state` says otherwise. */
288
+ list: listAsks,
289
+ get: (id, options) => t.json({ method: "GET", path: `/v1/agents/asks/${enc(id)}`, ...options }),
290
+ /** Every session asking it reads the answer next, and wakes. An ask no
291
+ * longer open is refused with `ask_closed`. */
292
+ answer: (id, answer, options) => t.json({
293
+ method: "POST",
294
+ path: `/v1/agents/asks/${enc(id)}/answer`,
295
+ body: answer,
296
+ ...options,
297
+ }),
298
+ },
230
299
  triggers: {
231
300
  create: (agent, input, options) => t.json({
232
301
  method: "POST",
@@ -239,7 +308,8 @@ export function agents(t) {
239
308
  path: `/v1/agents/${enc(agent)}/triggers`,
240
309
  ...options,
241
310
  })).data,
242
- /** Its events are refused, saying `why`; nothing else is held. */
311
+ /** Held: a webhook's calls are kept for you (see `held`), saying
312
+ * `why`; nothing else is held. */
243
313
  pause: (id, why, options) => t.json({
244
314
  method: "POST",
245
315
  path: `/v1/agents/triggers/${enc(id)}/pause`,
@@ -259,6 +329,40 @@ export function agents(t) {
259
329
  ...options,
260
330
  });
261
331
  },
332
+ /** Its rules, whole, in place: its secret stays. `{}` is every default. */
333
+ setRules: (id, rules, options) => t.json({
334
+ method: "PATCH",
335
+ path: `/v1/agents/triggers/${enc(id)}`,
336
+ body: { rules },
337
+ ...options,
338
+ }),
339
+ /** A webhook trigger's call, as its sender makes it: by the trigger's
340
+ * secret, never your key. A call with the key of an open session joins
341
+ * it. Pass `idempotencyKey` to make a retry the same call. */
342
+ call: (id, secret, call, options) => t.json({
343
+ method: "POST",
344
+ path: `/v1/agents/triggers/${enc(id)}/calls`,
345
+ body: call,
346
+ bearer: secret,
347
+ ...options,
348
+ }),
349
+ /** Calls it held for you, newest first. */
350
+ held: listHeld,
351
+ /** Start a held call: one session with it and every call held for its
352
+ * key since, oldest first. */
353
+ startHeld: (id, call, options) => t.json({
354
+ method: "POST",
355
+ path: `/v1/agents/triggers/${enc(id)}/held/${enc(call)}/start`,
356
+ body: {},
357
+ ...options,
358
+ }),
359
+ /** Dismiss a held call: nothing runs. */
360
+ dismissHeld: (id, call, options) => t.json({
361
+ method: "POST",
362
+ path: `/v1/agents/triggers/${enc(id)}/held/${enc(call)}/dismiss`,
363
+ body: {},
364
+ ...options,
365
+ }),
262
366
  },
263
367
  /** Its built-in memory: text files kept across sessions, which the
264
368
  * agent reads, writes and searches from inside its sessions. A scope is
@@ -292,7 +396,8 @@ export function agents(t) {
292
396
  })).deleted,
293
397
  },
294
398
  /** The harnesses, as data: claude-code, codex, gemini-cli,
295
- * claude-agent-sdk, openai-agents-sdk. */
399
+ * claude-agent-sdk, openai-agents-sdk, review (a CI/CD agent step's
400
+ * reviewer) and judge (an agent step held to your instructions alone). */
296
401
  templates: AGENT_TEMPLATES,
297
402
  /** The uses, as data: support (your customers) and team (your team). */
298
403
  uses: AGENT_USES,
@@ -39,7 +39,42 @@ export type StatefulSettings = {
39
39
  /** Seconds a stopped copy has after SIGTERM to exit. */
40
40
  stopGraceSeconds: number;
41
41
  };
42
- export type App = AppSettings & StatefulSettings & {
42
+ /** How an App's new version goes live: every copy together (at_once, the
43
+ * default), or staged: one copy of it beside the live version's, then about
44
+ * 10%, 50% and all of them, each stage judged on its visitors' errors and
45
+ * speed before the next. A stage that does worse goes back: its copies
46
+ * finish their requests and stop, then the deploy fails (deploy_stage_failed)
47
+ * and the live version never stops serving. */
48
+ export type ReleaseStages = "at_once" | "staged";
49
+ export type ReleaseSettings = {
50
+ releaseStages: ReleaseStages;
51
+ /** 60 to 3600 seconds; defaults to 300. How long each stage runs once its
52
+ * copies serve before it is judged. */
53
+ releaseSoakSeconds: number;
54
+ };
55
+ /** An App's staged release under way, or its last. */
56
+ export type StagedRelease = {
57
+ version: number;
58
+ /** The version live when it began, serving beside it. */
59
+ from: number;
60
+ /** rolling: its stages go live; back: a stage did worse and its copies
61
+ * leave; done: every copy runs it; failed: it went back (or its copies
62
+ * failed their health check) and the version failed; ended: another
63
+ * deploy or a rollback took its place. */
64
+ state: "rolling" | "back" | "done" | "failed" | "ended";
65
+ stage: number;
66
+ stages: number;
67
+ /** Copies of the new version the stage serves beside the old version's. */
68
+ copies: number;
69
+ /** Copies the release walks to. */
70
+ of: number;
71
+ soakSeconds: number;
72
+ /** Its last step, in words. */
73
+ detail: string;
74
+ startedAt: number;
75
+ updatedAt: number;
76
+ };
77
+ export type App = AppSettings & StatefulSettings & ReleaseSettings & {
43
78
  id: string;
44
79
  name: string | null;
45
80
  /** Its address for life, its name then its account's:
@@ -58,6 +93,8 @@ export type App = AppSettings & StatefulSettings & {
58
93
  } | null;
59
94
  liveVersion: number | null;
60
95
  previousVersion: number | null;
96
+ /** Its staged release under way, or its last; null before its first. */
97
+ stagedRelease: StagedRelease | null;
61
98
  /** While a copy waits for room in its region: its account's lane, its
62
99
  * place in line (1 is next), how many wait ahead by lane, and why.
63
100
  * Higher lanes get room first. Absent while nothing of it waits. */
@@ -69,7 +106,7 @@ export type AppLine = {
69
106
  ahead: Record<string, number>;
70
107
  words: string;
71
108
  };
72
- export type RuntimeFunction = Omit<App, "minCopies" | keyof StatefulSettings> & {
109
+ export type RuntimeFunction = Omit<App, "minCopies" | keyof StatefulSettings | keyof ReleaseSettings | "stagedRelease"> & {
73
110
  minCopies: 0;
74
111
  /** 250 to 5000 ms: at most how long a copy stays awake after its last request ends. */
75
112
  sleepAfterMs: number;
@@ -125,14 +162,18 @@ export type CreateApp = Omit<CreateFunction, "minCopies" | "sleepAfterMs"> & {
125
162
  volume?: AppVolume;
126
163
  /** 0 to 900; defaults to 30. */
127
164
  stopGraceSeconds?: number;
165
+ /** Defaults to "at_once"; see ReleaseStages. */
166
+ releaseStages?: ReleaseStages;
167
+ /** 60 to 3600; defaults to 300. */
168
+ releaseSoakSeconds?: number;
128
169
  };
129
- export type UpdateApp = Partial<AppSettings & StatefulSettings> & {
170
+ export type UpdateApp = Partial<AppSettings & StatefulSettings & ReleaseSettings> & {
130
171
  name?: string | null;
131
172
  labels?: Record<string, string>;
132
173
  /** Only Functions sleep on this rule; an App is refused it. */
133
174
  sleepAfterMs?: never;
134
175
  };
135
- export type UpdateFunction = Omit<UpdateApp, "minCopies" | "sleepAfterMs" | keyof StatefulSettings> & {
176
+ export type UpdateFunction = Omit<UpdateApp, "minCopies" | "sleepAfterMs" | keyof StatefulSettings | keyof ReleaseSettings> & {
136
177
  minCopies?: never;
137
178
  /** 250 to 5000 ms; see CreateFunction.sleepAfterMs. */
138
179
  sleepAfterMs?: number;
@@ -159,7 +200,7 @@ export type AppDeploy = {
159
200
  } | {
160
201
  state: "failed" | "superseded";
161
202
  error: {
162
- code: "deploy_build_failed" | "deploy_health_failed" | "deploy_stop_failed" | "deploy_switch_failed" | "deploy_superseded";
203
+ code: "deploy_build_failed" | "deploy_health_failed" | "deploy_stop_failed" | "deploy_stage_failed" | "deploy_switch_failed" | "deploy_superseded";
163
204
  message: string;
164
205
  hint: string;
165
206
  lastOutput: string;
@@ -40,6 +40,28 @@ export type BrowserInfo = {
40
40
  liveViewUrl?: string;
41
41
  hint?: string;
42
42
  };
43
+ export type BrowserScreenshot = {
44
+ /** An http(s) address, opened in a new tab that is closed after. */
45
+ url?: string;
46
+ /** The whole page, not only the window. */
47
+ fullPage?: boolean;
48
+ format?: "png" | "jpeg";
49
+ /** 0 to 10000 ms after the page loads, for late scripts. */
50
+ waitMs?: number;
51
+ };
52
+ export type BrowserScreenshotResult = {
53
+ /** Where the page ended, after redirects. */
54
+ url: string;
55
+ title: string;
56
+ /** The page's HTTP status; null for the page already shown. */
57
+ status: number | null;
58
+ mimeType: "image/png" | "image/jpeg";
59
+ bytes: number;
60
+ width: number | null;
61
+ height: number | null;
62
+ /** The image. */
63
+ base64: string;
64
+ };
43
65
  export type BrowserConnectOptions = {
44
66
  playwright: [endpointURL: string, options: {
45
67
  headers: Record<string, string>;
@@ -66,6 +88,10 @@ export declare function browsers(t: Transport): {
66
88
  list: (query?: ListBrowsers, options?: RequestOptions) => Promise<Page<Browser>>;
67
89
  /** Change a browser's name or labels without changing its compute settings. */
68
90
  update(id: string, input: UpdateBrowser, options?: RequestOptions): Promise<Browser>;
91
+ /** Open `url` in a new tab and shoot it once it loads (without `url`, what
92
+ * the browser shows now); the image is `base64`, its page's url, title
93
+ * and HTTP status beside it. Runs inside the browser's own sandbox. */
94
+ screenshot(id: string, input?: BrowserScreenshot, options?: RequestOptions): Promise<BrowserScreenshotResult>;
69
95
  /** End a browser by id; pass RequestOptions to bound or deduplicate the request. */
70
96
  delete: (id: string, options?: RequestOptions) => Promise<void>;
71
97
  };
@@ -96,6 +96,17 @@ export function browsers(t) {
96
96
  ...options,
97
97
  }));
98
98
  },
99
+ /** Open `url` in a new tab and shoot it once it loads (without `url`, what
100
+ * the browser shows now); the image is `base64`, its page's url, title
101
+ * and HTTP status beside it. Runs inside the browser's own sandbox. */
102
+ screenshot(id, input = {}, options) {
103
+ return t.json({
104
+ method: "POST",
105
+ path: `${path(id)}:screenshot`,
106
+ body: input,
107
+ ...options,
108
+ });
109
+ },
99
110
  /** End a browser by id; pass RequestOptions to bound or deduplicate the request. */
100
111
  delete: remove,
101
112
  };
@@ -144,7 +144,8 @@ export type CiReviewFinding = {
144
144
  /** What would put it right. */
145
145
  fix: string;
146
146
  };
147
- /** A review step's verdict on one commit: it passes only with no findings. */
147
+ /** An agent step's verdict on one commit (`review:` is its short form): it
148
+ * passes only with no findings. */
148
149
  export type CiReview = {
149
150
  verdict: "pass" | "block";
150
151
  summary: string;
@@ -155,10 +156,11 @@ export type CiReview = {
155
156
  line: number;
156
157
  what: string;
157
158
  }[];
158
- /** The Runtime Agent that reviewed, the account it ran on and its model. */
159
+ /** The Runtime Agent that judged, and the model the step asked for. */
159
160
  agent: string;
160
- account: string;
161
- model: string;
161
+ model: string | null;
162
+ /** The Claude account a verdict before agent steps ran on. */
163
+ account?: string;
162
164
  /** The agent session that gave the verdict. */
163
165
  session: string;
164
166
  /** True when the diff was too long and its end was not read. */
@@ -353,6 +355,10 @@ export declare function ci(t: Transport): {
353
355
  * are let go. A check that has ended is answered as it is; to a key
354
356
  * that may cancel it but not read it, with its id and state alone. */
355
357
  cancel: (id: string, options?: RequestOptions) => Promise<CiCheckDetail | CiCancelled>;
358
+ /** Run a check again, as GitHub's Re-run does: a new check of the
359
+ * same commit (a pull request's as it would land now), trusted only as
360
+ * the commit's last check was. A check still going is answered as it is. */
361
+ rerun: (id: string, options?: RequestOptions) => Promise<CiCheckDetail | CiCancelled>;
356
362
  };
357
363
  jobs: {
358
364
  /** A job with the tail of its log and the sandboxes it ran in. */
@@ -92,6 +92,14 @@ export function ci(t) {
92
92
  path: `${at("/v1/ci/checks", id)}:cancel`,
93
93
  ...options,
94
94
  }),
95
+ /** Run a check again, as GitHub's Re-run does: a new check of the
96
+ * same commit (a pull request's as it would land now), trusted only as
97
+ * the commit's last check was. A check still going is answered as it is. */
98
+ rerun: (id, options) => t.json({
99
+ method: "POST",
100
+ path: `${at("/v1/ci/checks", id)}:rerun`,
101
+ ...options,
102
+ }),
95
103
  },
96
104
  jobs: {
97
105
  /** A job with the tail of its log and the sandboxes it ran in. */
@@ -0,0 +1,71 @@
1
+ /** Desktops: a Linux desktop on its own sandbox, billed at the sandbox rates
2
+ * (packages/cloud/src/api/products/desktops.ts), at /v1/desktops, with a
3
+ * private live view and computer use: screenshot and act. In a private beta:
4
+ * an account outside it is refused with product_in_beta (403), and retrying
5
+ * does not change it. */
6
+ import type { RequestOptions, Transport } from "../transport.js";
7
+ import { type ResourceRecord } from "./resources.js";
8
+ export type DesktopState = "starting" | "running" | "paused" | "stopped" | "failed" | "deleted";
9
+ export type Desktop = ResourceRecord & {
10
+ name: string | null;
11
+ labels: Record<string, string>;
12
+ state: DesktopState;
13
+ sandboxId: string;
14
+ createdAt: number;
15
+ updatedAt: number;
16
+ deletedAt: number | null;
17
+ memoryMiB: number;
18
+ vcpu: number;
19
+ width: number;
20
+ height: number;
21
+ timeoutSeconds: number;
22
+ idlePauseSeconds: number;
23
+ /** Opens the live desktop in a browser; carries a private preview token. */
24
+ liveViewUrl?: string;
25
+ /** When liveViewUrl's token ends; get the desktop again for a fresh one. */
26
+ expiresAt: string | null;
27
+ actions: {
28
+ screenshot: string;
29
+ act: string;
30
+ record: string;
31
+ };
32
+ };
33
+ export type CreateDesktop = {
34
+ /** 1024–16384 MiB; the server defaults to 2048. */
35
+ memoryMiB?: number;
36
+ /** The server defaults to 2 vCPU. */
37
+ vcpu?: number;
38
+ /** The screen, 640x480 to 3840x2160; 1280x800 by default. */
39
+ width?: number;
40
+ height?: number;
41
+ timeoutSeconds?: number;
42
+ idlePauseSeconds?: number;
43
+ name?: string;
44
+ labels?: Record<string, string>;
45
+ };
46
+ /** Only the name and labels change; a null name clears it. */
47
+ export type UpdateDesktop = {
48
+ name?: string | null;
49
+ labels?: Record<string, string>;
50
+ };
51
+ /** One computer-use step, as POST /v1/desktops/{id}:act takes it. */
52
+ export type DesktopAct = {
53
+ action: string;
54
+ } & Record<string, unknown>;
55
+ export declare function desktops(t: Transport): {
56
+ /** The screen as PNG (or JPEG) bytes. A write: it runs in the desktop's
57
+ * sandbox and wakes a paused one, so a read-only key is refused it. */
58
+ screenshot(id: string, shot?: {
59
+ format?: "png" | "jpeg";
60
+ quality?: number;
61
+ }, options?: RequestOptions): Promise<Uint8Array<ArrayBufferLike>>;
62
+ /** Move, click, drag, scroll, type, press keys, open a URL or launch a program. */
63
+ act(id: string, step: DesktopAct, options?: RequestOptions): Promise<Record<string, unknown>>;
64
+ base: string;
65
+ create: (input: CreateDesktop, options?: RequestOptions) => Promise<Desktop>;
66
+ get: (id: string, options?: import("./resources.js").ResourceGetOptions<"paused" | "stopped" | "starting" | "running" | "deleted" | "failed">) => Promise<Desktop>;
67
+ list: (query?: import("./resources.js").ResourceListQuery<"paused" | "stopped" | "starting" | "running" | "deleted" | "failed">, options?: RequestOptions) => Promise<import("../page.js").Page<Desktop>>;
68
+ update: (id: string, input: UpdateDesktop, options?: RequestOptions) => Promise<Desktop>;
69
+ wait: (id: string, target: "paused" | "stopped" | "starting" | "running" | "deleted" | "failed", options?: import("./resources.js").ResourceWaitOptions) => Promise<Desktop>;
70
+ delete: (id: string, options?: import("./resources.js").ResourceDeleteOptions) => Promise<Desktop>;
71
+ };