@ornncompute/cli 1.0.107 → 1.0.110

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 CHANGED
@@ -78,6 +78,10 @@ market books | book | trades | bid | orders | cancel
78
78
  offers list | post | accept | cancel
79
79
  machines list | show | wait | switch | reboot | reset | metrics | logs
80
80
  clusters list | show | wait | eligible-machines | add-node | remove-node | teardown | metrics | logs
81
+ registry login | show | usage
82
+ registry repositories list
83
+ registry tags list | delete
84
+ registry copies list
81
85
  ssh-keys list | add | delete
82
86
  ssh-keys assignments list | assign | sync | status
83
87
  private-networks list | show | create | update | delete
@@ -110,7 +114,7 @@ reservations, schedule and spot alike; `reservations buy` books one window of a
110
114
  relisted (secondary) listing term with Markets `POST /v1/markets/bookings`
111
115
  (`{legs: [...]}`), at the term price `terms` shows; it becomes a reservation
112
116
  when the window starts. `market` and `offers` call Markets (`/v1/markets`):
113
- buy `--nodes` at market (Markets also takes GPU counts and limit bids; the
117
+ buy `--nodes` at market (Markets also takes limit bids; the
114
118
  CLI does not send them yet), end a fill with
115
119
  `market end` (Commerce `DELETE /commerce/reservations/{id}`), post an offer
116
120
  on a whole primary listing for one of its terms (`--listing-term-id`, optional
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornncompute/cli",
3
- "version": "1.0.107",
3
+ "version": "1.0.110",
4
4
  "description": "Command-line interface for Ornn compute access workflows.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,3 +1,5 @@
1
+ import { readFileSync } from "node:fs";
2
+
1
3
  import {
2
4
  CliApiError,
3
5
  cliRequest,
@@ -35,6 +37,7 @@ import {
35
37
  writeExternalBucketResultHuman,
36
38
  } from "./external-bucket-commands.mjs";
37
39
  import { executeEvidenceCommand, supplierOwnedRecord } from "./evidence-commands.mjs";
40
+ import { executeRegistryCommand } from "./registry-commands.mjs";
38
41
  import {
39
42
  executeKubernetesClusterCommand,
40
43
  kubernetesConnectModeHandler,
@@ -78,6 +81,9 @@ const MACHINE_SCHEMA = "ornn.cli/v1";
78
81
  const UPDATE_CHANNEL = "stable";
79
82
  const FORMATS = { human: true, json: true, ndjson: true };
80
83
  const SESSION_CAPABILITY_IDS = new Set(["identity.context", "identity.login", "identity.logout"]);
84
+ // Cloud Shell's welcome prints this file from the installed package.
85
+ const LOGO_URL = new URL("./ornn-logo.txt", import.meta.url);
86
+ const LOGO_COLUMNS = 72;
81
87
  export const CLI_EXIT_STATUS = Object.freeze({
82
88
  success: 0,
83
89
  failure: 1,
@@ -584,6 +590,9 @@ function writeRootHuman(stdout, catalog) {
584
590
  }
585
591
  stdout.write("\n");
586
592
  };
593
+ if (stdout.isTTY && stdout.columns >= LOGO_COLUMNS) {
594
+ stdout.write(`\n${readFileSync(LOGO_URL, "utf8")}\n`);
595
+ }
587
596
  stdout.write("Ornn CLI\n\n");
588
597
  stdout.write("Usage:\n ornn <command> [options]\n\n");
589
598
  stdout.write("Available commands:\n\n");
@@ -950,6 +959,13 @@ async function executeCapability(
950
959
  interaction: this,
951
960
  });
952
961
  },
962
+ registry(command, registryInput) {
963
+ return executeRegistryCommand(command, registryInput, {
964
+ fetch: (path, init) => customerCapabilityFetch(io, path, init, authSnapshot),
965
+ interaction: this,
966
+ spawnProcess: io.spawnProcess,
967
+ });
968
+ },
953
969
  storage(command, storageInput) {
954
970
  return executeStorageCommand(command, storageInput, {
955
971
  env: io.env,
@@ -0,0 +1,8 @@
1
+ ▄██████▀▀▀▀▀▀▀▀ ▄▄█▀▀▀█▄▄
2
+ ▀▀▀▀▀▀ ▄▄▄▄▄▄▄ ▄█▀ ▀█▄
3
+ ████████ ▀▀▀▀▀▀ ██▀ ▀██ ▄▄▄ ▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄▄
4
+ ▄▄▄▄▄▄▄ ██ ██▄ ████▀▀▀ ███▄▀▀▀██▄ ██▄▀▀▀▀██
5
+ ▀▀▀▀▀▀▀▀ ██ ██▀ ███ ███ ███ ██▀ ██
6
+ ████████ ██▄ ▄██ ██▄ ███ ███ ██ ██
7
+ ▀▀▀▀▀▀▀ ▀█▄ ▄██ ███ ███ ███ ██ ██
8
+ ▄▄▄▄▄▄▄███████▀ ▀██▄▄▄██▀▀ ███ ███ ███ ██▄ ███
@@ -0,0 +1,96 @@
1
+ import { spawn as spawnProcessDefault } from "node:child_process";
2
+ import os from "node:os";
3
+
4
+ /** One key per machine: a new login revokes the key this machine's last one made. */
5
+ const KEY_NAME_PREFIX = "Docker login on ";
6
+
7
+ export async function executeRegistryCommand(command, input, runtime) {
8
+ if (command !== "registry.login") {
9
+ runtime.interaction.error("Unknown registry command.", { code: "unknown_command" });
10
+ }
11
+ return login(runtime);
12
+ }
13
+
14
+ async function login({
15
+ fetch,
16
+ interaction,
17
+ spawnProcess = spawnProcessDefault,
18
+ hostname = os.hostname(),
19
+ }) {
20
+ const registry = await fetch("/v1/orchestrator/registry");
21
+ const session = await fetch("/v1/cli/session");
22
+ const organizationId = (session?.selectedOrganization ?? session?.selected_organization)?.id;
23
+ if (typeof organizationId !== "string" || !organizationId) {
24
+ interaction.usage("Join an organization before logging in to its registry.", {
25
+ code: "organization_required",
26
+ field: "organization",
27
+ });
28
+ }
29
+ const keysPath = `/v1/organizations/${encodeURIComponent(organizationId)}/api-keys`;
30
+ const name = `${KEY_NAME_PREFIX}${hostname}`.slice(0, 100);
31
+
32
+ const existing = await fetch(keysPath);
33
+ for (const key of existing?.api_keys ?? []) {
34
+ if (key?.name === name && typeof key.id === "string") {
35
+ await fetch(`${keysPath}/${encodeURIComponent(key.id)}`, { method: "DELETE" });
36
+ }
37
+ }
38
+ const created = await fetch(keysPath, {
39
+ method: "POST",
40
+ body: { name, access: "read_write" },
41
+ });
42
+
43
+ let exit;
44
+ try {
45
+ exit = await dockerLogin(spawnProcess, registry.host, created.token);
46
+ } catch (error) {
47
+ await fetch(`${keysPath}/${encodeURIComponent(created.id)}`, { method: "DELETE" });
48
+ const missing = error?.code === "ENOENT";
49
+ interaction.error(
50
+ missing
51
+ ? "Docker is not installed, or `docker` is not on your PATH. Install Docker and run ornn registry login again."
52
+ : `Docker could not be started: ${error?.message ?? error}`,
53
+ { code: missing ? "docker_not_found" : "docker_unavailable", exitCode: 6 }
54
+ );
55
+ }
56
+ if (exit.code !== 0) {
57
+ await fetch(`${keysPath}/${encodeURIComponent(created.id)}`, { method: "DELETE" });
58
+ interaction.error(`docker login ${registry.host} failed; no key was kept.`, {
59
+ code: "docker_login_failed",
60
+ exitCode: 1,
61
+ retryable: true,
62
+ });
63
+ }
64
+
65
+ return interaction.result({
66
+ data: {
67
+ host: registry.host,
68
+ namespace: registry.namespace,
69
+ api_key: { id: created.id, name: created.name },
70
+ },
71
+ presentation: {
72
+ lines: [
73
+ `Logged in to ${registry.host}.`,
74
+ `Push images under ${registry.host}/${registry.namespace}/<name>:<tag>.`,
75
+ ],
76
+ },
77
+ });
78
+ }
79
+
80
+ /** `docker login --password-stdin`: the key never reaches argv or the shell history. */
81
+ function dockerLogin(spawnProcess, host, token) {
82
+ return new Promise((resolve, reject) => {
83
+ let child;
84
+ try {
85
+ child = spawnProcess("docker", ["login", host, "--username", "ornn", "--password-stdin"], {
86
+ stdio: ["pipe", "inherit", "inherit"],
87
+ });
88
+ } catch (error) {
89
+ reject(error);
90
+ return;
91
+ }
92
+ child.once("error", reject);
93
+ child.once("exit", (code, signal) => resolve({ code: signal ? 1 : code, signal }));
94
+ child.stdin.end(token);
95
+ });
96
+ }
@@ -6852,15 +6852,347 @@ var networkVerbCapabilities = [
6852
6852
  })
6853
6853
  ];
6854
6854
 
6855
- // ../../packages/capabilities/dist/capabilities/reservation-list.js
6855
+ // ../../packages/capabilities/dist/capabilities/registry.js
6856
6856
  import { z as z28 } from "zod";
6857
- var reservationListInput = z28.object({
6858
- customerId: z28.string().uuid().optional(),
6859
- listingId: z28.string().uuid().optional(),
6860
- listingTermId: z28.string().uuid().optional(),
6861
- status: z28.enum(["confirmed", "active", "completed", "cancelled"]).optional(),
6862
- cursor: z28.string().optional(),
6863
- limit: z28.number().int().min(1).max(100).optional()
6857
+ var REGISTRY_PATH = "/v1/orchestrator/registry";
6858
+ var globalInput2 = {
6859
+ $positionals: z28.array(z28.string()).default([]),
6860
+ yes: z28.boolean().optional()
6861
+ };
6862
+ var emptyInput4 = z28.object(globalInput2).strict();
6863
+ var repositoryInput = z28.object({
6864
+ ...globalInput2,
6865
+ repository: z28.string().optional().describe("Repository name, with or without your organization's namespace.")
6866
+ }).strict();
6867
+ var tagInput = z28.object({
6868
+ ...globalInput2,
6869
+ repository: z28.string().optional().describe("Repository name, with or without your organization's namespace."),
6870
+ tag: z28.string().optional().describe("Tag to delete, such as v1.")
6871
+ }).strict();
6872
+ function cliInteraction(context) {
6873
+ return context.cli?.interaction;
6874
+ }
6875
+ function qualifiedRepository(value, registry) {
6876
+ let name = value.trim();
6877
+ if (name.startsWith(`${registry.host}/`))
6878
+ name = name.slice(registry.host.length + 1);
6879
+ return name.startsWith(`${registry.namespace}/`) ? name : `${registry.namespace}/${name}`;
6880
+ }
6881
+ function shortName(repository, registry) {
6882
+ return repository.startsWith(`${registry.namespace}/`) ? repository.slice(registry.namespace.length + 1) : repository;
6883
+ }
6884
+ function formatBytes(bytes) {
6885
+ const units = ["B", "KB", "MB", "GB", "TB"];
6886
+ let value = bytes;
6887
+ let unit = 0;
6888
+ while (value >= 1024 && unit < units.length - 1) {
6889
+ value /= 1024;
6890
+ unit += 1;
6891
+ }
6892
+ return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
6893
+ }
6894
+ async function registryOf(context) {
6895
+ return await context.fetch(REGISTRY_PATH, { method: "GET" });
6896
+ }
6897
+ function repositoryArgument(input, interaction2) {
6898
+ const raw = input.repository ?? input.$positionals[0];
6899
+ if (!raw) {
6900
+ const message = "Name a repository, such as trainer.";
6901
+ if (interaction2)
6902
+ interaction2.usage(message, { code: "repository_required", field: "repository" });
6903
+ throw new Error(message);
6904
+ }
6905
+ const reference = raw.trim();
6906
+ const slash = reference.lastIndexOf("/");
6907
+ const colon = reference.lastIndexOf(":");
6908
+ if (colon > slash) {
6909
+ return { repository: reference.slice(0, colon), tag: input.tag ?? reference.slice(colon + 1) };
6910
+ }
6911
+ return { repository: reference, tag: input.tag ?? input.$positionals[1] };
6912
+ }
6913
+ var registryShowCapability = defineCapability({
6914
+ id: "registry.show",
6915
+ domain: "registry",
6916
+ roles: ["user"],
6917
+ description: "Show the organization's container registry: the host to docker login to and the namespace every image is pushed under.",
6918
+ mutation: "read",
6919
+ http: { method: "GET", path: REGISTRY_PATH },
6920
+ input: emptyInput4,
6921
+ cli: {
6922
+ command: ["registry", "show"],
6923
+ vnext: {
6924
+ audience: "customer",
6925
+ category: "resource",
6926
+ order: 600,
6927
+ outcome: "Show where your organization pushes container images.",
6928
+ human: "ornn registry show",
6929
+ automation: "ornn registry show --format json",
6930
+ related: ["registry login", "registry repositories list"]
6931
+ }
6932
+ },
6933
+ slack: false,
6934
+ execute: async (context) => {
6935
+ const registry = await registryOf(context);
6936
+ const interaction2 = cliInteraction(context);
6937
+ if (!interaction2)
6938
+ return registry;
6939
+ return interaction2.result({
6940
+ data: registry,
6941
+ presentation: {
6942
+ lines: [`Image prefix: ${registry.host}/${registry.namespace}`],
6943
+ next: "ornn registry login"
6944
+ }
6945
+ });
6946
+ }
6947
+ });
6948
+ var registryRepositoriesListCapability = defineCapability({
6949
+ id: "registry.repositories.list",
6950
+ domain: "registry",
6951
+ roles: ["user"],
6952
+ description: "List the repositories in the organization's container registry that have a tag.",
6953
+ mutation: "read",
6954
+ http: { method: "GET", path: `${REGISTRY_PATH}/repositories` },
6955
+ input: emptyInput4,
6956
+ cli: {
6957
+ command: ["registry", "repositories", "list"],
6958
+ vnext: {
6959
+ audience: "customer",
6960
+ category: "resource",
6961
+ order: 601,
6962
+ outcome: "List the repositories your organization has pushed.",
6963
+ human: "ornn registry repositories list",
6964
+ automation: "ornn registry repositories list --format json",
6965
+ related: ["registry tags list", "registry show"]
6966
+ }
6967
+ },
6968
+ slack: false,
6969
+ execute: async (context) => {
6970
+ const listed = await context.fetch(`${REGISTRY_PATH}/repositories`, { method: "GET" });
6971
+ const interaction2 = cliInteraction(context);
6972
+ if (!interaction2)
6973
+ return listed;
6974
+ const registry = await registryOf(context);
6975
+ return interaction2.result({
6976
+ data: listed,
6977
+ presentation: {
6978
+ lines: listed.repositories.length ? listed.repositories.map((repository) => `${shortName(repository.name, registry)} ${repository.tag_count} ${repository.tag_count === 1 ? "tag" : "tags"}`) : ["No images yet. Push one with docker push after ornn registry login."]
6979
+ }
6980
+ });
6981
+ }
6982
+ });
6983
+ var registryTagsListCapability = defineCapability({
6984
+ id: "registry.tags.list",
6985
+ domain: "registry",
6986
+ roles: ["user"],
6987
+ description: "List one repository's tags with the digest each names, the bytes the image occupies, and when it was built.",
6988
+ mutation: "read",
6989
+ http: { method: "GET", path: `${REGISTRY_PATH}/tags` },
6990
+ input: repositoryInput,
6991
+ cli: {
6992
+ command: ["registry", "tags", "list"],
6993
+ vnext: {
6994
+ arguments: "semantic",
6995
+ audience: "customer",
6996
+ category: "resource",
6997
+ order: 602,
6998
+ outcome: "List a repository's tags.",
6999
+ human: "ornn registry tags list <repository>",
7000
+ automation: "ornn registry tags list <repository> --format json",
7001
+ acceptedReferences: ["repository name", "<namespace>/<repository>"],
7002
+ related: ["registry tags delete", "registry copies list"]
7003
+ }
7004
+ },
7005
+ slack: false,
7006
+ execute: async (context, input) => {
7007
+ const interaction2 = cliInteraction(context);
7008
+ const registry = await registryOf(context);
7009
+ const repository = qualifiedRepository(repositoryArgument(input, interaction2).repository, registry);
7010
+ const listed = await context.fetch(`${REGISTRY_PATH}/tags?${new URLSearchParams({ repository })}`, { method: "GET" });
7011
+ if (!interaction2)
7012
+ return listed;
7013
+ return interaction2.result({
7014
+ data: listed,
7015
+ presentation: {
7016
+ lines: listed.tags.map((tag) => `${tag.tag} ${tag.digest.slice(0, 19)} ${formatBytes(tag.size_bytes)}${tag.created_at ? ` built ${tag.created_at}` : ""}`)
7017
+ }
7018
+ });
7019
+ }
7020
+ });
7021
+ var registryTagsDeleteCapability = defineCapability({
7022
+ id: "registry.tags.delete",
7023
+ domain: "registry",
7024
+ roles: ["user"],
7025
+ description: "Delete a tag from the organization's container registry. Pods and Slurm jobs that name it can no longer pull it; each cluster drops its copy within a minute, and the registry frees the space no other tag uses, pausing pushes for about a minute while it does.",
7026
+ mutation: "preview-confirm",
7027
+ http: { method: "DELETE", path: `${REGISTRY_PATH}/tags` },
7028
+ input: tagInput,
7029
+ cli: {
7030
+ command: ["registry", "tags", "delete"],
7031
+ vnext: {
7032
+ arguments: "semantic",
7033
+ audience: "customer",
7034
+ category: "resource",
7035
+ order: 603,
7036
+ outcome: "Delete one tag after review.",
7037
+ human: "ornn registry tags delete <repository>:<tag>",
7038
+ automation: "ornn registry tags delete <repository>:<tag> --yes --format json",
7039
+ acceptedReferences: ["<repository>:<tag>"],
7040
+ review: "Shows the tag before deleting it; --yes skips the review.",
7041
+ related: ["registry tags list"]
7042
+ }
7043
+ },
7044
+ slack: false,
7045
+ execute: async (context, input) => {
7046
+ const interaction2 = cliInteraction(context);
7047
+ const registry = await registryOf(context);
7048
+ const argument = repositoryArgument(input, interaction2);
7049
+ const repository = qualifiedRepository(argument.repository, registry);
7050
+ if (!argument.tag) {
7051
+ const message = "Name the tag to delete, such as trainer:v1.";
7052
+ if (interaction2)
7053
+ interaction2.usage(message, { code: "tag_required", field: "tag" });
7054
+ throw new Error(message);
7055
+ }
7056
+ const target = { repository, tag: argument.tag };
7057
+ if (interaction2) {
7058
+ if (!input.yes) {
7059
+ const approved = await interaction2.review({
7060
+ title: "Delete this image tag?",
7061
+ terms: [
7062
+ { label: "Image", value: `${registry.host}/${repository}:${argument.tag}` },
7063
+ {
7064
+ label: "Effect",
7065
+ value: "Pulls of this tag stop working; clusters drop their copy within a minute."
7066
+ }
7067
+ ],
7068
+ prompt: "Delete it?"
7069
+ });
7070
+ if (!approved) {
7071
+ return interaction2.result({
7072
+ data: target,
7073
+ outcome: { class: "cancelled", phase: "review" },
7074
+ presentation: { lines: ["Nothing was deleted."] }
7075
+ });
7076
+ }
7077
+ }
7078
+ } else if (!context.confirmed) {
7079
+ return preview("registry.tags.delete", target);
7080
+ }
7081
+ await context.fetch(`${REGISTRY_PATH}/tags?${new URLSearchParams(target)}`, {
7082
+ method: "DELETE"
7083
+ });
7084
+ const deleted = { deleted: true, ...target };
7085
+ if (!interaction2)
7086
+ return deleted;
7087
+ return interaction2.result({
7088
+ data: deleted,
7089
+ presentation: { lines: [`Deleted ${shortName(repository, registry)}:${argument.tag}.`] }
7090
+ });
7091
+ }
7092
+ });
7093
+ var registryUsageCapability = defineCapability({
7094
+ id: "registry.usage",
7095
+ domain: "registry",
7096
+ roles: ["user"],
7097
+ description: "Show the bytes the organization's tagged images occupy in its container registry, each layer counted once.",
7098
+ mutation: "read",
7099
+ http: { method: "GET", path: `${REGISTRY_PATH}/usage` },
7100
+ input: emptyInput4,
7101
+ cli: {
7102
+ command: ["registry", "usage"],
7103
+ vnext: {
7104
+ audience: "customer",
7105
+ category: "resource",
7106
+ order: 604,
7107
+ outcome: "Show how much registry storage your images use.",
7108
+ human: "ornn registry usage",
7109
+ automation: "ornn registry usage --format json",
7110
+ related: ["registry repositories list"]
7111
+ }
7112
+ },
7113
+ slack: false,
7114
+ execute: async (context) => {
7115
+ const usage = await context.fetch(`${REGISTRY_PATH}/usage`, { method: "GET" });
7116
+ const interaction2 = cliInteraction(context);
7117
+ if (!interaction2)
7118
+ return usage;
7119
+ return interaction2.result({
7120
+ data: usage,
7121
+ presentation: { lines: [`Storage used: ${formatBytes(usage.bytes)}`] }
7122
+ });
7123
+ }
7124
+ });
7125
+ var registryCopiesListCapability = defineCapability({
7126
+ id: "registry.copies.list",
7127
+ domain: "registry",
7128
+ roles: ["user"],
7129
+ description: "List, for each of the organization's clusters, the registry tags its own copy holds now and the digest it holds them at, so a push or delete can be followed until every cluster has it.",
7130
+ mutation: "read",
7131
+ http: { method: "GET", path: `${REGISTRY_PATH}/caches` },
7132
+ input: emptyInput4,
7133
+ cli: {
7134
+ command: ["registry", "copies", "list"],
7135
+ vnext: {
7136
+ audience: "customer",
7137
+ category: "resource",
7138
+ order: 605,
7139
+ outcome: "Show which tags each of your clusters already holds.",
7140
+ human: "ornn registry copies list",
7141
+ automation: "ornn registry copies list --format json",
7142
+ related: ["registry tags list"]
7143
+ }
7144
+ },
7145
+ slack: false,
7146
+ execute: async (context) => context.fetch(`${REGISTRY_PATH}/caches`, { method: "GET" })
7147
+ });
7148
+ var registryLoginCapability = defineCapability({
7149
+ id: "registry.login",
7150
+ domain: "registry",
7151
+ roles: ["user"],
7152
+ description: "Log Docker on this machine in to the organization's container registry, with a read-write API key the CLI creates for it.",
7153
+ mutation: "local",
7154
+ input: emptyInput4,
7155
+ cli: {
7156
+ command: ["registry", "login"],
7157
+ vnext: {
7158
+ audience: "customer",
7159
+ category: "resource",
7160
+ order: 599,
7161
+ outcome: "Log Docker in to your organization's registry.",
7162
+ human: "ornn registry login",
7163
+ automation: "ornn registry login --format json",
7164
+ related: ["registry show"]
7165
+ }
7166
+ },
7167
+ mcp: false,
7168
+ slack: false,
7169
+ execute: async (context, input) => {
7170
+ const interaction2 = context.cli?.interaction;
7171
+ if (!interaction2?.registry) {
7172
+ throw new Error("ornn registry login runs only in the Ornn CLI.");
7173
+ }
7174
+ return interaction2.registry.call(interaction2, "registry.login", input);
7175
+ }
7176
+ });
7177
+ var registryCapabilities = [
7178
+ registryLoginCapability,
7179
+ registryShowCapability,
7180
+ registryRepositoriesListCapability,
7181
+ registryTagsListCapability,
7182
+ registryTagsDeleteCapability,
7183
+ registryUsageCapability,
7184
+ registryCopiesListCapability
7185
+ ];
7186
+
7187
+ // ../../packages/capabilities/dist/capabilities/reservation-list.js
7188
+ import { z as z29 } from "zod";
7189
+ var reservationListInput = z29.object({
7190
+ customerId: z29.string().uuid().optional(),
7191
+ listingId: z29.string().uuid().optional(),
7192
+ listingTermId: z29.string().uuid().optional(),
7193
+ status: z29.enum(["confirmed", "active", "completed", "cancelled"]).optional(),
7194
+ cursor: z29.string().optional(),
7195
+ limit: z29.number().int().min(1).max(100).optional()
6864
7196
  });
6865
7197
  var reservationListCapability = defineCapability({
6866
7198
  id: "reservation.list",
@@ -6912,20 +7244,20 @@ var reservationListCapability = defineCapability({
6912
7244
  });
6913
7245
 
6914
7246
  // ../../packages/capabilities/dist/capabilities/volumes.js
6915
- import { z as z29 } from "zod";
6916
- var storageCliInput = z29.object({
6917
- $positionals: z29.array(z29.string()).optional(),
6918
- contentType: z29.string().optional(),
6919
- cursor: z29.string().optional(),
6920
- idempotencyKey: z29.string().optional(),
6921
- limit: z29.union([z29.string(), z29.number()]).optional(),
6922
- name: z29.string().optional(),
6923
- output: z29.string().optional(),
6924
- overwrite: z29.boolean().optional(),
6925
- path: z29.string().optional(),
6926
- prefix: z29.string().optional(),
6927
- source: z29.string().optional(),
6928
- yes: z29.boolean().optional()
7247
+ import { z as z30 } from "zod";
7248
+ var storageCliInput = z30.object({
7249
+ $positionals: z30.array(z30.string()).optional(),
7250
+ contentType: z30.string().optional(),
7251
+ cursor: z30.string().optional(),
7252
+ idempotencyKey: z30.string().optional(),
7253
+ limit: z30.union([z30.string(), z30.number()]).optional(),
7254
+ name: z30.string().optional(),
7255
+ output: z30.string().optional(),
7256
+ overwrite: z30.boolean().optional(),
7257
+ path: z30.string().optional(),
7258
+ prefix: z30.string().optional(),
7259
+ source: z30.string().optional(),
7260
+ yes: z30.boolean().optional()
6929
7261
  }).strict();
6930
7262
  function storageExecutor(context) {
6931
7263
  const interaction2 = context.cli?.interaction;
@@ -7098,22 +7430,22 @@ function storageDrivePath(driveId, action) {
7098
7430
  function reservationStorageRoute(reservationId, suffix) {
7099
7431
  return `/v1/workflows/compute/nodes/reservations/${encodeURIComponent(reservationId)}/${suffix}`;
7100
7432
  }
7101
- var reservationInput = z29.object({ reservationId: z29.string() });
7102
- var reservationWrite = reservationInput.extend({ confirm: z29.boolean().optional() });
7103
- var driveInput = z29.object({ driveId: z29.string() });
7104
- var driveWrite = driveInput.extend({ confirm: z29.boolean().optional() });
7105
- var bucketConnectInput = z29.object({
7106
- provider: z29.enum(["gcs", "s3", "r2"]),
7107
- bucket: z29.string(),
7108
- name: z29.string().optional(),
7109
- prefix: z29.string().optional(),
7110
- region: z29.string().optional(),
7111
- endpointUrl: z29.string().optional(),
7112
- accountId: z29.string().optional(),
7113
- accessKeyId: z29.string().optional(),
7114
- secretAccessKey: z29.string().optional(),
7115
- readOnly: z29.boolean().optional(),
7116
- confirm: z29.boolean().optional()
7433
+ var reservationInput = z30.object({ reservationId: z30.string() });
7434
+ var reservationWrite = reservationInput.extend({ confirm: z30.boolean().optional() });
7435
+ var driveInput = z30.object({ driveId: z30.string() });
7436
+ var driveWrite = driveInput.extend({ confirm: z30.boolean().optional() });
7437
+ var bucketConnectInput = z30.object({
7438
+ provider: z30.enum(["gcs", "s3", "r2"]),
7439
+ bucket: z30.string(),
7440
+ name: z30.string().optional(),
7441
+ prefix: z30.string().optional(),
7442
+ region: z30.string().optional(),
7443
+ endpointUrl: z30.string().optional(),
7444
+ accountId: z30.string().optional(),
7445
+ accessKeyId: z30.string().optional(),
7446
+ secretAccessKey: z30.string().optional(),
7447
+ readOnly: z30.boolean().optional(),
7448
+ confirm: z30.boolean().optional()
7117
7449
  }).refine((input) => !(input.provider === "gcs" && (input.accessKeyId || input.secretAccessKey)), {
7118
7450
  message: "Access key credentials are only supported for S3-compatible buckets."
7119
7451
  }).refine((input) => Boolean(input.accessKeyId) === Boolean(input.secretAccessKey), {
@@ -7132,7 +7464,7 @@ var storageVerbCapabilities = [
7132
7464
  method: "POST",
7133
7465
  path: "/v1/workflows/compute/nodes/reservations/{reservationId}/storage-deployment"
7134
7466
  },
7135
- input: reservationWrite.extend({ driveId: z29.string(), readOnly: z29.boolean().optional() }),
7467
+ input: reservationWrite.extend({ driveId: z30.string(), readOnly: z30.boolean().optional() }),
7136
7468
  slack: false,
7137
7469
  execute: (ctx, input) => ctx.fetch(reservationStorageRoute(input.reservationId, "storage-deployment"), {
7138
7470
  method: "POST",
@@ -7182,8 +7514,8 @@ var storageVerbCapabilities = [
7182
7514
  path: "/v1/workflows/compute/nodes/reservations/{reservationId}/filesystem-deployment"
7183
7515
  },
7184
7516
  input: reservationWrite.extend({
7185
- performanceTier: z29.enum(["standard", "performance", "enterprise"]),
7186
- capacityGib: z29.number().int().positive()
7517
+ performanceTier: z30.enum(["standard", "performance", "enterprise"]),
7518
+ capacityGib: z30.number().int().positive()
7187
7519
  }),
7188
7520
  slack: false,
7189
7521
  execute: (ctx, input) => ctx.fetch(reservationStorageRoute(input.reservationId, "filesystem-deployment"), {
@@ -7214,7 +7546,7 @@ var storageVerbCapabilities = [
7214
7546
  description: "List reservations that can receive a storage deploy, grouped the same way as the console picker.",
7215
7547
  mutation: "read",
7216
7548
  http: { method: "GET", path: "/v1/orchestrator/storage-targets" },
7217
- input: z29.object({}),
7549
+ input: z30.object({}),
7218
7550
  slack: false,
7219
7551
  execute: (ctx) => ctx.fetch("/v1/orchestrator/storage-targets", { method: "GET" })
7220
7552
  }),
@@ -7225,9 +7557,9 @@ var storageVerbCapabilities = [
7225
7557
  description: "List a page of storage volumes, newest updated first. Pass next_cursor as cursor to continue.",
7226
7558
  mutation: "read",
7227
7559
  http: { method: "GET", path: DRIVES_ROUTE },
7228
- input: z29.object({
7229
- limit: z29.number().int().min(1).max(100).optional(),
7230
- cursor: z29.string().optional()
7560
+ input: z30.object({
7561
+ limit: z30.number().int().min(1).max(100).optional(),
7562
+ cursor: z30.string().optional()
7231
7563
  }),
7232
7564
  mcp: { name: "storage_volumes_list" },
7233
7565
  slack: false,
@@ -7257,10 +7589,10 @@ var storageVerbCapabilities = [
7257
7589
  description: "Create a storage volume (drive), optionally cloned from an existing source drive.",
7258
7590
  mutation: "preview-confirm",
7259
7591
  http: { method: "POST", path: DRIVES_ROUTE },
7260
- input: z29.object({
7261
- name: z29.string(),
7262
- sourceDriveId: z29.string().optional(),
7263
- confirm: z29.boolean().optional()
7592
+ input: z30.object({
7593
+ name: z30.string(),
7594
+ sourceDriveId: z30.string().optional(),
7595
+ confirm: z30.boolean().optional()
7264
7596
  }),
7265
7597
  mcp: { name: "storage_volumes_create" },
7266
7598
  slack: false,
@@ -7362,7 +7694,7 @@ var storageVerbCapabilities = [
7362
7694
  description: "Update a connected S3-compatible bucket's access key credentials.",
7363
7695
  mutation: "preview-confirm",
7364
7696
  http: { method: "PATCH", path: `${STORAGE_DRIVES_ROUTE}/{driveId}/source-credentials` },
7365
- input: driveWrite.extend({ accessKeyId: z29.string(), secretAccessKey: z29.string() }),
7697
+ input: driveWrite.extend({ accessKeyId: z30.string(), secretAccessKey: z30.string() }),
7366
7698
  mcp: { name: "storage_buckets_update_credentials" },
7367
7699
  slack: false,
7368
7700
  execute: (ctx, input) => ctx.fetch(storageDrivePath(input.driveId, "source-credentials"), {
@@ -7382,9 +7714,9 @@ var storageCompositionCapabilities = [
7382
7714
  description: "List a page of connected external buckets.",
7383
7715
  mutation: "read",
7384
7716
  http: { method: "GET", path: DRIVES_ROUTE },
7385
- input: z29.object({
7386
- limit: z29.number().int().min(1).max(100).optional(),
7387
- cursor: z29.string().optional()
7717
+ input: z30.object({
7718
+ limit: z30.number().int().min(1).max(100).optional(),
7719
+ cursor: z30.string().optional()
7388
7720
  }),
7389
7721
  mcp: false,
7390
7722
  slack: false,
@@ -7402,10 +7734,10 @@ var storageCompositionCapabilities = [
7402
7734
  description: "List one page of a storage volume's contents.",
7403
7735
  mutation: "read",
7404
7736
  http: { method: "GET", path: `${DRIVES_ROUTE}/{driveId}/contents` },
7405
- input: z29.object({
7406
- driveId: z29.string(),
7407
- path: z29.string().optional(),
7408
- cursor: z29.union([z29.string(), z29.number()]).optional()
7737
+ input: z30.object({
7738
+ driveId: z30.string(),
7739
+ path: z30.string().optional(),
7740
+ cursor: z30.union([z30.string(), z30.number()]).optional()
7409
7741
  }),
7410
7742
  mcp: false,
7411
7743
  slack: false,
@@ -7464,6 +7796,7 @@ var catalog = [
7464
7796
  machinePushKeysCapability,
7465
7797
  ...machineMetricsCapabilities,
7466
7798
  ...billingCapabilities,
7799
+ ...registryCapabilities,
7467
7800
  ...adminNodeLifecycleCapabilities
7468
7801
  ])),
7469
7802
  ...adminCapabilities.filter((capability) => capability.id === "nodes.health"),