withruntime 0.33.2 → 0.34.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 (43) 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 +66 -13
  14. package/dist/cli.d.ts +4 -0
  15. package/dist/cli.js +94 -10
  16. package/dist/desktops/index.d.ts +9 -0
  17. package/dist/desktops/index.js +10 -0
  18. package/dist/e2b/code-interpreter.d.ts +3 -12
  19. package/dist/e2b/code-interpreter.js +3 -6
  20. package/dist/e2b/index.d.ts +7 -1
  21. package/dist/e2b/index.js +9 -2
  22. package/dist/index.d.ts +6 -4
  23. package/dist/products/agents.d.ts +162 -8
  24. package/dist/products/agents.js +108 -3
  25. package/dist/products/apps.d.ts +46 -5
  26. package/dist/products/browsers.d.ts +26 -0
  27. package/dist/products/browsers.js +11 -0
  28. package/dist/products/ci.d.ts +49 -7
  29. package/dist/products/ci.js +15 -1
  30. package/dist/products/desktops.d.ts +71 -0
  31. package/dist/products/desktops.js +27 -0
  32. package/dist/products/index.d.ts +4 -0
  33. package/dist/products/index.js +5 -0
  34. package/dist/products/network.d.ts +4 -2
  35. package/dist/products/secrets.d.ts +10 -2
  36. package/dist/products/secrets.js +27 -7
  37. package/dist/products/uptime.d.ts +97 -0
  38. package/dist/products/uptime.js +42 -0
  39. package/dist/products/volumes.d.ts +41 -9
  40. package/dist/products/volumes.js +5 -2
  41. package/dist/transport.d.ts +4 -1
  42. package/dist/transport.js +2 -2
  43. package/package.json +13 -2
@@ -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
  };
