nylorun 0.15.1-beta → 0.17.0-beta
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/CHANGELOG.md +134 -0
- package/README.md +136 -74
- package/dist/cli.js +31 -12
- package/dist/client/agent-manifests.d.ts +4 -0
- package/dist/client/agent-manifests.js +100 -0
- package/dist/client/agents.d.ts +1 -3
- package/dist/client/agents.js +459 -117
- package/dist/client/apply.d.ts +7 -0
- package/dist/client/apply.js +99 -0
- package/dist/client/artifacts.js +3 -3
- package/dist/client/doctor.d.ts +1 -1
- package/dist/client/doctor.js +2 -2
- package/dist/client/io.d.ts +2 -0
- package/dist/client/io.js +11 -0
- package/dist/client/mcp.d.ts +5 -3
- package/dist/client/mcp.js +28 -25
- package/dist/client/migrate.d.ts +4 -0
- package/dist/client/migrate.js +140 -0
- package/dist/client/model/pi-ai.d.ts +1 -1
- package/dist/client/model/pi-ai.js +1 -1
- package/dist/client/models.d.ts +5 -2
- package/dist/client/models.js +17 -8
- package/dist/client/runtime.js +3 -3
- package/dist/client/sessions.js +29 -18
- package/dist/client/settings.d.ts +5 -5
- package/dist/client/settings.js +38 -18
- package/dist/client/tenant.d.ts +1 -1
- package/dist/client/tenant.js +10 -7
- package/dist/project/seed.js +2 -1
- package/dist/sandbox/commands.js +10 -8
- package/dist/sandbox/kubectl.js +2 -1
- package/dist/sandbox/manifests.js +3 -2
- package/dist/sandbox/probe.js +9 -7
- package/dist/stack/commands.js +12 -11
- package/dist/stack/compose-file.d.ts +3 -0
- package/dist/stack/compose-file.js +32 -36
- package/dist/stack/operator-keys.js +7 -6
- package/dist/stack/ports.js +2 -1
- package/dist/stack/studio-login.js +2 -1
- package/dist/tuning.d.ts +90 -0
- package/dist/tuning.js +143 -0
- package/package.json +9 -9
- package/dist/client/environment-manifests.d.ts +0 -10
- package/dist/client/environment-manifests.js +0 -173
- package/dist/client/environments.d.ts +0 -4
- package/dist/client/environments.js +0 -295
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `nylorun environments manifests`: the Tenant's environment manifests (protocol 14, D63), named
|
|
3
|
-
* and versioned definitions of a kind of Environment, saved like agents. `save` reads each JSON
|
|
4
|
-
* file (its `$schema` is dropped), turns a `files` entry with `from` (a folder, relative to the
|
|
5
|
-
* file) into files by content hash and uploads those the Runtime lacks, then saves the next
|
|
6
|
-
* version under `If-Match` when `--if-match` is given. `--dry-run` prints the plan and exits 1
|
|
7
|
-
* when the Runtime would refuse the save.
|
|
8
|
-
*/
|
|
9
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
10
|
-
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
11
|
-
import { environmentFiles } from "@nylorun/agents";
|
|
12
|
-
import { CliError } from "../errors.js";
|
|
13
|
-
import { integerFlag, parseFlags, positional, printJson, printTable, readJson, runtimeCall, runtimeClient, usageError, } from "./runtime.js";
|
|
14
|
-
export const manifestsUsage = ` manifests list [--json] each environment manifest's latest version
|
|
15
|
-
manifests get <name> [--version <n>]
|
|
16
|
-
a manifest's latest version (or version n), as JSON
|
|
17
|
-
manifests versions <name> its versions, with the Environments made from each
|
|
18
|
-
manifests save <manifest.json>... [--if-match <n>] [--dry-run]
|
|
19
|
-
save each manifest's next version (a files entry with
|
|
20
|
-
"from": a folder beside the file, uploaded by hash);
|
|
21
|
-
--dry-run prints the plan and saves nothing
|
|
22
|
-
manifests rm <name> delete every version (refused while an Environment
|
|
23
|
-
was made from one)`;
|
|
24
|
-
/** Each file under `dir`, by its path relative to it (`/`-separated). */
|
|
25
|
-
async function folderOf(dir) {
|
|
26
|
-
const found = {};
|
|
27
|
-
const visit = async (at) => {
|
|
28
|
-
for (const entry of await readdir(at, { withFileTypes: true })) {
|
|
29
|
-
const path = join(at, entry.name);
|
|
30
|
-
if (entry.isDirectory())
|
|
31
|
-
await visit(path);
|
|
32
|
-
else if (entry.isFile())
|
|
33
|
-
found[relative(dir, path).split(sep).join("/")] = new Uint8Array(await readFile(path));
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
try {
|
|
37
|
-
await visit(dir);
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
throw new CliError(`Cannot read ${dir}: ${error.message}`, 1);
|
|
41
|
-
}
|
|
42
|
-
if (Object.keys(found).length === 0)
|
|
43
|
-
throw new CliError(`${dir} holds no files.`, 1);
|
|
44
|
-
return found;
|
|
45
|
-
}
|
|
46
|
-
/** The manifest in `path`, its `from` folders hashed: the body to save and the bytes to upload. */
|
|
47
|
-
export async function manifestFrom(path) {
|
|
48
|
-
const raw = await readJson(path, "The manifest");
|
|
49
|
-
if (typeof raw.name !== "string" || raw.name === "")
|
|
50
|
-
throw usageError(`${path}: the manifest has no name.`);
|
|
51
|
-
const bytes = {};
|
|
52
|
-
const files = Array.isArray(raw.files) ? raw.files : undefined;
|
|
53
|
-
const entries = [];
|
|
54
|
-
for (const entry of files ?? []) {
|
|
55
|
-
if (typeof entry?.from !== "string") {
|
|
56
|
-
entries.push(entry);
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const { from, ...rest } = entry;
|
|
60
|
-
if (typeof rest.path !== "string")
|
|
61
|
-
throw usageError(`${path}: a files entry with from needs a path.`);
|
|
62
|
-
const folder = await environmentFiles(rest.path, await folderOf(resolve(dirname(path), from)));
|
|
63
|
-
Object.assign(bytes, folder.bytes);
|
|
64
|
-
entries.push({ ...rest, files: folder.entry.files });
|
|
65
|
-
}
|
|
66
|
-
const { $schema: _schema, ...manifest } = raw;
|
|
67
|
-
return {
|
|
68
|
-
manifest: (files === undefined ? manifest : { ...manifest, files: entries }),
|
|
69
|
-
bytes,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
async function save(deps, args) {
|
|
73
|
-
const usage = "nylorun environments manifests save <manifest.json>... [--if-match <n>] [--dry-run]";
|
|
74
|
-
const flags = parseFlags(args, { booleans: ["--dry-run"], values: ["--if-match"] }, usage);
|
|
75
|
-
if (flags.rest.length === 0)
|
|
76
|
-
throw usageError(`Usage: ${usage}`);
|
|
77
|
-
const ifMatch = integerFlag(flags, "--if-match");
|
|
78
|
-
if (ifMatch !== undefined && flags.rest.length > 1)
|
|
79
|
-
throw usageError("--if-match takes one manifest.");
|
|
80
|
-
const { client, connection } = await runtimeClient(deps, flags);
|
|
81
|
-
let blocked = false;
|
|
82
|
-
for (const path of flags.rest) {
|
|
83
|
-
const { manifest, bytes } = await manifestFrom(path);
|
|
84
|
-
const options = { files: bytes, ...(ifMatch === undefined ? {} : { ifMatch }) };
|
|
85
|
-
if (flags.booleans.has("--dry-run")) {
|
|
86
|
-
const plan = await runtimeCall(() => client.environments.manifests.plan(manifest, options));
|
|
87
|
-
printJson(deps, plan);
|
|
88
|
-
if (plan.errors.length > 0)
|
|
89
|
-
blocked = true;
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
const saved = await runtimeCall(() => client.environments.manifests.save(manifest, options));
|
|
93
|
-
deps.err(saved.unchanged
|
|
94
|
-
? `Environment manifest ${saved.manifest.name} is unchanged at version ${saved.manifest.version} on ${connection.label}.`
|
|
95
|
-
: `Saved environment manifest ${saved.manifest.name} version ${saved.manifest.version} on ${connection.label}.`);
|
|
96
|
-
for (const warning of saved.warnings)
|
|
97
|
-
deps.err(` warning: ${warning.message}`);
|
|
98
|
-
printJson(deps, saved);
|
|
99
|
-
}
|
|
100
|
-
return blocked ? 1 : 0;
|
|
101
|
-
}
|
|
102
|
-
async function list(deps, args) {
|
|
103
|
-
const usage = "nylorun environments manifests list [--json]";
|
|
104
|
-
const flags = parseFlags(args, { booleans: ["--json"] }, usage);
|
|
105
|
-
positional(flags, 0, usage);
|
|
106
|
-
const { client, connection } = await runtimeClient(deps, flags);
|
|
107
|
-
const manifests = await runtimeCall(() => client.environments.manifests.list());
|
|
108
|
-
if (flags.booleans.has("--json")) {
|
|
109
|
-
printJson(deps, manifests);
|
|
110
|
-
return 0;
|
|
111
|
-
}
|
|
112
|
-
if (manifests.length === 0)
|
|
113
|
-
deps.out(`No environment manifests on ${connection.label}.`);
|
|
114
|
-
else
|
|
115
|
-
printTable(deps, [
|
|
116
|
-
["NAME", "VERSION", "KIND", "ENVIRONMENTS", "SAVED BY"],
|
|
117
|
-
...manifests.map((manifest) => [
|
|
118
|
-
manifest.name,
|
|
119
|
-
String(manifest.version),
|
|
120
|
-
manifest.manifest.kind ?? "virtual",
|
|
121
|
-
String(manifest.environments),
|
|
122
|
-
manifest.savedBy.actor,
|
|
123
|
-
]),
|
|
124
|
-
]);
|
|
125
|
-
return 0;
|
|
126
|
-
}
|
|
127
|
-
async function get(deps, args) {
|
|
128
|
-
const usage = "nylorun environments manifests get <name> [--version <n>]";
|
|
129
|
-
const flags = parseFlags(args, { values: ["--version"] }, usage);
|
|
130
|
-
const [name] = positional(flags, 1, usage);
|
|
131
|
-
const version = integerFlag(flags, "--version");
|
|
132
|
-
const { client } = await runtimeClient(deps, flags);
|
|
133
|
-
printJson(deps, await runtimeCall(() => client.environments.manifests.get(name, version === undefined ? {} : { version })));
|
|
134
|
-
return 0;
|
|
135
|
-
}
|
|
136
|
-
async function versions(deps, args) {
|
|
137
|
-
const usage = "nylorun environments manifests versions <name>";
|
|
138
|
-
const flags = parseFlags(args, {}, usage);
|
|
139
|
-
const [name] = positional(flags, 1, usage);
|
|
140
|
-
const { client } = await runtimeClient(deps, flags);
|
|
141
|
-
printJson(deps, await runtimeCall(() => client.environments.manifests.versions(name)));
|
|
142
|
-
return 0;
|
|
143
|
-
}
|
|
144
|
-
async function remove(deps, args) {
|
|
145
|
-
const usage = "nylorun environments manifests rm <name>";
|
|
146
|
-
const flags = parseFlags(args, {}, usage);
|
|
147
|
-
const [name] = positional(flags, 1, usage);
|
|
148
|
-
const { client, connection } = await runtimeClient(deps, flags);
|
|
149
|
-
const deleted = await runtimeCall(() => client.environments.manifests.delete(name));
|
|
150
|
-
if (!deleted.deleted) {
|
|
151
|
-
deps.err(`No environment manifest ${name} on ${connection.label}.`);
|
|
152
|
-
return 1;
|
|
153
|
-
}
|
|
154
|
-
deps.out(`Deleted environment manifest ${name}: every version.`);
|
|
155
|
-
return 0;
|
|
156
|
-
}
|
|
157
|
-
const COMMANDS = {
|
|
158
|
-
list,
|
|
159
|
-
ls: list,
|
|
160
|
-
get,
|
|
161
|
-
versions,
|
|
162
|
-
save,
|
|
163
|
-
rm: remove,
|
|
164
|
-
delete: remove,
|
|
165
|
-
};
|
|
166
|
-
/** `nylorun environments manifests <command> ...` */
|
|
167
|
-
export async function manifestsCommand(deps, args, usage) {
|
|
168
|
-
const [sub, ...rest] = args;
|
|
169
|
-
const command = sub !== undefined && Object.hasOwn(COMMANDS, sub) ? COMMANDS[sub] : undefined;
|
|
170
|
-
if (!command)
|
|
171
|
-
throw usageError(`Usage: nylorun environments manifests <list|get|versions|save|rm> …\n\n${usage}`);
|
|
172
|
-
return command(deps, rest);
|
|
173
|
-
}
|
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import { manifestsCommand, manifestsUsage } from "./environment-manifests.js";
|
|
2
|
-
import { readSecret } from "./io.js";
|
|
3
|
-
import { integerFlag, labelsOf, parseFlags, positional, printCursor, printJson, printTable, readJson, runtimeCall, runtimeClient, runtimeFlagsUsage, usageError, } from "./runtime.js";
|
|
4
|
-
export const environmentsUsage = `nylorun environments <command>
|
|
5
|
-
|
|
6
|
-
The Tenant's Environments (one sandbox and one vault each), through the Runtime API with an
|
|
7
|
-
application key (or NYLORUN_TOKEN).
|
|
8
|
-
|
|
9
|
-
list [--label <key=value>]... [--behind] [--limit <n>] [--cursor <c>] [--json]
|
|
10
|
-
id, kind, manifest, state, sessions and labels;
|
|
11
|
-
--behind: those made from an older manifest version
|
|
12
|
-
get <id> the Environment, as JSON
|
|
13
|
-
put <id> --manifest <name[@n]> [--label <key=value>]...
|
|
14
|
-
put <id> [<inline.json|->] [--kind <virtual|pod|none>] [--label <key=value>]...
|
|
15
|
-
create it from a manifest (its latest version, or n)
|
|
16
|
-
or inline fields, or find it and change its labels
|
|
17
|
-
(what it runs never changes: fork it for that)
|
|
18
|
-
fork <id> <new-id> [--manifest <name[@n]>] [--disk <latest|n|empty>]
|
|
19
|
-
[--secrets <copy|none>] [--label <key=value>]... [--dry-run]
|
|
20
|
-
a new Environment from a manifest version (default
|
|
21
|
-
its manifest's latest), with this one's disk and the
|
|
22
|
-
secrets it declares; --dry-run prints the plan
|
|
23
|
-
stop <id> | reset <id> stop its sandbox; reset its disk
|
|
24
|
-
delete <id> delete it: its sandbox, files and vault (refused while a
|
|
25
|
-
turn runs in it)
|
|
26
|
-
snapshot <id> keep a version of its disk
|
|
27
|
-
versions <id> its disk versions
|
|
28
|
-
restore <id> <version|latest> put a version of its disk back
|
|
29
|
-
delete-version <id> <version>
|
|
30
|
-
events <id> [--from <n>] [--types <type,…>] [--since <time>] [--until <time>]
|
|
31
|
-
its events (lifecycle, and environment.egress for every
|
|
32
|
-
connection, naming the turns running), as JSON
|
|
33
|
-
secrets list <id> its secrets' names, types and bindings (never a value)
|
|
34
|
-
secrets get <id> <name>
|
|
35
|
-
secrets put <id> <name> the value of a slot its manifest declares, piped in
|
|
36
|
-
on standard input
|
|
37
|
-
secrets put <id> <name> <secret.json|->
|
|
38
|
-
create or replace a secret: {"type": "bearer", ...}, read
|
|
39
|
-
from a file or standard input
|
|
40
|
-
secrets rm <id> <name>
|
|
41
|
-
${manifestsUsage}
|
|
42
|
-
|
|
43
|
-
${runtimeFlagsUsage}`;
|
|
44
|
-
async function list(deps, args) {
|
|
45
|
-
const usage = "nylorun environments list [--label <key=value>]... [--behind] [--limit <n>] [--cursor <c>] [--json]";
|
|
46
|
-
const flags = parseFlags(args, { booleans: ["--json", "--behind"], values: ["--limit", "--cursor"], lists: ["--label"] }, usage);
|
|
47
|
-
positional(flags, 0, usage);
|
|
48
|
-
const labels = labelsOf(flags);
|
|
49
|
-
const limit = integerFlag(flags, "--limit");
|
|
50
|
-
const cursor = flags.values.get("--cursor");
|
|
51
|
-
const { client, connection } = await runtimeClient(deps, flags);
|
|
52
|
-
const paged = limit !== undefined || cursor !== undefined;
|
|
53
|
-
const page = paged
|
|
54
|
-
? await runtimeCall(() => client.environments.page({
|
|
55
|
-
...(labels ? { labels } : {}),
|
|
56
|
-
...(limit === undefined ? {} : { limit }),
|
|
57
|
-
...(cursor ? { cursor } : {}),
|
|
58
|
-
}))
|
|
59
|
-
: {
|
|
60
|
-
environments: await runtimeCall(() => client.environments.list(labels ? { labels } : {})),
|
|
61
|
-
nextCursor: null,
|
|
62
|
-
};
|
|
63
|
-
let environments = page.environments;
|
|
64
|
-
if (flags.booleans.has("--behind")) {
|
|
65
|
-
// Made from a manifest version older than its latest: fork them to move on (D63).
|
|
66
|
-
const latest = new Map((await runtimeCall(() => client.environments.manifests.list())).map((manifest) => [manifest.name, manifest.version]));
|
|
67
|
-
environments = environments.filter((environment) => environment.manifestName !== undefined &&
|
|
68
|
-
(environment.manifestVersion ?? 0) < (latest.get(environment.manifestName) ?? 0));
|
|
69
|
-
}
|
|
70
|
-
if (flags.booleans.has("--json")) {
|
|
71
|
-
printJson(deps, paged ? page : environments);
|
|
72
|
-
return 0;
|
|
73
|
-
}
|
|
74
|
-
if (environments.length === 0)
|
|
75
|
-
deps.out(`No Environments on ${connection.label}.`);
|
|
76
|
-
else
|
|
77
|
-
printTable(deps, [
|
|
78
|
-
["ID", "KIND", "MANIFEST", "STATE", "SESSIONS", "LABELS"],
|
|
79
|
-
...environments.map((environment) => [
|
|
80
|
-
environment.id,
|
|
81
|
-
environment.kind,
|
|
82
|
-
environment.manifestName === undefined ? "-" : `${environment.manifestName}@${environment.manifestVersion}`,
|
|
83
|
-
environment.state,
|
|
84
|
-
String(environment.sessions.length),
|
|
85
|
-
Object.entries(environment.labels)
|
|
86
|
-
.map(([key, value]) => `${key}=${value}`)
|
|
87
|
-
.join(",") || "-",
|
|
88
|
-
]),
|
|
89
|
-
]);
|
|
90
|
-
printCursor(deps, page.nextCursor);
|
|
91
|
-
return 0;
|
|
92
|
-
}
|
|
93
|
-
/** A command that takes one Environment id and prints the Runtime's answer. */
|
|
94
|
-
function byId(name, call) {
|
|
95
|
-
return async (deps, args) => {
|
|
96
|
-
const usage = `nylorun environments ${name} <id>`;
|
|
97
|
-
const flags = parseFlags(args, {}, usage);
|
|
98
|
-
const [id] = positional(flags, 1, usage);
|
|
99
|
-
const { client } = await runtimeClient(deps, flags);
|
|
100
|
-
printJson(deps, await runtimeCall(() => call(client, id)));
|
|
101
|
-
return 0;
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
async function put(deps, args) {
|
|
105
|
-
const usage = "nylorun environments put <id> [--manifest <name[@n]> | <inline.json|-> [--kind <virtual|pod|none>]] [--label <key=value>]...";
|
|
106
|
-
const flags = parseFlags(args, { values: ["--kind", "--manifest"], lists: ["--label"] }, usage);
|
|
107
|
-
if (flags.rest.length < 1 || flags.rest.length > 2)
|
|
108
|
-
throw usageError(`Usage: ${usage}`);
|
|
109
|
-
const [id, path] = flags.rest;
|
|
110
|
-
const manifest = flags.values.get("--manifest");
|
|
111
|
-
const kind = flags.values.get("--kind");
|
|
112
|
-
if (manifest !== undefined && (path !== undefined || kind !== undefined))
|
|
113
|
-
throw usageError("--manifest makes it from the manifest: give no inline fields or --kind with it.");
|
|
114
|
-
const recipe = path === undefined ? {} : await readJson(path, "The inline fields");
|
|
115
|
-
const labels = labelsOf(flags);
|
|
116
|
-
const body = {
|
|
117
|
-
...recipe,
|
|
118
|
-
...(manifest ? { manifest } : {}),
|
|
119
|
-
...(kind ? { kind } : {}),
|
|
120
|
-
...(labels ? { labels: { ...recipe.labels, ...labels } } : {}),
|
|
121
|
-
};
|
|
122
|
-
const { client } = await runtimeClient(deps, flags);
|
|
123
|
-
printJson(deps, await runtimeCall(() => client.environments.put(id, body)));
|
|
124
|
-
return 0;
|
|
125
|
-
}
|
|
126
|
-
async function fork(deps, args) {
|
|
127
|
-
const usage = "nylorun environments fork <id> <new-id> [--manifest <name[@n]>] [--disk <latest|n|empty>] [--secrets <copy|none>] [--label <key=value>]... [--dry-run]";
|
|
128
|
-
const flags = parseFlags(args, { booleans: ["--dry-run"], values: ["--manifest", "--disk", "--secrets"], lists: ["--label"] }, usage);
|
|
129
|
-
const [id, next] = positional(flags, 2, usage);
|
|
130
|
-
const disk = flags.values.get("--disk");
|
|
131
|
-
if (disk !== undefined && disk !== "latest" && disk !== "empty" && !/^[1-9]\d*$/.test(disk))
|
|
132
|
-
throw usageError("--disk is latest, empty or a version number.");
|
|
133
|
-
const secrets = flags.values.get("--secrets");
|
|
134
|
-
if (secrets !== undefined && secrets !== "copy" && secrets !== "none")
|
|
135
|
-
throw usageError("--secrets is copy or none.");
|
|
136
|
-
const manifest = flags.values.get("--manifest");
|
|
137
|
-
const labels = labelsOf(flags);
|
|
138
|
-
const options = {
|
|
139
|
-
id: next,
|
|
140
|
-
...(manifest ? { manifest } : {}),
|
|
141
|
-
...(disk === undefined ? {} : { disk: disk === "latest" || disk === "empty" ? disk : Number(disk) }),
|
|
142
|
-
...(secrets ? { secrets: secrets } : {}),
|
|
143
|
-
...(labels ? { labels } : {}),
|
|
144
|
-
};
|
|
145
|
-
const { client, connection } = await runtimeClient(deps, flags);
|
|
146
|
-
if (flags.booleans.has("--dry-run")) {
|
|
147
|
-
printJson(deps, await runtimeCall(() => client.environments.planFork(id, options)));
|
|
148
|
-
return 0;
|
|
149
|
-
}
|
|
150
|
-
const forked = await runtimeCall(() => client.environments.fork(id, options));
|
|
151
|
-
const { plan } = forked;
|
|
152
|
-
deps.err(`Forked Environment ${id} into ${next} on ${connection.label}: ${plan.manifest ? `${plan.manifest.name}@${plan.manifest.version}` : "its fields"}, ${plan.disk === null ? "an empty disk" : `disk version ${plan.disk}`}, ${plan.secrets.copied.length} secrets copied${plan.setup ? "; its setup runs before the first turn" : ""}.`);
|
|
153
|
-
if (plan.secrets.missing.length > 0)
|
|
154
|
-
deps.err(` set before use: ${plan.secrets.missing.join(", ")} (nylorun environments secrets put ${next} <name>)`);
|
|
155
|
-
printJson(deps, forked);
|
|
156
|
-
return 0;
|
|
157
|
-
}
|
|
158
|
-
async function deleteEnvironment(deps, args) {
|
|
159
|
-
const usage = "nylorun environments delete <id>";
|
|
160
|
-
const flags = parseFlags(args, {}, usage);
|
|
161
|
-
const [id] = positional(flags, 1, usage);
|
|
162
|
-
const { client, connection } = await runtimeClient(deps, flags);
|
|
163
|
-
const deleted = await runtimeCall(async () => {
|
|
164
|
-
try {
|
|
165
|
-
return await client.environments.delete(id);
|
|
166
|
-
}
|
|
167
|
-
catch (error) {
|
|
168
|
-
if (error.status === 404)
|
|
169
|
-
return undefined;
|
|
170
|
-
throw error;
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
if (!deleted || deleted.deleted === false) {
|
|
174
|
-
deps.err(`No Environment ${id} on ${connection.label}.`);
|
|
175
|
-
return 1;
|
|
176
|
-
}
|
|
177
|
-
deps.out(`Deleted Environment ${id}: its sandbox, files and vault.`);
|
|
178
|
-
return 0;
|
|
179
|
-
}
|
|
180
|
-
async function restore(deps, args) {
|
|
181
|
-
const usage = "nylorun environments restore <id> <version|latest>";
|
|
182
|
-
const flags = parseFlags(args, {}, usage);
|
|
183
|
-
const [id, version] = positional(flags, 2, usage);
|
|
184
|
-
if (version !== "latest" && !/^[1-9]\d*$/.test(version))
|
|
185
|
-
throw usageError("The version is a positive number or latest.");
|
|
186
|
-
const { client } = await runtimeClient(deps, flags);
|
|
187
|
-
printJson(deps, await runtimeCall(() => client.environments.restore(id, version === "latest" ? "latest" : Number(version))));
|
|
188
|
-
return 0;
|
|
189
|
-
}
|
|
190
|
-
async function deleteVersion(deps, args) {
|
|
191
|
-
const usage = "nylorun environments delete-version <id> <version>";
|
|
192
|
-
const flags = parseFlags(args, {}, usage);
|
|
193
|
-
const [id, version] = positional(flags, 2, usage);
|
|
194
|
-
if (!/^[1-9]\d*$/.test(version))
|
|
195
|
-
throw usageError("The version is a positive number.");
|
|
196
|
-
const { client } = await runtimeClient(deps, flags);
|
|
197
|
-
printJson(deps, await runtimeCall(() => client.environments.deleteVersion(id, Number(version))));
|
|
198
|
-
return 0;
|
|
199
|
-
}
|
|
200
|
-
async function events(deps, args) {
|
|
201
|
-
const usage = "nylorun environments events <id> [--from <n>] [--types <type,…>] [--since <time>] [--until <time>]";
|
|
202
|
-
const flags = parseFlags(args, { values: ["--from", "--types", "--since", "--until"] }, usage);
|
|
203
|
-
const [id] = positional(flags, 1, usage);
|
|
204
|
-
const from = integerFlag(flags, "--from");
|
|
205
|
-
const types = flags.values.get("--types")?.split(",").map((type) => type.trim()).filter(Boolean);
|
|
206
|
-
const since = flags.values.get("--since");
|
|
207
|
-
const until = flags.values.get("--until");
|
|
208
|
-
const { client } = await runtimeClient(deps, flags);
|
|
209
|
-
printJson(deps, await runtimeCall(() => client.environments.events(id, {
|
|
210
|
-
...(from === undefined ? {} : { from }),
|
|
211
|
-
...(types === undefined || types.length === 0 ? {} : { types }),
|
|
212
|
-
...(since === undefined ? {} : { since }),
|
|
213
|
-
...(until === undefined ? {} : { until }),
|
|
214
|
-
})));
|
|
215
|
-
return 0;
|
|
216
|
-
}
|
|
217
|
-
async function secrets(deps, args) {
|
|
218
|
-
const [verb, ...rest] = args;
|
|
219
|
-
if (verb === "list" || verb === "ls") {
|
|
220
|
-
const usage = "nylorun environments secrets list <id>";
|
|
221
|
-
const flags = parseFlags(rest, {}, usage);
|
|
222
|
-
const [id] = positional(flags, 1, usage);
|
|
223
|
-
const { client } = await runtimeClient(deps, flags);
|
|
224
|
-
printJson(deps, await runtimeCall(() => client.environments.secrets.list(id)));
|
|
225
|
-
return 0;
|
|
226
|
-
}
|
|
227
|
-
if (verb === "get") {
|
|
228
|
-
const usage = "nylorun environments secrets get <id> <name>";
|
|
229
|
-
const flags = parseFlags(rest, {}, usage);
|
|
230
|
-
const [id, name] = positional(flags, 2, usage);
|
|
231
|
-
const { client } = await runtimeClient(deps, flags);
|
|
232
|
-
printJson(deps, await runtimeCall(() => client.environments.secrets.get(id, name)));
|
|
233
|
-
return 0;
|
|
234
|
-
}
|
|
235
|
-
if (verb === "put") {
|
|
236
|
-
const usage = "nylorun environments secrets put <id> <name> [<secret.json|->]";
|
|
237
|
-
const flags = parseFlags(rest, {}, usage);
|
|
238
|
-
if (flags.rest.length < 2 || flags.rest.length > 3)
|
|
239
|
-
throw usageError(`Usage: ${usage}`);
|
|
240
|
-
const [id, name, path] = flags.rest;
|
|
241
|
-
if (path === undefined) {
|
|
242
|
-
// A slot its manifest declares (D64): the value only, piped in; the binding is the slot's.
|
|
243
|
-
const value = await readSecret(deps, `value of ${name}`, `printf %s "$TOKEN" | nylorun environments secrets put ${id} ${name}`);
|
|
244
|
-
const { client } = await runtimeClient(deps, flags);
|
|
245
|
-
printJson(deps, await runtimeCall(() => client.environments.secrets.put(id, name, { value })));
|
|
246
|
-
return 0;
|
|
247
|
-
}
|
|
248
|
-
const secret = await readJson(path, "The secret");
|
|
249
|
-
if (typeof secret.type !== "string")
|
|
250
|
-
throw usageError('The secret needs a "type".');
|
|
251
|
-
const { client } = await runtimeClient(deps, flags);
|
|
252
|
-
printJson(deps, await runtimeCall(() => client.environments.secrets.put(id, name, secret)));
|
|
253
|
-
return 0;
|
|
254
|
-
}
|
|
255
|
-
if (verb === "rm" || verb === "delete") {
|
|
256
|
-
const usage = "nylorun environments secrets rm <id> <name>";
|
|
257
|
-
const flags = parseFlags(rest, {}, usage);
|
|
258
|
-
const [id, name] = positional(flags, 2, usage);
|
|
259
|
-
const { client } = await runtimeClient(deps, flags);
|
|
260
|
-
await runtimeCall(() => client.environments.secrets.delete(id, name));
|
|
261
|
-
deps.out(`Deleted secret ${name} of Environment ${id}.`);
|
|
262
|
-
return 0;
|
|
263
|
-
}
|
|
264
|
-
throw usageError(`Usage: nylorun environments secrets <list|get|put|rm> …\n\n${environmentsUsage}`);
|
|
265
|
-
}
|
|
266
|
-
const COMMANDS = {
|
|
267
|
-
list,
|
|
268
|
-
ls: list,
|
|
269
|
-
get: byId("get", (client, id) => client.environments.get(id)),
|
|
270
|
-
put,
|
|
271
|
-
stop: byId("stop", (client, id) => client.environments.stop(id)),
|
|
272
|
-
reset: byId("reset", (client, id) => client.environments.reset(id)),
|
|
273
|
-
delete: deleteEnvironment,
|
|
274
|
-
rm: deleteEnvironment,
|
|
275
|
-
snapshot: byId("snapshot", (client, id) => client.environments.snapshot(id)),
|
|
276
|
-
versions: byId("versions", (client, id) => client.environments.versions(id)),
|
|
277
|
-
restore,
|
|
278
|
-
"delete-version": deleteVersion,
|
|
279
|
-
events,
|
|
280
|
-
secrets,
|
|
281
|
-
fork,
|
|
282
|
-
manifests: (deps, args) => manifestsCommand(deps, args, manifestsUsage),
|
|
283
|
-
};
|
|
284
|
-
/** `nylorun environments <command> ...` */
|
|
285
|
-
export async function environmentsCommand(deps, args) {
|
|
286
|
-
const [sub, ...rest] = args;
|
|
287
|
-
if (sub === "--help" || sub === "-h") {
|
|
288
|
-
deps.out(environmentsUsage);
|
|
289
|
-
return 0;
|
|
290
|
-
}
|
|
291
|
-
const command = sub !== undefined && Object.hasOwn(COMMANDS, sub) ? COMMANDS[sub] : undefined;
|
|
292
|
-
if (!command)
|
|
293
|
-
throw usageError(sub ? `Unknown environments command ${sub}.\n${environmentsUsage}` : environmentsUsage);
|
|
294
|
-
return command(deps, rest);
|
|
295
|
-
}
|