withruntime 0.11.2 → 0.14.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/BLAXEL.md +2 -2
- package/COMPATIBILITY.md +74 -9
- package/DAYTONA.md +33 -5
- package/E2B.md +85 -24
- package/README.md +11 -10
- package/README.src.md +10 -9
- package/VERCEL.md +43 -5
- package/compatibility-lock.json +58 -49
- package/dist/billing-cli.d.ts +1 -1
- package/dist/billing-cli.js +85 -5
- package/dist/blaxel/errors.d.ts +14 -0
- package/dist/blaxel/errors.js +29 -0
- package/dist/blaxel/index.d.ts +2 -2
- package/dist/blaxel/index.js +4 -4
- package/dist/blaxel/interpreter.d.ts +2 -5
- package/dist/blaxel/sandbox.d.ts +15 -6
- package/dist/blaxel/sandbox.js +64 -8
- package/dist/blaxel/snapshot.d.ts +4 -0
- package/dist/blaxel/snapshot.js +4 -0
- package/dist/cli/logs.d.ts +21 -0
- package/dist/cli/logs.js +188 -0
- package/dist/cli-extras.d.ts +3 -3
- package/dist/cli-extras.js +17 -12
- package/dist/cli-words.d.ts +10 -1
- package/dist/cli-words.js +18 -0
- package/dist/cli.d.ts +22 -3
- package/dist/cli.js +647 -273
- package/dist/client.d.ts +2 -4
- package/dist/client.js +27 -11
- package/dist/cloudflare/errors.d.ts +143 -0
- package/dist/cloudflare/errors.js +167 -0
- package/dist/cloudflare/index.d.ts +175 -6
- package/dist/cloudflare/index.js +416 -26
- package/dist/cloudflare/interpreter.d.ts +119 -0
- package/dist/cloudflare/interpreter.js +223 -0
- package/dist/cloudflare/streams.d.ts +38 -0
- package/dist/cloudflare/streams.js +145 -0
- package/dist/cloudflare/watch.d.ts +9 -0
- package/dist/cloudflare/watch.js +24 -0
- package/dist/codesandbox/index.d.ts +216 -28
- package/dist/codesandbox/index.js +478 -78
- package/dist/compat/core.d.ts +18 -0
- package/dist/compat/core.js +29 -0
- package/dist/compat/files.d.ts +1 -0
- package/dist/compat/files.js +25 -5
- package/dist/credentials.d.ts +3 -0
- package/dist/credentials.js +15 -0
- package/dist/daytona/computer-use.d.ts +13 -4
- package/dist/daytona/computer-use.js +66 -8
- package/dist/daytona/daytona.d.ts +7 -1
- package/dist/daytona/daytona.js +31 -4
- package/dist/daytona/errors.d.ts +11 -0
- package/dist/daytona/errors.js +18 -0
- package/dist/daytona/filesystem.js +2 -1
- package/dist/daytona/image.d.ts +13 -9
- package/dist/daytona/image.js +18 -12
- package/dist/daytona/index.d.ts +1 -1
- package/dist/daytona/sandbox.d.ts +8 -2
- package/dist/daytona/sandbox.js +16 -2
- package/dist/domains/index.d.ts +9 -0
- package/dist/domains/index.js +10 -0
- package/dist/e2b/commands.d.ts +1 -1
- package/dist/e2b/commands.js +6 -7
- package/dist/e2b/errors.d.ts +17 -0
- package/dist/e2b/errors.js +40 -1
- package/dist/e2b/index.d.ts +2 -2
- package/dist/e2b/index.js +1 -1
- package/dist/e2b/sandbox.d.ts +28 -22
- package/dist/e2b/sandbox.js +34 -8
- package/dist/e2b/unsupported.js +1 -1
- package/dist/errors.d.ts +11 -2
- package/dist/errors.js +17 -5
- package/dist/freestyle/index.d.ts +285 -37
- package/dist/freestyle/index.js +656 -144
- package/dist/identity.d.ts +3 -0
- package/dist/identity.js +27 -0
- package/dist/images/index.d.ts +9 -0
- package/dist/images/index.js +10 -0
- package/dist/index.d.ts +3 -1
- package/dist/ips/index.d.ts +9 -0
- package/dist/ips/index.js +10 -0
- package/dist/jobs/index.d.ts +9 -0
- package/dist/jobs/index.js +10 -0
- package/dist/keys.js +2 -0
- package/dist/login.js +2 -0
- package/dist/machine.d.ts +27 -4
- package/dist/machine.js +46 -14
- package/dist/mcp.js +144 -20
- package/dist/modal/index.d.ts +339 -61
- package/dist/modal/index.js +781 -121
- package/dist/network-cli.d.ts +3 -1
- package/dist/network-cli.js +78 -36
- package/dist/networks/index.d.ts +11 -0
- package/dist/networks/index.js +10 -0
- package/dist/ports/index.d.ts +9 -0
- package/dist/ports/index.js +10 -0
- package/dist/product-names.d.ts +52 -0
- package/dist/product-names.js +164 -0
- package/dist/product-renames.d.ts +103 -0
- package/dist/product-renames.js +189 -0
- package/dist/products/api-keys.d.ts +73 -0
- package/dist/products/api-keys.js +23 -0
- package/dist/products/apps.d.ts +157 -0
- package/dist/products/apps.js +60 -0
- package/dist/products/balancers.d.ts +87 -0
- package/dist/products/balancers.js +8 -0
- package/dist/products/billing.d.ts +41 -0
- package/dist/products/billing.js +13 -0
- package/dist/products/browser.d.ts +10 -0
- package/dist/products/browsers.d.ts +71 -0
- package/dist/products/browsers.js +102 -0
- package/dist/products/builds.d.ts +156 -0
- package/dist/products/builds.js +227 -0
- package/dist/products/index.d.ts +5 -16
- package/dist/products/index.js +5 -14
- package/dist/products/jobs.d.ts +19 -2
- package/dist/products/jobs.js +28 -11
- package/dist/products/logs.d.ts +245 -0
- package/dist/products/logs.js +274 -0
- package/dist/products/network-products.d.ts +38 -7
- package/dist/products/network-products.js +31 -18
- package/dist/products/observability.d.ts +8 -2
- package/dist/products/private-network.js +1 -1
- package/dist/products/queues.d.ts +149 -0
- package/dist/products/queues.js +213 -0
- package/dist/products/referrals.d.ts +21 -7
- package/dist/products/referrals.js +3 -3
- package/dist/products/resources.d.ts +54 -0
- package/dist/products/resources.js +122 -0
- package/dist/products/secrets.d.ts +29 -3
- package/dist/products/secrets.js +47 -18
- package/dist/products/signed-requests.d.ts +21 -0
- package/dist/products/signed-requests.js +11 -0
- package/dist/products/streams.d.ts +73 -0
- package/dist/products/streams.js +17 -0
- package/dist/products/switching.d.ts +35 -7
- package/dist/products/switching.js +4 -3
- package/dist/products/volumes.d.ts +6 -0
- package/dist/record-cli.d.ts +23 -0
- package/dist/record-cli.js +308 -0
- package/dist/renamed-products.d.ts +38 -0
- package/dist/renamed-products.js +34 -0
- package/dist/runloop/index.d.ts +9 -2
- package/dist/runloop/index.js +29 -8
- package/dist/runloop/sdk.d.ts +131 -0
- package/dist/runloop/sdk.js +167 -0
- package/dist/sandbox.d.ts +7 -2
- package/dist/sandbox.js +41 -11
- package/dist/sandboxes/index.d.ts +11 -0
- package/dist/sandboxes/index.js +12 -0
- package/dist/snapshots/index.d.ts +9 -0
- package/dist/snapshots/index.js +11 -0
- package/dist/snapshots.d.ts +7 -4
- package/dist/sprites/index.d.ts +343 -31
- package/dist/sprites/index.js +866 -84
- package/dist/ssh.d.ts +1 -1
- package/dist/ssh.js +11 -11
- package/dist/terminal.d.ts +24 -0
- package/dist/terminal.js +32 -0
- package/dist/transport.d.ts +18 -1
- package/dist/transport.js +80 -6
- package/dist/tunnel.js +1 -1
- package/dist/types.d.ts +71 -4
- package/dist/vercel/sandbox.d.ts +1 -1
- package/dist/vercel/sandbox.js +6 -4
- package/dist/vercel/snapshot.js +10 -2
- package/dist/volumes/index.d.ts +9 -0
- package/dist/volumes/index.js +10 -0
- package/dist/wallet.d.ts +4 -1
- package/dist/wallet.js +2 -1
- package/package.json +48 -14
package/dist/blaxel/sandbox.d.ts
CHANGED
|
@@ -40,6 +40,18 @@ export type SandboxArchiveOptions = {
|
|
|
40
40
|
maxWait?: number;
|
|
41
41
|
interval?: number;
|
|
42
42
|
};
|
|
43
|
+
/** The longest creation `timeout` Blaxel accepts, in seconds. */
|
|
44
|
+
export declare const MAX_CREATION_TIMEOUT_SECONDS = 50;
|
|
45
|
+
/** Options of SandboxInstance.create / createIfNotExists, as Blaxel's. */
|
|
46
|
+
export type SandboxCreateOptions = {
|
|
47
|
+
/** List `/` once it runs, and delete it if that fails. */
|
|
48
|
+
safe?: boolean;
|
|
49
|
+
/** Answer the sandbox already holding the name instead of a 409. */
|
|
50
|
+
createIfNotExist?: boolean;
|
|
51
|
+
/** Give up after this many whole seconds (1 to 50): the sandbox is deleted
|
|
52
|
+
* and the call rejects with SandboxCreationTimeoutError. */
|
|
53
|
+
timeout?: number;
|
|
54
|
+
};
|
|
43
55
|
/** What a create asked for that no label keeps: shown by `spec` in the
|
|
44
56
|
* client that created the sandbox. */
|
|
45
57
|
type Asked = {
|
|
@@ -127,15 +139,12 @@ export declare class SandboxInstance {
|
|
|
127
139
|
get expiresIn(): number | undefined;
|
|
128
140
|
/** Creates a sandbox and answers once it runs. Blaxel's defaults: the base
|
|
129
141
|
* image (Runtime's stock image) and 4096 MB, with vCPUs at one per 2048 MB.
|
|
130
|
-
* Funding is left to Runtime: the
|
|
142
|
+
* Funding is left to Runtime: the free usage first, then prepaid credit. A name another live sandbox holds is refused
|
|
131
143
|
* with a 409, as in Blaxel. */
|
|
132
|
-
static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel,
|
|
133
|
-
safe?: boolean;
|
|
134
|
-
createIfNotExist?: boolean;
|
|
135
|
-
}): Promise<InstanceType<T>>;
|
|
144
|
+
static create<T extends typeof SandboxInstance>(this: T, sandbox?: SandboxCreateConfiguration | SandboxModel, options?: SandboxCreateOptions): Promise<InstanceType<T>>;
|
|
136
145
|
/** The named sandbox, or a new one when no live sandbox has the name.
|
|
137
146
|
* Runtime settles a race between two callers: both get the same sandbox. */
|
|
138
|
-
static createIfNotExists<T extends typeof SandboxInstance>(this: T, sandbox: SandboxCreateConfiguration | SandboxModel): Promise<InstanceType<T>>;
|
|
147
|
+
static createIfNotExists<T extends typeof SandboxInstance>(this: T, sandbox: SandboxCreateConfiguration | SandboxModel, options?: Omit<SandboxCreateOptions, "createIfNotExist">): Promise<InstanceType<T>>;
|
|
139
148
|
/** The live sandbox with this name (or Runtime id). It is not woken: the
|
|
140
149
|
* next call wakes it. */
|
|
141
150
|
static get<T extends typeof SandboxInstance>(this: T, sandboxName: string, options?: RuntimeOptions): Promise<InstanceType<T>>;
|
package/dist/blaxel/sandbox.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RuntimeError } from "../errors.js";
|
|
2
2
|
import { clientFor, defaultRegion, } from "./client.js";
|
|
3
3
|
import { checkEnvNames, envFileCommand, envFileLines, parseProcessLine, toRuntimePath, } from "./context.js";
|
|
4
|
-
import { codeOf, guard, NotSupportedError, responseError, translate } from "./errors.js";
|
|
4
|
+
import { codeOf, guard, NotSupportedError, responseError, SandboxCreationTimeoutError, translate, } from "./errors.js";
|
|
5
5
|
import { SandboxFileSystem } from "./filesystem.js";
|
|
6
6
|
import { ARCHIVED, DISPLAY_NAME, EXTERNAL_ID, IDLE_PAUSE, LABEL, findByExternalId, findSandbox, LEASE_SECONDS, ownLabels, STANDBY, userLabels, whenNameFree, } from "./lookup.js";
|
|
7
7
|
import { paginate } from "./pagination.js";
|
|
@@ -38,6 +38,56 @@ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
|
38
38
|
const DAY_MS = 86_400_000;
|
|
39
39
|
/** The lease is renewed in the background once this little of it is left. */
|
|
40
40
|
const RENEW_BELOW_MS = 10 * 60_000;
|
|
41
|
+
/** The longest creation `timeout` Blaxel accepts, in seconds. */
|
|
42
|
+
export const MAX_CREATION_TIMEOUT_SECONDS = 50;
|
|
43
|
+
/** Blaxel's own check of `timeout`, with its words. */
|
|
44
|
+
function creationTimeout({ timeout }) {
|
|
45
|
+
if (timeout === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
if (!Number.isInteger(timeout) || timeout < 1 || timeout > MAX_CREATION_TIMEOUT_SECONDS)
|
|
48
|
+
throw new Error(`SandboxInstance.create: 'timeout' must be a whole number of seconds between 1 and ${MAX_CREATION_TIMEOUT_SECONDS}, got ${timeout}.`);
|
|
49
|
+
return timeout;
|
|
50
|
+
}
|
|
51
|
+
/** A create that must be running within `timeout` seconds of the call, the
|
|
52
|
+
* wait for capacity included. One that is not is deleted, so the name is
|
|
53
|
+
* free again, and the call rejects with SandboxCreationTimeoutError. */
|
|
54
|
+
async function createWithin(client, input, timeout) {
|
|
55
|
+
const deadline = performance.now() + timeout * 1000;
|
|
56
|
+
const runtime = await guard(() => whenNameFree(client, () => client.sandboxes.create({ ...input, wait: false }, { waitForCapacityMs: timeout * 1000 })));
|
|
57
|
+
// A sandbox the name already had is the caller's, whatever its state: it is
|
|
58
|
+
// answered as it is, as without a timeout, and never deleted here.
|
|
59
|
+
if (runtime.state === "running" || runtime.info.reused)
|
|
60
|
+
return runtime;
|
|
61
|
+
const left = deadline - performance.now();
|
|
62
|
+
if (left > 0)
|
|
63
|
+
try {
|
|
64
|
+
await runtime.waitFor("running", {
|
|
65
|
+
timeoutSeconds: Math.max(1, Math.ceil(left / 1000)),
|
|
66
|
+
timeoutMs: Math.ceil(left) + 5_000,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (!(error instanceof RuntimeError && error.code === "timeout")) {
|
|
71
|
+
await runtime.delete().catch(() => undefined);
|
|
72
|
+
throw translate(error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// waitFor updated the state TypeScript narrowed above.
|
|
76
|
+
const state = runtime.state;
|
|
77
|
+
if (state === "running")
|
|
78
|
+
return runtime;
|
|
79
|
+
await runtime.delete().catch(() => undefined);
|
|
80
|
+
if (state !== "starting")
|
|
81
|
+
throw translate(new RuntimeError({
|
|
82
|
+
message: `Sandbox ${runtime.id} is ${runtime.state}, not running.`,
|
|
83
|
+
code: "start_failed",
|
|
84
|
+
status: 0,
|
|
85
|
+
hint: "Create it again; SandboxInstance.get(name) reads why it stopped.",
|
|
86
|
+
}));
|
|
87
|
+
throw new SandboxCreationTimeoutError(input.name, timeout, {
|
|
88
|
+
message: `It was still starting after ${timeout}s.`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
41
91
|
/** The labels a new sandbox carries: the caller's, and under `blaxel/` what
|
|
42
92
|
* Blaxel keeps and Runtime has no field for, so any client (the Python
|
|
43
93
|
* adapter too) reads the same `spec`. */
|
|
@@ -212,7 +262,7 @@ async function resolveImage(client, image) {
|
|
|
212
262
|
if (found && found.state === "ready")
|
|
213
263
|
return { image: found.id };
|
|
214
264
|
const feature = `The image ${image}, which is not a Runtime image`;
|
|
215
|
-
const alternative = `Build it as a Runtime image named ${name}: \`npx withruntime
|
|
265
|
+
const alternative = `Build it as a Runtime image named ${name}: \`npx withruntime images build --dockerfile Dockerfile --name ${name} -t ${name}:${tag}\`. The code can keep "${image}": the adapter starts from ${name}:${tag}.`;
|
|
216
266
|
throw new NotSupportedError(feature, alternative, `${feature}, is not supported on Runtime. ${alternative}`);
|
|
217
267
|
}
|
|
218
268
|
/** Blaxel volumes (by name) as Runtime volumes. */
|
|
@@ -228,7 +278,7 @@ async function resolveVolumes(client, volumes) {
|
|
|
228
278
|
return Promise.all(volumes.map(async (volume) => {
|
|
229
279
|
const found = (await guard(() => client.volumes.list({ name: volume.name }))).data[0];
|
|
230
280
|
if (!found)
|
|
231
|
-
throw new NotSupportedError(`The volume ${volume.name}, which is not a Runtime volume`, `Create it first: runtime.volumes.create({ name: "${volume.name}" }) or \`npx withruntime
|
|
281
|
+
throw new NotSupportedError(`The volume ${volume.name}, which is not a Runtime volume`, `Create it first: runtime.volumes.create({ name: "${volume.name}" }) or \`npx withruntime volumes create --name ${volume.name}\`.`);
|
|
232
282
|
return { volumeId: found.id, path: toRuntimePath(volume.mountPath) };
|
|
233
283
|
}));
|
|
234
284
|
}
|
|
@@ -523,9 +573,11 @@ export class SandboxInstance {
|
|
|
523
573
|
// ---- create, get, list ---------------------------------------------------
|
|
524
574
|
/** Creates a sandbox and answers once it runs. Blaxel's defaults: the base
|
|
525
575
|
* image (Runtime's stock image) and 4096 MB, with vCPUs at one per 2048 MB.
|
|
526
|
-
* Funding is left to Runtime: the
|
|
576
|
+
* Funding is left to Runtime: the free usage first, then prepaid credit. A name another live sandbox holds is refused
|
|
527
577
|
* with a 409, as in Blaxel. */
|
|
528
|
-
static async create(sandbox,
|
|
578
|
+
static async create(sandbox, options = {}) {
|
|
579
|
+
const { createIfNotExist = false, safe = false } = options;
|
|
580
|
+
const timeout = creationTimeout(options);
|
|
529
581
|
const config = configOf(sandbox);
|
|
530
582
|
const region = config.region || defaultRegion();
|
|
531
583
|
checkRegion(region);
|
|
@@ -559,7 +611,9 @@ export class SandboxInstance {
|
|
|
559
611
|
...(createIfNotExist && config.name ? { getOrCreate: true } : {}),
|
|
560
612
|
...config.withruntime?.create,
|
|
561
613
|
};
|
|
562
|
-
const runtime =
|
|
614
|
+
const runtime = timeout === undefined
|
|
615
|
+
? await guard(() => whenNameFree(client, () => client.sandboxes.create(input)))
|
|
616
|
+
: await createWithin(client, input, timeout);
|
|
563
617
|
const asked = {
|
|
564
618
|
...(Object.keys(envs).length ? { envs } : {}),
|
|
565
619
|
...(config.network ? { network: config.network } : {}),
|
|
@@ -571,6 +625,8 @@ export class SandboxInstance {
|
|
|
571
625
|
const instance = new this({ runtime, client, asked });
|
|
572
626
|
try {
|
|
573
627
|
await instance.#setUp(envs, lifetime.days);
|
|
628
|
+
if (safe)
|
|
629
|
+
await instance.fs.ls("/");
|
|
574
630
|
}
|
|
575
631
|
catch (error) {
|
|
576
632
|
await runtime.stop({ wait: false }).catch(() => undefined);
|
|
@@ -580,8 +636,8 @@ export class SandboxInstance {
|
|
|
580
636
|
}
|
|
581
637
|
/** The named sandbox, or a new one when no live sandbox has the name.
|
|
582
638
|
* Runtime settles a race between two callers: both get the same sandbox. */
|
|
583
|
-
static async createIfNotExists(sandbox) {
|
|
584
|
-
return this.create(sandbox, { createIfNotExist: true });
|
|
639
|
+
static async createIfNotExists(sandbox, options = {}) {
|
|
640
|
+
return this.create(sandbox, { ...options, createIfNotExist: true });
|
|
585
641
|
}
|
|
586
642
|
/** The live sandbox with this name (or Runtime id). It is not woken: the
|
|
587
643
|
* next call wakes it. */
|
|
@@ -71,6 +71,10 @@ export declare function appendEnvs(runtime: RuntimeSandbox, envs: Record<string,
|
|
|
71
71
|
export declare function startFromSnapshot(client: Runtime, snapshotId: string, name: string, labels: Record<string, string>, envs: Record<string, string>): Promise<RuntimeSandbox>;
|
|
72
72
|
declare function refuseApplication(options?: {
|
|
73
73
|
targetType?: string;
|
|
74
|
+
port?: number;
|
|
75
|
+
traffic?: number;
|
|
76
|
+
customDomain?: string;
|
|
77
|
+
prefix?: string;
|
|
74
78
|
}): void;
|
|
75
79
|
/** A snapshot, as Blaxel's Snapshot class. */
|
|
76
80
|
export declare class Snapshot {
|
package/dist/blaxel/snapshot.js
CHANGED
|
@@ -63,6 +63,10 @@ export async function startFromSnapshot(client, snapshotId, name, labels, envs)
|
|
|
63
63
|
function refuseApplication(options = {}) {
|
|
64
64
|
if (options.targetType === "application")
|
|
65
65
|
throw new NotSupportedError("Forking into an application", "Fork into a sandbox and share its port with sandbox.previews.create.");
|
|
66
|
+
// Blaxel's application-fork routing: a sandbox fork has no use for them.
|
|
67
|
+
for (const key of ["port", "traffic", "customDomain", "prefix"])
|
|
68
|
+
if (options[key] !== undefined)
|
|
69
|
+
throw new NotSupportedError(`A fork's ${key}`, "Fork without it, then share a port of the copy with sandbox.previews.create({ metadata: { name }, spec: { port } }).");
|
|
66
70
|
}
|
|
67
71
|
/** A snapshot, as Blaxel's Snapshot class. */
|
|
68
72
|
export class Snapshot {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ObservabilityClient } from "../products/logs.js";
|
|
2
|
+
type Product = "logs" | "traces" | "alerts";
|
|
3
|
+
type Args = {
|
|
4
|
+
positional: string[];
|
|
5
|
+
flags: Map<string, string[]>;
|
|
6
|
+
};
|
|
7
|
+
type Out = {
|
|
8
|
+
json: boolean;
|
|
9
|
+
tty?: boolean;
|
|
10
|
+
drain?: () => Promise<void>;
|
|
11
|
+
write(text: string): void;
|
|
12
|
+
error(text: string): void;
|
|
13
|
+
};
|
|
14
|
+
export declare const LOGS_HELP = "runtime logs tail <selector|app> [--since 1h] [--grep text] [--json] [--raw]\nruntime logs query '<LogQL>' [--from <time>] [--to <time>] [--limit <n>]\nruntime logs labels | values <label>\nruntime logs views ls|get|create|update|delete [id] [--body '<JSON>']\nruntime traces get <id> | search '<TraceQL>' | tags\nruntime traces views ls|get|create|update|delete [id] [--body '<JSON>']\nruntime logs ingest --body '<OTLP JSON>'\nruntime traces ingest --body '<OTLP JSON>'\nruntime alerts ls|get|create|update|delete|test|silence [id]\n create/update: --body '<JSON: name, labels, query, condition, for, actions>'\n silence: --until <RFC3339> [--reason <text>]\nEvery command takes --json. Writes take --idempotency-key <key>.\nOn a terminal, control characters in logs show as \\uXXXX; --raw prints them as written.";
|
|
15
|
+
/** Same parsed argument and output ports as the existing CLI. No registration
|
|
16
|
+
* occurs here: the launch owner supplies a client only after launch. */
|
|
17
|
+
export declare function logsProductCommand(product: Product, argv: string[], args: Args, out: Out, client: () => Promise<ObservabilityClient>, options?: {
|
|
18
|
+
signal?: AbortSignal;
|
|
19
|
+
now?: number;
|
|
20
|
+
}): Promise<number>;
|
|
21
|
+
export {};
|
package/dist/cli/logs.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
2
|
+
import { terminalSafe } from "../terminal.js";
|
|
3
|
+
export const LOGS_HELP = `runtime logs tail <selector|app> [--since 1h] [--grep text] [--json] [--raw]
|
|
4
|
+
runtime logs query '<LogQL>' [--from <time>] [--to <time>] [--limit <n>]
|
|
5
|
+
runtime logs labels | values <label>
|
|
6
|
+
runtime logs views ls|get|create|update|delete [id] [--body '<JSON>']
|
|
7
|
+
runtime traces get <id> | search '<TraceQL>' | tags
|
|
8
|
+
runtime traces views ls|get|create|update|delete [id] [--body '<JSON>']
|
|
9
|
+
runtime logs ingest --body '<OTLP JSON>'
|
|
10
|
+
runtime traces ingest --body '<OTLP JSON>'
|
|
11
|
+
runtime alerts ls|get|create|update|delete|test|silence [id]
|
|
12
|
+
create/update: --body '<JSON: name, labels, query, condition, for, actions>'
|
|
13
|
+
silence: --until <RFC3339> [--reason <text>]
|
|
14
|
+
Every command takes --json. Writes take --idempotency-key <key>.
|
|
15
|
+
On a terminal, control characters in logs show as \\uXXXX; --raw prints them as written.`;
|
|
16
|
+
const usage = (message) => new RuntimeError({ code: "usage", status: 0, message, hint: LOGS_HELP });
|
|
17
|
+
function since(text, now) {
|
|
18
|
+
const match = /^(\d+)(s|m|h|d)$/.exec(text);
|
|
19
|
+
if (!match)
|
|
20
|
+
throw usage("Use --since with seconds, minutes, hours or days, such as 1h.");
|
|
21
|
+
const factors = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 };
|
|
22
|
+
const at = now - Number(match[1]) * factors[match[2]];
|
|
23
|
+
if (!Number.isSafeInteger(at) || at < 0)
|
|
24
|
+
throw usage("--since is outside the supported time range.");
|
|
25
|
+
return new Date(at).toISOString();
|
|
26
|
+
}
|
|
27
|
+
/** Same parsed argument and output ports as the existing CLI. No registration
|
|
28
|
+
* occurs here: the launch owner supplies a client only after launch. */
|
|
29
|
+
export async function logsProductCommand(product, argv, args, out, client, options = {}) {
|
|
30
|
+
const verb = argv[0];
|
|
31
|
+
const rest = args.positional.slice(1);
|
|
32
|
+
const flag = (name) => args.flags.get(name)?.at(-1);
|
|
33
|
+
const json = out.json || flag("json") === "true";
|
|
34
|
+
// On a terminal, what customers' programs wrote is shown escaped, JSON
|
|
35
|
+
// included (an escape is still valid JSON); --raw prints it as it is.
|
|
36
|
+
const safe = (text) => (out.tty && flag("raw") !== "true" ? terminalSafe(text) : text);
|
|
37
|
+
const lines = (text) => text.split("\n").map(safe).join("\n");
|
|
38
|
+
const print = (value, text) => out.write(json ? safe(JSON.stringify(value)) : lines(text ?? JSON.stringify(value, null, 2)));
|
|
39
|
+
const need = (value, name) => {
|
|
40
|
+
if (!value)
|
|
41
|
+
throw usage(`Give ${name}.`);
|
|
42
|
+
return value;
|
|
43
|
+
};
|
|
44
|
+
const body = () => {
|
|
45
|
+
try {
|
|
46
|
+
const value = JSON.parse(need(flag("body"), "--body with a JSON object"));
|
|
47
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
48
|
+
throw usage("--body must be a JSON object.");
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
if (error instanceof RuntimeError)
|
|
53
|
+
throw error;
|
|
54
|
+
throw usage("--body is not valid JSON.");
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const request = {
|
|
58
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
59
|
+
...(flag("idempotency-key") ? { idempotencyKey: flag("idempotency-key") } : {}),
|
|
60
|
+
};
|
|
61
|
+
if (!verb || verb === "help" || verb === "--help") {
|
|
62
|
+
print({ usage: LOGS_HELP }, LOGS_HELP);
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
const runtime = await client();
|
|
66
|
+
if ((product === "logs" || product === "traces") && verb === "views") {
|
|
67
|
+
const views = runtime[product].views;
|
|
68
|
+
const action = need(rest[0], "a views command");
|
|
69
|
+
if (action === "ls") {
|
|
70
|
+
const result = await views.list({}, request);
|
|
71
|
+
print({ data: result.data, nextCursor: result.nextCursor });
|
|
72
|
+
}
|
|
73
|
+
else if (action === "create")
|
|
74
|
+
print(await views.create(body(), request));
|
|
75
|
+
else {
|
|
76
|
+
const id = need(rest[1], "a view id");
|
|
77
|
+
if (action === "get")
|
|
78
|
+
print(await views.get(id, request));
|
|
79
|
+
else if (action === "update")
|
|
80
|
+
print(await views.update(id, body(), request));
|
|
81
|
+
else if (action === "delete") {
|
|
82
|
+
await views.delete(id, request);
|
|
83
|
+
print({ deleted: id });
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
throw usage(`Unknown views command: ${action}.`);
|
|
87
|
+
}
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if ((product === "logs" || product === "traces") && verb === "ingest") {
|
|
91
|
+
const input = body();
|
|
92
|
+
if (product === "logs") {
|
|
93
|
+
if (!Array.isArray(input.resourceLogs))
|
|
94
|
+
throw usage("OTLP logs need resourceLogs.");
|
|
95
|
+
const resourceLogs = input.resourceLogs;
|
|
96
|
+
print(await runtime.logs.ingest({ resourceLogs }, request));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
if (!Array.isArray(input.resourceSpans))
|
|
100
|
+
throw usage("OTLP spans need resourceSpans.");
|
|
101
|
+
const resourceSpans = input.resourceSpans;
|
|
102
|
+
print(await runtime.traces.ingest({ resourceSpans }, request));
|
|
103
|
+
}
|
|
104
|
+
return 0;
|
|
105
|
+
}
|
|
106
|
+
if (product === "logs") {
|
|
107
|
+
if (verb === "tail") {
|
|
108
|
+
const selector = need(rest[0], "a selector or app name");
|
|
109
|
+
let query = selector.trim().startsWith("{") ? selector : `{app=${JSON.stringify(selector)}}`;
|
|
110
|
+
if (flag("grep") !== undefined)
|
|
111
|
+
query += ` |= ${JSON.stringify(flag("grep"))}`;
|
|
112
|
+
for await (const event of runtime.logs.tail(query, {
|
|
113
|
+
...request,
|
|
114
|
+
...(flag("since") ? { start: since(flag("since"), options.now ?? Date.now()) } : {}),
|
|
115
|
+
})) {
|
|
116
|
+
if (json)
|
|
117
|
+
out.write(safe(JSON.stringify(event)));
|
|
118
|
+
else if (event.gap) {
|
|
119
|
+
const text = safe(`Logs expired between ${event.from} and ${event.to}; continuing from retained logs.`);
|
|
120
|
+
out.write(out.tty ? `\x1b[2m${text}\x1b[0m` : text);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const time = safe(event.time);
|
|
124
|
+
const text = safe(typeof event.body === "string" ? event.body : JSON.stringify(event.body));
|
|
125
|
+
out.write(`${out.tty ? `\x1b[2m${time}\x1b[0m` : time} ${safe(event.severityText)} ${text}`);
|
|
126
|
+
}
|
|
127
|
+
await out.drain?.();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (verb === "query") {
|
|
131
|
+
const limit = flag("limit") === undefined ? undefined : Number(flag("limit"));
|
|
132
|
+
if (limit !== undefined && (!Number.isSafeInteger(limit) || limit < 1))
|
|
133
|
+
throw usage("--limit must be a positive integer.");
|
|
134
|
+
print(await runtime.logs.queryRange({
|
|
135
|
+
query: need(rest[0], "a LogQL query"),
|
|
136
|
+
...(flag("from") ? { start: flag("from") } : {}),
|
|
137
|
+
...(flag("to") ? { end: flag("to") } : {}),
|
|
138
|
+
...(limit !== undefined ? { limit } : {}),
|
|
139
|
+
}, request));
|
|
140
|
+
}
|
|
141
|
+
else if (verb === "labels")
|
|
142
|
+
print(await runtime.logs.labels({}, request));
|
|
143
|
+
else if (verb === "values")
|
|
144
|
+
print(await runtime.logs.labelValues(need(rest[0], "a label name"), {}, request));
|
|
145
|
+
else
|
|
146
|
+
throw usage(`Unknown logs command: ${verb}.`);
|
|
147
|
+
}
|
|
148
|
+
else if (product === "traces") {
|
|
149
|
+
if (verb === "get")
|
|
150
|
+
print(await runtime.traces.get(need(rest[0], "a trace id"), request));
|
|
151
|
+
else if (verb === "search")
|
|
152
|
+
print(await runtime.traces.search(need(rest[0], "a TraceQL query"), request));
|
|
153
|
+
else if (verb === "tags")
|
|
154
|
+
print(await runtime.traces.tags(request));
|
|
155
|
+
else
|
|
156
|
+
throw usage(`Unknown traces command: ${verb}.`);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
if (verb === "ls") {
|
|
160
|
+
const result = await runtime.alerts.list({}, request);
|
|
161
|
+
print({ data: result.data, nextCursor: result.nextCursor });
|
|
162
|
+
}
|
|
163
|
+
else if (verb === "create")
|
|
164
|
+
print(await runtime.alerts.create(body(), request));
|
|
165
|
+
else {
|
|
166
|
+
const id = need(rest[0], "an alert id");
|
|
167
|
+
if (verb === "get")
|
|
168
|
+
print(await runtime.alerts.get(id, request));
|
|
169
|
+
else if (verb === "update")
|
|
170
|
+
print(await runtime.alerts.update(id, body(), request));
|
|
171
|
+
else if (verb === "delete") {
|
|
172
|
+
await runtime.alerts.delete(id, request);
|
|
173
|
+
print({ deleted: id });
|
|
174
|
+
}
|
|
175
|
+
else if (verb === "test")
|
|
176
|
+
print(await runtime.alerts.test(id, request));
|
|
177
|
+
else if (verb === "silence") {
|
|
178
|
+
const until = need(flag("until"), "--until with an RFC3339 time");
|
|
179
|
+
if (!/T.*(?:Z|[+-]\d\d:\d\d)$/.test(until) || !Number.isFinite(Date.parse(until)))
|
|
180
|
+
throw usage("--until must be an RFC3339 time with timezone.");
|
|
181
|
+
print(await runtime.alerts.silence(id, { until, ...(flag("reason") ? { reason: flag("reason") } : {}) }, request));
|
|
182
|
+
}
|
|
183
|
+
else
|
|
184
|
+
throw usage(`Unknown alerts command: ${verb}.`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
package/dist/cli-extras.d.ts
CHANGED
|
@@ -22,9 +22,9 @@ export declare function lostOutput(result: {
|
|
|
22
22
|
stdoutTruncated?: boolean;
|
|
23
23
|
stderrTruncated?: boolean;
|
|
24
24
|
}, id: string): string | undefined;
|
|
25
|
-
/** Feeds `runtime
|
|
25
|
+
/** Feeds `runtime sandboxes shell` from standard input. When piped input ends,
|
|
26
26
|
* the shell is told so the way a terminal says it, Ctrl-D, after a newline
|
|
27
|
-
* if the last line had none: `echo ls | runtime
|
|
27
|
+
* if the last line had none: `echo ls | runtime sandboxes shell <id>` runs `ls`
|
|
28
28
|
* and exits, as ssh does, where it used to wait forever (25 September 2026).
|
|
29
29
|
* A keyboard never ends, so a terminal's input is left alone. Returns the
|
|
30
30
|
* function that unhooks it. */
|
|
@@ -33,7 +33,7 @@ export declare function pipeShellInput(stdin: NodeJS.ReadableStream & {
|
|
|
33
33
|
}, terminal: {
|
|
34
34
|
write(data: Uint8Array | string): void;
|
|
35
35
|
}): () => void;
|
|
36
|
-
/** `runtime
|
|
36
|
+
/** `runtime snapshots get`, as `runtime sandboxes get` reads: one fact a line.
|
|
37
37
|
* It printed raw JSON until 25 September 2026; `--json` still does. */
|
|
38
38
|
export declare function describeSnapshot(s: Snapshot, table: (rows: string[][]) => string): string;
|
|
39
39
|
export {};
|
package/dist/cli-extras.js
CHANGED
|
@@ -13,12 +13,12 @@ export async function recordCommand(sbx, argv, out, kit) {
|
|
|
13
13
|
...(integer(args, "max-seconds") ? { maxSeconds: integer(args, "max-seconds") } : {}),
|
|
14
14
|
...(integer(args, "max-mib") ? { maxMiB: integer(args, "max-mib") } : {}),
|
|
15
15
|
});
|
|
16
|
-
print(`Recording ${rec.id}. Stop it: ${me}
|
|
16
|
+
print(`Recording ${rec.id}. Stop it: ${me} sandboxes desktop ${sbx.id} record stop ${rec.id}`, rec);
|
|
17
17
|
return 0;
|
|
18
18
|
}
|
|
19
19
|
case "stop": {
|
|
20
20
|
const rec = await r.stop(need(rest[0], "the recording id"));
|
|
21
|
-
print(`Stopped ${rec.id}: ${(rec.bytes / 1_048_576).toFixed(1)} MiB (${rec.reason ?? "stopped"}). Fetch it: ${me}
|
|
21
|
+
print(`Stopped ${rec.id}: ${(rec.bytes / 1_048_576).toFixed(1)} MiB (${rec.reason ?? "stopped"}). Fetch it: ${me} sandboxes desktop ${sbx.id} record fetch ${rec.id}`, rec);
|
|
22
22
|
return 0;
|
|
23
23
|
}
|
|
24
24
|
case "ls": {
|
|
@@ -47,7 +47,7 @@ export async function recordCommand(sbx, argv, out, kit) {
|
|
|
47
47
|
print("Deleted.", await r.delete(need(rest[0], "the recording id")));
|
|
48
48
|
return 0;
|
|
49
49
|
}
|
|
50
|
-
throw usage(`${me}
|
|
50
|
+
throw usage(`${me} sandboxes desktop <id> record start|stop|ls|fetch|rm`);
|
|
51
51
|
}
|
|
52
52
|
export async function watchCommand(sbx, argv, out, kit) {
|
|
53
53
|
const { parse, flag, has, need } = kit;
|
|
@@ -110,7 +110,7 @@ export async function mcpCommand(sbx, argv, out, kit) {
|
|
|
110
110
|
case "start": {
|
|
111
111
|
const args = parse(rest, ["replace"], ["secret", "env", "option", "port"]);
|
|
112
112
|
if (!args.positional.length)
|
|
113
|
-
throw usage("Name the servers: runtime
|
|
113
|
+
throw usage("Name the servers: runtime sandboxes mcp <id> start github fetch");
|
|
114
114
|
const scoped = (name) => {
|
|
115
115
|
const found = {};
|
|
116
116
|
for (const [key, value] of Object.entries(pairs(args, name))) {
|
|
@@ -134,7 +134,7 @@ export async function mcpCommand(sbx, argv, out, kit) {
|
|
|
134
134
|
...(integer(args, "port") ? { port: integer(args, "port") } : {}),
|
|
135
135
|
...(has(args, "replace") ? { replace: true } : {}),
|
|
136
136
|
});
|
|
137
|
-
print(`${show(gw)}\nServers are installing; \`${me}
|
|
137
|
+
print(`${show(gw)}\nServers are installing; \`${me} sandboxes mcp ${sbx.id}\` shows when they are ready.`, gw);
|
|
138
138
|
return 0;
|
|
139
139
|
}
|
|
140
140
|
case "status": {
|
|
@@ -146,7 +146,7 @@ export async function mcpCommand(sbx, argv, out, kit) {
|
|
|
146
146
|
print("Stopped.", await sbx.mcp.stop());
|
|
147
147
|
return 0;
|
|
148
148
|
}
|
|
149
|
-
throw usage(`${me}
|
|
149
|
+
throw usage(`${me} sandboxes mcp <id> start|status|stop, or ${me} sandboxes mcp catalog`);
|
|
150
150
|
}
|
|
151
151
|
/** Standard input when it is piped or redirected from a file, read whole, up
|
|
152
152
|
* to the API's 1 MiB; undefined for a terminal. A pipe that says nothing for
|
|
@@ -184,7 +184,7 @@ export async function pipedStdin(options = {}) {
|
|
|
184
184
|
clearTimeout(quiet);
|
|
185
185
|
size += chunk.length;
|
|
186
186
|
if (size > limit)
|
|
187
|
-
return done(undefined, Object.assign(new Error(`Standard input is over ${limit / 1_048_576} MiB. Copy the file in with \`${me}
|
|
187
|
+
return done(undefined, Object.assign(new Error(`Standard input is over ${limit / 1_048_576} MiB. Copy the file in with \`${me} sandboxes cp\` and read it there.`), { code: "usage" }));
|
|
188
188
|
chunks.push(chunk);
|
|
189
189
|
};
|
|
190
190
|
const onEnd = () => done(size ? new Uint8Array(Buffer.concat(chunks)) : undefined);
|
|
@@ -201,11 +201,11 @@ export async function pipedStdin(options = {}) {
|
|
|
201
201
|
export function lostOutput(result, id) {
|
|
202
202
|
if (!result.stdoutTruncated && !result.stderrTruncated)
|
|
203
203
|
return undefined;
|
|
204
|
-
return `runtime: some of the command's output was lost: it wrote faster than it was read, and the sandbox keeps the latest 1 MiB. Write it to a file and copy it out: ${me}
|
|
204
|
+
return `runtime: some of the command's output was lost: it wrote faster than it was read, and the sandbox keeps the latest 1 MiB. Write it to a file and copy it out: ${me} sandboxes cp ${id}:/workspace/out.txt .`;
|
|
205
205
|
}
|
|
206
|
-
/** Feeds `runtime
|
|
206
|
+
/** Feeds `runtime sandboxes shell` from standard input. When piped input ends,
|
|
207
207
|
* the shell is told so the way a terminal says it, Ctrl-D, after a newline
|
|
208
|
-
* if the last line had none: `echo ls | runtime
|
|
208
|
+
* if the last line had none: `echo ls | runtime sandboxes shell <id>` runs `ls`
|
|
209
209
|
* and exits, as ssh does, where it used to wait forever (25 September 2026).
|
|
210
210
|
* A keyboard never ends, so a terminal's input is left alone. Returns the
|
|
211
211
|
* function that unhooks it. */
|
|
@@ -229,7 +229,7 @@ export function pipeShellInput(stdin, terminal) {
|
|
|
229
229
|
stdin.off("end", onEnd);
|
|
230
230
|
};
|
|
231
231
|
}
|
|
232
|
-
/** `runtime
|
|
232
|
+
/** `runtime snapshots get`, as `runtime sandboxes get` reads: one fact a line.
|
|
233
233
|
* It printed raw JSON until 25 September 2026; `--json` still does. */
|
|
234
234
|
export function describeSnapshot(s, table) {
|
|
235
235
|
const mib = (bytes) => bytes === null ? "-" : `${Math.ceil(bytes / 1_048_576).toLocaleString("en-US")} MiB`;
|
|
@@ -249,7 +249,12 @@ export function describeSnapshot(s, table) {
|
|
|
249
249
|
: s.durability.state,
|
|
250
250
|
],
|
|
251
251
|
["created", s.createdAt],
|
|
252
|
-
[
|
|
252
|
+
[
|
|
253
|
+
"kept until",
|
|
254
|
+
s.expiresAt === null
|
|
255
|
+
? "kept while you have credit"
|
|
256
|
+
: `${s.expiresAt} (${s.retentionDays} days)`,
|
|
257
|
+
],
|
|
253
258
|
[
|
|
254
259
|
"labels",
|
|
255
260
|
Object.entries(labels)
|
package/dist/cli-words.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { RuntimeError } from "./errors.js";
|
|
2
|
+
import type { ProductName } from "./product-names.js";
|
|
2
3
|
import type { SandboxMetrics } from "./products/observability.js";
|
|
3
4
|
/** A refusal of what a command sent, reworded for the command line: every
|
|
4
5
|
* issue named by its option, since the CLI never prints details.issues, and
|
|
@@ -25,3 +26,11 @@ export declare function newestCpu(m: SandboxMetrics, now?: number): {
|
|
|
25
26
|
* help` filed "help" as feedback, and `runtime support help` sent it to
|
|
26
27
|
* support, until 30 September 2026. */
|
|
27
28
|
export declare function topicHelp(help: string, command: string): string | null;
|
|
29
|
+
/** A command line's product words (CLOUD.md section 4): the plural, or the
|
|
30
|
+
* singular as a typing shortcut, reach the product silently; an old word
|
|
31
|
+
* reaches it with `warning` to print, and from its date throws name_retired
|
|
32
|
+
* naming the new command. Anything else passes through. */
|
|
33
|
+
export declare function productWords(argv: string[], now?: Date, table?: readonly ProductName[]): {
|
|
34
|
+
argv: string[];
|
|
35
|
+
warning?: string;
|
|
36
|
+
};
|
package/dist/cli-words.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { RuntimeError } from "./errors.js";
|
|
2
|
+
import { cliWords } from "./product-renames.js";
|
|
1
3
|
/* What the CLI says in its own words where the API's would mislead: the
|
|
2
4
|
option a refusal is about rather than the request field it was sent as,
|
|
3
5
|
one fact a line for a resource read, and the newest CPU reading a
|
|
@@ -133,3 +135,19 @@ export function topicHelp(help, command) {
|
|
|
133
135
|
}
|
|
134
136
|
return out.length ? out.join("\n") : null;
|
|
135
137
|
}
|
|
138
|
+
/** A command line's product words (CLOUD.md section 4): the plural, or the
|
|
139
|
+
* singular as a typing shortcut, reach the product silently; an old word
|
|
140
|
+
* reaches it with `warning` to print, and from its date throws name_retired
|
|
141
|
+
* naming the new command. Anything else passes through. */
|
|
142
|
+
export function productWords(argv, now = new Date(), table) {
|
|
143
|
+
const found = cliWords(argv, now, table);
|
|
144
|
+
if (!found)
|
|
145
|
+
return { argv };
|
|
146
|
+
const { use } = found;
|
|
147
|
+
if (use.kind === "retired")
|
|
148
|
+
throw new RuntimeError({ ...use.error });
|
|
149
|
+
return {
|
|
150
|
+
argv: found.args,
|
|
151
|
+
...(use.kind === "renamed" ? { warning: use.warning } : {}),
|
|
152
|
+
};
|
|
153
|
+
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { RuntimeError } from "./errors.js";
|
|
3
|
-
import type { Usage } from "./types.js";
|
|
3
|
+
import type { OutOfMemory, Usage } from "./types.js";
|
|
4
4
|
import type { SwitchProvider } from "./products/switching.js";
|
|
5
|
-
import type { SecretRule } from "./products/secrets.js";
|
|
5
|
+
import type { SecretRule, SecretScope } from "./products/secrets.js";
|
|
6
6
|
type Out = {
|
|
7
7
|
json: boolean;
|
|
8
8
|
write: (text: string) => void;
|
|
@@ -30,7 +30,7 @@ declare const kit: {
|
|
|
30
30
|
};
|
|
31
31
|
export type CliKit = typeof kit;
|
|
32
32
|
export declare function run(argv: string[], env?: NodeJS.ProcessEnv, out?: Out): Promise<number>;
|
|
33
|
-
/** `runtime usage` for a person: the balance, the
|
|
33
|
+
/** `runtime usage` for a person: the balance, the free usage and what each kind
|
|
34
34
|
* of resource was charged, in dollars. --json keeps every figure, and each
|
|
35
35
|
* resource with its rates and CPU time. */
|
|
36
36
|
/** One row per resource, for a spreadsheet: when it ran, how big it was, how
|
|
@@ -38,14 +38,33 @@ export declare function run(argv: string[], env?: NodeJS.ProcessEnv, out?: Out):
|
|
|
38
38
|
* microdollar (the API's integer microdollars moved six places), so a column
|
|
39
39
|
* sums to the ledger to the last digit. */
|
|
40
40
|
export declare function usageCsv(u: Usage): string;
|
|
41
|
+
/** What a person reads when the sandbox's out-of-memory killer ended a
|
|
42
|
+
* command: the API's message and hint, on standard error. A bare exit -9 (or
|
|
43
|
+
* 137) said nothing of memory until 9 October 2026. */
|
|
44
|
+
export declare function outOfMemoryLines(memory: OutOfMemory | undefined): string | undefined;
|
|
41
45
|
/** How to move a rival's code across, when one import does it. */
|
|
42
46
|
export declare function dropInLines(provider: SwitchProvider | undefined): string[];
|
|
47
|
+
/** A secret's value, from standard input only, so it never sits in shell
|
|
48
|
+
* history or a process list. Piped: everything, less one trailing newline.
|
|
49
|
+
* A terminal: one line, not shown. */
|
|
50
|
+
/** A pasted secret as the header it becomes: no line breaks (a token copied
|
|
51
|
+
* from a terminal arrives wrapped), no bracketed-paste markers, no space at
|
|
52
|
+
* either end. 13 October 2026: Marc's pasted Claude token was refused as
|
|
53
|
+
* "not visible ASCII". A header cannot hold a line break, so none is lost. */
|
|
54
|
+
export declare function cleanSecret(raw: string): string;
|
|
43
55
|
/** `--allow` values as secret rules: each is `[METHOD[,METHOD]...] PATH`, and
|
|
44
56
|
* rules naming the same methods share one rule's paths. Only the shape is read
|
|
45
57
|
* here; the API holds every rule to the same check the host makes
|
|
46
58
|
* (ARCHITECTURE.md section 10, "Per-path rules on an egress secret") and says
|
|
47
59
|
* which one it refused. */
|
|
48
60
|
export declare function parseSecretRules(values: string[]): SecretRule[];
|
|
61
|
+
/** `--only-label role=hub,tier=x --only-sandbox <id>`: a sandbox whose labels
|
|
62
|
+
* hold every pair of any one --only-label gets the secret, and so does each
|
|
63
|
+
* --only-sandbox. `--all-sandboxes`: every sandbox again. Nothing: undefined,
|
|
64
|
+
* so a replacement keeps the scope it has. */
|
|
65
|
+
export declare function parseSecretScope(labels: string[] | undefined, sandboxes: string[] | undefined, all: boolean): SecretScope | undefined;
|
|
66
|
+
/** Who gets a secret, in a few words. */
|
|
67
|
+
export declare const scopeText: (only: SecretScope | undefined) => string;
|
|
49
68
|
export declare function secretsCommand(argv: string[], env: NodeJS.ProcessEnv, out: Out,
|
|
50
69
|
/** Tests give the value here; the CLI reads standard input. */
|
|
51
70
|
read?: () => Promise<string>): Promise<number>;
|