@@ -65,7 +65,7 @@ export type CiCheck = {
65
65
  /** The GitHub login that pushed, opened or re-ran it. */
66
66
  actor: string | null;
67
67
  /** The repository's writers' code. A fork's pull request is not, and runs
68
- * nothing until a writer re-runs it on GitHub. */
68
+ * nothing; a writer can open it again from a branch of the repository. */
69
69
  trusted: boolean;
70
70
  /** Queued for a writer's approval: nothing of it runs. */
71
71
  waiting: boolean;
@@ -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. */
@@ -168,6 +170,12 @@ export type CiReview = {
168
170
  export type CiCheckDetail = CiCheck & {
169
171
  jobs: CiJob[];
170
172
  };
173
+ /** A cancel's answer to a key that may cancel the check but not read it:
174
+ * its id and state, nothing of its jobs or logs. */
175
+ export type CiCancelled = {
176
+ id: string;
177
+ state: CiCheckState;
178
+ };
171
179
  /** A job with the tail of its output: at most 256 KiB, the oldest dropped first. */
172
180
  export type CiJobDetail = CiJob & {
173
181
  log: string;
@@ -291,6 +299,30 @@ export type UpdateCiFlake = {
291
299
  owner?: string;
292
300
  deleteReason?: string;
293
301
  };
302
+ /** One step a release took, as it took it: a migration's copy test or
303
+ * apply, a deploy ref moved, a server's canary or release, the website's
304
+ * deploy or promote, or a wait with why. */
305
+ export type CiReleaseStep = {
306
+ id: number;
307
+ repositoryId: string;
308
+ /** The commit this step of the release is of. */
309
+ commit: string;
310
+ /** Who took it: `mover` (the release on CI/CD's pass) or the deploy
311
+ * target that walks it (`hostd`, `controller`, `settings`, `follower`). */
312
+ source: string;
313
+ /** The server it was on, when it was on one. */
314
+ host: string | null;
315
+ line: string;
316
+ /** Unix milliseconds. */
317
+ at: number;
318
+ };
319
+ export type ListCiReleaseSteps = {
320
+ repositoryId?: string;
321
+ /** Only this commit's release. */
322
+ commit?: string;
323
+ limit?: number;
324
+ cursor?: string;
325
+ };
294
326
  export declare function ci(t: Transport): {
295
327
  repositories: {
296
328
  /** Connect a GitHub repository for checks. Only a full key connects
@@ -320,8 +352,13 @@ export declare function ci(t: Transport): {
320
352
  /** A check with its jobs in plan order. */
321
353
  get: (id: string, options?: RequestOptions) => Promise<CiCheckDetail>;
322
354
  /** Cancel a queued or running check: its jobs end and its machines
323
- * are let go. A check that has ended is answered as it is. */
324
- cancel: (id: string, options?: RequestOptions) => Promise<CiCheckDetail>;
355
+ * are let go. A check that has ended is answered as it is; to a key
356
+ * that may cancel it but not read it, with its id and state alone. */
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>;
325
362
  };
326
363
  jobs: {
327
364
  /** A job with the tail of its log and the sandboxes it ran in. */
@@ -331,6 +368,11 @@ export declare function ci(t: Transport): {
331
368
  /** A repository's test files by name, with their quarantine. */
332
369
  list: (repositoryId: string, query?: ListCiTests, options?: RequestOptions) => Promise<Page<CiTest>>;
333
370
  };
371
+ releases: {
372
+ /** The steps releases took, newest first, of one repository or one
373
+ * commit: only repositories whose releases CI/CD runs have any. */
374
+ list: (query?: ListCiReleaseSteps, options?: RequestOptions) => Promise<Page<CiReleaseStep>>;
375
+ };
334
376
  flakes: {
335
377
  /** Flaky tests, newest first; `state: ["quarantined", "gating"]`
336
378
  * lists the open ones. */
@@ -85,12 +85,21 @@ export function ci(t) {
85
85
  /** A check with its jobs in plan order. */
86
86
  get: (id, options) => t.json({ method: "GET", path: at("/v1/ci/checks", id), ...options }),
87
87
  /** Cancel a queued or running check: its jobs end and its machines
88
- * are let go. A check that has ended is answered as it is. */
88
+ * are let go. A check that has ended is answered as it is; to a key
89
+ * that may cancel it but not read it, with its id and state alone. */
89
90
  cancel: (id, options) => t.json({
90
91
  method: "POST",
91
92
  path: `${at("/v1/ci/checks", id)}:cancel`,
92
93
  ...options,
93
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
+ }),
94
103
  },
95
104
  jobs: {
96
105
  /** A job with the tail of its log and the sandboxes it ran in. */
@@ -100,6 +109,11 @@ export function ci(t) {
100
109
  /** A repository's test files by name, with their quarantine. */
101
110
  list: (repositoryId, query = {}, options) => paged("/v1/ci/tests", { ...query, repositoryId }, options),
102
111
  },
112
+ releases: {
113
+ /** The steps releases took, newest first, of one repository or one
114
+ * commit: only repositories whose releases CI/CD runs have any. */
115
+ list: (query = {}, options) => paged("/v1/ci/releases", query, options),
116
+ },
103
117
  flakes: {
104
118
  /** Flaky tests, newest first; `state: ["quarantined", "gating"]`
105
119
  * lists the open ones. */
@@ -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
+ };
@@ -0,0 +1,27 @@
1
+ import { enc, resource } from "./resources.js";
2
+ /** A wait ends at its target or at one of these, with the desktop's error. */
3
+ const SETTLED = ["failed", "deleted"];
4
+ export function desktops(t) {
5
+ return {
6
+ ...resource(t, "desktops", SETTLED),
7
+ /** The screen as PNG (or JPEG) bytes. A write: it runs in the desktop's
8
+ * sandbox and wakes a paused one, so a read-only key is refused it. */
9
+ screenshot(id, shot = {}, options) {
10
+ return t.bytes({
11
+ method: "POST",
12
+ path: `/v1/desktops/${enc(id)}:screenshot`,
13
+ body: shot,
14
+ ...options,
15
+ });
16
+ },
17
+ /** Move, click, drag, scroll, type, press keys, open a URL or launch a program. */
18
+ act(id, step, options) {
19
+ return t.json({
20
+ method: "POST",
21
+ path: `/v1/desktops/${enc(id)}:act`,
22
+ body: step,
23
+ ...options,
24
+ });
25
+ },
26
+ };
27
+ }
@@ -27,6 +27,8 @@ import { agents } from "./agents.js";
27
27
  import { builds } from "./builds.js";
28
28
  import { ci } from "./ci.js";
29
29
  import { containers } from "./containers.js";
30
+ import { browsers } from "./browsers.js";
31
+ import { desktops } from "./desktops.js";
30
32
  import { apps } from "./apps.js";
31
33
  export declare const clientExtensions: {
32
34
  images: typeof images;
@@ -54,6 +56,8 @@ export declare const clientExtensions: {
54
56
  builds: typeof builds;
55
57
  ci: typeof ci;
56
58
  containers: typeof containers;
59
+ browsers: typeof browsers;
60
+ desktops: typeof desktops;
57
61
  apps: typeof apps;
58
62
  };
59
63
  export declare const sandboxExtensions: {
@@ -25,6 +25,8 @@ import { agents } from "./agents.js";
25
25
  import { builds } from "./builds.js";
26
26
  import { ci } from "./ci.js";
27
27
  import { containers } from "./containers.js";
28
+ import { browsers } from "./browsers.js";
29
+ import { desktops } from "./desktops.js";
28
30
  // The hub loads this file, so it loads apps.ts and resources.ts too: request
29
31
  // builders over Transport whose top level holds only types, functions and
30
32
  // imports of files the hub loads, so importing them runs nothing in the hub
@@ -73,6 +75,9 @@ export const clientExtensions = {
73
75
  // CI/CD (beta): the API answers product_in_beta outside its list.
74
76
  ci,
75
77
  containers,
78
+ // Browsers and Desktops (beta): the API answers product_in_beta outside its list.
79
+ browsers,
80
+ desktops,
76
81
  // A private beta (PRODUCT_BETAS): an account outside it is refused with
77
82
  // product_in_beta until Apps launches.
78
83
  apps,
@@ -2,9 +2,11 @@ import type { Sandbox } from "../sandbox.js";
2
2
  import type { RequestOptions, Transport } from "../transport.js";
3
3
  /** A sandbox's own network rules. */
4
4
  export type NetworkRules = {
5
- /** false refuses every outbound connection. */
5
+ /** false refuses every outbound connection; with `allow`, everything but the
6
+ * list (allow-list only, stored as `internet: true` with that list). */
6
7
  internet: boolean;
7
- /** When not empty, only these web destinations are reachable: `example.com`,
8
+ /** When not empty, only these web destinations are reachable, the internet on
9
+ * or off: `example.com`,
8
10
  * `*.example.com` (subdomains, not the apex), an address or a CIDR range. */
9
11
  allow?: string[];
10
12
  /** Never reachable. Wins over everything. */
@@ -171,6 +171,13 @@ export type JobSecret = {
171
171
  /** One secret by name, and where its value may go: to sandboxes through the
172
172
  * egress proxy (`sandboxes`), into scheduled jobs' environments (`jobs`), or
173
173
  * both. */
174
+ /** A page of `secrets.list`: at most `limit` (1 to 100, default 50) secrets,
175
+ * by name, those named after `after`. The next page's `after` is the last
176
+ * name of this one; a page shorter than `limit` is the last. */
177
+ export type ListSecrets = {
178
+ limit?: number;
179
+ after?: string;
180
+ };
174
181
  export type SecretUse = {
175
182
  name: string;
176
183
  sandboxes: Secret | null;
@@ -219,8 +226,9 @@ export declare function secrets(t: Transport): {
219
226
  enforced: boolean;
220
227
  }>;
221
228
  /** The sandboxes' secrets: names, hosts and placeholders. Never values.
222
- * `all()` includes the jobs copies. */
223
- list: (options?: RequestOptions) => Promise<Secret[]>;
229
+ * `list({ limit, after })` gives one page, by name; `all()` includes
230
+ * the jobs copies. */
231
+ list: (query?: ListSecrets & RequestOptions) => Promise<Secret[]>;
224
232
  /** Every secret by name, with where its value may go. */
225
233
  all: (options?: RequestOptions) => Promise<SecretUse[]>;
226
234
  /** One secret by name, with where its value may go. */