@ornncompute/cli 1.0.109 → 1.0.112

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
@@ -125,6 +129,9 @@ billing stay in the web app. Launch consumes already allocated
125
129
  capacity; internal reservation lookups remain necessary for access and
126
130
  ownership.
127
131
 
132
+ Where upfront card checkout is enabled, complete Fixed term purchases in the
133
+ console to review the full price and finish any bank verification.
134
+
128
135
  Only admins can create primary listings or reservations through
129
136
  `ornn admin capacity-offers create` and `ornn admin reservations create`.
130
137
  They post to the role-aware `POST /commerce/v2/listings` and Markets
@@ -458,8 +465,8 @@ request conflicts, and an expired incomplete request requires a new key.
458
465
  The upload replay contract requires the matching gateway/orchestrator release;
459
466
  see [the service contract](../../services/orchestrator/README.md#file-upload-replay-and-usage).
460
467
 
461
- Staff can use `ornn admin ssh <node-id>` for certificate access on explicitly
462
- opted-in nodes. It requires an interactive staff login, creates a temporary
468
+ Staff can use `ornn admin ssh <node-id>` for certificate access on nodes that trust
469
+ the environment's SSH CA. It requires an interactive staff login, creates a temporary
463
470
  local key, obtains a 15-minute certificate through the gateway and launches
464
471
  OpenSSH with normal host-key verification. Temporary files are removed when
465
472
  the command exits. Shared and per-node key access remain available.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ornncompute/cli",
3
- "version": "1.0.109",
3
+ "version": "1.0.112",
4
4
  "description": "Command-line interface for Ornn compute access workflows.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -37,6 +37,7 @@ import {
37
37
  writeExternalBucketResultHuman,
38
38
  } from "./external-bucket-commands.mjs";
39
39
  import { executeEvidenceCommand, supplierOwnedRecord } from "./evidence-commands.mjs";
40
+ import { executeRegistryCommand } from "./registry-commands.mjs";
40
41
  import {
41
42
  executeKubernetesClusterCommand,
42
43
  kubernetesConnectModeHandler,
@@ -958,6 +959,13 @@ async function executeCapability(
958
959
  interaction: this,
959
960
  });
960
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
+ },
961
969
  storage(command, storageInput) {
962
970
  return executeStorageCommand(command, storageInput, {
963
971
  env: io.env,
@@ -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
+ }
@@ -72,7 +72,7 @@ var adminSshCapability = defineCapability({
72
72
  audience: "admin",
73
73
  category: "journey",
74
74
  arguments: "semantic",
75
- outcome: "Open an SSH session to one opted-in node with a 15-minute certificate.",
75
+ outcome: "Open an SSH session to a node that trusts the SSH CA with a 15-minute certificate.",
76
76
  human: "ornn admin ssh <node-id>",
77
77
  automation: "Requires an interactive terminal."
78
78
  }
@@ -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"),