@zocomputer/cli 0.1.1 → 0.2.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.
- package/README.md +33 -15
- package/dist/auth.d.ts +4 -0
- package/dist/auth.js +82 -10
- package/dist/generated/commands.js +29 -29
- package/dist/http.d.ts +5 -1
- package/dist/http.js +10 -2
- package/dist/login.d.ts +23 -7
- package/dist/login.js +81 -90
- package/dist/main.js +18 -11
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,25 +6,26 @@ see [runtime requirements](../README.md#set-up).
|
|
|
6
6
|
|
|
7
7
|
## Install or upgrade
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Install the latest published version from npm:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
npm install --global @zocomputer/cli@
|
|
12
|
+
npm install --global @zocomputer/cli@latest
|
|
13
13
|
zo --version
|
|
14
14
|
zo login
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Run the same install command again to upgrade. The CLI
|
|
18
18
|
installs its matching public SDK dependency. It performs no update check when
|
|
19
19
|
you run a command.
|
|
20
20
|
|
|
21
|
-
To
|
|
21
|
+
To try the CLI without installing it globally:
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
|
|
25
|
-
zo --version
|
|
24
|
+
npx -y @zocomputer/cli@latest --help
|
|
26
25
|
```
|
|
27
26
|
|
|
27
|
+
Replace `--help` with a command such as `login` or `--version`.
|
|
28
|
+
|
|
28
29
|
## Develop locally
|
|
29
30
|
|
|
30
31
|
Install the independent client workspace, then build the CLI:
|
|
@@ -50,8 +51,10 @@ node dist/main.js auth status
|
|
|
50
51
|
```
|
|
51
52
|
|
|
52
53
|
Use `node dist/main.js` while working in this repository. The repository's
|
|
53
|
-
internal operator CLI is `./zocli/
|
|
54
|
-
|
|
54
|
+
internal operator CLI is `zd` (`./zocli/zd` from the repository root).
|
|
55
|
+
If an old internal `zo` symlink is still on PATH, run `./zocli/zd setup` from
|
|
56
|
+
your main checkout and refresh your shell's command cache. Run `type -a zd zo`
|
|
57
|
+
to check both commands; the two clients store separate sign-ins.
|
|
55
58
|
|
|
56
59
|
## Accounts and workspaces
|
|
57
60
|
|
|
@@ -78,13 +81,26 @@ workspaces, a terminal prompts for a selection; scripts must supply
|
|
|
78
81
|
person separately from the effective subject in the selected workspace.
|
|
79
82
|
`context list`, `context use` and status refresh that view from the server.
|
|
80
83
|
|
|
81
|
-
`login`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
`login` uses the OAuth device authorization grant (RFC 8628). It prints a
|
|
85
|
+
sign-in URL and a code on stderr, opens your browser, and polls the token
|
|
86
|
+
endpoint until you approve or deny. Approve only if the page shows the same
|
|
87
|
+
code. Nothing connects back to the CLI's machine, so the URL works from any
|
|
88
|
+
browser or device. The request expires after 10 minutes; Ctrl-C cancels it
|
|
89
|
+
(exit 130). Denial exits 4 with `access_denied`; expiry exits 3 with
|
|
90
|
+
`login_timeout`.
|
|
91
|
+
|
|
92
|
+
Over SSH (`SSH_CONNECTION` or `SSH_TTY` set), or with no `DISPLAY` or
|
|
93
|
+
`WAYLAND_DISPLAY` outside macOS, login doesn't open a browser and asks you to
|
|
94
|
+
visit the URL on any device. `login --no-browser` does the same anywhere.
|
|
95
|
+
|
|
96
|
+
After approval, login lists every approved workspace with the identity the CLI
|
|
97
|
+
acts as there (`as you` or `as service account <id>`), even when there is only
|
|
98
|
+
one. A workspace you don't recognize means someone else approved your sign-in
|
|
99
|
+
link; run `logout` to revoke it.
|
|
85
100
|
|
|
86
|
-
|
|
87
|
-
|
|
101
|
+
Each poll waits up to 20 seconds. After a timeout or network error the CLI
|
|
102
|
+
retries once at once, inside the issuer's 30-second redemption window, then
|
|
103
|
+
resumes polling every `interval` seconds; `slow_down` and a 429 add 5 seconds.
|
|
88
104
|
|
|
89
105
|
## Tokens and logout
|
|
90
106
|
|
|
@@ -131,7 +147,9 @@ Before sending, the CLI durably marks the outcome uncertain. If syncing that
|
|
|
131
147
|
marker fails after replacement, it attempts to restore the original ready
|
|
132
148
|
credential and reports the storage error; no exchange was sent. A lost response
|
|
133
149
|
may be retried once under the lock within the server's 30-second recovery
|
|
134
|
-
window.
|
|
150
|
+
window. A 429 comes only from the rate limiter, before any exchange, so the
|
|
151
|
+
CLI restores the ready state, does not retry, and asks you to try again
|
|
152
|
+
shortly; a 429 on that retry leaves the marker in place. Saving the received successor clears the marker. A crash, failure to
|
|
135
153
|
replace the credential file, or unresolved second request leaves the marker
|
|
136
154
|
in place and requires login;
|
|
137
155
|
later processes cannot unknowingly replay that refresh token.
|
package/dist/auth.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface AuthOptions {
|
|
|
12
12
|
environment?: Binding;
|
|
13
13
|
env?: NodeJS.ProcessEnv;
|
|
14
14
|
now?: () => number;
|
|
15
|
+
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
15
16
|
signal?: AbortSignal;
|
|
16
17
|
}
|
|
17
18
|
export declare class AuthClient {
|
|
@@ -22,6 +23,7 @@ export declare class AuthClient {
|
|
|
22
23
|
private readonly fetcher;
|
|
23
24
|
private readonly env;
|
|
24
25
|
private readonly now;
|
|
26
|
+
private readonly sleep;
|
|
25
27
|
private readonly signal?;
|
|
26
28
|
constructor(profile: Profile, directory: string, options?: AuthOptions);
|
|
27
29
|
private locked;
|
|
@@ -31,6 +33,8 @@ export declare class AuthClient {
|
|
|
31
33
|
session(): Promise<Session>;
|
|
32
34
|
private revoke;
|
|
33
35
|
private cleanup;
|
|
36
|
+
/** RFC 8628 section 3.4 polling until approval, denial or expiry. */
|
|
37
|
+
private poll;
|
|
34
38
|
login(options?: LoginOptions): Promise<{
|
|
35
39
|
cleanupPending: boolean;
|
|
36
40
|
}>;
|
package/dist/auth.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { CliError, record, throwIfInterrupted } from "./errors.js";
|
|
3
3
|
import { requestJson, RequestFailure } from "./http.js";
|
|
4
|
-
import {
|
|
4
|
+
import { browserAvailable, DEVICE_CODE_GRANT, deviceAuthorization, openBrowser, pause, } from "./login.js";
|
|
5
5
|
import { environments, profileName } from "./profiles.js";
|
|
6
6
|
import { parseSession } from "./session.js";
|
|
7
7
|
import { privateDirectory, PrivateWriteDurabilityError, readPrivate, removePrivate, withLock, writePrivate, } from "./storage.js";
|
|
8
|
+
// Longer than requestJson's 8-second default, and short enough that a retry
|
|
9
|
+
// after a lost approval lands inside the issuer's 30-second redemption window.
|
|
10
|
+
const DEVICE_POLL_TIMEOUT_MS = 20_000;
|
|
8
11
|
function tokens(raw, now) {
|
|
9
12
|
if (!record(raw) ||
|
|
10
13
|
raw.error !== undefined ||
|
|
@@ -36,6 +39,7 @@ export class AuthClient {
|
|
|
36
39
|
fetcher;
|
|
37
40
|
env;
|
|
38
41
|
now;
|
|
42
|
+
sleep;
|
|
39
43
|
signal;
|
|
40
44
|
constructor(profile, directory, options = {}) {
|
|
41
45
|
this.profile = profile;
|
|
@@ -45,6 +49,7 @@ export class AuthClient {
|
|
|
45
49
|
this.fetcher = options.fetch ?? fetch;
|
|
46
50
|
this.env = options.env ?? process.env;
|
|
47
51
|
this.now = options.now ?? Date.now;
|
|
52
|
+
this.sleep = options.sleep ?? pause;
|
|
48
53
|
this.signal = options.signal;
|
|
49
54
|
}
|
|
50
55
|
async locked(work, signal = this.signal) {
|
|
@@ -97,7 +102,7 @@ export class AuthClient {
|
|
|
97
102
|
refreshState: raw.refreshState,
|
|
98
103
|
};
|
|
99
104
|
}
|
|
100
|
-
async tokenRequest(form, signal = this.signal) {
|
|
105
|
+
async tokenRequest(form, signal = this.signal, timeoutMs) {
|
|
101
106
|
const issuedAt = this.now();
|
|
102
107
|
return tokens(await requestJson(`${this.binding.issuer}/zo-system-api/oauth/token`, {
|
|
103
108
|
method: "POST",
|
|
@@ -107,7 +112,7 @@ export class AuthClient {
|
|
|
107
112
|
client_id: this.binding.clientId,
|
|
108
113
|
resource: this.binding.audience,
|
|
109
114
|
}),
|
|
110
|
-
}, this.fetcher), issuedAt);
|
|
115
|
+
}, this.fetcher, timeoutMs === undefined ? {} : { timeoutMs }), issuedAt);
|
|
111
116
|
}
|
|
112
117
|
async accessToken() {
|
|
113
118
|
throwIfInterrupted(this.signal);
|
|
@@ -150,6 +155,13 @@ export class AuthClient {
|
|
|
150
155
|
}
|
|
151
156
|
catch (error) {
|
|
152
157
|
throwIfInterrupted(this.signal);
|
|
158
|
+
if (error instanceof RequestFailure && error.status === 429) {
|
|
159
|
+
// Only the rate limiter answers 429, before any exchange, so the
|
|
160
|
+
// refresh token is unused. Retrying now would hit the same limit.
|
|
161
|
+
credential.refreshState = "ready";
|
|
162
|
+
await writePrivate(this.path, credential);
|
|
163
|
+
throw new CliError("Too many sign-in requests right now. Try again shortly.", 5, "rate_limited");
|
|
164
|
+
}
|
|
153
165
|
// Two eight-second requests fit the issuer's thirty-second recovery
|
|
154
166
|
// window. Wall time also catches suspension of the monotonic clock.
|
|
155
167
|
const elapsed = this.now() - startedAt;
|
|
@@ -208,6 +220,61 @@ export class AuthClient {
|
|
|
208
220
|
throwIfInterrupted(signal);
|
|
209
221
|
}
|
|
210
222
|
}
|
|
223
|
+
/** RFC 8628 section 3.4 polling until approval, denial or expiry. */
|
|
224
|
+
async poll(device, signal) {
|
|
225
|
+
const deadline = this.now() + device.expiresInMs;
|
|
226
|
+
const form = {
|
|
227
|
+
grant_type: DEVICE_CODE_GRANT,
|
|
228
|
+
device_code: device.deviceCode,
|
|
229
|
+
};
|
|
230
|
+
const expired = () => new CliError("Login timed out. Run zo login to try again.", 3, "login_timeout");
|
|
231
|
+
let interval = device.intervalMs;
|
|
232
|
+
let retryNow = false;
|
|
233
|
+
for (;;) {
|
|
234
|
+
if (!retryNow)
|
|
235
|
+
await this.sleep(interval, signal);
|
|
236
|
+
throwIfInterrupted(signal);
|
|
237
|
+
if (this.now() >= deadline)
|
|
238
|
+
throw expired();
|
|
239
|
+
const retry = retryNow;
|
|
240
|
+
retryNow = false;
|
|
241
|
+
try {
|
|
242
|
+
return await this.tokenRequest(form, signal, DEVICE_POLL_TIMEOUT_MS);
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
throwIfInterrupted(signal);
|
|
246
|
+
if (!(error instanceof RequestFailure))
|
|
247
|
+
throw error;
|
|
248
|
+
if (error.status === 400) {
|
|
249
|
+
if (error.code === "authorization_pending")
|
|
250
|
+
continue;
|
|
251
|
+
if (error.code === "slow_down") {
|
|
252
|
+
interval += 5_000;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (error.code === "access_denied")
|
|
256
|
+
throw new CliError("Authorization was denied. Run zo login to try again.", 4, "access_denied");
|
|
257
|
+
if (error.code === "expired_token")
|
|
258
|
+
throw expired();
|
|
259
|
+
if (error.code === "invalid_grant")
|
|
260
|
+
throw new CliError("This sign-in request can no longer be completed. Run zo login again.", 3, "invalid_grant");
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
// The rate limiter answered before the issuer saw the poll.
|
|
264
|
+
if (error.status === 429) {
|
|
265
|
+
interval += 5_000;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
// A timeout, network error or 5xx may have lost an approval the issuer
|
|
269
|
+
// already redeemed. One immediate retry gets the same refresh token.
|
|
270
|
+
if (error.ambiguous) {
|
|
271
|
+
retryNow = !retry;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
211
278
|
async login(options = {}) {
|
|
212
279
|
const signal = this.signal && options.signal
|
|
213
280
|
? AbortSignal.any([this.signal, options.signal])
|
|
@@ -218,13 +285,18 @@ export class AuthClient {
|
|
|
218
285
|
return this.locked(async () => {
|
|
219
286
|
const previous = await this.read();
|
|
220
287
|
throwIfInterrupted(signal);
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
288
|
+
const device = await deviceAuthorization(this.binding.issuer, this.binding.audience, this.binding.clientId, this.fetcher, signal);
|
|
289
|
+
const browser = !options.noBrowser &&
|
|
290
|
+
browserAvailable(this.env, options.platform ?? process.platform);
|
|
291
|
+
options.announce?.({
|
|
292
|
+
url: device.url,
|
|
293
|
+
userCode: device.userCode,
|
|
294
|
+
browser,
|
|
295
|
+
});
|
|
296
|
+
// The printed URL is the fallback when the opener fails.
|
|
297
|
+
if (browser)
|
|
298
|
+
void (options.openBrowser ?? openBrowser)(device.url).catch(() => { });
|
|
299
|
+
const active = await this.poll(device, signal);
|
|
228
300
|
const credential = {
|
|
229
301
|
version: 1,
|
|
230
302
|
binding: this.binding,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by scripts/generate-commands.mjs. Do not edit.
|
|
2
2
|
export const commandManifest = {
|
|
3
|
-
schemaDigest: "sha256:
|
|
3
|
+
schemaDigest: "sha256:8f3267de41a6d06b71c959bca7eae3d05a1bda6e63304a51a9bbfa315ef0af31",
|
|
4
4
|
commands: [
|
|
5
5
|
{
|
|
6
6
|
action: "zo.activity.list",
|
|
@@ -33,8 +33,8 @@ export const commandManifest = {
|
|
|
33
33
|
versions: [
|
|
34
34
|
{
|
|
35
35
|
version: 1,
|
|
36
|
-
description: "Create an Agent in a workspace. A zo.native Agent requires the workspace to be on Metronome billing.",
|
|
37
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"},"implementation":{"const":"zo.native","title":"Implementation","type":"string"},"configuration":{"$ref":"#/$defs/NativeConfiguration"}},"required":["workspace_id","display_name","implementation","configuration"],"title":"AgentCreateInput","type":"object","$defs":{"NativeConfiguration":{"additionalProperties":false,"description":"The ``zo.native`` configuration. Unknown fields are rejected.","properties":{"model":{"description":"Model identifier the runner calls.","maxLength":200,"minLength":1,"title":"Model","type":"string"},"system_prompt":{"anyOf":[{"maxLength":50000,"type":"string"},{"type":"null"}],"default":null,"description":"The Agent\'s instructions.","title":"System Prompt"},"instructions_file":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"Knowledge file ID, such as an AGENTS.md, appended to the instructions each turn.","title":"Instructions File"},"skill_files":{"default":[],"description":"Knowledge file IDs of skills, each a Markdown file with Agent Skills frontmatter, indexed in the instructions.","items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":32,"title":"Skill Files","type":"array"}},"required":["model"],"title":"NativeConfiguration","type":"object"}}}',
|
|
36
|
+
description: "Create an Agent in a workspace. A zo.native Agent requires the workspace to be on Metronome billing. Describe what this Agent is for in the user's terms.",
|
|
37
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this Agent is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"},"implementation":{"const":"zo.native","title":"Implementation","type":"string"},"configuration":{"$ref":"#/$defs/NativeConfiguration"}},"required":["workspace_id","display_name","implementation","configuration"],"title":"AgentCreateInput","type":"object","$defs":{"NativeConfiguration":{"additionalProperties":false,"description":"The ``zo.native`` configuration. Unknown fields are rejected.","properties":{"model":{"description":"Model identifier the runner calls.","maxLength":200,"minLength":1,"title":"Model","type":"string"},"system_prompt":{"anyOf":[{"maxLength":50000,"type":"string"},{"type":"null"}],"default":null,"description":"The Agent\'s instructions.","title":"System Prompt"},"instructions_file":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"Knowledge file ID, such as an AGENTS.md, appended to the instructions each turn.","title":"Instructions File"},"skill_files":{"default":[],"description":"Knowledge file IDs of skills, each a Markdown file with Agent Skills frontmatter, indexed in the instructions.","items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":32,"title":"Skill Files","type":"array"}},"required":["model"],"title":"NativeConfiguration","type":"object"}}}',
|
|
38
38
|
resultKind: "inline",
|
|
39
39
|
},
|
|
40
40
|
],
|
|
@@ -108,7 +108,7 @@ export const commandManifest = {
|
|
|
108
108
|
{
|
|
109
109
|
version: 1,
|
|
110
110
|
description: "Rename an Agent or replace its configuration. Changes apply from each session's next turn.",
|
|
111
|
-
inputJson: '{"additionalProperties":false,"description":"Omitted fields keep their value; ``configuration`` replaces the whole configuration.","properties":{"agent_id":{"maxLength":200,"minLength":1,"title":"Agent Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"anyOf":[{"maxLength":120,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Display Name"},"configuration":{"anyOf":[{"$ref":"#/$defs/NativeConfiguration"},{"type":"null"}],"default":null}},"required":["agent_id","expected_revision"],"title":"AgentUpdateInput","type":"object","$defs":{"NativeConfiguration":{"additionalProperties":false,"description":"The ``zo.native`` configuration. Unknown fields are rejected.","properties":{"model":{"description":"Model identifier the runner calls.","maxLength":200,"minLength":1,"title":"Model","type":"string"},"system_prompt":{"anyOf":[{"maxLength":50000,"type":"string"},{"type":"null"}],"default":null,"description":"The Agent\'s instructions.","title":"System Prompt"},"instructions_file":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"Knowledge file ID, such as an AGENTS.md, appended to the instructions each turn.","title":"Instructions File"},"skill_files":{"default":[],"description":"Knowledge file IDs of skills, each a Markdown file with Agent Skills frontmatter, indexed in the instructions.","items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":32,"title":"Skill Files","type":"array"}},"required":["model"],"title":"NativeConfiguration","type":"object"}}}',
|
|
111
|
+
inputJson: '{"additionalProperties":false,"description":"Omitted fields keep their value; ``configuration`` replaces the whole configuration.","properties":{"agent_id":{"maxLength":200,"minLength":1,"title":"Agent Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"anyOf":[{"maxLength":120,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Display Name"},"description":{"anyOf":[{"maxLength":2000,"type":"string"},{"type":"null"}],"default":null,"description":"Describe what this Agent is for in the user\'s terms.","title":"Description"},"configuration":{"anyOf":[{"$ref":"#/$defs/NativeConfiguration"},{"type":"null"}],"default":null}},"required":["agent_id","expected_revision"],"title":"AgentUpdateInput","type":"object","$defs":{"NativeConfiguration":{"additionalProperties":false,"description":"The ``zo.native`` configuration. Unknown fields are rejected.","properties":{"model":{"description":"Model identifier the runner calls.","maxLength":200,"minLength":1,"title":"Model","type":"string"},"system_prompt":{"anyOf":[{"maxLength":50000,"type":"string"},{"type":"null"}],"default":null,"description":"The Agent\'s instructions.","title":"System Prompt"},"instructions_file":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"Knowledge file ID, such as an AGENTS.md, appended to the instructions each turn.","title":"Instructions File"},"skill_files":{"default":[],"description":"Knowledge file IDs of skills, each a Markdown file with Agent Skills frontmatter, indexed in the instructions.","items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":32,"title":"Skill Files","type":"array"}},"required":["model"],"title":"NativeConfiguration","type":"object"}}}',
|
|
112
112
|
resultKind: "inline",
|
|
113
113
|
},
|
|
114
114
|
],
|
|
@@ -182,8 +182,8 @@ export const commandManifest = {
|
|
|
182
182
|
versions: [
|
|
183
183
|
{
|
|
184
184
|
version: 1,
|
|
185
|
-
description: "Create a connection from a published definition. A protected connection is reachable only by its owner and the principals they grant.",
|
|
186
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"definition_id":{"maxLength":200,"minLength":1,"
|
|
185
|
+
description: "Create a connection from a published definition, or from named values on a private definition Zo publishes for it. A protected connection is reachable only by its owner and the principals they grant. Describe what this connection is for in the user's terms.",
|
|
186
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"definition_id":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"The published definition to connect to. Give it, or `values`, not both.","title":"Definition Id"},"definition_version":{"anyOf":[{"exclusiveMinimum":0,"maximum":2147483647,"type":"integer"},{"type":"null"}],"default":null,"description":"The version of `definition_id` to connect to; required with it.","title":"Definition Version"},"display_name":{"maxLength":256,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this connection is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"configuration":{"anyOf":[{"additionalProperties":{"x-zo-json-value":true},"type":"object"},{"type":"null"}],"default":null,"description":"The connection\'s configuration; required with `definition_id`.","title":"Configuration"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"},"values":{"anyOf":[{"additionalProperties":{"description":"Secret: the value. Stored sealed and never returned.","maxLength":16384,"minLength":1,"type":"string"},"maxProperties":100,"minProperties":1,"type":"object"},{"type":"null"}],"default":null,"description":"Named values to store, in place of a definition: Zo publishes a private definition named after `display_name`, with one required key credential per name delivered as the environment variable of that name, creates the connection and stores every value. A definition name already taken in the workspace returns `conflict`. A name Zo refuses as an environment variable returns `invalid_input` with the `invalid_environment` violation.","title":"Values"},"environment":{"additionalProperties":{"maxLength":4096,"type":"string"},"default":{},"description":"Environment variables delivered, exactly as written, to machines that list this connection, beside its credential and the variables its definition sets. Plain strings, not secrets: put a secret in the vault. Names are upper-case letters, digits and underscores; at most 64 variables of at most 4096 characters each.","maxProperties":64,"title":"Environment","type":"object"}},"required":["workspace_id","display_name"],"title":"ConnectionCreateInput","type":"object"}',
|
|
187
187
|
resultKind: "inline",
|
|
188
188
|
},
|
|
189
189
|
],
|
|
@@ -279,8 +279,8 @@ export const commandManifest = {
|
|
|
279
279
|
versions: [
|
|
280
280
|
{
|
|
281
281
|
version: 1,
|
|
282
|
-
description: "Replace a connection's configuration, rename it, or
|
|
283
|
-
inputJson: '{"additionalProperties":false,"properties":{"connection_id":{"maxLength":200,"minLength":1,"title":"Connection Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"configuration":{"anyOf":[{"additionalProperties":{"x-zo-json-value":true},"type":"object"},{"type":"null"}],"default":null,"description":"The configuration that replaces the stored one; omit it to keep the stored configuration, which reads never return.","title":"Configuration"},"display_name":{"anyOf":[{"maxLength":256,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"A new name for the connection; omit it to keep the current name.","title":"Display Name"}},"required":["connection_id","expected_revision"],"title":"ConnectionUpdateInput","type":"object"}',
|
|
282
|
+
description: "Replace a connection's configuration or environment, rename it, move it to another version of its definition, or set and remove its named values; a field left out keeps its current value.",
|
|
283
|
+
inputJson: '{"additionalProperties":false,"properties":{"connection_id":{"maxLength":200,"minLength":1,"title":"Connection Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"configuration":{"anyOf":[{"additionalProperties":{"x-zo-json-value":true},"type":"object"},{"type":"null"}],"default":null,"description":"The configuration that replaces the stored one; omit it to keep the stored configuration, which reads never return.","title":"Configuration"},"display_name":{"anyOf":[{"maxLength":256,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"description":"A new name for the connection; omit it to keep the current name.","title":"Display Name"},"description":{"anyOf":[{"maxLength":2000,"type":"string"},{"type":"null"}],"default":null,"description":"Describe what this connection is for in the user\'s terms.","title":"Description"},"definition_version":{"anyOf":[{"exclusiveMinimum":0,"maximum":2147483647,"type":"integer"},{"type":"null"}],"default":null,"description":"Move the connection to this version of its definition, keeping its id and grants. Credentials in both versions keep their values, credentials only the current version has are erased, and credentials only the new version has start empty. Omit it to stay on the current version.","title":"Definition Version"},"values":{"anyOf":[{"additionalProperties":{"anyOf":[{"description":"Secret: the value. Stored sealed and never returned.","maxLength":16384,"minLength":1,"type":"string"},{"type":"null"}]},"maxProperties":100,"minProperties":1,"type":"object"},{"type":"null"}],"default":null,"description":"Named values to set, or `null` to remove a name, on a connection whose definition is private to its workspace and holds only single-value key credentials, as one created from `values` does. Changing a value replaces that credential. Adding or removing a name publishes the definition\'s next version from the connection\'s own version and moves the connection to it, keeping its id and grants; other connections to the definition stay on their versions. A connection keeps at least one name. Any other connection returns `invalid_input`.","title":"Values"},"environment":{"anyOf":[{"additionalProperties":{"maxLength":4096,"type":"string"},"maxProperties":64,"type":"object"},{"type":"null"}],"default":null,"description":"The environment that replaces the stored one; omit it to keep the stored environment. Environment variables delivered, exactly as written, to machines that list this connection, beside its credential and the variables its definition sets. Plain strings, not secrets: put a secret in the vault. Names are upper-case letters, digits and underscores; at most 64 variables of at most 4096 characters each.","title":"Environment"}},"required":["connection_id","expected_revision"],"title":"ConnectionUpdateInput","type":"object"}',
|
|
284
284
|
resultKind: "inline",
|
|
285
285
|
},
|
|
286
286
|
],
|
|
@@ -558,8 +558,8 @@ export const commandManifest = {
|
|
|
558
558
|
versions: [
|
|
559
559
|
{
|
|
560
560
|
version: 1,
|
|
561
|
-
description: "Create a workspace-owned function.",
|
|
562
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","display_name"],"title":"FunctionCreateInput","type":"object"}',
|
|
561
|
+
description: "Create a workspace-owned function. Describe what this function is for in the user's terms.",
|
|
562
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this function is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","display_name"],"title":"FunctionCreateInput","type":"object"}',
|
|
563
563
|
resultKind: "inline",
|
|
564
564
|
},
|
|
565
565
|
],
|
|
@@ -680,8 +680,8 @@ export const commandManifest = {
|
|
|
680
680
|
versions: [
|
|
681
681
|
{
|
|
682
682
|
version: 1,
|
|
683
|
-
description: "Create a managed machine from a machine image and return its current view.",
|
|
684
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"idempotency_key":{"maxLength":255,"minLength":1,"pattern":"^[!-~]{1,255}$","title":"Idempotency Key","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"source":{"$ref":"#/$defs/MachineSourceInput"},"resources":{"$ref":"#/$defs/MachineResourcesInput"},"lifecycle":{"$ref":"#/$defs/MachineLifecycleInput"},"region":{"default":"us","pattern":"^[a-z0-9][a-z0-9-]{0,31}$","title":"Region","type":"string"},"init":{"default":"none","description":"Which process runs first at boot. `none` (default): nothing; the machine waits for exec. `image`: the init system inside the machine\'s image (systemd, OpenRC) becomes PID 1 and starts the services enabled on its disk. This does not choose the image; `source.machine_image_id` does. Debian and Ubuntu images need `systemd systemd-sysv` installed first. A unit restarts after a crash only when it sets `Restart=`.","enum":["none","image"],"title":"Init","type":"string"},"command":{"anyOf":[{"items":{"minLength":1,"type":"string"},"maxItems":64,"minItems":1,"type":"array"},{"type":"null"}],"default":null,"description":"Run these arguments as the main process on every boot, without a shell. Use [\\"sh\\", \\"-c\\", ...] for shell syntax. Find ENTRYPOINT and CMD on the image\'s registry page; Zo does not return them. Pass ENTRYPOINT then CMD. With `init: image`, the command must wait for services it needs. The machine stops when it exits; resume runs it again. It may run more than once after a lost create or resume response, so make it safe to rerun. Each argument is at most 4,096 UTF-8 bytes and all arguments total at most 65,536 bytes. A running command is not activity: set `idle_timeout_seconds` at least as long as the job. The maximum is published by `zo.machine.list_configurations
|
|
683
|
+
description: "Create a managed machine from a machine image and return its current view. Describe what this machine is for in the user's terms.",
|
|
684
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"idempotency_key":{"maxLength":255,"minLength":1,"pattern":"^[!-~]{1,255}$","title":"Idempotency Key","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this machine is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"source":{"$ref":"#/$defs/MachineSourceInput"},"resources":{"$ref":"#/$defs/MachineResourcesInput"},"lifecycle":{"$ref":"#/$defs/MachineLifecycleInput"},"region":{"default":"us","pattern":"^[a-z0-9][a-z0-9-]{0,31}$","title":"Region","type":"string"},"init":{"default":"none","description":"Which process runs first at boot. `none` (default): nothing; the machine waits for exec. `image`: the init system inside the machine\'s image (systemd, OpenRC) becomes PID 1 and starts the services enabled on its disk. This does not choose the image; `source.machine_image_id` does. Debian and Ubuntu images need `systemd systemd-sysv` installed first. A unit restarts after a crash only when it sets `Restart=`. GPU machines require `none`.","enum":["none","image"],"title":"Init","type":"string"},"command":{"anyOf":[{"items":{"minLength":1,"type":"string"},"maxItems":64,"minItems":1,"type":"array"},{"type":"null"}],"default":null,"description":"Run these arguments as the main process on every boot, without a shell. Use [\\"sh\\", \\"-c\\", ...] for shell syntax. Find ENTRYPOINT and CMD on the image\'s registry page; Zo does not return them. Pass ENTRYPOINT then CMD. With `init: image`, the command must wait for services it needs. The machine stops when it exits; resume runs it again. It may run more than once after a lost create or resume response, so make it safe to rerun. Each argument is at most 4,096 UTF-8 bytes and all arguments total at most 65,536 bytes. A running command is not activity: set `idle_timeout_seconds` at least as long as the job. The maximum is published by `zo.machine.list_configurations`: 3,600 s for CPU machines and 86,400 s for GPU machines. Longer CPU jobs need Zo exec or file calls, or HTTP through a tunnel or connect token. After exit, `get` may show `running` for a few minutes until the stop is recorded. Zo reports no exit reason or code. Write a job\'s result to disk. A resume runs the command again, so to read it, clear the command, resume, then use `zo.machine.read_bytes`. With `init: image` and a command, a missing `/sbin/init` ends the generation as an exit stop, without `incompatible_image`.","title":"Command"},"environment":{"additionalProperties":{"maxLength":4096,"type":"string"},"default":{},"description":"Environment variables set, exactly as written, in the boot process and every command run on the machine. Plain strings, not secrets: they are part of the machine\'s configuration, which anyone who can read the machine sees. Names are upper-case letters, digits and underscores, and reserved names such as `PATH` or ones starting with `ZO_` are refused; at most 64 variables of at most 4096 characters each. A variable here wins over a connection in `credentials` that sets the same name.","maxProperties":64,"title":"Environment","type":"object"},"credentials":{"default":[],"description":"Connection IDs whose credentials the machine receives as environment variables, in the boot process and every command. Each slot of a listed connection sets the variable its definition names, with the variables the slot and the connection declare. The machine also needs a use grant on each connection (`zo.grant.create` with the machine as assignee); a listed connection without one delivers nothing. When two listed connections set the same variable, the later one in the list wins. At most 100 connections, each listed once.","items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":100,"title":"Credentials","type":"array"},"visibility":{"default":"workspace","description":"`workspace` (default): every member can see and use it. `protected`: only you, and whoever you share it with; workspace-wide grants don\'t reach it. Fixed at creation.","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","idempotency_key","display_name","source","resources","lifecycle"],"title":"MachineCreateInput","type":"object","$defs":{"GpuType":{"enum":["T4","L4","A10","L40S","A100","A100-40GB","A100-80GB","RTX-PRO-6000","H100","H100!","H200","B200","B200+","B300"],"type":"string"},"MachineGpu":{"additionalProperties":false,"properties":{"type":{"$ref":"#/$defs/GpuType"},"count":{"maximum":8,"minimum":1,"title":"Count","type":"integer"}},"required":["type","count"],"title":"MachineGpu","type":"object"},"MachineLifecycleInput":{"additionalProperties":false,"properties":{"idle_timeout_seconds":{"anyOf":[{"maximum":86400,"minimum":1,"type":"integer"},{"type":"null"}],"default":null,"description":"Omit for 900 seconds on CPU. For GPU, the default is the smaller of 300 seconds and max_run_seconds. An explicit GPU idle timeout must not exceed max_run_seconds.","title":"Idle Timeout Seconds"},"max_run_seconds":{"maximum":86400,"minimum":1,"title":"Max Run Seconds","type":"integer"}},"required":["max_run_seconds"],"title":"MachineLifecycleInput","type":"object"},"MachineResourcesInput":{"additionalProperties":false,"properties":{"vcpus":{"description":"Whole vCPUs of CPU capacity; each is half a Modal physical core. A quarter is reserved; the full allocation can burst when capacity allows. Guest logical CPU count is separate.","maximum":2147483647,"minimum":1,"title":"Vcpus","type":"integer"},"memory_mib":{"maximum":2147483647,"minimum":1,"title":"Memory Mib","type":"integer"},"gpu":{"anyOf":[{"$ref":"#/$defs/MachineGpu"},{"type":"null"}],"default":null}},"required":["vcpus","memory_mib"],"title":"MachineResourcesInput","type":"object"},"MachineSourceInput":{"additionalProperties":false,"properties":{"machine_image_id":{"description":"The machine image to boot (from `zo.machine_image.import`). Separate from `init`, which only chooses what runs first at boot.","minLength":1,"title":"Machine Image Id","type":"string"}},"required":["machine_image_id"],"title":"MachineSourceInput","type":"object"}}}',
|
|
685
685
|
resultKind: "inline",
|
|
686
686
|
},
|
|
687
687
|
],
|
|
@@ -741,7 +741,7 @@ export const commandManifest = {
|
|
|
741
741
|
versions: [
|
|
742
742
|
{
|
|
743
743
|
version: 1,
|
|
744
|
-
description: "List independent
|
|
744
|
+
description: "List independent CPU/RAM bounds, GPU allocations, runtime capabilities, timers and per-second unit prices.",
|
|
745
745
|
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"}},"required":["workspace_id"],"title":"MachineListConfigurationsInput","type":"object"}',
|
|
746
746
|
resultKind: "inline",
|
|
747
747
|
},
|
|
@@ -790,8 +790,8 @@ export const commandManifest = {
|
|
|
790
790
|
versions: [
|
|
791
791
|
{
|
|
792
792
|
version: 1,
|
|
793
|
-
description: "Save a running managed machine's filesystem as a ready image. Destination options live under image. Image visibility defaults to the source; choose workspace or protected explicitly to override it. Finish filesystem writes first. Processes and credentials are not rebound from the source. User-written secrets remain in captured files. Never automatically retry an uncertain result.",
|
|
794
|
-
inputJson: '{"additionalProperties":false,"properties":{"machine_id":{"title":"Machine Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"image":{"$ref":"#/$defs/MachineImageCreateOptions"},"timeout_seconds":{"default":60,"description":"Maximum seconds for filesystem capture, including provider lookup. The remaining request deadline can shorten this budget.","maximum":180,"minimum":1,"title":"Timeout Seconds","type":"integer"}},"required":["machine_id","expected_revision","image"],"title":"MachineSnapshotInput","type":"object","$defs":{"MachineImageCreateOptions":{"additionalProperties":false,"properties":{"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"visibility":{"anyOf":[{"enum":["workspace","protected"],"type":"string"},{"type":"null"}],"default":null,"description":"Image visibility. Omit or pass null to use the creating operation\'s default. Protected images use ordinary verified-human creator ownership.","title":"Visibility"}},"required":["display_name"],"title":"MachineImageCreateOptions","type":"object"}}}',
|
|
793
|
+
description: "Save a running managed machine's filesystem as a ready image. Destination options live under image. Image visibility defaults to the source; choose workspace or protected explicitly to override it. Finish filesystem writes first. Processes and credentials are not rebound from the source. User-written secrets remain in captured files. Never automatically retry an uncertain result. Describe what this machine image is for in the user's terms.",
|
|
794
|
+
inputJson: '{"additionalProperties":false,"properties":{"machine_id":{"title":"Machine Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"image":{"$ref":"#/$defs/MachineImageCreateOptions"},"timeout_seconds":{"default":60,"description":"Maximum seconds for filesystem capture, including provider lookup. The remaining request deadline can shorten this budget.","maximum":180,"minimum":1,"title":"Timeout Seconds","type":"integer"}},"required":["machine_id","expected_revision","image"],"title":"MachineSnapshotInput","type":"object","$defs":{"MachineImageCreateOptions":{"additionalProperties":false,"properties":{"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this machine image is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"visibility":{"anyOf":[{"enum":["workspace","protected"],"type":"string"},{"type":"null"}],"default":null,"description":"Image visibility. Omit or pass null to use the creating operation\'s default. Protected images use ordinary verified-human creator ownership.","title":"Visibility"}},"required":["display_name"],"title":"MachineImageCreateOptions","type":"object"}}}',
|
|
795
795
|
resultKind: "inline",
|
|
796
796
|
},
|
|
797
797
|
],
|
|
@@ -827,7 +827,7 @@ export const commandManifest = {
|
|
|
827
827
|
{
|
|
828
828
|
version: 1,
|
|
829
829
|
description: "Change a managed machine's name, timers or next-boot settings against its current revision.",
|
|
830
|
-
inputJson: '{"additionalProperties":false,"properties":{"machine_id":{"title":"Machine Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"anyOf":[{"maxLength":120,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Display Name"},"lifecycle":{"anyOf":[{"$ref":"#/$defs/MachineLifecycleUpdate"},{"type":"null"}],"default":null},"init":{"anyOf":[{"enum":["none","image"],"type":"string"},{"type":"null"}],"default":null,"description":"Which process runs first at boot. `none` (default): nothing; the machine waits for exec. `image`: the image\'s init system (systemd, OpenRC) becomes PID 1 and starts enabled services. `source.machine_image_id` chooses the image. Debian and Ubuntu need `systemd systemd-sysv`.
|
|
830
|
+
inputJson: '{"additionalProperties":false,"properties":{"machine_id":{"title":"Machine Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"anyOf":[{"maxLength":120,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Display Name"},"description":{"anyOf":[{"maxLength":2000,"type":"string"},{"type":"null"}],"default":null,"description":"Describe what this machine is for in the user\'s terms.","title":"Description"},"lifecycle":{"anyOf":[{"$ref":"#/$defs/MachineLifecycleUpdate"},{"type":"null"}],"default":null},"init":{"anyOf":[{"enum":["none","image"],"type":"string"},{"type":"null"}],"default":null,"description":"Which process runs first at boot. `none` (default): nothing; the machine waits for exec. `image`: the image\'s init system (systemd, OpenRC) becomes PID 1 and starts enabled services. `source.machine_image_id` chooses the image. Debian and Ubuntu need `systemd systemd-sysv`. Write access to boot files can run code as root at next boot.","title":"Init"},"command":{"anyOf":[{"items":{"minLength":1,"type":"string"},"maxItems":64,"minItems":1,"type":"array"},{"type":"null"}],"default":null,"description":"Set the main process for the next resume. Arguments run without a shell; use [\\"sh\\", \\"-c\\", ...] for shell syntax. Find ENTRYPOINT and CMD on the image\'s registry page; Zo does not return them. Pass ENTRYPOINT then CMD. With `init: image`, wait for needed services. The machine stops when the command exits; resume runs it again. It may run more than once after a lost create or resume response, so make it safe to rerun. Each argument is at most 4,096 UTF-8 bytes and all arguments total at most 65,536 bytes. A running command is not activity: set `idle_timeout_seconds` at least as long as the job. The maximum is published by `zo.machine.list_configurations`: 3,600 s for CPU machines and 86,400 s for GPU machines. Longer CPU jobs need Zo exec or file calls, or HTTP through a tunnel or connect token. After exit, `get` may show `running` for a few minutes. Zo reports no exit reason or code. Write a job\'s result to disk. A resume runs the command again, so to read it, clear the command, resume, then use `zo.machine.read_bytes`. With `init: image` and a command, a missing `/sbin/init` ends the generation as an exit stop, without `incompatible_image`. Write access to its script can run code as root at next boot.","title":"Command"},"clear_command":{"default":false,"description":"Remove the main process on the next resume.","title":"Clear Command","type":"boolean"},"environment":{"anyOf":[{"additionalProperties":{"maxLength":4096,"type":"string"},"maxProperties":64,"type":"object"},{"type":"null"}],"default":null,"description":"The environment that replaces the stored one; omit it to keep it. Environment variables set, exactly as written, in the boot process and every command run on the machine. Plain strings, not secrets: they are part of the machine\'s configuration, which anyone who can read the machine sees. Names are upper-case letters, digits and underscores, and reserved names such as `PATH` or ones starting with `ZO_` are refused; at most 64 variables of at most 4096 characters each. A variable here wins over a connection in `credentials` that sets the same name.","title":"Environment"},"credentials":{"anyOf":[{"items":{"maxLength":200,"minLength":1,"type":"string"},"maxItems":100,"type":"array"},{"type":"null"}],"default":null,"description":"The list that replaces the stored one; omit it to keep it. Connection IDs whose credentials the machine receives as environment variables, in the boot process and every command. Each slot of a listed connection sets the variable its definition names, with the variables the slot and the connection declare. The machine also needs a use grant on each connection (`zo.grant.create` with the machine as assignee); a listed connection without one delivers nothing. When two listed connections set the same variable, the later one in the list wins. At most 100 connections, each listed once.","title":"Credentials"}},"required":["machine_id","expected_revision"],"title":"MachineUpdateInput","type":"object","$defs":{"MachineLifecycleUpdate":{"additionalProperties":false,"description":"The timers a caller may change after create. Modal fixes them at\\nsandbox create, so a change takes effect at the next resume.","properties":{"idle_timeout_seconds":{"anyOf":[{"maximum":86400,"minimum":1,"type":"integer"},{"type":"null"}],"default":null,"title":"Idle Timeout Seconds"},"max_run_seconds":{"anyOf":[{"maximum":86400,"minimum":1,"type":"integer"},{"type":"null"}],"default":null,"title":"Max Run Seconds"}},"title":"MachineLifecycleUpdate","type":"object","required":[]}}}',
|
|
831
831
|
resultKind: "inline",
|
|
832
832
|
},
|
|
833
833
|
],
|
|
@@ -874,8 +874,8 @@ export const commandManifest = {
|
|
|
874
874
|
versions: [
|
|
875
875
|
{
|
|
876
876
|
version: 1,
|
|
877
|
-
description: "Import a registry image, pinned to its manifest digest, and return the image view.",
|
|
878
|
-
inputJson: '{"additionalProperties":false,"properties":{"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"visibility":{"default":"workspace","description":"`workspace` (default): every member can see and use it. `protected`: only you, and whoever you share it with; workspace-wide grants don\'t reach it. Fixed at creation.","enum":["workspace","protected"],"title":"Visibility","type":"string"},"workspace_id":{"title":"Workspace Id","type":"string"},"idempotency_key":{"maxLength":255,"minLength":1,"pattern":"^[!-~]{1,255}$","title":"Idempotency Key","type":"string"},"source":{"$ref":"#/$defs/RegistrySourceInput"}},"required":["display_name","workspace_id","idempotency_key","source"],"title":"MachineImageImportInput","type":"object","$defs":{"RegistrySourceInput":{"additionalProperties":false,"properties":{"kind":{"const":"registry","title":"Kind","type":"string"},"ref":{"maxLength":1024,"minLength":1,"pattern":"^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]{1,5})?/)?[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*(?:/[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*)*(?::[A-Za-z0-9_][A-Za-z0-9_.-]{0,127})?(?:@sha256:[0-9a-f]{64})?$","title":"Ref","type":"string"},"platform":{"const":"linux/amd64","default":"linux/amd64","title":"Platform","type":"string"}},"required":["kind","ref"],"title":"RegistrySourceInput","type":"object"}}}',
|
|
877
|
+
description: "Import a registry image, pinned to its manifest digest, and return the image view. Describe what this machine image is for in the user's terms.",
|
|
878
|
+
inputJson: '{"additionalProperties":false,"properties":{"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this machine image is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"visibility":{"default":"workspace","description":"`workspace` (default): every member can see and use it. `protected`: only you, and whoever you share it with; workspace-wide grants don\'t reach it. Fixed at creation.","enum":["workspace","protected"],"title":"Visibility","type":"string"},"workspace_id":{"title":"Workspace Id","type":"string"},"idempotency_key":{"maxLength":255,"minLength":1,"pattern":"^[!-~]{1,255}$","title":"Idempotency Key","type":"string"},"source":{"$ref":"#/$defs/RegistrySourceInput"}},"required":["display_name","workspace_id","idempotency_key","source"],"title":"MachineImageImportInput","type":"object","$defs":{"RegistrySourceInput":{"additionalProperties":false,"properties":{"kind":{"const":"registry","title":"Kind","type":"string"},"ref":{"maxLength":1024,"minLength":1,"pattern":"^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*(?::[0-9]{1,5})?/)?[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*(?:/[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*)*(?::[A-Za-z0-9_][A-Za-z0-9_.-]{0,127})?(?:@sha256:[0-9a-f]{64})?$","title":"Ref","type":"string"},"platform":{"const":"linux/amd64","default":"linux/amd64","title":"Platform","type":"string"}},"required":["kind","ref"],"title":"RegistrySourceInput","type":"object"}}}',
|
|
879
879
|
resultKind: "inline",
|
|
880
880
|
},
|
|
881
881
|
],
|
|
@@ -972,8 +972,8 @@ export const commandManifest = {
|
|
|
972
972
|
versions: [
|
|
973
973
|
{
|
|
974
974
|
version: 1,
|
|
975
|
-
description: "Create a schedule.",
|
|
976
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"rrule":{"maxLength":1000,"minLength":1,"title":"Rrule","type":"string"},"start_at":{"title":"Start At","type":"string"},"timezone":{"title":"Timezone","type":"string"},"data":{"additionalProperties":{"x-zo-json-value":true},"default":{},"title":"Data","type":"object"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","display_name","rrule","start_at","timezone"],"title":"ScheduleCreateInput","type":"object"}',
|
|
975
|
+
description: "Create a schedule. Describe what this schedule is for in the user's terms.",
|
|
976
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this schedule is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"rrule":{"maxLength":1000,"minLength":1,"title":"Rrule","type":"string"},"start_at":{"title":"Start At","type":"string"},"timezone":{"title":"Timezone","type":"string"},"data":{"additionalProperties":{"x-zo-json-value":true},"default":{},"title":"Data","type":"object"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","display_name","rrule","start_at","timezone"],"title":"ScheduleCreateInput","type":"object"}',
|
|
977
977
|
resultKind: "inline",
|
|
978
978
|
},
|
|
979
979
|
],
|
|
@@ -1022,7 +1022,7 @@ export const commandManifest = {
|
|
|
1022
1022
|
{
|
|
1023
1023
|
version: 1,
|
|
1024
1024
|
description: "Update a schedule.",
|
|
1025
|
-
inputJson: '{"additionalProperties":false,"properties":{"schedule_id":{"maxLength":200,"minLength":1,"title":"Schedule Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"rrule":{"maxLength":1000,"minLength":1,"title":"Rrule","type":"string"},"start_at":{"title":"Start At","type":"string"},"timezone":{"title":"Timezone","type":"string"},"data":{"additionalProperties":{"x-zo-json-value":true},"title":"Data","type":"object"},"lifecycle":{"enum":["active","paused"],"title":"Lifecycle","type":"string"}},"required":["schedule_id","expected_revision","display_name","rrule","start_at","timezone","data","lifecycle"],"title":"ScheduleUpdateInput","type":"object"}',
|
|
1025
|
+
inputJson: '{"additionalProperties":false,"properties":{"schedule_id":{"maxLength":200,"minLength":1,"title":"Schedule Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"anyOf":[{"maxLength":2000,"type":"string"},{"type":"null"}],"default":null,"description":"Describe what this schedule is for in the user\'s terms.","title":"Description"},"rrule":{"maxLength":1000,"minLength":1,"title":"Rrule","type":"string"},"start_at":{"title":"Start At","type":"string"},"timezone":{"title":"Timezone","type":"string"},"data":{"additionalProperties":{"x-zo-json-value":true},"title":"Data","type":"object"},"lifecycle":{"enum":["active","paused"],"title":"Lifecycle","type":"string"}},"required":["schedule_id","expected_revision","display_name","rrule","start_at","timezone","data","lifecycle"],"title":"ScheduleUpdateInput","type":"object"}',
|
|
1026
1026
|
resultKind: "inline",
|
|
1027
1027
|
},
|
|
1028
1028
|
],
|
|
@@ -1075,8 +1075,8 @@ export const commandManifest = {
|
|
|
1075
1075
|
},
|
|
1076
1076
|
{
|
|
1077
1077
|
version: 2,
|
|
1078
|
-
description: "Bind an event definition to a function entrypoint or a workflow's start run as a non-human execution principal, or to an Agent whose sessions receive each occurrence.",
|
|
1079
|
-
inputJson: '{"additionalProperties":false,"description":"Bind an event definition to a handler. ``handler_resource_type`` is\\n``function``, ``workflow`` or ``agent``. A Function target names\\n``handler_resource_id``, ``handler_entrypoint``, ``input_contract_version``,\\n``input_contract_kind`` and the ``execution_principal_id`` service account it\\nruns as. A workflow target names ``workflow_id`` and the same fields but\\n``handler_resource_id``: ``handler_entrypoint`` is ``start``, which begins a\\nnew run per occurrence with the envelope as its ``event`` input, and\\n``input_contract_version`` is 1, the contract of that input. An Agent\\ntarget names ``agent_id``, the ``agent_priority`` an occurrence enters a turn\\nwith (``queue``, ``steer`` or ``interrupt``), the ``agent_session_policy``\\nthat picks its session (``new``; ``fixed``, with ``agent_session_id``; or\\n``per_conversation``, for an event with a ``conversation_path``, keyed in\\n``agent_session_scope``, the event\'s ``<publisher>/<name>`` when omitted)\\nand optional ``agent_instructions`` shown with every occurrence. Fields of\\nthe other handler type are refused. Omit ``filter`` to receive every\\noccurrence.","properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"event_id":{"title":"Event Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"filter":{"anyOf":[{"discriminator":{"mapping":{"all":"#/$defs/All1","any":"#/$defs/Any1","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All1"},{"$ref":"#/$defs/Any1"}]},{"type":"null"}],"default":null,"title":"Filter"},"handler_resource_type":{"enum":["function","workflow","agent"],"title":"Handler Resource Type","type":"string"},"handler_resource_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Handler Resource Id"},"workflow_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Workflow Id"},"handler_entrypoint":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Handler Entrypoint"},"input_contract_version":{"anyOf":[{"exclusiveMinimum":0,"maximum":2147483647,"type":"integer"},{"type":"null"}],"default":null,"title":"Input Contract Version"},"input_contract_kind":{"anyOf":[{"$ref":"#/$defs/InputContractKind"},{"type":"null"}],"default":null},"execution_principal_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Execution Principal Id"},"agent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Agent Id"},"agent_priority":{"default":"queue","enum":["queue","steer","interrupt"],"title":"Agent Priority","type":"string"},"agent_session_policy":{"default":"new","enum":["new","fixed","per_conversation"],"title":"Agent Session Policy","type":"string"},"agent_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Agent Session Id"},"agent_session_scope":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Agent Session Scope"},"agent_instructions":{"anyOf":[{"maxLength":4096,"type":"string"},{"type":"null"}],"default":null,"title":"Agent Instructions"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","event_id","display_name","handler_resource_type"],"title":"SubscriptionCreateInputV2","type":"object","$defs":{"All1":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All2","any":"#/$defs/Any2","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All2"},{"$ref":"#/$defs/Any2"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All1","type":"object"},"All2":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All3","any":"#/$defs/Any3","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All3"},{"$ref":"#/$defs/Any3"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All2","type":"object"},"All3":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All3","type":"object"},"Any1":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All2","any":"#/$defs/Any2","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All2"},{"$ref":"#/$defs/Any2"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any1","type":"object"},"Any2":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All3","any":"#/$defs/Any3","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All3"},{"$ref":"#/$defs/Any3"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any2","type":"object"},"Any3":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any3","type":"object"},"EqFilter":{"additionalProperties":false,"properties":{"op":{"const":"eq","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"},"value":{"x-zo-json-value":true}},"required":["op","path","value"],"title":"EqFilter","type":"object"},"ExistsFilter":{"additionalProperties":false,"properties":{"op":{"const":"exists","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"}},"required":["op","path"],"title":"ExistsFilter","type":"object"},"InFilter":{"additionalProperties":false,"properties":{"op":{"const":"in","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"},"values":{"items":{"x-zo-json-value":true},"maxItems":32,"minItems":1,"title":"Values","type":"array"}},"required":["op","path","values"],"title":"InFilter","type":"object"},"InputContractKind":{"enum":["exact_event","generic_envelope"],"type":"string"}}}',
|
|
1078
|
+
description: "Bind an event definition to a function entrypoint or a workflow's start run as a non-human execution principal, or to an Agent whose sessions receive each occurrence. Describe what this subscription is for in the user's terms.",
|
|
1079
|
+
inputJson: '{"additionalProperties":false,"description":"Bind an event definition to a handler. ``handler_resource_type`` is\\n``function``, ``workflow`` or ``agent``. A Function target names\\n``handler_resource_id``, ``handler_entrypoint``, ``input_contract_version``,\\n``input_contract_kind`` and the ``execution_principal_id`` service account it\\nruns as. A workflow target names ``workflow_id`` and the same fields but\\n``handler_resource_id``: ``handler_entrypoint`` is ``start``, which begins a\\nnew run per occurrence with the envelope as its ``event`` input, and\\n``input_contract_version`` is 1, the contract of that input. An Agent\\ntarget names ``agent_id``, the ``agent_priority`` an occurrence enters a turn\\nwith (``queue``, ``steer`` or ``interrupt``), the ``agent_session_policy``\\nthat picks its session (``new``; ``fixed``, with ``agent_session_id``; or\\n``per_conversation``, for an event with a ``conversation_path``, keyed in\\n``agent_session_scope``, the event\'s ``<publisher>/<name>`` when omitted)\\nand optional ``agent_instructions`` shown with every occurrence. Fields of\\nthe other handler type are refused. Omit ``filter`` to receive every\\noccurrence.","properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"event_id":{"title":"Event Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this subscription is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"filter":{"anyOf":[{"discriminator":{"mapping":{"all":"#/$defs/All1","any":"#/$defs/Any1","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All1"},{"$ref":"#/$defs/Any1"}]},{"type":"null"}],"default":null,"title":"Filter"},"handler_resource_type":{"enum":["function","workflow","agent"],"title":"Handler Resource Type","type":"string"},"handler_resource_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Handler Resource Id"},"workflow_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Workflow Id"},"handler_entrypoint":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Handler Entrypoint"},"input_contract_version":{"anyOf":[{"exclusiveMinimum":0,"maximum":2147483647,"type":"integer"},{"type":"null"}],"default":null,"title":"Input Contract Version"},"input_contract_kind":{"anyOf":[{"$ref":"#/$defs/InputContractKind"},{"type":"null"}],"default":null},"execution_principal_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Execution Principal Id"},"agent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Agent Id"},"agent_priority":{"default":"queue","enum":["queue","steer","interrupt"],"title":"Agent Priority","type":"string"},"agent_session_policy":{"default":"new","enum":["new","fixed","per_conversation"],"title":"Agent Session Policy","type":"string"},"agent_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Agent Session Id"},"agent_session_scope":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Agent Session Scope"},"agent_instructions":{"anyOf":[{"maxLength":4096,"type":"string"},{"type":"null"}],"default":null,"title":"Agent Instructions"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","event_id","display_name","handler_resource_type"],"title":"SubscriptionCreateInputV2","type":"object","$defs":{"All1":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All2","any":"#/$defs/Any2","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All2"},{"$ref":"#/$defs/Any2"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All1","type":"object"},"All2":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All3","any":"#/$defs/Any3","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All3"},{"$ref":"#/$defs/Any3"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All2","type":"object"},"All3":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All3","type":"object"},"Any1":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All2","any":"#/$defs/Any2","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All2"},{"$ref":"#/$defs/Any2"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any1","type":"object"},"Any2":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All3","any":"#/$defs/Any3","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All3"},{"$ref":"#/$defs/Any3"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any2","type":"object"},"Any3":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any3","type":"object"},"EqFilter":{"additionalProperties":false,"properties":{"op":{"const":"eq","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"},"value":{"x-zo-json-value":true}},"required":["op","path","value"],"title":"EqFilter","type":"object"},"ExistsFilter":{"additionalProperties":false,"properties":{"op":{"const":"exists","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"}},"required":["op","path"],"title":"ExistsFilter","type":"object"},"InFilter":{"additionalProperties":false,"properties":{"op":{"const":"in","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"},"values":{"items":{"x-zo-json-value":true},"maxItems":32,"minItems":1,"title":"Values","type":"array"}},"required":["op","path","values"],"title":"InFilter","type":"object"},"InputContractKind":{"enum":["exact_event","generic_envelope"],"type":"string"}}}',
|
|
1080
1080
|
resultKind: "inline",
|
|
1081
1081
|
},
|
|
1082
1082
|
],
|
|
@@ -1144,7 +1144,7 @@ export const commandManifest = {
|
|
|
1144
1144
|
{
|
|
1145
1145
|
version: 2,
|
|
1146
1146
|
description: "Replace a subscription's configuration and lifecycle at the expected revision.",
|
|
1147
|
-
inputJson: '{"additionalProperties":false,"description":"
|
|
1147
|
+
inputJson: '{"additionalProperties":false,"description":"Replace create fields except workspace, event and optional description.\\nA new event definition or version requires a new subscription.\\nOmitted or null description keeps its value. ``lifecycle``: ``active``\\nresumes a paused or suspended subscription, ``paused`` pauses it;\\n``zo.subscription.delete`` retires. ``handler_resource_type`` must be the\\nsubscription\'s own: a different handler type is a new subscription.","properties":{"subscription_id":{"title":"Subscription Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"anyOf":[{"maxLength":2000,"type":"string"},{"type":"null"}],"default":null,"description":"Describe what this subscription is for in the user\'s terms.","title":"Description"},"filter":{"anyOf":[{"discriminator":{"mapping":{"all":"#/$defs/All1","any":"#/$defs/Any1","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All1"},{"$ref":"#/$defs/Any1"}]},{"type":"null"}],"default":null,"title":"Filter"},"handler_resource_type":{"enum":["function","workflow","agent"],"title":"Handler Resource Type","type":"string"},"handler_resource_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Handler Resource Id"},"workflow_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Workflow Id"},"handler_entrypoint":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Handler Entrypoint"},"input_contract_version":{"anyOf":[{"exclusiveMinimum":0,"maximum":2147483647,"type":"integer"},{"type":"null"}],"default":null,"title":"Input Contract Version"},"input_contract_kind":{"anyOf":[{"$ref":"#/$defs/InputContractKind"},{"type":"null"}],"default":null},"execution_principal_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Execution Principal Id"},"agent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Agent Id"},"agent_priority":{"default":"queue","enum":["queue","steer","interrupt"],"title":"Agent Priority","type":"string"},"agent_session_policy":{"default":"new","enum":["new","fixed","per_conversation"],"title":"Agent Session Policy","type":"string"},"agent_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"default":null,"title":"Agent Session Id"},"agent_session_scope":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Agent Session Scope"},"agent_instructions":{"anyOf":[{"maxLength":4096,"type":"string"},{"type":"null"}],"default":null,"title":"Agent Instructions"},"lifecycle":{"enum":["active","paused"],"title":"Lifecycle","type":"string"}},"required":["subscription_id","expected_revision","display_name","handler_resource_type","lifecycle"],"title":"SubscriptionUpdateInputV2","type":"object","$defs":{"All1":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All2","any":"#/$defs/Any2","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All2"},{"$ref":"#/$defs/Any2"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All1","type":"object"},"All2":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All3","any":"#/$defs/Any3","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All3"},{"$ref":"#/$defs/Any3"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All2","type":"object"},"All3":{"additionalProperties":false,"properties":{"op":{"const":"all","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"All3","type":"object"},"Any1":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All2","any":"#/$defs/Any2","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All2"},{"$ref":"#/$defs/Any2"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any1","type":"object"},"Any2":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"all":"#/$defs/All3","any":"#/$defs/Any3","eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"},{"$ref":"#/$defs/All3"},{"$ref":"#/$defs/Any3"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any2","type":"object"},"Any3":{"additionalProperties":false,"properties":{"op":{"const":"any","title":"Op","type":"string"},"filters":{"items":{"discriminator":{"mapping":{"eq":"#/$defs/EqFilter","exists":"#/$defs/ExistsFilter","in":"#/$defs/InFilter"},"propertyName":"op"},"oneOf":[{"$ref":"#/$defs/EqFilter"},{"$ref":"#/$defs/InFilter"},{"$ref":"#/$defs/ExistsFilter"}]},"maxItems":32,"minItems":1,"title":"Filters","type":"array"}},"required":["op","filters"],"title":"Any3","type":"object"},"EqFilter":{"additionalProperties":false,"properties":{"op":{"const":"eq","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"},"value":{"x-zo-json-value":true}},"required":["op","path","value"],"title":"EqFilter","type":"object"},"ExistsFilter":{"additionalProperties":false,"properties":{"op":{"const":"exists","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"}},"required":["op","path"],"title":"ExistsFilter","type":"object"},"InFilter":{"additionalProperties":false,"properties":{"op":{"const":"in","title":"Op","type":"string"},"path":{"maxLength":256,"minLength":1,"pattern":"^(?:/[^/]*)+$","title":"Path","type":"string"},"values":{"items":{"x-zo-json-value":true},"maxItems":32,"minItems":1,"title":"Values","type":"array"}},"required":["op","path","values"],"title":"InFilter","type":"object"},"InputContractKind":{"enum":["exact_event","generic_envelope"],"type":"string"}}}',
|
|
1148
1148
|
resultKind: "inline",
|
|
1149
1149
|
},
|
|
1150
1150
|
],
|
|
@@ -1448,8 +1448,8 @@ export const commandManifest = {
|
|
|
1448
1448
|
versions: [
|
|
1449
1449
|
{
|
|
1450
1450
|
version: 1,
|
|
1451
|
-
description: "Create a Website address in a workspace.",
|
|
1452
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"slug":{"pattern":"^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$","title":"Slug","type":"string"},"display_name":{"maxLength":200,"minLength":1,"title":"Display Name","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","slug","display_name"],"title":"WebsiteCreateInput","type":"object"}',
|
|
1451
|
+
description: "Create a Website address in a workspace. Describe what this Website is for in the user's terms.",
|
|
1452
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"maxLength":200,"minLength":1,"title":"Workspace Id","type":"string"},"slug":{"pattern":"^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$","title":"Slug","type":"string"},"display_name":{"maxLength":200,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this Website is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","slug","display_name"],"title":"WebsiteCreateInput","type":"object"}',
|
|
1453
1453
|
resultKind: "inline",
|
|
1454
1454
|
},
|
|
1455
1455
|
],
|
|
@@ -1498,7 +1498,7 @@ export const commandManifest = {
|
|
|
1498
1498
|
{
|
|
1499
1499
|
version: 1,
|
|
1500
1500
|
description: "Update a Website display name or custom hostname.",
|
|
1501
|
-
inputJson: '{"additionalProperties":false,"properties":{"website_id":{"maxLength":200,"minLength":1,"title":"Website Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Display Name"},"custom_hostname":{"anyOf":[{"$ref":"#/$defs/CustomHostnameChange"},{"type":"null"}],"default":null}},"required":["website_id","expected_revision"],"title":"WebsiteUpdateInput","type":"object","$defs":{"CustomHostnameChange":{"additionalProperties":false,"properties":{"hostname":{"anyOf":[{"maxLength":253,"minLength":4,"type":"string"},{"type":"null"}],"title":"Hostname"}},"required":["hostname"],"title":"CustomHostnameChange","type":"object"}}}',
|
|
1501
|
+
inputJson: '{"additionalProperties":false,"properties":{"website_id":{"maxLength":200,"minLength":1,"title":"Website Id","type":"string"},"expected_revision":{"exclusiveMinimum":0,"maximum":9007199254740991,"title":"Expected Revision","type":"integer"},"display_name":{"anyOf":[{"maxLength":200,"minLength":1,"type":"string"},{"type":"null"}],"default":null,"title":"Display Name"},"description":{"anyOf":[{"maxLength":2000,"type":"string"},{"type":"null"}],"default":null,"description":"Describe what this Website is for in the user\'s terms.","title":"Description"},"custom_hostname":{"anyOf":[{"$ref":"#/$defs/CustomHostnameChange"},{"type":"null"}],"default":null}},"required":["website_id","expected_revision"],"title":"WebsiteUpdateInput","type":"object","$defs":{"CustomHostnameChange":{"additionalProperties":false,"properties":{"hostname":{"anyOf":[{"maxLength":253,"minLength":4,"type":"string"},{"type":"null"}],"title":"Hostname"}},"required":["hostname"],"title":"CustomHostnameChange","type":"object"}}}',
|
|
1502
1502
|
resultKind: "inline",
|
|
1503
1503
|
},
|
|
1504
1504
|
],
|
|
@@ -1618,8 +1618,8 @@ export const commandManifest = {
|
|
|
1618
1618
|
versions: [
|
|
1619
1619
|
{
|
|
1620
1620
|
version: 1,
|
|
1621
|
-
description: "Create a workflow in a workspace.",
|
|
1622
|
-
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","display_name"],"title":"WorkflowCreateInput","type":"object"}',
|
|
1621
|
+
description: "Create a workflow in a workspace. Describe what this workflow is for in the user's terms.",
|
|
1622
|
+
inputJson: '{"additionalProperties":false,"properties":{"workspace_id":{"title":"Workspace Id","type":"string"},"display_name":{"maxLength":120,"minLength":1,"title":"Display Name","type":"string"},"description":{"default":"","description":"Describe what this workflow is for in the user\'s terms.","maxLength":2000,"title":"Description","type":"string"},"visibility":{"default":"workspace","enum":["workspace","protected"],"title":"Visibility","type":"string"}},"required":["workspace_id","display_name"],"title":"WorkflowCreateInput","type":"object"}',
|
|
1623
1623
|
resultKind: "inline",
|
|
1624
1624
|
},
|
|
1625
1625
|
],
|
package/dist/http.d.ts
CHANGED
|
@@ -3,7 +3,11 @@ import { CliError } from "./errors.ts";
|
|
|
3
3
|
export declare function systemApiFailure(response: Response, raw: string | Uint8Array, operation: string): SystemAPIError;
|
|
4
4
|
export declare class RequestFailure extends CliError {
|
|
5
5
|
readonly ambiguous: boolean;
|
|
6
|
-
|
|
6
|
+
/** The HTTP status when the server answered; absent for transport failures. */
|
|
7
|
+
readonly status?: number | undefined;
|
|
8
|
+
constructor(ambiguous: boolean, code?: string, exitCode?: number,
|
|
9
|
+
/** The HTTP status when the server answered; absent for transport failures. */
|
|
10
|
+
status?: number | undefined);
|
|
7
11
|
}
|
|
8
12
|
export declare function requestJson(url: string, init?: RequestInit, fetcher?: typeof fetch, options?: {
|
|
9
13
|
timeoutMs?: number;
|
package/dist/http.js
CHANGED
|
@@ -46,11 +46,15 @@ export function systemApiFailure(response, raw, operation) {
|
|
|
46
46
|
}
|
|
47
47
|
export class RequestFailure extends CliError {
|
|
48
48
|
ambiguous;
|
|
49
|
-
|
|
49
|
+
status;
|
|
50
|
+
constructor(ambiguous, code = "transport_error", exitCode = 5,
|
|
51
|
+
/** The HTTP status when the server answered; absent for transport failures. */
|
|
52
|
+
status) {
|
|
50
53
|
super(code === "invalid_grant"
|
|
51
54
|
? "Your sign-in ended. Run zo login."
|
|
52
55
|
: "The authentication request failed. Try again or run zo login.", exitCode, code);
|
|
53
56
|
this.ambiguous = ambiguous;
|
|
57
|
+
this.status = status;
|
|
54
58
|
}
|
|
55
59
|
}
|
|
56
60
|
export async function requestJson(url, init = {}, fetcher = fetch, options = {}) {
|
|
@@ -106,6 +110,10 @@ export async function requestJson(url, init = {}, fetcher = fetch, options = {})
|
|
|
106
110
|
body = JSON.parse(raw);
|
|
107
111
|
}
|
|
108
112
|
catch {
|
|
113
|
+
// Cloudflare's edge rate limits answer 429 with a non-JSON page before the
|
|
114
|
+
// worker runs; the status alone says the request was not processed.
|
|
115
|
+
if (response.status === 429)
|
|
116
|
+
throw new RequestFailure(true, "temporarily_unavailable", 5, 429);
|
|
109
117
|
throw new RequestFailure(false, "invalid_response");
|
|
110
118
|
}
|
|
111
119
|
if (!response.ok) {
|
|
@@ -118,7 +126,7 @@ export async function requestJson(url, init = {}, fetcher = fetch, options = {})
|
|
|
118
126
|
? 3
|
|
119
127
|
: response.status === 403
|
|
120
128
|
? 4
|
|
121
|
-
: 5);
|
|
129
|
+
: 5, response.status);
|
|
122
130
|
}
|
|
123
131
|
return body;
|
|
124
132
|
}
|
package/dist/login.d.ts
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
export declare const DEVICE_CODE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
2
|
+
export interface LoginPrompt {
|
|
3
|
+
url: string;
|
|
4
|
+
userCode: string;
|
|
5
|
+
/** False when the CLI won't open a browser: --no-browser, SSH or no display. */
|
|
6
|
+
browser: boolean;
|
|
7
|
+
}
|
|
1
8
|
export interface LoginOptions {
|
|
2
9
|
noBrowser?: boolean;
|
|
3
|
-
timeoutMs?: number;
|
|
4
10
|
signal?: AbortSignal;
|
|
5
|
-
|
|
11
|
+
platform?: NodeJS.Platform;
|
|
12
|
+
announce?: (prompt: LoginPrompt) => void;
|
|
6
13
|
openBrowser?: (url: string) => Promise<void>;
|
|
7
14
|
}
|
|
8
|
-
export interface
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
export interface DeviceAuthorization {
|
|
16
|
+
deviceCode: string;
|
|
17
|
+
userCode: string;
|
|
18
|
+
url: string;
|
|
19
|
+
expiresInMs: number;
|
|
20
|
+
intervalMs: number;
|
|
12
21
|
}
|
|
13
22
|
export declare function openBrowser(url: string): Promise<void>;
|
|
14
|
-
|
|
23
|
+
/**
|
|
24
|
+
* A browser opened over SSH, or with no display, lands on the wrong machine or
|
|
25
|
+
* nowhere. xdg-open needs a display on every system other than macOS.
|
|
26
|
+
*/
|
|
27
|
+
export declare function browserAvailable(env: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
|
|
28
|
+
export declare function pause(ms: number, signal?: AbortSignal | null): Promise<void>;
|
|
29
|
+
export declare function parseDeviceAuthorization(raw: unknown, issuer: string): DeviceAuthorization;
|
|
30
|
+
export declare function deviceAuthorization(issuer: string, audience: string, clientId: string, fetcher: typeof fetch, signal?: AbortSignal): Promise<DeviceAuthorization>;
|
package/dist/login.js
CHANGED
|
@@ -1,102 +1,93 @@
|
|
|
1
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
-
import { createServer } from "node:http";
|
|
3
1
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { CliError } from "./errors.js";
|
|
2
|
+
import { CliError, record, throwIfInterrupted } from "./errors.js";
|
|
3
|
+
import { requestJson, RequestFailure } from "./http.js";
|
|
4
|
+
export const DEVICE_CODE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
5
5
|
export async function openBrowser(url) {
|
|
6
6
|
await new Promise((resolve, reject) => {
|
|
7
7
|
const child = spawn(process.platform === "darwin" ? "open" : "xdg-open", [url], { stdio: "ignore", detached: true });
|
|
8
8
|
child.unref();
|
|
9
|
-
child.once("error",
|
|
10
|
-
child.once("exit", (status) => status === 0
|
|
11
|
-
? resolve()
|
|
12
|
-
: reject(new CliError("Could not open a browser. Retry with --no-browser.")));
|
|
9
|
+
child.once("error", reject);
|
|
10
|
+
child.once("exit", (status) => status === 0 ? resolve() : reject(new Error("Browser opener failed.")));
|
|
13
11
|
});
|
|
14
12
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
const params = url.searchParams;
|
|
37
|
-
const keys = [...params.keys()];
|
|
38
|
-
const valid = !accepted &&
|
|
39
|
-
request.method === "GET" &&
|
|
40
|
-
url.pathname === "/callback" &&
|
|
41
|
-
keys.length === new Set(keys).size &&
|
|
42
|
-
params.get("state") === state &&
|
|
43
|
-
params.get("iss") === issuer &&
|
|
44
|
-
params.has("code") !== params.has("error");
|
|
45
|
-
response.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
46
|
-
response.setHeader("Cache-Control", "no-store");
|
|
47
|
-
if (!valid) {
|
|
48
|
-
response.writeHead(400).end("Invalid callback.");
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
accepted = true;
|
|
52
|
-
response.end("You may close this window and return to Zo.");
|
|
53
|
-
if (params.has("error"))
|
|
54
|
-
fail(new CliError("Authorization was denied. Run zo login to try again.", 4, "access_denied"));
|
|
55
|
-
else {
|
|
56
|
-
const code = params.get("code");
|
|
57
|
-
if (code)
|
|
58
|
-
complete(code);
|
|
59
|
-
else
|
|
60
|
-
fail(new CliError("Authorization returned an empty code.", 3, "invalid_response"));
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
server.requestTimeout = 5_000;
|
|
64
|
-
server.headersTimeout = 5_000;
|
|
65
|
-
await new Promise((resolve, reject) => {
|
|
66
|
-
server.once("error", reject);
|
|
67
|
-
server.listen(0, "127.0.0.1", resolve);
|
|
13
|
+
/**
|
|
14
|
+
* A browser opened over SSH, or with no display, lands on the wrong machine or
|
|
15
|
+
* nowhere. xdg-open needs a display on every system other than macOS.
|
|
16
|
+
*/
|
|
17
|
+
export function browserAvailable(env, platform = process.platform) {
|
|
18
|
+
if (env.SSH_CONNECTION || env.SSH_TTY)
|
|
19
|
+
return false;
|
|
20
|
+
return platform === "darwin" || !!env.DISPLAY || !!env.WAYLAND_DISPLAY;
|
|
21
|
+
}
|
|
22
|
+
export function pause(ms, signal) {
|
|
23
|
+
throwIfInterrupted(signal);
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const abort = () => {
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
reject(new CliError("Interrupted.", 130, "interrupted"));
|
|
28
|
+
};
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
signal?.removeEventListener("abort", abort);
|
|
31
|
+
resolve();
|
|
32
|
+
}, ms);
|
|
33
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
68
34
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
35
|
+
}
|
|
36
|
+
function seconds(value, maximum) {
|
|
37
|
+
return typeof value === "number" &&
|
|
38
|
+
Number.isSafeInteger(value) &&
|
|
39
|
+
value > 0 &&
|
|
40
|
+
value <= maximum
|
|
41
|
+
? value
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
44
|
+
export function parseDeviceAuthorization(raw, issuer) {
|
|
45
|
+
const invalid = () => new CliError("The sign-in service returned an invalid response.", 5, "invalid_response");
|
|
46
|
+
if (!record(raw) ||
|
|
47
|
+
typeof raw.device_code !== "string" ||
|
|
48
|
+
!/^[A-Za-z0-9._~-]{1,512}$/.test(raw.device_code) ||
|
|
49
|
+
typeof raw.user_code !== "string" ||
|
|
50
|
+
!/^[A-Z0-9]{1,8}(?:-[A-Z0-9]{1,8}){0,3}$/.test(raw.user_code) ||
|
|
51
|
+
typeof raw.verification_uri_complete !== "string")
|
|
52
|
+
throw invalid();
|
|
53
|
+
const expiresIn = seconds(raw.expires_in, 3_600);
|
|
54
|
+
const interval = raw.interval === undefined ? 2 : seconds(raw.interval, 60);
|
|
55
|
+
if (expiresIn === undefined || interval === undefined)
|
|
56
|
+
throw invalid();
|
|
57
|
+
let url;
|
|
58
|
+
try {
|
|
59
|
+
url = new URL(raw.verification_uri_complete);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw invalid();
|
|
63
|
+
}
|
|
64
|
+
// The URL goes to the system opener; only the issuer's own scheme is safe.
|
|
65
|
+
// Production is https; the local test issuer is http.
|
|
66
|
+
if (url.protocol !== new URL(issuer).protocol || url.username || url.password)
|
|
67
|
+
throw invalid();
|
|
68
|
+
return {
|
|
69
|
+
deviceCode: raw.device_code,
|
|
70
|
+
userCode: raw.user_code,
|
|
71
|
+
url: url.href,
|
|
72
|
+
expiresInMs: expiresIn * 1000,
|
|
73
|
+
intervalMs: interval * 1000,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export async function deviceAuthorization(issuer, audience, clientId, fetcher, signal) {
|
|
77
|
+
let raw;
|
|
86
78
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
void (options.openBrowser ?? openBrowser)(authorize.href).catch(fail);
|
|
93
|
-
}
|
|
94
|
-
return { code: await received, verifier, redirectUri };
|
|
79
|
+
raw = await requestJson(`${issuer}/zo-system-api/oauth/device_authorization`, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
signal,
|
|
82
|
+
body: new URLSearchParams({ client_id: clientId, resource: audience }),
|
|
83
|
+
}, fetcher);
|
|
95
84
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error instanceof RequestFailure && error.status === 429)
|
|
87
|
+
throw new CliError("Too many sign-in attempts from this network. Wait a minute, then run zo login again.", 5, "rate_limited");
|
|
88
|
+
if (error instanceof RequestFailure && error.code === "unauthorized_client")
|
|
89
|
+
throw new CliError("This environment does not allow Zo CLI sign-in yet.", 5, "unauthorized_client");
|
|
90
|
+
throw error;
|
|
101
91
|
}
|
|
92
|
+
return parseDeviceAuthorization(raw, issuer);
|
|
102
93
|
}
|
package/dist/main.js
CHANGED
|
@@ -26,7 +26,7 @@ Use --profile to keep separate sign-ins. New profiles use production.
|
|
|
26
26
|
ZO_SYSTEM_API_ACCESS_TOKEN overrides saved credentials; ZO_WORKSPACE_ID selects a workspace.
|
|
27
27
|
`;
|
|
28
28
|
const localHelp = {
|
|
29
|
-
login: "Usage: zo login [--profile <name>] [--workspace <id>] [--no-browser]\nPrint
|
|
29
|
+
login: "Usage: zo login [--profile <name>] [--workspace <id>] [--no-browser]\nPrint a sign-in URL and code, open your browser, and wait for approval.\nNew profiles use production. Browser consent approves workspaces and identities.\n--no-browser prints the URL without opening a browser; approve it on any device.\nInternal testing: --environment staging explicitly binds a separate profile to staging.\n",
|
|
30
30
|
logout: "Usage: zo logout [--profile <name>] [--local-only]\nRevoke the saved sign-in and pending replaced sign-ins. --local-only removes local credentials without revoking server access.\n",
|
|
31
31
|
auth: "Usage: zo auth status | token [--headers]\nStatus shows the current identity; token explicitly prints an access token.\n",
|
|
32
32
|
"auth status": "Usage: zo auth status [--profile <name>] [--workspace <id>] [--json]\nShow the approving person, sign-in expiry and effective identity in the selected workspace.\n",
|
|
@@ -41,6 +41,16 @@ const localHelp = {
|
|
|
41
41
|
rpc: "Usage: zo rpc <action> [--input <json> | --input-file <path|->] [--version <integer>]\n --query <json> Declared list-query options; one page per call\n --idempotency-key <key> Envelope key where the action supports it\n --preview Print the request without invoking\n --envelope Print the complete success envelope\n --json Print exact result JSON\n --profile <name> --workspace <id>\nThe live catalog supplies the default version. RPC preserves supplied inputs. Invocations are never retried.\n",
|
|
42
42
|
completion: "Usage: zo completion bash|zsh|fish\nPrint completion from installed metadata without credentials or network requests.\n",
|
|
43
43
|
};
|
|
44
|
+
function identity(session, workspace) {
|
|
45
|
+
const { type, id } = workspace.subject;
|
|
46
|
+
if (type === "user" &&
|
|
47
|
+
session.approving_subject?.type === "user" &&
|
|
48
|
+
session.approving_subject.id === id)
|
|
49
|
+
return "as you";
|
|
50
|
+
if (type === "service_account")
|
|
51
|
+
return `as service account ${safeText(id)}`;
|
|
52
|
+
return `as ${type} ${safeText(id)}`;
|
|
53
|
+
}
|
|
44
54
|
async function showHelp(args, stdout) {
|
|
45
55
|
if (!args.length) {
|
|
46
56
|
stdout.write(help);
|
|
@@ -121,19 +131,17 @@ export async function run(argv = process.argv.slice(2), runtime = {}) {
|
|
|
121
131
|
const login = await auth.login({
|
|
122
132
|
noBrowser: parsed.flags.has("no-browser"),
|
|
123
133
|
signal,
|
|
124
|
-
announce: (url) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
!options.json &&
|
|
128
|
-
env.NO_COLOR === undefined &&
|
|
129
|
-
env.TERM !== "dumb";
|
|
130
|
-
stderr.write(dim ? `\u001b[2m${message}\u001b[22m` : message);
|
|
131
|
-
},
|
|
134
|
+
announce: ({ url, userCode, browser }) => stderr.write(`${browser
|
|
135
|
+
? "Opening your browser to sign in. If it doesn't open, visit:"
|
|
136
|
+
: "To sign in, visit this URL on any device:"}\n\n ${url}\n\nCode: ${userCode}. Approve only if your browser shows the same code.\nWaiting for approval… (Ctrl-C to cancel)\n`),
|
|
132
137
|
});
|
|
133
|
-
stderr.write(
|
|
138
|
+
stderr.write(`\nApproved in the browser. Sign-in saved for profile ${profile.name}.\n`);
|
|
134
139
|
if (login.cleanupPending)
|
|
135
140
|
stderr.write("A previous sign-in could not be revoked. Cleanup remains saved for the next login; the current sign-in is active. You can revoke the previous sign-in in Authorized apps.\n");
|
|
136
141
|
const session = await auth.session();
|
|
142
|
+
// Always list the approved workspaces, so a sign-in someone else
|
|
143
|
+
// approved shows up as workspaces or identities you don't recognize.
|
|
144
|
+
session.workspaces.forEach((workspace, index) => stderr.write(`${index + 1}. ${safeText(workspace.name)} (${workspace.workspace_id}), ${identity(session, workspace)}\n`));
|
|
137
145
|
const desired = options.workspace ?? env.ZO_WORKSPACE_ID ?? profile.workspaceId;
|
|
138
146
|
let chosen;
|
|
139
147
|
if (options.workspace !== undefined)
|
|
@@ -152,7 +160,6 @@ export async function run(argv = process.argv.slice(2), runtime = {}) {
|
|
|
152
160
|
process.stdin.isTTY &&
|
|
153
161
|
stderr.isTTY &&
|
|
154
162
|
session.workspaces.length > 0) {
|
|
155
|
-
session.workspaces.forEach((workspace, index) => stderr.write(`${index + 1}. ${safeText(workspace.name)} (${workspace.workspace_id})\n`));
|
|
156
163
|
const input = createInterface({
|
|
157
164
|
input: process.stdin,
|
|
158
165
|
output: process.stderr,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zocomputer/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Public Zo command line client",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"node": "^22.23.4 || ^24.22.1 || ^26.13.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@zocomputer/system-api": "0.1.
|
|
17
|
+
"@zocomputer/system-api": "0.1.2"
|
|
18
18
|
},
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public",
|